CFB Mode

From Crypto++ Wiki
Jump to: navigation, search
CFB Mode
Documentation
#include <cryptopp/modes.h>

CFB Mode is cipher feedback. 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.

If you are used to working in languages like Jave 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.

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 understand why you should prefer to use CCM, GCM, or EAX over other modes, such as CBC or CTR.

Sample Program

The sample program below demonstrates AES in CFB mode using filters (see pipelining). Though the key is declared on the stack, a SecByteBlock is used to ensure the sensitive material is zeroized. Similar could be used for both plain text and recovered text.

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