From 371ae93fcdcebd907a0dda06a9a821ac489211ca Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 23 Mar 2023 19:20:33 +0100 Subject: [PATCH] Added support for AES CCM. Signed-off-by: Pol Henarejos --- src/hsm/cmd_cipher_sym.c | 46 ++++++++++++++++++++++++++++++ src/hsm/oid.h | 3 ++ tests/pico-hsm/test_052_aes_ext.py | 43 +++++++++++++++++++++++++++- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/hsm/cmd_cipher_sym.c b/src/hsm/cmd_cipher_sym.c index dbb29fd..1a32f76 100644 --- a/src/hsm/cmd_cipher_sym.c +++ b/src/hsm/cmd_cipher_sym.c @@ -33,6 +33,7 @@ #include "mbedtls/asn1.h" #include "mbedtls/cipher.h" #include "mbedtls/oid.h" +#include "mbedtls/ccm.h" /* This is copied from pkcs5.c Mbedtls */ /** Unfortunately it is declared as static, so I cannot call it. **/ @@ -577,6 +578,51 @@ int cmd_cipher_sym() { } res_APDU_size = enc_len; } + else if (aes_algo == 0x07 || aes_algo == 0x1B || aes_algo == 0x2F) { /* CCM */ + mbedtls_aes_free(&ctx); // No AES ctx used + mbedtls_ccm_context gctx; + mbedtls_ccm_init(&gctx); + r = mbedtls_ccm_setkey(&gctx, MBEDTLS_CIPHER_ID_AES, kdata, key_size * 8); + if (r != 0) { + return SW_EXEC_ERROR(); + } + if (iv_len == 16) { + iv_len = 12; + } + mbedtls_platform_zeroize(kdata, sizeof(kdata)); + if (algo == ALGO_EXT_CIPHER_ENCRYPT) { + r = mbedtls_ccm_encrypt_and_tag(&gctx, + enc_len, + iv, + iv_len, + aad, + aad_len, + enc, + res_APDU, + res_APDU + enc_len, + 16); + res_APDU_size = enc_len + 16; + } + else if (algo == ALGO_EXT_CIPHER_DECRYPT) { + r = mbedtls_ccm_auth_decrypt(&gctx, + enc_len - 16, + iv, + iv_len, + aad, + aad_len, + enc, + res_APDU, + enc + enc_len - 16, + 16); + res_APDU_size = enc_len - 16; + } + mbedtls_ccm_free(&gctx); + printf("r %d\n", r); + if (r != 0) + { + return SW_EXEC_ERROR(); + } + } } else if (memcmp(oid, OID_IEEE_ALG, 8) == 0) { if (oid_len != 9) { diff --git a/src/hsm/oid.h b/src/hsm/oid.h index d9dcb81..820f90b 100644 --- a/src/hsm/oid.h +++ b/src/hsm/oid.h @@ -151,18 +151,21 @@ #define OID_AES128_OFB OID_NIST_AES "\x03" #define OID_AES128_CFB OID_NIST_AES "\x04" #define OID_AES128_GCM OID_NIST_AES "\x06" +#define OID_AES128_CCM OID_NIST_AES "\x07" #define OID_AES128_CTR OID_NIST_AES "\x09" // Not existing #define OID_AES192_ECB OID_NIST_AES "\x15" #define OID_AES192_CBC OID_NIST_AES "\x16" #define OID_AES192_OFB OID_NIST_AES "\x17" #define OID_AES192_CFB OID_NIST_AES "\x18" #define OID_AES192_GCM OID_NIST_AES "\x1A" +#define OID_AES192_CCM OID_NIST_AES "\x1B" #define OID_AES192_CTR OID_NIST_AES "\x1D" // Not existing #define OID_AES256_ECB OID_NIST_AES "\x29" #define OID_AES256_CBC OID_NIST_AES "\x2A" #define OID_AES256_OFB OID_NIST_AES "\x2B" #define OID_AES256_CFB OID_NIST_AES "\x2C" #define OID_AES256_GCM OID_NIST_AES "\x2E" +#define OID_AES256_CCM OID_NIST_AES "\x2F" #define OID_AES256_CTR OID_NIST_AES "\x31" // Not existing #define OID_IEEE_ALG "\x2B\x6F\x02\x8C\x53\x00\x00\x01" diff --git a/tests/pico-hsm/test_052_aes_ext.py b/tests/pico-hsm/test_052_aes_ext.py index 30e95f1..1cb71c4 100644 --- a/tests/pico-hsm/test_052_aes_ext.py +++ b/tests/pico-hsm/test_052_aes_ext.py @@ -19,7 +19,7 @@ import pytest import os -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes, aead import cryptography.exceptions from picohsm import APDUResponse, DOPrefixes, EncryptionMode, SWCodes, AES from picohsm.const import DEFAULT_DKEK_SHARES @@ -299,3 +299,44 @@ def test_aes_ctr_iv(device, size): assert(dtA == dtB) assert(dtA == MESSAGE) device.delete_key(keyid) + +@pytest.mark.parametrize( + "size", [128, 192, 256] +) +def test_aes_ccm_no_iv(device, size): + pkey, keyid = generate_key(device, size) + ctA = device.aes(keyid, EncryptionMode.ENCRYPT, AES.CCM, MESSAGE, aad=AAD) + + iv = b'\x00' * 12 + encryptor = aead.AESCCM(pkey) + ctB = encryptor.encrypt(iv, MESSAGE, AAD) + assert(ctA == ctB) + + dtA = device.aes(keyid, EncryptionMode.DECRYPT, AES.CCM, ctA, aad=AAD) + decryptor = encryptor + dtB = decryptor.decrypt(iv, ctB, AAD) + assert(dtA == dtB) + assert(dtA == MESSAGE) + device.delete_key(keyid) + +@pytest.mark.parametrize( + "size", [128, 192, 256] +) +@pytest.mark.parametrize( + "iv_len", [7, 8, 9, 10, 11, 12, 13] +) +def test_aes_ccm_iv(device, size, iv_len): + pkey, keyid = generate_key(device, size) + iv = os.urandom(iv_len) + ctA = device.aes(keyid, EncryptionMode.ENCRYPT, AES.CCM, MESSAGE, iv=iv, aad=AAD) + + encryptor = aead.AESCCM(pkey) + ctB = encryptor.encrypt(iv, MESSAGE, AAD) + assert(ctA == ctB) + + dtA = device.aes(keyid, EncryptionMode.DECRYPT, AES.CCM, ctA, iv=iv, aad=AAD) + decryptor = encryptor + dtB = decryptor.decrypt(iv, ctB, AAD) + assert(dtA == dtB) + assert(dtA == MESSAGE) + device.delete_key(keyid)