Multiple Encryption
Multiple Encryption is the process of encrypting an already encrypted message one or more times. It is also known as cascade encryption or cascade ciphering. Multiple encryption can use the same cipher multiple times or different ciphers. Some ciphers use the technique, like 3DES and DESX. This wiki page will show you how to create a program that performs Multiple Encryption.
Generally speaking you usually don't need to encrypt multiple times. According to Matthew Green, multiple encryption addresses a problem that mostly doesn’t exist: Modern ciphers rarely get broken... You’re far more likely to get hit by malware or an implementation bug than you are to suffer a catastrophic attack on AES. Also see Multiple Encryption on Green's blog.
Encryption Keys
It is important to use a unique security context for each message or encryption operation. Given a master key you should derive a key for each encryption transformation. If the cipher needs an initialization vector (IV), then you derive a unique iv for each encryption transformation. This is called key independence, and you can use a key derivation function like HKDF to derive a unique key or iv for each transformation.
If you don't use a unique security context for each message or encryption transformation then you could leak information like the plaintext of a message. For an example, see Re-encrypting the encrypted data file generates a decrypted output on Stack Overflow.
Multiple Encryption
The following is an example of applying the encryption operation twice on a message. It also shows you how to derive keys and iv's for use in each application of the encryption operation.
#include "cryptlib.h" #include "filters.h" #include "files.h" #include "aes.h" #include "gcm.h" #include "hex.h" #include "hkdf.h" #include "sha.h" #include <string> #include <iostream> int main(int argc, char* argv[]) { using namespace CryptoPP; std::string password = "super secret password"; SecByteBlock key(32), iv(32); HKDF<SHA256> hkdf; hkdf.DeriveKey(key, key.size(), (const byte*)password.data(), password.size(), NULL, 0, // salt (const byte*)"key derivation", 14); hkdf.DeriveKey(iv, iv.size(), (const byte*)password.data(), password.size(), NULL, 0, // salt (const byte*)"iv derivation", 13); std::string m = "Yoda said, Do or do not. There is no try."; std::string c1, c2; GCM<AES>::Encryption encryptor; encryptor.SetKeyWithIV(key, 16, iv, 16); StringSource(m, true, new AuthenticatedEncryptionFilter( encryptor, new StringSink(c1))); encryptor.SetKeyWithIV(key+16, 16, iv+16, 16); StringSource(c1, true, new AuthenticatedEncryptionFilter( encryptor, new StringSink(c2))); std::cout << "Hex(m):" << std::endl; StringSource(m, true, new HexEncoder(new FileSink(std::cout))); std::cout << std::endl; std::cout << "Hex(Enc(m)):" << std::endl; StringSource(c1, true, new HexEncoder(new FileSink(std::cout))); std::cout << std::endl; std::cout << "Hex(Enc(Enc(m))):" << std::endl; StringSource(c2, true, new HexEncoder(new FileSink(std::cout))); std::cout << std::endl; return 0; }
Running the program results in the following output.
cryptopp$ ./test.exe Hex(m): 596F646120736169642C20446F206F7220646F206E6F742E205468657265206973206E6F20747279 2E Hex(Enc(m)): D4A9063DE7400E90627DE90D16346DC5A99740C55F6FEE092A99071F55F1BDB25A72B7422126CCC4 09B5B5C0076E39EBF7256D5DC3151A738D Hex(Enc(Enc(m))): 83A459F2D4A1627624AF162590465AC705C8AC0F4D915E4A4A9D300156C5F9E042CAA47903353F0A A1FAE408D5747DD223AC4F9AEF3C320EEF7E79E08AB2C6FBEAE7A3A5B4978C45C7
Decryption of the ciphertext would occur in reverse using an AuthenticatedDecryptionFilter
:
GCM<AES>::Decryption decryptor; decryptor.SetKeyWithIV(key+16, 16, iv+16, 16); StringSource(c2, true, new AuthenticatedDecryptionFilter( decryptor, new StringSink(c1))); decryptor.SetKeyWithIV(key, 16, iv, 16); StringSource(c1, true, new AuthenticatedDecryptionFilter( decryptor, new StringSink(m)));