Using the Symmetric Ciphers

This section provides several code samples for encrypting and decrypting arbitrary data buffers using the symmetric ciphers provided by the CDK.

The AES, TDES, and EES examples illustrate the processing of a single block of data. Obviously, one can process successive blocks by placing the crypt() call within a while or for loop. In practice, however, when using these block ciphers you'll need to pad out your data to a multiple of the cipher's block size. Further information on padding appears in the section Padding Before Encryption at the bottom of this page.

The sample code fragments provided in this section

all implement the following pseudocode:

  1. generate a random session key of the proper length
  2. create an instance of the desired cipher object
  3. initialize the cipher object for encryption
  4. encrypt a single block of plaintext
  5. clear the cipher object
  6. reinitialize the cipher object for decryption
  7. decrypt the ciphertext block


AES Encryption/Decryption, ECB Mode

// generate a random 192-bit (24-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(24);

// instantiate an AES object; initialize it to perform ECB encryption
cdk::AES aesi;
aesi.init(AES::ENCRYPT, +strKey, strKey.c_str());

// encrypt a block of plaintext
char *pbuf ="0123456789abcdef";   // sample plaintext
char cbuf[16];                    // output buffer for ciphertext
aesi.crypt(16, pbuf, cbuf);       // cbuf now contains ciphertext

// reinitialize the AES object to perform decryption
aesi.clear();
aesi.init(AES::DECRYPT, +strKey, strKey.c_str());

// decrypt a block of ciphertext
char obuf[16];                   // buffer for plaintext
aesi.crypt(16, cbuf, obuf);      // obuf now contains copy of plaintext


AES Encryption/Decryption, CBC Mode

// generate a random 192-bit (24-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(24);
cdk::str strIV = prngi.gens(16); // need a 16-byte IV for AES-CBC

// instantiate an AES object; initialize it to perform CBC encryption
cdk::AES aesi;
aesi.init(AES::ENCRYPT, +strKey, strKey.c_str(), AES::CBC, strIV.c_str());

// encrypt a block of plaintext
char *pbuf ="0123456789abcdef";   // sample plaintext
char cbuf[16];                    // output buffer for ciphertext
aesi.crypt(16, pbuf, cbuf);       // cbuf now contains ciphertext

// reinitialize the AES object to perform decryption
aesi.clear();
aesi.init(AES::DECRYPT, +strKey, strKey.c_str(), AES::CBC, strIV.c_str());

// decrypt a block of ciphertext
char obuf[16];                   // buffer for plaintext
aesi.crypt(16, cbuf, obuf);      // obuf now contains copy of plaintext


TDES Encryption/Decryption, ECB Mode

// generate a random 192-bit (24-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(24);

// instantiate a DES object; initialize it to perform TDES-ECB encryption
cdk::DES desi;
desi.init(DES::ENCRYPT, +strKey, strKey.c_str(), DES::ALG_TDES);

// encrypt a block of plaintext
char *pbuf ="01234567";           // sample plaintext
char cbuf[8];                     // output buffer for ciphertext
desi.crypt(8, pbuf, cbuf);        // cbuf now contains ciphertext

// reinitialize the DES object to perform decryption
desi.clear();
desi.init(DES::DECRYPT, +strKey, strKey.c_str(), DES::ALG_TDES);

// decrypt a block of ciphertext
char obuf[8];                     // buffer for plaintext
desi.crypt(8, out, obuf);         // obuf now contains copy of plaintext


TDES Encryption/Decryption, CBC Mode

// generate a random 192-bit (24-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(24); 
cdk::str strIV = prngi.gens(8);  // need an 8-byte IV for TDES-CBC

// instantiate a DES object; initialize it to perform TDES-CBC encryption
cdk::DES desi;
desi.init(DES::ENCRYPT, +strKey, strKey.c_str(), DES::ALG_TDES, DES::CBC, strIV.c_str());

// encrypt a block of plaintext
char *pbuf ="01234567";           // sample plaintext
char cbuf[8];                     // output buffer for ciphertext
desi.crypt(8, pbuf, cbuf);        // cbuf now contains ciphertext

// reinitialize the DES object to perform decryption
desi.clear();
desi.init(DES::DECRYPT, +strKey, strKey.c_str(), DES::ALG_TDES, DES::CBC, strIV.c_str());

// decrypt a block of ciphertext
char obuf[8];                     // buffer for plaintext
desi.crypt(8, out, obuf);         // obuf now contains copy of plaintext


EES Encryption/Decryption, ECB Mode

// generate a random 80-bit (10-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(10);

// instantiate an EES object; initialize it to perform ECB encryption
cdk::EES eesi;
eesi.init(EES::ENCRYPT, +strKey, strKey.c_str());

// encrypt a block of plaintext
char *pbuf ="01234567";           // sample plaintext
char cbuf[8];                     // output buffer for ciphertext
eesi.crypt(8, pbuf, cbuf);        // cbuf now contains ciphertext

// reinitialize the EES object to perform decryption
eesi.clear();
eesi.init(EES::DECRYPT, +strKey, strKey.c_str());

// decrypt a block of ciphertext
char obuf[8];                     // buffer for plaintext
eesi.crypt(8, out, obuf);         // obuf now contains copy of plaintext


EES Encryption/Decryption, CBC Mode

// generate a random 80-bit (10-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(10);
cdk::str strIV = prngi.gens(8);   // need an 8-byte IV for EES-CBC

// instantiate an EES object; initialize it to perform CBC encryption
cdk::EES eesi;
eesi.init(EES::ENCRYPT, +strKey, strKey.c_str(), EES::CBC, strIV.c_str());

