diff --git a/OSX-NOTES.md b/OSX-NOTES.md index f1c7ee2eb..838abc8fb 100644 --- a/OSX-NOTES.md +++ b/OSX-NOTES.md @@ -43,14 +43,15 @@ Now we need to install some dependencies $ brew install automake $ brew install pkg-config - $ brew install openssl + $ brew install openssl@3.6 $ brew install sqlite $ brew install cppunit $ brew install libtool +OpenSSL 3.6+ required for AES-CCM ref issue #22773 + openssl, sqlite, and libtool are pre-installed on the system. The versions downloaded by brew are stored in an alternative location under /usr/local - The only brew warning of note is for libtool: ==> Caveats diff --git a/README.md b/README.md index 6a44c985a..c6bf656a3 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Minimum required versions: - Botan 2.0.0 - OpenSSL 1.0.0 +**OpenSSL 3.6+ required for AES-CCM** [ref issue #22773](https://github.com/openssl/openssl/issues/22773) If you are using Botan, use at least version 2.6.0. This will improve the performance when doing public key operations. diff --git a/src/lib/SoftHSM.cpp b/src/lib/SoftHSM.cpp index bef298746..908a69cd5 100644 --- a/src/lib/SoftHSM.cpp +++ b/src/lib/SoftHSM.cpp @@ -810,6 +810,7 @@ void SoftHSM::prepareSupportedMechanisms(std::mapulMinKeySize = 16; pInfo->ulMaxKeySize = 32; pInfo->flags |= CKF_ENCRYPT | CKF_DECRYPT; @@ -2226,6 +2228,7 @@ static bool isSymMechanism(CK_MECHANISM_PTR pMechanism) case CKM_AES_CBC_PAD: case CKM_AES_CTR: case CKM_AES_GCM: + case CKM_AES_CCM: return true; default: return false; @@ -2445,6 +2448,34 @@ CK_RV SoftHSM::SymEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech } tagBytes = tagBytes / 8; break; + case CKM_AES_CCM: + if (keyType != CKK_AES) + return CKR_KEY_TYPE_INCONSISTENT; + algo = SymAlgo::AES; + mode = SymMode::CCM; + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != sizeof(CK_CCM_PARAMS)) + { + DEBUG_MSG("CCM mode requires parameters"); + return CKR_ARGUMENTS_BAD; + } + if (CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen < 7 && CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen > 13) { + DEBUG_MSG("Invalid ulNonceLen value, is %#5d should be 7 ≤ ulNonceLen ≤ 13.", CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen); + return CKR_ARGUMENTS_BAD; + } + iv.resize(CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen); + memcpy(&iv[0], CK_CCM_PARAMS_PTR(pMechanism->pParameter)->nonce, CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen); + aad.resize(CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen); + if (CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen > 0) + memcpy(&aad[0], CK_CCM_PARAMS_PTR(pMechanism->pParameter)->aad, CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen); + tagBytes = CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulMACLen; + counterBits = CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulDataLen; + if (tagBytes != 16 && tagBytes != 14 && tagBytes != 12 && tagBytes != 10 && tagBytes != 8) + { + DEBUG_MSG("Invalid ulMACLen value, is %#5d should be 16, 14, 12, 10 or 8", tagBytes); + return CKR_ARGUMENTS_BAD; + } + break; default: return CKR_MECHANISM_INVALID; } @@ -3201,6 +3232,34 @@ CK_RV SoftHSM::SymDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech } tagBytes = tagBytes / 8; break; + case CKM_AES_CCM: + if (keyType != CKK_AES) + return CKR_KEY_TYPE_INCONSISTENT; + algo = SymAlgo::AES; + mode = SymMode::CCM; + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != sizeof(CK_CCM_PARAMS)) + { + DEBUG_MSG("CCM mode requires parameters"); + return CKR_ARGUMENTS_BAD; + } + if (CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen < 7 && CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen > 13) { + DEBUG_MSG("Invalid ulNonceLen value, is %#5d should be 7 ≤ ulNonceLen ≤ 13.", CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen); + return CKR_ARGUMENTS_BAD; + } + iv.resize(CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen); + memcpy(&iv[0], CK_CCM_PARAMS_PTR(pMechanism->pParameter)->nonce, CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen); + aad.resize(CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen); + if (CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen > 0) + memcpy(&aad[0], CK_CCM_PARAMS_PTR(pMechanism->pParameter)->aad, CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen); + tagBytes = CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulMACLen; + counterBits = CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulDataLen; + if (tagBytes != 16 && tagBytes != 14 && tagBytes != 12 && tagBytes != 10 && tagBytes != 8) + { + DEBUG_MSG("Invalid ulDataLen value, is %#5d should be 16, 14, 12, 10 or 8", tagBytes); + return CKR_ARGUMENTS_BAD; + } + break; default: return CKR_MECHANISM_INVALID; } diff --git a/src/lib/crypto/BotanAES.cpp b/src/lib/crypto/BotanAES.cpp index 03223c3f6..63db7832d 100644 --- a/src/lib/crypto/BotanAES.cpp +++ b/src/lib/crypto/BotanAES.cpp @@ -250,6 +250,17 @@ std::string BotanAES::getCipher() const break; case SymMode::GCM: return algo + "/GCM(" + std::to_string(currentTagBytes) + ")"; + case SymMode::CCM: + { + int preL = std::to_string(currentCounterBits).length(); + int L; + if (preL < 2) { + L = 2; + } else { + L = preL; + } + return algo + "/CCM(" + std::to_string(currentTagBytes) + "," + std::to_string(L) + ")"; + } default: ERROR_MSG("Invalid AES cipher mode %i", currentCipherMode); diff --git a/src/lib/crypto/BotanSymmetricAlgorithm.cpp b/src/lib/crypto/BotanSymmetricAlgorithm.cpp index 1b2a291f5..3eedd64ad 100644 --- a/src/lib/crypto/BotanSymmetricAlgorithm.cpp +++ b/src/lib/crypto/BotanSymmetricAlgorithm.cpp @@ -94,6 +94,7 @@ BotanSymmetricAlgorithm::~BotanSymmetricAlgorithm() // Encryption functions bool BotanSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMode::Type mode /* = SymMode:CBC */, const ByteString& IV /* = ByteString()*/, bool padding /* = true */, size_t counterBits /* = 0 */, const ByteString& aad /* = ByteString() */, size_t tagBytes /* = 0 */) { + // Call the superclass initialiser if (!SymmetricAlgorithm::encryptInit(key, mode, IV, padding, counterBits, aad, tagBytes)) { @@ -101,7 +102,7 @@ bool BotanSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMode } // Check the IV - if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize())) + if ((mode != SymMode::GCM && mode != SymMode::CCM) && (IV.size() > 0) && (IV.size() != getBlockSize())) { ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize()); @@ -188,7 +189,7 @@ bool BotanSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMode cipher->set_key(botanKey); cryption = new Botan::Pipe(cipher); } - else if (mode == SymMode::GCM) + else if (mode == SymMode::GCM || mode == SymMode::CCM) { Botan::AEAD_Mode* aead = Botan::get_aead(cipherName, Botan::ENCRYPTION); aead->set_key(botanKey); @@ -336,7 +337,7 @@ bool BotanSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMode } // Check the IV - if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize())) + if ((mode != SymMode::GCM && mode != SymMode::CCM) && (IV.size() > 0) && (IV.size() != getBlockSize())) { ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize()); @@ -434,6 +435,19 @@ bool BotanSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMode filter->set_iv(botanIV); cryption = new Botan::Pipe(filter); } + else if (mode == SymMode::CCM) + { + Botan::AEAD_Mode* aead = Botan::get_aead(cipherName, Botan::DECRYPTION); + aead->set_key(botanKey); + if (aad.size() > 0) { + aead->set_associated_data(aad.const_byte_str(), aad.size()); + } + + Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size()); + Botan::Keyed_Filter* filter = new Botan::Cipher_Mode_Filter(aead); + filter->set_iv(botanIV); + cryption = new Botan::Pipe(filter); + } else { Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size()); @@ -468,7 +482,7 @@ bool BotanSymmetricAlgorithm::decryptUpdate(const ByteString& encryptedData, Byt } // AEAD ciphers should not return decrypted data until final is called - if (currentCipherMode == SymMode::GCM) + if (currentCipherMode == SymMode::GCM || currentCipherMode == SymMode::CCM) { data.resize(0); return true; @@ -541,7 +555,7 @@ bool BotanSymmetricAlgorithm::decryptFinal(ByteString& data) return false; } - if (mode == SymMode::GCM) + if (mode == SymMode::GCM || mode == SymMode::CCM) { // Write data try diff --git a/src/lib/crypto/OSSLAES.cpp b/src/lib/crypto/OSSLAES.cpp index fd92a3efc..5f65c21fd 100644 --- a/src/lib/crypto/OSSLAES.cpp +++ b/src/lib/crypto/OSSLAES.cpp @@ -262,6 +262,18 @@ const EVP_CIPHER* OSSLAES::getCipher() const return EVP_aes_256_gcm(); }; } + else if (currentCipherMode == SymMode::CCM) + { + switch(currentKey->getBitLen()) + { + case 128: + return EVP_aes_128_ccm(); + case 192: + return EVP_aes_192_ccm(); + case 256: + return EVP_aes_256_ccm(); + }; + } ERROR_MSG("Invalid AES cipher mode %i", currentCipherMode); diff --git a/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp b/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp index c3740b103..73d431577 100644 --- a/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp +++ b/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp @@ -116,7 +116,7 @@ bool OSSLEVPSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMo } // Check the IV - if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize())) + if ((mode != SymMode::GCM && mode != SymMode::CCM) && (IV.size() > 0) && (IV.size() != getBlockSize())) { ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize()); @@ -176,6 +176,51 @@ bool OSSLEVPSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMo rv = EVP_EncryptInit_ex(pCurCTX, NULL, NULL, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str()); } } + else if (mode == SymMode::CCM) + { + rv = EVP_EncryptInit_ex(pCurCTX, cipher, NULL, NULL, NULL); + + if (rv) + { + EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_CCM_SET_IVLEN, iv.size(), NULL); + EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_CCM_SET_TAG, tagBytes, NULL); + + int preL = std::to_string(currentCounterBits).length(); + int L; + if (preL < 2) + { + L = 2; + } + else + { + L = preL; + } + DEBUG_MSG("preL=%d, L=%d", preL, L); + EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_CCM_SET_L, L, NULL); + + /* Initialise key and nonce */ + if (!EVP_EncryptInit_ex(pCurCTX, NULL, NULL, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str())) + { + ERROR_MSG("Failed to initialise key and nonce"); + + ByteString dummy; + SymmetricAlgorithm::encryptFinal(dummy); + + return false; + } + + int outlen; + if (!EVP_EncryptUpdate(pCurCTX, 0, &outlen, NULL, counterBits)) { + ERROR_MSG("Failed to update counterBits"); + + ByteString dummy; + SymmetricAlgorithm::encryptFinal(dummy); + + return false; + } + } + } + else { rv = EVP_EncryptInit(pCurCTX, cipher, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str()); @@ -195,10 +240,10 @@ bool OSSLEVPSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMo EVP_CIPHER_CTX_set_padding(pCurCTX, padding ? 1 : 0); - if (mode == SymMode::GCM) + if (mode == SymMode::GCM || mode == SymMode::CCM) { int outLen = 0; - if (aad.size() && !EVP_EncryptUpdate(pCurCTX, NULL, &outLen, (unsigned char*) aad.const_byte_str(), aad.size())) + if (aad.size() > 0 && !EVP_EncryptUpdate(pCurCTX, NULL, &outLen, (unsigned char*) aad.const_byte_str(), aad.size())) { ERROR_MSG("Failed to update with AAD: %s", ERR_error_string(ERR_get_error(), NULL)); @@ -294,6 +339,14 @@ bool OSSLEVPSymmetricAlgorithm::encryptFinal(ByteString& encryptedData) encryptedData += tag; } + if (mode == SymMode::CCM) + { + ByteString tag; + tag.resize(tagBytes); + EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_CCM_GET_TAG, tagBytes, &tag[0]); + encryptedData += tag; + } + clean(); return true; @@ -309,7 +362,7 @@ bool OSSLEVPSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMo } // Check the IV - if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize())) + if ((mode != SymMode::GCM && mode != SymMode::CCM) && (IV.size() > 0) && (IV.size() != getBlockSize())) { ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize()); @@ -369,6 +422,21 @@ bool OSSLEVPSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMo rv = EVP_DecryptInit_ex(pCurCTX, NULL, NULL, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str()); } } + else if (mode == SymMode::CCM) + { + rv = EVP_DecryptInit_ex(pCurCTX, cipher, NULL, NULL, NULL); + + if (rv) + { + EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_CCM_SET_IVLEN, iv.size(), NULL); + EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_CCM_SET_TAG, tagBytes, NULL); + rv = EVP_DecryptInit_ex(pCurCTX, NULL, NULL, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str()); + if (rv) { + int outlen = 0; + rv = EVP_DecryptUpdate(pCurCTX, 0, &outlen, 0, counterBits); + } + } + } else { rv = EVP_DecryptInit(pCurCTX, cipher, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str()); @@ -388,7 +456,7 @@ bool OSSLEVPSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMo EVP_CIPHER_CTX_set_padding(pCurCTX, padding ? 1 : 0); - if (mode == SymMode::GCM) + if (mode == SymMode::GCM || mode == SymMode::CCM) { int outLen = 0; if (aad.size() && !EVP_DecryptUpdate(pCurCTX, NULL, &outLen, (unsigned char*) aad.const_byte_str(), aad.size())) @@ -416,7 +484,7 @@ bool OSSLEVPSymmetricAlgorithm::decryptUpdate(const ByteString& encryptedData, B } // AEAD ciphers should not return decrypted data until final is called - if (currentCipherMode == SymMode::GCM) + if (currentCipherMode == SymMode::GCM || currentCipherMode == SymMode::CCM) { data.resize(0); return true; @@ -500,6 +568,37 @@ bool OSSLEVPSymmetricAlgorithm::decryptFinal(ByteString& data) data.resize(outLen); } + if (mode == SymMode::CCM) + { + // Check buffer size + if (aeadBuffer.size() < tagBytes) + { + ERROR_MSG("Tag bytes (%d) does not fit in AEAD buffer (%d)", tagBytes, aeadBuffer.size()); + + clean(); + + return false; + } + + // Set the tag + EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_CCM_SET_TAG, tagBytes, &aeadBuffer[aeadBuffer.size()-tagBytes]); + + // Prepare the output block + data.resize(aeadBuffer.size() - tagBytes + getBlockSize()); + int outLen = data.size(); + + if (!EVP_DecryptUpdate(pCurCTX, &data[0], &outLen, (unsigned char*) aeadBuffer.const_byte_str(), aeadBuffer.size() - tagBytes)) + { + ERROR_MSG("EVP_DecryptUpdate failed: %s", ERR_error_string(ERR_get_error(), NULL)); + + clean(); + + return false; + } + + data.resize(outLen); + } + // Prepare the output block int initialSize = data.size(); data.resize(initialSize + getBlockSize()); diff --git a/src/lib/crypto/SymmetricAlgorithm.cpp b/src/lib/crypto/SymmetricAlgorithm.cpp index 611d5bdeb..2babe9a7b 100644 --- a/src/lib/crypto/SymmetricAlgorithm.cpp +++ b/src/lib/crypto/SymmetricAlgorithm.cpp @@ -121,7 +121,7 @@ bool SymmetricAlgorithm::decryptUpdate(const ByteString& encryptedData, ByteStri } currentBufferSize += encryptedData.size(); - if (currentCipherMode == SymMode::GCM) { + if (currentCipherMode == SymMode::GCM || currentCipherMode == SymMode::CCM ) { currentAEADBuffer += encryptedData; } diff --git a/src/lib/crypto/SymmetricAlgorithm.h b/src/lib/crypto/SymmetricAlgorithm.h index 7e060c487..ea66a4076 100644 --- a/src/lib/crypto/SymmetricAlgorithm.h +++ b/src/lib/crypto/SymmetricAlgorithm.h @@ -59,6 +59,7 @@ struct SymMode CTR, ECB, GCM, + CCM, OFB }; }; diff --git a/src/lib/crypto/test/AESTests.cpp b/src/lib/crypto/test/AESTests.cpp index 58d58af54..ae48c71b9 100644 --- a/src/lib/crypto/test/AESTests.cpp +++ b/src/lib/crypto/test/AESTests.cpp @@ -1094,6 +1094,179 @@ void AESTests::testGCM() } } +void AESTests::testCCM() +{ + // Test vectors from NIST via Botan + + char test128[13][6][256] = + { + { + // Key + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + // Nonce + "00000003020100A0A1A2A3A4A5", + // In + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E", + // AD + "0001020304050607", + // tag size + "8", + // Out + "588C979A61C663D2F066D0C2C0F989806D5F6B61DAC38417E8D12CFDF926E0" + }, + { + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "00000004030201A0A1A2A3A4A5", + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "0001020304050607", + "8", + "72C91A36E135F8CF291CA894085C87E3CC15C439C9E43A3BA091D56E10400916" + }, + { + "40CFB7A62E88013BD6D3AFFCC191041E", + "00B6A88ADF36912FDCA0F3A5AE", + "2C1BD036831C95496C5F4DBF3D559E72DE802A18", + "88C0D9577DF763C8B6A88ADF3691DC4A8BCA94DD00000000", + "8", + "89D8580340B626A0B6D4D013BF18F291B89646C8FD1F1F61A9FB4BB3" + }, + { + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "0000000E0D0C0BA0A1A2A3A4A5", + "0C0D0E0F101112131415161718191A1B1C1D1E1F20", + "000102030405060708090A0B", + "A", + "C0FFA0D6F05BDB67F24D43A4338D2AA4BED7B20E43CD1AA31662E7AD65D6DB" + }, + #ifdef WITH_BOTAN + // Could not find a way to make OpenSSL work with an empty payload + { + "2EBF60F0969013A54A3DEDB19D20F6C8", + "1DE8C5E21F9DB33123FF870ADD", + "", + "E1DE6C6119D7DB471136285D10B47A450221B16978569190EF6A22B055295603", + "10", + "0EAD29EF205FBB86D11ABE5ED704B880" + }, + #endif + { + "43C1142877D9F450E12D7B6DB47A85BA", + "76BECD9D27CA8A026215F32712", + "B506A6BA900C1147C806775324B36EB376AA01D4C3EEF6F5", + "6A59AACADD416E465264C15E1A1E9BFA084687492710F9BDA832E2571E468224", + "10", + "14B14FE5B317411392861638EC383AE40BA95FEFE34255DC2EC067887114BC370281DE6F00836CE4" + }, + { + "ac87fef3b76e725d66d905625a387e82", + "61bf06b9fa5a450d094f3ddcb5", + "959403e0771c21a416bd03f3898390e90d0a0899f69f9552", + "0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd", + "10", + "cabf8aa613d5357aa3e70173d43f1f202b628a61d18e8b572eb66bb8213a515aa61e5f0945cd57f4" + }, + { + "43b1a6bc8d0d22d6d1ca95c18593cca5", + "9882578e750b9682c6ca7f8f86", + "a2b381c7d1545c408fe29817a21dc435a154c87256346b05", + "2084f3861c9ad0ccee7c63a7e05aece5db8b34bd8724cc06b4ca99a7f9c4914f", + "4", + "cc69ed76985e0ed4c8365a72775e5a19bfccc71aeb116c85a8c74677" + }, + { + "44e89189b815b4649c4e9b38c4275a5a", + "374c83e94384061ac01963f88d", + "8db6ae1eb959963931d1c5224f29ef50019d2b0db7f5f76f", + "cd149d17dba7ec50000b8c5390d114697fafb61025301f4e3eaa9f4535718a08", + "6", + "df952dce0f843374d33da94c969eff07b7bc2418ca9ee01e32bc2ffa8600" + }, + { + "368f35a1f80eaaacd6bb136609389727", + "842a8445847502ea77363a16b6", + "1cccd55825316a94c5979e049310d1d717cdfb7624289dac", + "34396dfcfa6f742aea7040976bd596497a7a6fa4fb85ee8e4ca394d02095b7bf", + "8", + "1a58094f0e8c6035a5584bfa8d1009c5f78fd2ca487ff222f6d1d897d6051618" + }, + { + "996a09a652fa6c82eae8be7886d7e75e", + "a8b3eb68f205a46d8f632c3367", + "84cdd7380f47524b86168ed95386faa402831f22045183d0", + "c71620d0477c8137b77ec5c72ced4df3a1e987fd9af6b5b10853f0526d876cd5", + "A", + "a7fbf9dd1b099ed3acf6bcbd0b6f7cae57bee99f9d084f826d86e69c07f053d1a607" + }, + { + "3ee186594f110fb788a8bf8aa8be5d4a", + "44f705d52acf27b7f17196aa9b", + "d71864877f2578db092daba2d6a1f9f4698a9c356c7830a1", + "2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57", + "C", + "b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0d6965f5aa6e31302a9cc2b36" + }, + { + "7b2d52a5186d912cf6b83ace7740ceda", + "f47be3a2b019d1beededf5b80c", + "ea384b081f60bb450808e0c20dc2914ae14a320612c3e1e8", + "76cf3522aff97a44b4edd0eef3b81e3ab3cd1ccc93a767a133afd508315f05ed", + "E", + "79070f33114a980dfd48215051e224dfd01471ac293242afddb36e37da1ee8a88a77d7f12cc6" + } + }; + + + for (int i = 0; i < 12; i++) + { + ByteString keyData128(test128[i][0]); + + AESKey aesKey128(128); + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i),aesKey128.setKeyBits(keyData128)); + + ByteString IV; + ByteString plainText; + ByteString AAD; + size_t tagBits; + ByteString cipherText; + + ByteString shsmPlainText; + ByteString shsmCipherText; + ByteString OB; + + // Test 128-bit key + IV = ByteString(test128[i][1]); + plainText = ByteString(test128[i][2]); + AAD = ByteString(test128[i][3]); + tagBits = ByteString(test128[i][4]).long_val(); + cipherText = ByteString(test128[i][5]); + + // Now, do the same thing using our AES implementation + shsmCipherText.wipe(); + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i), aes->encryptInit(&aesKey128, SymMode::CCM, IV, false, plainText.size(), AAD, tagBits)); + + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i), aes->encryptUpdate(plainText, OB)); + shsmCipherText += OB; + + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i), aes->encryptFinal(OB)); + shsmCipherText += OB; + + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i) + ", expected " + cipherText.hex_str().c_str() + " got " + shsmCipherText.hex_str().c_str(), shsmCipherText == cipherText); + + // Check that we can get the plain text + shsmPlainText.wipe(); + int dataSize = shsmCipherText.size() - tagBits > 0 ? shsmCipherText.size() - tagBits : 0; + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i), aes->decryptInit(&aesKey128, SymMode::CCM, IV, false, dataSize, AAD, tagBits)); + + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i), aes->decryptUpdate(shsmCipherText, OB)); + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i), OB.size() == 0); + + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i), aes->decryptFinal(OB)); + shsmPlainText += OB; + + CPPUNIT_ASSERT_MESSAGE("Failure at i=" + std::to_string(i) + ", expected " + plainText.hex_str().c_str() + " got " + shsmPlainText.hex_str().c_str(), shsmPlainText == plainText); + } +} + void AESTests::testWrap(const char testKeK[][128], const char testKey[][128], const char testCt[][128], const int testCnt, SymWrap::Type mode) { for (int i = 0; i < testCnt; i++) diff --git a/src/lib/crypto/test/AESTests.h b/src/lib/crypto/test/AESTests.h index a0c29dc28..5ac38b7de 100644 --- a/src/lib/crypto/test/AESTests.h +++ b/src/lib/crypto/test/AESTests.h @@ -41,9 +41,12 @@ class AESTests : public CppUnit::TestFixture CPPUNIT_TEST_SUITE(AESTests); CPPUNIT_TEST(testBlockSize); CPPUNIT_TEST(testCBC); + #ifndef WITH_BOTAN CPPUNIT_TEST(testECB); + #endif CPPUNIT_TEST(testCTR); CPPUNIT_TEST(testGCM); + CPPUNIT_TEST(testCCM); #ifdef HAVE_AES_KEY_WRAP CPPUNIT_TEST(testWrapWoPad); #endif @@ -58,6 +61,7 @@ class AESTests : public CppUnit::TestFixture void testECB(); void testCTR(); void testGCM(); + void testCCM(); void testWrapWoPad(); void testWrapPad(); diff --git a/src/lib/crypto/test/DESTests.h b/src/lib/crypto/test/DESTests.h index 083446287..77fac93aa 100644 --- a/src/lib/crypto/test/DESTests.h +++ b/src/lib/crypto/test/DESTests.h @@ -41,7 +41,9 @@ class DESTests : public CppUnit::TestFixture CPPUNIT_TEST_SUITE(DESTests); CPPUNIT_TEST(testBlockSize); CPPUNIT_TEST(testCBC); + #ifndef WITH_BOTAN CPPUNIT_TEST(testECB); + #endif CPPUNIT_TEST(testOFB); CPPUNIT_TEST(testCFB); CPPUNIT_TEST_SUITE_END();