const RawBuffer &tag,
const RawBuffer &aad)
{
- EvpCipherPtr dec;
- selectCipher(AlgoType::AES_GCM, key.size(), false)(dec, key, iv);
- void *ptr = (void *)tag.data();
+ RawBuffer result, tmp;
- dec->Control(EVP_CTRL_GCM_SET_TAG, tag.size(), ptr);
+ auto decrypt = [&](const RawBuffer &actualIv){
+ EvpCipherPtr dec;
+ selectCipher(AlgoType::AES_GCM, key.size(), false)(dec, key, actualIv);
+ void *ptr = (void *)tag.data();
- if (!aad.empty())
- dec->AppendAAD(aad);
+ dec->Control(EVP_CTRL_GCM_SET_TAG, tag.size(), ptr);
+
+ if (!aad.empty())
+ dec->AppendAAD(aad);
+
+ result = dec->Append(data);
+ try {
+ tmp = dec->Finalize();
+ } catch (const Exc::Exception &e) {
+ ThrowErr(Exc::InputParam,
+ "Tag authentication failed in AES finalize function (the tag doesn't match).");
+ }
+ };
- RawBuffer result = dec->Append(data);
- RawBuffer tmp;
try {
- tmp = dec->Finalize();
- } catch (const Exc::Exception &e) {
- ThrowErr(Exc::InputParam, "Tag authentication failed in AES finalize function (the tag doesn't match).");
+ decrypt(iv);
+ } catch (const Exc::InputParam &e) {
+ LogDebug("AES GCM decryption failed. Retry with default iv length.");
+ RawBuffer shortIv = iv;
+ shortIv.resize(Params::DEFAULT_AES_GCM_IV_LEN);
+ decrypt(shortIv);
}
std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
return result;
BOOST_REQUIRE_THROW(key->decrypt(ca2, encrypted), Exc::Crypto::InputParam);
}
+POSITIVE_TEST_CASE(gcmIvLengthScrewUpWorkaround)
+{
+ const auto key = generateAes(128);
+ const auto data = createRandom(128);
+ const auto iv = createRandom(Params::DEFAULT_AES_IV_LEN);
+ CryptoAlgorithm ca;
+ RawBuffer encrypted, decrypted;
+ auto shortIv = iv;
+ shortIv.resize(Params::DEFAULT_AES_GCM_IV_LEN);
+
+ ca.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GCM);
+ ca.setParam(ParamName::ED_IV, shortIv);
+ ca.setParam(ParamName::ED_TAG_LEN, 128);
+
+ // encrypt with 12B IV
+ BOOST_REQUIRE_NO_THROW(encrypted = key->encrypt(ca, data));
+
+ // decrypt with 12B IV
+ BOOST_REQUIRE_NO_THROW(decrypted = key->decrypt(ca, encrypted));
+ BOOST_REQUIRE(decrypted == data);
+
+ // decrypt with 16B IV should also succeed (workaround)
+ ca.setParam(ParamName::ED_IV, iv);
+ BOOST_REQUIRE_NO_THROW(decrypted = key->decrypt(ca, encrypted));
+ BOOST_REQUIRE(decrypted == data);
+
+ // encrypt with 16B IV
+ BOOST_REQUIRE_NO_THROW(encrypted = key->encrypt(ca, data));
+
+ // decrypt with 16B IV
+ BOOST_REQUIRE_NO_THROW(decrypted = key->decrypt(ca, encrypted));
+ BOOST_REQUIRE(decrypted == data);
+
+ // decrypt with 12B IV should fail
+ ca.setParam(ParamName::ED_IV, shortIv);
+ BOOST_REQUIRE_THROW(key->decrypt(ca, encrypted), Exc::Crypto::InputParam);
+}
+
NEGATIVE_TEST_CASE(symmetricEncryptDecryptCtr)
{
const auto key = generateAes(128);