// encrypt the data
char *pbuf ="01234567";           // sample plaintext
char cbuf[8];                     // output buffer for ciphertext
eesi.crypt(8, pbuf, cbuf);        // cbuf now contains ciphertext

// reinitialize the EES object to perform decryption
eesi.clear();
eesi.init(EES::DECRYPT, +strKey, strKey.c_str(), EES::CBC, strIV.c_str());

// decrypt a block of ciphertext
char obuf[8];                     // buffer for plaintext
eesi.crypt(8, out, obuf);         // obuf now contains copy of plaintext


RC2 Encryption/Decryption, ECB Mode

// generate a random 128-bit (16-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(16);

// instantiate an RC2 object; initialize it to perform ECB encryption
cdk::RC2 rc2i;
rc2i.init(RC2::ENCRYPT, +strKey, strKey.c_str());

// encrypt a block of plaintext
char *pbuf ="01234567";           // sample plaintext
char cbuf[8];                     // output buffer for ciphertext
rc2i.crypt(8, pbuf, cbuf);        // cbuf now contains ciphertext

// reinitialize the RC2 object to perform decryption
rc2i.clear();
rc2i.init(RC2::DECRYPT, +strKey, strKey.c_str());

// decrypt a block of ciphertext
char obuf[8];                     // buffer for plaintext
rc2i.crypt(8, out, obuf);         // obuf now contains copy of plaintext


RC2 Encryption/Decryption, CBC Mode

// generate a random 128-bit (16-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(16);
cdk::str strIV = prngi.gens(8);   // need an 8-byte IV for RC2-CBC

// instantiate an RC2 object; initialize it to perform CBC encryption
cdk::RC2 rc2i;
rc2i.init(RC2::ENCRYPT, +strKey, strKey.c_str(), strIV.c_str());

// encrypt a block of plaintext
char *pbuf ="01234567";           // sample plaintext
char cbuf[8];                     // output buffer for ciphertext
rc2i.crypt(8, pbuf, cbuf);        // cbuf now contains ciphertext

// reinitialize the RC2 object to perform decryption
rc2i.clear();
rc2i.init(RC2::DECRYPT, +strKey, strKey.c_str(), strIV.c_str());

// decrypt a block of ciphertext
char obuf[8];                     // buffer for plaintext
rc2i.crypt(8, out, obuf);         // obuf now contains copy of plaintext


RC4 Encryption/Decryption

// generate a random 128-bit (16-byte) session key
cdk::PRNG prngi;
cdk::str strKey = prngi.gens(16);

// instantiate an RC2 object and initialize it
cdk::RC4 rc4i;
rc4i.init(+strKey, strKey.c_str());

// encrypt the plaintext
char *pbuf ="01234567abc";        // sample plaintext (arbitrary length)
char cbuf[11];                    // output buffer for ciphertext
rc4i.crypt(11, pbuf, cbuf);       // cbuf now contains ciphertext

// reinitialize the RC2 object to perform decryption
rc4i.init(+strKey, strKey.c_str());

// decrypt the ciphertext
char obuf[11];                    // buffer for plaintext
rc4i.crypt(11, out, obuf);        // obuf now contains copy of plaintext


Padding Before Encryption

In nearly all modes, the block ciphers AES, EES, DES, and RC2 require that the length of their inputs be a multiple of their respective block sizes. If the input data is not already of the appropriate length, you must pad it. (The only exceptions to this rule is CFB8 mode, since AES, EES, and TDES are essentially stream ciphers in this mode.)

NOTE: RC4 is a stream cipher so padding is not required.

A standard padding mechanism is specified in PKCS #5. It is relatively straightforward to implement, but since it is not exposed in the CDK the code and a use case are provided here. Note that you only need to pad the last block of your data.

cdk::str makep5(const cdk::str x, int n=8)
{
  // pad according to PKCS #5 (RFC 1423), n = 8 or 16
  cdk::str y = x;
  int len = n * ((+x + n)/n);
  cdk::str fill = cdk::single(n - (+x % n));
  while ( +y < len ) y += fill;
  return y;
}

cdk::str parsep5(const cdk::str x, int n=8)
{
  // strip padding according to PKCS #5 (RFC 1423)
  cdk::str strRetVal = cdk::str(0);
  if ( +x != 0 )
  {
    int pad = x[+x-1];
    if ( !(pad < 1 || pad > n) )
      strRetVal = x.trunc(+x-pad);
  }
  return strRetVal;
}

int main()
{
  int i;
  cdk::str strIn = "short";
  cdk::str strPadded;
  char szOut[16];
  cdk::PRNG prngi;
  cdk::str strKey = prngi.gens(24); // 16 = 128-bit, 24 = 192-bit, 32 = 256-bit
  // instantiate a AES object to perform encryption.
  cdk::AES aesi;
  i = aesi.init(AES::ENCRYPT, +strKey, strKey.c_str());
  if (i) return i;
  if (+strIn % 16 != 0) // padding required
  {
    strPadded = makep5(strIn, 16);
  }
  // encrypt the data
  char out[16];
  i = aesi.crypt(16, strPadded.c_str(), out);
  if (i) return i;
  
  // Decrypt it and unpad
  i = aesi.init(AES::DECRYPT, +strKey, strKey.c_str());
  if (i) return i;
  i = aesi.crypt(16, out, out);
  cdk::str strOut(16, out);
  strOut = parsep5(strOut, 16);
  if (strOut != strIn) return 1; // error
  return 0;
}


For information concerning the objects used here see:


The next topic is Using the Message Digest Functions.


ISC Cryptographic Development Kit - User's Guide
ISC website
Questions? E-mail ISC technical support
Copyright© 2002-2006 Information Security Corp. All rights reserved.