CTR Mode

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

CTR is counter mode. CTR mode was standardized in 2001 by NIST in SP 800-38A. CTR mode uses a counter rather than a traditional IV. The counter has additional properties, including a nonce and initial counter block. The mode does not require padding the plain text to the block size of the cipher.

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.

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

Counter Increment

Broadly speaking, NIST specifies two types of counters. First is a counter which is made up of a nonce and counter. The nonce is random, and the remaining bytes are counter bytes (which are incremented). For example, a 16 byte block cipher might use the high 8 bytes as a nonce, and the low 8 bytes as a counter. Second is a counter block, where all bytes are counter bytes and can be incremented as carries are generated. For example, in a 16 byte block cipher, all 16 bytes are counter bytes.

Crypto++ uses the second method, which means the entire byte block is treated as counter bytes. Counter mode is declared in modes.h:

class CTR_ModePolicy : public ModePolicyCommonTemplate<AdditiveCipherAbstractPolicy>
{
public:
    bool CipherIsRandomAccess() const {return true;}
    IV_Requirement IVRequirement() const {return RANDOM_IV;}
    static const char * StaticAlgorithmName() {return "CTR";}

protected:
    virtual void IncrementCounterBy256();
    ...
};

The implementation increments the entire counter block. modes.cpp offers IncrementCounterBy256:

void CTR_ModePolicy::IncrementCounterBy256()
{
    IncrementCounterByOne(m_counterArray, BlockSize()-1);
}

IncrementCounterByOne is located in misc.h, and it performs:

inline void IncrementCounterByOne(byte *inout, unsigned int s)
{
    for (int i=s-1, carry=1; i>=0 && carry; i--)
        carry = !++inout[i];
}

Sample Program

Below are a few sample programs.

Pipelines

The sample program below demonstrates AES in CTR 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 ctr[ AES::BLOCKSIZE ];
prng.GenerateBlock( ctr, sizeof(ctr) );

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

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

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

    CTR_Mode< AES >::Encryption e;
    e.SetKeyWithIV( key, key.size(), ctr );

    // The StreamTransformationFilter adds padding
    //  as required. ECB and CBC Mode must be padded
    //  to the block size of the cipher. CTR does not.
    StringSource ss1( plain, true, 
        new StreamTransformationFilter( e,
            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
{
    CTR_Mode< AES >::Decryption d;
    d.SetKeyWithIV( key, key.size(), ctr );

    // The StreamTransformationFilter removes
    //  padding as required.
    StringSource ss3( cipher, true, 
        new StreamTransformationFilter( d,
            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 initial counter block are randomly generated.

$ ./Driver.exe 
key: F534FC7F0565A8CF1629F01DB31AE3CA
counter: A4D16CBC010DACAA2E54FA676B57A345
plain text: CTR Mode Test
cipher text: 12455EDB41020E6D751F207EE6
recovered text: CTR Mode Test

Non-pipeline

To manually insert bytes into the filter, perform multiple Puts. Though Get is used below, a StringSink could easily be attached and save the administrivia.

const size_t SIZE = 16 * 4;
string plain(SIZE, 0x00);

for(size_t i = 0; i < plain.size(); i++)
    plain[i] = 'A' + (i%26);
...

CTR_Mode < AES >::Encryption encryption(key, sizeof(key), iv);
StreamTransformationFilter encryptor(encryption, NULL);

for(size_t j = 0; j < plain.size(); j++)
    encryptor.Put((byte)plain[j]);

encryptor.MessageEnd();
size_t ready = encryptor.MaxRetrievable();

string cipher(ready, 0x00);
encryptor.Get((byte*) &cipher[0], cipher.size());

Seeking

The following program seeks in the AES/CTR stream. Using a Crypto++ Pipeline is a tad bit awkward because Discard or Skip on a Source does not work as expected. You have to Pump data into "nothing" under the current implementation. Also see Skip'ing on a Source does not work as expected on Stack Overflow.

Below is an example of using AES/CTR and seeking in the stream. It needs to perform a "two part" seek. First, it discards bytes on the Source called cipher. Second, it seeks in the keystream on the encryption object called enc to synchronize the counter. Once the seek is performed, the remainder of the cipher text is decrypted by calling PumpAll(), which pumps the remainder of the data through the pipeline.

#include "modes.h"
#include "aes.h"
using namespace CryptoPP;
    
int main(int argc, char* argv[])
{
    string plain = "Now is the time for all good men to come to the aide of their country";
    	
    byte key[AES::DEFAULT_KEYLENGTH] = {0};
    byte nonce[AES::BLOCKSIZE] = {0};
    	
    CTR_Mode<AES>::Encryption enc;
    enc.SetKeyWithIV(key, sizeof(key), nonce, sizeof(nonce));
    	
    string cipher;
    StringSource ss1(plain, true, new StreamTransformationFilter(enc, new StringSink(cipher)));
    
    for(size_t i=0; i<cipher.size(); i++)
    {	
        CTR_Mode<AES>::Decryption dec;
        dec.SetKeyWithIV(key, sizeof(key), nonce, sizeof(nonce));
    		
        StringSource ss2(cipher, false);
        ss2.Pump(i);
        dec.Seek(i);
    		
        string recover;
        StreamTransformationFilter stf(dec, new StringSink(recover));
    
        // Attach the decryption filter after seeking
        ss2.Attach(new Redirector(stf));
        ss2.PumpAll();
    		
        cout << i << ": " << recover << endl;
    }
    
    return 0;
}

Here is the result:

$ ./test.exe 
 0: Now is the time for all good men to come to the aide of their country
 1: ow is the time for all good men to come to the aide of their country
 2: w is the time for all good men to come to the aide of their country
 3:  is the time for all good men to come to the aide of their country
 4: is the time for all good men to come to the aide of their country
 5: s the time for all good men to come to the aide of their country
 6:  the time for all good men to come to the aide of their country
 7: the time for all good men to come to the aide of their country
 8: he time for all good men to come to the aide of their country
 9: e time for all good men to come to the aide of their country
10:  time for all good men to come to the aide of their country
...
58: eir country
59: ir country
60: r country
61:  country
62: country
63: ountry
64: untry
65: ntry
66: try
67: ry
68: y

Downloads

IDEA-CTR-Filter.zip - Demonstrates encryption and decryption using IDEA in CTR mode with filters

Blowfish-CTR-Filter.zip - Demonstrates encryption and decryption using Blowfish in CTR mode with filters

Twofish-CTR-Filter.zip - Demonstrates encryption and decryption using Twofish in CTR mode with filters

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

Serpent-CTR-Filter.zip - Demonstrates encryption and decryption using Serpent in CTR mode with filters

Camellia-CTR-Filter.zip - Demonstrates encryption and decryption using Camellia in CTR mode with filters