I've implemented a C++ wrapper library for Crypto++ v5.6.2 and have a question about combinations of symmetric algorithms (e. g. Blowfish) and block modes (e. g. GCM).
I am able to encrypt and decrypt data via Blowfish/EAX, but I can't achieve the same by using Blowfish/GCM. AES/EAX and AES/GCM both work.
The following simple application demonstrates my problem:
#include <iostream>
#include <string>
#include "cryptopp/blowfish.h"
#include "cryptopp/filters.h"
#include "cryptopp/eax.h"
#include "cryptopp/gcm.h"
#include "cryptopp/osrng.h"
#include "cryptopp/hex.h"
std::string encrypt(
CryptoPP::AuthenticatedSymmetricCipher &encryption,
std::string const kPlainText,
CryptoPP::SecByteBlock const kKey,
unsigned const char * kIV) {
std::string cipher_text;
// TODO Is this the source of the problem?
// BlockSize always returns 0 which leads to an exception if GCM block mode is used!
std::cout << encryption.BlockSize() << " bytes" << std::endl;
encryption.SetKeyWithIV(
kKey,
kKey.size(),
kIV
);
CryptoPP::StringSink *string_sink = new CryptoPP::StringSink(cipher_text);
CryptoPP::BufferedTransformation *transformator = NULL;
// The AuthenticatedEncryptionFilter adds padding as required.
transformator = new CryptoPP::AuthenticatedEncryptionFilter(
encryption,
string_sink);
bool const kPumpAll = true;
CryptoPP::StringSource(
kPlainText,
kPumpAll,
transformator);
return cipher_text;
}
std::string decrypt(
CryptoPP::AuthenticatedSymmetricCipher &decryption,
std::string const kCipherText,
CryptoPP::SecByteBlock const kKey,
unsigned const char * kIV) {
std::string recovered_plain_text;
decryption.SetKeyWithIV(
kKey,
kKey.size(),
kIV);
CryptoPP::StringSink *string_sink = new CryptoPP::StringSink(
recovered_plain_text);
CryptoPP::BufferedTransformation *transformator = NULL;
CryptoPP::AuthenticatedDecryptionFilter *decryption_filter = NULL;
decryption_filter = new CryptoPP::AuthenticatedDecryptionFilter(
decryption,
string_sink);
transformator = new CryptoPP::Redirector(*decryption_filter);
bool const kPumpAll = true;
CryptoPP::StringSource(
kCipherText,
kPumpAll,
transformator);
return recovered_plain_text;
}
int main() {
CryptoPP::AutoSeededRandomPool prng;
CryptoPP::SecByteBlock key(CryptoPP::Blowfish::DEFAULT_KEYLENGTH);
prng.GenerateBlock(key, key.size());
byte iv[CryptoPP::Blowfish::BLOCKSIZE];
prng.GenerateBlock(iv, sizeof(iv));
// Creates templated mode objects of block ciphers.
// This works...
// CryptoPP::EAX<CryptoPP::Blowfish>::Encryption encryption;
// CryptoPP::EAX<CryptoPP::Blowfish>::Decryption decryption;
// This does NOT work...
CryptoPP::GCM<CryptoPP::Blowfish>::Encryption encryption;
CryptoPP::GCM<CryptoPP::Blowfish>::Decryption decryption;
std::string plain_text = "Block Mode Test";
std::string cipher_text = encrypt(encryption, plain_text, key, iv);
// terminate called after throwing an instance of 'CryptoPP::InvalidArgument'
// what(): Blowfish/GCM: block size of underlying block cipher is not 16
std::cout << "cipher text: " << std::hex << cipher_text << std::endl;
std::cout << "recovered plain text: " << decrypt(decryption, cipher_text, key, iv) << std::endl;
}
A CryptoPP::InvalidArgument
exception is thrown if running the code above with the following text:
Blowfish/GCM: block size of underlying block cipher is not 16
But when running the code instead with the block mode EAX, no exception is thrown. So my questions are:
- Does GCM only work with AES? Can GCM also be used with Blowfish or 3DES?
- Is there a matrix available which lists all possible combinations of symmetric algorithms with block modes?
- Or is this a bug in Crypto++? Because the method
BlockSize()
always returns0
but the exception is only raised if using Blowfish (or 3DES) instead of AES. This seems to raise the exception mentioned.
GCM has been designed to work with 128-bit (=16 byte) block size only. You can find this in the original paper in Section 5.1.
Blowfish is a 64-bit block size algorithm, so the two are not compatible as an "out-of-the-box" authenticated encryption combination. The same is true for
3DES
. The exception is not a bug in Crypto++.GCM will work with other Crypto++ objects that have 128-bit block sizes. They include
AES
,Cast-256
,Rijndael
Cameilla
,MARS
,Serpent
andTwofish
. A table of the block sizes is available at Applied Crypto++: Block Ciphers.GCM will not work with larger block sizes either. For example,
Rijndael
(the parent ofAES
) offers 192-bit and 256-bit block sizes (AES
only specifies the 128-bit block size). GCM will not work with the larger block sizes. And the same is true forSHACAL-2
, with a 256-bit block size.Crypto++'s
BlockSize()
sometimes returns 0 (it has to do with the template parameters). Instead, use the compile time constants likeAES::BLOCKSIZE
,Camellia::BLOCKSIZE
andRijndael::BLOCKSIZE
. This could be considered a bug.