CTR Mode
From Crypto++ Wiki
CTR is counter mode. CTR mode was proposed by Lipmaa, Rogaway, and Wagner; and 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 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.
[edit] 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];
}
[edit] Sample Program
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( 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( 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( 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
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());
[edit] 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
AES-CTR-Filter.zip - Demonstrates encryption and decryption using AES in CTR mode with filters
Camellia-CTR-Filter.zip - Demonstrates encryption and decryption using Camellia in CTR mode with filters