CFB Mode

From Crypto++ Wiki
(Redirected from CFB)
Jump to navigation Jump to search
CFB Mode
Documentation
#include <cryptopp/modes.h>

CFB Mode, or Cipher Feedback mode, is a mode of operation for block ciphers. CFB was originally specified by NIST in FIPS 81. The standard, issued in 1980, only offers confidentiality. Other modes, such as CCM and GCM, offer authenticated encryption which includes an integrity assurance over the encrpyted data.

CFB does not require the plain text be padded to the block size of the cipher. For additional information on this mode, see Block Cipher Modes of Operation.

Crypto++ offers several modes of operation, including ECB, CBC, OFB, CFB, CBC-CTS, CTR, XTS, CCM, EAX, GCM and OCB.

Crypto++ does not provide a way to retrieve the current IV or counter used for encryption or decryption. If you need the current IV or counter then you need to manage it yourself. Some ciphers allow you to seek a number of bytes or blocks in the stream.

If you are used to working in languages like Java or libraries like OpenSSL, then you might want to visit the Init-Update-Final wiki page. Crypto++ provides the transformation model, but its not obvious because its often shrouded behind Pipelines.

Note: if your project is using encryption alone to secure your data, encryption alone is usually not enough. Please take a moment to read Authenticated Encryption and consider using an algorithm or mode like CCM, GCM, EAX or ChaCha20Poly1305.

Sample Program

There are three sample programs for CFB mode. The samples use filters in a pipeline). Pipelining is a high level abstraction and it handles buffering input, buffering output and padding for you. The first sample shows the basic use of a pipeline. The second sample shows how to change padding. The third shows how to manually insert into a filter.

If you are benchmarking then you may want to visit Benchmarks | Sample Program . It shows you how to use StreamTransformation and its ProcessString method to process multiple blocks at a time. ProcessString eventually calls BlockTransformation and ProcessBlock. Calling a cipher's ProcessString or ProcessBlock eventually call ProcessAndXorBlock or AdvancedProcessBlocks, and they are the lowest level API you can use.

AutoSeededRandomPool prng;

SecByteBlock key(AES::DEFAULT_KEYLENGTH);
prng.GenerateBlock( key, key.size() );

byte iv[ AES::BLOCKSIZE ];
prng.GenerateBlock( iv, sizeof(iv) );

string plain = "CFB Mode Test";
string cipher, encoded, recovered;

/*********************************\
\*********************************/

try
{
    cout << "plain text: " << plain << endl;

    CFB_Mode< AES >::Encryption enc;
    enc.SetKeyWithIV( key, key.size(), iv );

    // CFB mode must not use padding. Specifying
    //  a scheme will result in an exception
    StringSource ss1( plain, true, 
        new StreamTransformationFilter( enc,
            new StringSink( cipher )
        ) // StreamTransformationFilter      
    ); // StringSource
}
catch( CryptoPP::Exception& e )
{
    cerr << e.what() << endl;
    exit(1);
}

/*********************************\
\*********************************/

// Pretty print cipher text
StringSource ss2( cipher, true,
    new HexEncoder(
        new StringSink( encoded )
    ) // HexEncoder
); // StringSource
cout << "cipher text: " << encoded << endl;

/*********************************\
\*********************************/

try
{
    CFB_Mode< AES >::Decryption dec;
    dec.SetKeyWithIV( key, key.size(), iv );

    // The StreamTransformationFilter removes
    //  padding as required.
    StringSource ss3( cipher, true, 
        new StreamTransformationFilter( dec,
            new StringSink( recovered )
        ) // StreamTransformationFilter
    ); // StringSource

    cout << "recovered text: " << recovered << endl;
}
catch( CryptoPP::Exception& e )
{
    cerr << e.what() << endl;
    exit(1);
}

A typical output is shown below. Note that each run will produce different results because the key and initialization vector are randomly generated.

$ ./Driver.exe 
key: CC8CC446D001133ED4E0729F12AE0A5F
iv: 52941361970066391CD17C50408ECB0E
plain text: CFB Mode Test
cipher text: 5E01512F851B3D3B6562B59B34
recovered text: CFB Mode Test

Feedback Size

Crypto++ uses the full blocksize for the feedback size by default. Other libraries sometimes use a different size and it leads to interoperability issues. For example, Mcrypt and .Net use a smaller feedback size. Using less than the full block size for the feedback size can reduce the security in some modes of operation. If given a choice, you should probably prefer libraries like Mcrypt and .Net use the full block size rather than a smaller feedback size.

