TripleDES
Documentation |
#include <cryptopp/des.h>
|
TripleDES, TDEA or 3DES, is multiple applications of the DES algorithm to plain text data to increase the security of the original DES algorithm. As the name implies, the DES algorithm is applied 3 times. There are two variants of TripleDES: the first is two key; and the second is three key. 2-key TDEA provides approximately 80 bits of security, while 3-key TDEA provides approximately 112 bits of security. In contrast, AES provides a minimum security level of 128.
DES was originally specified by NIST in FIPS 46, effective July 1977. In May 2005, DES was withdrawn, and is now only approved as a component of TDEA. You will still encounter it on occasion, such as with a Microsoft VPN using PPTP.
TripleDES was specified by NIST in May 2004 by SP 800-67. 2-key TDEA is no longer recommended for use in US government information systems. 3-key TDEA and AES are approved, and will coexist as approved algorithms until 2030. See SP 800-57, Part 1.
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 Programs
There are two sample programs. The first uses 2-key TDEA, and the second exercises 3-key TDEA. Both programs use filters (see Pipelining). The key is declared on the stack using a SecByteBlock to ensure the sensitive material is zeroized. Similar could be used for both plain text and recovered text.
If you are benchmarking then you may want to visit Benchmarks | Sample Program . It shows you how to use StreamTransformation::ProcessString
method to process blocks at a time. Calling a cipher's ProcessString
or ProcessBlock
eventually call a cipher's ProcessAndXorBlock
or AdvancedProcessBlocks
, and they are the lowest level API you can use.
2-Key TripleDES
The two key variant has a block size of 8 bytes (64-bits) and uses a key with 16 bytes. The DES implementation in Crypto++ ignores the parity bits (the least significant bits of each byte) in the key.
cout << "key length: " << DES_EDE2::DEFAULT_KEYLENGTH << endl; cout << "block size: " << DES_EDE2::BLOCKSIZE << endl;
The snippet above produces the following output. Note that BLOCKSIZE
is used for the initialization vector rather than IV_LENGTH
because IV_LENGTH
returns 0.
key length: 16 block size: 8
The following program shows how to operate 2-key TripleDES in CBC mode using a pipeline.
AutoSeededRandomPool prng; SecByteBlock key(0x00, DES_EDE2::DEFAULT_KEYLENGTH); prng.GenerateBlock(key, key.size()); byte iv[DES_EDE2::BLOCKSIZE]; prng.GenerateBlock(iv, sizeof(iv)); string plain = "CBC Mode Test"; string cipher, encoded, recovered; /*********************************\ \*********************************/ try { cout << "plain text: " << plain << endl; CBC_Mode< DES_EDE2 >::Encryption e; e.SetKeyWithIV(key, key.size(), iv); // The StreamTransformationFilter adds padding // as required. ECB and CBC Mode must be padded // to the block size of the cipher. StringSource ss1(plain, true, new StreamTransformationFilter(e, new StringSink(cipher) ) // StreamTransformationFilter ); // StringSource } catch(const CryptoPP::Exception& e) { cerr << e.what() << endl; exit(1); } /*********************************\ \*********************************/ // Pretty print StringSource ss2(cipher, true, new HexEncoder( new StringSink(encoded) ) // HexEncoder ); // StringSource cout << "cipher text: " << encoded << endl; /*********************************\ \*********************************/ try { CBC_Mode< DES_EDE2 >::Decryption d; d.SetKeyWithIV(key, key.size(), iv); // The StreamTransformationFilter removes // padding as required. StringSource ss3(cipher, true, new StreamTransformationFilter(d, new StringSink(recovered) ) // StreamTransformationFilter ); // StringSource cout << "recovered text: " << recovered << endl; } catch(const 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.
$ ./test.exe key: 9893BDEA99457F04C742B64109C80069 iv: 11F0B687DABAED4B plain text: CBC Mode Test cipher text: 82605EECEDF764373E205742AC947A0B recovered text: CBC Mode Test
3-Key TripleDES
The three key variant has a block size of 8 bytes (64-bits) and uses a key with 24 bytes. The DES implementation in Crypto++ ignores the parity bits (the least significant bits of each byte) in the key.
cout << "key length: " << DES_EDE3::DEFAULT_KEYLENGTH << endl; cout << "block size: " << DES_EDE3::BLOCKSIZE << endl;
The snippet above produces the following output. Note that BLOCKSIZE
is used for the initialization vector rather than IV_LENGTH
because IV_LENGTH
returns 0.
key length: 24 block size: 8
The following program shows how to operate 3-key TripleDES in CBC mode using a pipeline.
AutoSeededRandomPool prng; SecByteBlock key(0x00, DES_EDE3::DEFAULT_KEYLENGTH); prng.GenerateBlock(key, key.size()); byte iv[DES_EDE3::BLOCKSIZE]; prng.GenerateBlock(iv, sizeof(iv)); string plain = "CBC Mode Test"; string cipher, encoded, recovered; /*********************************\ \*********************************/ try { cout << "plain text: " << plain << endl; CBC_Mode< DES_EDE3 >::Encryption e; e.SetKeyWithIV(key, key.size(), iv); // The StreamTransformationFilter adds padding // as required. ECB and CBC Mode must be padded // to the block size of the cipher. StringSource ss1(plain, true, new StreamTransformationFilter(e, new StringSink(cipher) ) // StreamTransformationFilter ); // StringSource } catch(const CryptoPP::Exception& e) { cerr << e.what() << endl; exit(1); } /*********************************\ \*********************************/ // Pretty print StringSource ss2(cipher, true, new HexEncoder( new StringSink(encoded) ) // HexEncoder ); // StringSource cout << "cipher text: " << encoded << endl; /*********************************\ \*********************************/ try { CBC_Mode< DES_EDE3 >::Decryption d; d.SetKeyWithIV(key, key.size(), iv); // The StreamTransformationFilter removes // padding as required. StringSource ss3(cipher, true, new StreamTransformationFilter(d, new StringSink(recovered) ) // StreamTransformationFilter ); // StringSource cout << "recovered text: " << recovered << endl; } catch(const 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: 81F8E1ECCDFBBCE1E2FB523CDAB32B10B479AB53D9819DEF iv: 07DD427883B74970 plain text: CBC Mode Test cipher text: 6DF4AE5D60BC8FF1AAE4CCFD11A05FB5 recovered text: CBC Mode Test
To manually insert bytes into the filter, perform multiple Put
s. 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); ... CBC_Mode < DES_EDE3 >::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());
Downloads
3TDEA-CBC-Filter.zip - Demonstrates encryption and decryption using 3-key TripleDES in CBC mode with filters (confidentiality only)
2TDEA-CBC-Filter.zip - Demonstrates encryption and decryption using 2-key TripleDES in CBC mode with filters (confidentiality only)
DES-CBC-Filter.zip - Demonstrates encryption and decryption using DES in CBC mode with filters (confidentiality only)