Crypto++ symmetric algorithms and authenticated block modes combinations

1.3k views Asked by At

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 returns 0 but the exception is only raised if using Blowfish (or 3DES) instead of AES. This seems to raise the exception mentioned.
1

There are 1 answers

0
mockinterface On

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 and Twofish. 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 of AES) 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 for SHACAL-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 like AES::BLOCKSIZE, Camellia::BLOCKSIZE and Rijndael::BLOCKSIZE. This could be considered a bug.