In Crypto++ the feedback size can be changed in one of two ways. First, you can use NameValuePairs and set the parameter with a call to SetKey. Second, you can use an external cipher, like CFB_Mode_ExternalCipher. CFB_Mode_ExternalCipher has a dedicated parameter for feedback size.

Below are examples of using the first method to change the feedback size. To help see the differences among different feedback sizes, a null key and iv was used (i.e, a string of 0's).

SecByteBlock key(AES::DEFAULT_KEYLENGTH), iv(AES::BLOCKSIZE);
memset(key, 0x00, key.size());
memset(iv, 0x00, iv.size());

string plain = "CFB Mode Test";
string cipher, encoded, recovered;

/*********************************\
\*********************************/

try
{
   cout << "plain text: " << plain << endl;

   CFB_Mode< AES >::Encryption enc;
   enc.SetKeyWithIV( key, key.size(), iv );

   // CFB mode must not use padding. Specifying
   //  a scheme will result in an exception
   StringSource ss1( plain, true, 
      new StreamTransformationFilter( enc,
         new StringSink( cipher )
      ) // StreamTransformationFilter      
   ); // StringSource
}
catch( CryptoPP::Exception& ex )
{
   cerr << ex.what() << endl;
   exit(1);
}

/*********************************\
\*********************************/

// Pretty print cipher text
StringSource ss2( cipher, true,
   new HexEncoder(
      new StringSink( encoded )
   ) // HexEncoder
); // StringSource
cout << "cipher text: " << encoded << endl;

/*********************************\
\*********************************/

try
{
   CFB_Mode< AES >::Decryption dec;
   dec.SetKeyWithIV( key, key.size(), iv );

   // The StreamTransformationFilter removes
   //  padding as required.
   StringSource ss3( cipher, true, 
      new StreamTransformationFilter( dec,
         new StringSink( recovered )
      ) // StreamTransformationFilter
   ); // StringSource

   cout << "recovered text: " << recovered << endl;
}
catch( CryptoPP::Exception& ex )
{
   cerr << ex.what() << endl;
   exit(1);
}

The program above uses the full feedback size and produces the following output. Its really no different than the earlier examples.

$ ./test.exe
plain text: CFB Mode Test
cipher text: 25AF09F4A2E5485EA8189F2ABE
recovered text: CFB Mode Test

The next example uses NameValuePairs to set the feedback size to 8-bits. It differs from earlier examples by (1) using AlgorithmParameters (the NameValuePairs), and (2) it calls SetKey rather than SetKeyWithIV.

SecByteBlock key(AES::DEFAULT_KEYLENGTH), iv(AES::BLOCKSIZE);
memset(key, 0x00, key.size());
memset(iv, 0x00, iv.size());

AlgorithmParameters params = MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
                                      (Name::IV(), ConstByteArrayParameter(iv));

string plain = "CFB Mode Test";
string cipher, encoded, recovered;

/*********************************\
\*********************************/

try
{
   cout << "plain text: " << plain << endl;

   CFB_Mode< AES >::Encryption enc;
   enc.SetKey( key, key.size(), params );

   // CFB mode must not use padding. Specifying
   //  a scheme will result in an exception
   StringSource ss1( plain, true, 
      new StreamTransformationFilter( enc,
         new StringSink( cipher )
      ) // StreamTransformationFilter      
   ); // StringSource
}
catch( CryptoPP::Exception& ex )
{
   cerr << ex.what() << endl;
   exit(1);
}

/*********************************\
\*********************************/

// Pretty print cipher text
StringSource ss2( cipher, true,
   new HexEncoder(
      new StringSink( encoded )
   ) // HexEncoder
); // StringSource
cout << "cipher text: " << encoded << endl;

/*********************************\
\*********************************/

try
{
   CFB_Mode< AES >::Decryption dec;
   dec.SetKey( key, key.size(), params );

   // The StreamTransformationFilter removes
   //  padding as required.
   StringSource ss3( cipher, true, 
      new StreamTransformationFilter( dec,
         new StringSink( recovered )
      ) // StreamTransformationFilter
   ); // StringSource

   cout << "recovered text: " << recovered << endl;
}
catch( CryptoPP::Exception& ex )
{
   cerr << ex.what() << endl;
   exit(1);
}

The program above produces the following output. Notice the ciphertext differs at the second octet due to the smaller feedback size.

$ ./test.exe
plain text: CFB Mode Test
cipher text: 2506FBCA6F97DC7653B414C291
recovered text: CFB Mode Test

Downloads

AES-CFB-Filter.zip - Demonstrates encryption and decryption using AES in CFB mode with filters