Workaround for GCM IV length issue 71/293271/3
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 23 May 2023 09:07:23 +0000 (11:07 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 5 Jun 2023 14:05:26 +0000 (16:05 +0200)
GCM implementation was ignoring IV bytes except first 12B. The issue has
been fixed but we need to support the decryption of the data encrypted
the old way.

This workaround retries the decryption with an IV truncated to 12B if
the decryption with original IV length fails.

Unit-test included.

Change-Id: Ia1c06d9a7c6f3b75a69c2e1cb3e5f0801776e057

src/manager/crypto/sw-backend/internals.cpp
unit-tests/test_sw-backend.cpp

index b6aecae6bfa356a1b427acd9055d7ede0cec1b9e..529f4f141e72e0c3e256821f2c6e5e386d436a4d 100644 (file)
@@ -823,21 +823,34 @@ RawBuffer decryptDataAesGcm(
        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;
index 9fd02642a34d855de6ce1f0a54b0c228ddd8c217..c06434034ceb3c24058f7c5d15429a51b623c20e 100644 (file)
@@ -675,6 +675,44 @@ NEGATIVE_TEST_CASE(symmetricEncryptDecryptGcm)
        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);