Serpent
Documentation |
#include <cryptopp/serpent.h>
|
Serpent is a block cipher designed by Ross Anderson, Eli Biham, and Lars Knudsen. It was ranked 2nd in the Advanced Encryption Standard contest. The Serpent homepage is located at http://www.cl.cam.ac.uk/~rja14/serpent.html.
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 three sample programs. The first shows Serpent key and block sizes. The second and third use filters in a pipeline. Pipelining is a high level abstraction and it handles buffering input, buffering output and padding for you.
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.
The first snippet dumps the minimum, maximum, and default key lengths used by Serpent.
cout << "key length: " << Serpent::DEFAULT_KEYLENGTH << endl; cout << "key length (min): " << Serpent::MIN_KEYLENGTH << endl; cout << "key length (max): " << Serpent::MAX_KEYLENGTH << endl; cout << "block size: " << Serpent::BLOCKSIZE << endl;
Output from the above snippet produces the following. Notice the default key size is 128 bits or 16 bytes. The minimum key size of 0 is probably a bug in Crypto++.
key length: 16 key length (min): 0 key length (max): 32 block size: 16
The following program demonstrates CBC encryption using Serpent. 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.
AutoSeededRandomPool prng; SecByteBlock key(Serpent::DEFAULT_KEYLENGTH); prng.GenerateBlock(key, key.size()); byte iv[Serpent::BLOCKSIZE]; prng.GenerateBlock(iv, sizeof(iv)); string plain = "CBC Mode Test"; string cipher, encoded, recovered; /*********************************\ \*********************************/ try { cout << "plain text: " << plain << endl; CBC_Mode< Serpent >::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< Serpent >::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: BE4295539F6BD1752FD0A80229EF8847 iv: 00963F59224794D5AD4252094358FBC3 plain text: CBC Mode Test cipher text: CF2CF2547E02F6D34D97246E8042ED89 recovered text: CBC Mode Test
By switching to EAX mode, authenticity assurances can placed on the cipher text for nearly no programming costs. Below the StreamTransformationFilter was replaced by AuthenticatedEncryptionFilter and AuthenticatedDecryptionFilter.
EAX< Serpent >::Encryption e; e.SetKeyWithIV(key, key.size(), iv); StringSource ss1(plain, true, new AuthenticatedEncryptionFilter(e, new StringSink(cipher) ) // StreamTransformationFilter ); // StringSource ... EAX< Serpent >::Decryption d; d.SetKeyWithIV(key, key.size(), iv); StringSource ss2(cipher, true, new AuthenticatedDecryptionFilter(d, new StringSink(recovered) ) // StreamTransformationFilter ); // StringSource
Typical output is as follows. Notice the additional cipher text bytes due to the MAC bytes. See EAX Mode for details.
$ ./Driver.exe key: 7494A57648FB420043BFBFC5639EB82D iv: 6DF94638B83E01458F3E30C9A1D6AF1C plain text: EAX Mode Test cipher text: 96C521F32DC5E9BBC369DDE4914CB13B710EEBBAB7D706D3ABE06A99DC recovered text: EAX 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 < Serpent >::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
Serpent-CBC-Filter.zip - Demonstrates encryption and decryption using Serpent in CBC mode with filters (confidentiality only)
Serpent-CTR-Filter.zip - Demonstrates encryption and decryption using Serpent in CTR mode with filters (confidentiality only)
Serpent-GCM-Filter.zip - Demonstrates encryption and decryption using Serpent in GCM mode with filters (confidentiality and authenticity)
Serpent-EAX-Filter.zip - Demonstrates encryption and decryption using Serpent in EAX mode with filters (confidentiality and authenticity)