From ffcac9caca72ec703395080e511ba6dc80c53163 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 19 Sep 2019 17:29:57 +0800 Subject: [PATCH] feat(util): add AES XTS and its unit test --- components/util/include/esp_aes.h | 40 ++++++++ components/util/src/aes.c | 148 +++++++++++++++++++++++++++++- components/util/test/test_aes.c | 136 +++++++++++++++++++++++++++ 3 files changed, 321 insertions(+), 3 deletions(-) diff --git a/components/util/include/esp_aes.h b/components/util/include/esp_aes.h index 2d2bb891..9f693b33 100644 --- a/components/util/include/esp_aes.h +++ b/components/util/include/esp_aes.h @@ -27,6 +27,10 @@ typedef struct esp_aes { uint32_t buf[68]; /*!< The AES calculation cache */ } esp_aes_t; +typedef struct esp_aes_xts { + esp_aes_t crypt; /*!< The AES context to use for AES block encryption or decryption. */ + esp_aes_t tweak; /*!< The AES context used for tweak computation. */ +} esp_aes_xts_t; /** * @brief Set AES encrypt key @@ -225,6 +229,42 @@ static inline int esp_aes_decrypt_ctr(esp_aes_t *aes, size_t *nc_off, void *p_no return esp_aes_encrypt_ctr(aes, nc_off, p_nonce_counter, p_stream_block, p_src, slen, p_dst, dlen); } +/** + * @brief Set AES XTS encrypt key + * + * @param aes AES XTS contex pointer + * @param p_key AES XTS key data buffer + * @param keybits number of AES XTS key bits + * + * @return 0 if success or fail + */ +int esp_aes_xts_set_encrypt_key(esp_aes_xts_t *aes, const void *p_key, size_t keybits); + +/** + * @brief Set AES XTS decrypt key + * + * @param aes AES XTS contex pointer + * @param p_key AES XTS key data buffer + * @param keybits number of AES XTS key bits + * + * @return 0 if success or fail + */ +int esp_aes_xts_set_decrypt_key(esp_aes_xts_t *aes, const void *p_key, size_t keybits); + +/** + * @brief AES XTS encrypt/decrypt calculation + * + * @param aes AES contex pointer + * @param encrypt 1 : encrypt, 0 : decrypt + * @param length data unit data length by bytes + * @param p_data_unit data unit buffer + * @param p_src input data buffer + * @param p_dst output data buffer + * + * @return 0 if success or fail + */ +int esp_aes_crypt_xts(esp_aes_xts_t *aes, int encrypt, size_t length, const void *p_data_unit, const void *p_src, void *p_dst); + #ifdef __cplusplus } #endif diff --git a/components/util/src/aes.c b/components/util/src/aes.c index 129f69e9..b32c79b5 100644 --- a/components/util/src/aes.c +++ b/components/util/src/aes.c @@ -528,7 +528,7 @@ static void __esp_aes_encrypt(esp_aes_t *aes, const void *p_src, void *p_dst) PUT_UINT32_LE(X3, output, 12); } -static int __esp_aes_decrypt(esp_aes_t *aes, const void *p_src, void *p_dst) +static void __esp_aes_decrypt(esp_aes_t *aes, const void *p_src, void *p_dst) { int i; uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; @@ -573,8 +573,6 @@ static int __esp_aes_decrypt(esp_aes_t *aes, const void *p_src, void *p_dst) PUT_UINT32_LE(X1, output, 4); PUT_UINT32_LE(X2, output, 8); PUT_UINT32_LE(X3, output, 12); - - return 0; } int esp_aes_encrypt(esp_aes_t *aes, @@ -864,3 +862,147 @@ int esp_aes_encrypt_ctr(esp_aes_t *aes, return 0; } + +static void aes_xts_decode_keys(const uint8_t *key, + size_t keybits, + const uint8_t **key1, + size_t *key1bits, + const uint8_t **key2, + size_t *key2bits) +{ + const size_t half_keybits = keybits / 2; + const size_t half_keybytes = half_keybits / 8; + + *key1bits = half_keybits; + *key2bits = half_keybits; + *key1 = &key[0]; + *key2 = &key[half_keybytes]; +} + +static void aes_gf128mul_x_ble(uint8_t *r, const uint8_t *i) +{ + uint64_t x[2], y[2]; + + memcpy(x, i, 16); + + y[0] = (x[0] << 1) ^ 0x0087 >> (8 - ((x[1] >> 63 ) << 3)); + y[1] = (x[0] >> 63) | (x[1] << 1); + + memcpy(r, y, 16); +} + +int esp_aes_xts_set_encrypt_key(esp_aes_xts_t *ctx, const void *p_key, size_t keybits) +{ + int ret; + const uint8_t *key1, *key2; + size_t key1bits, key2bits; + const uint8_t *key = (const uint8_t *)p_key; + + util_assert(ctx); + util_assert(key); + + if (keybits != 256 && keybits != 512) + return -EINVAL; + + aes_xts_decode_keys(key, keybits, &key1, &key1bits, &key2, &key2bits); + + ret = esp_aes_set_encrypt_key(&ctx->tweak, key2, key2bits); + if (ret) + return ret; + + return esp_aes_set_encrypt_key(&ctx->crypt, key1, key1bits); +} + +int esp_aes_xts_set_decrypt_key(esp_aes_xts_t *ctx, const void *p_key, size_t keybits) +{ + int ret; + const uint8_t *key1, *key2; + size_t key1bits, key2bits; + const uint8_t *key = (const uint8_t *)p_key; + + util_assert(ctx); + util_assert(key); + + if (keybits != 256 && keybits != 512) + return -EINVAL; + + aes_xts_decode_keys(key, keybits, &key1, &key1bits, &key2, &key2bits); + + ret = esp_aes_set_encrypt_key(&ctx->tweak, key2, key2bits); + if (ret) + return ret; + + return esp_aes_set_decrypt_key(&ctx->crypt, key1, key1bits); +} + +int esp_aes_crypt_xts(esp_aes_xts_t *ctx, + int encrypt, + size_t length, + const void *p_data_unit, + const void *p_src, + void *p_dst) +{ + size_t blocks = length / 16; + size_t leftover = length % 16; + uint8_t tweak[16]; + uint8_t prev_tweak[16]; + uint8_t tmp[16]; + void (*crypt_func)(esp_aes_t *aes, const void *p_src, void *p_dst); + + const uint8_t *data_unit = (const uint8_t *)p_data_unit; + const uint8_t *input = (const uint8_t *)p_src; + uint8_t *output = (uint8_t *)p_dst; + + util_assert(ctx); + util_assert(data_unit); + util_assert(input); + util_assert(output); + + if (length < 16 || (length > (1 << 20) * 16)) + return -EINVAL; + + crypt_func = encrypt ? __esp_aes_encrypt : __esp_aes_decrypt; + + __esp_aes_encrypt(&ctx->tweak, data_unit, tweak); + + while (blocks--) { + if (blocks == 0 && leftover && !encrypt) { + memcpy(prev_tweak, tweak, sizeof(tweak)); + aes_gf128mul_x_ble(tweak, tweak); + } + + for (int i = 0; i < 16; i++) + tmp[i] = input[i] ^ tweak[i]; + + crypt_func(&ctx->crypt, tmp, tmp); + + for (int i = 0; i < 16; i++) + output[i] = tmp[i] ^ tweak[i]; + + aes_gf128mul_x_ble(tweak, tweak); + + output += 16; + input += 16; + } + + if (leftover) { + int i; + uint8_t *t = encrypt ? tweak : prev_tweak; + uint8_t *prev_output = output - 16; + + for (i = 0; i < leftover; i++) { + output[i] = prev_output[i]; + tmp[i] = input[i] ^ t[i]; + } + + for (; i < 16; i++ ) + tmp[i] = prev_output[i] ^ t[i]; + + crypt_func(&ctx->crypt, tmp, tmp); + + for (i = 0; i < 16; i++) + prev_output[i] = tmp[i] ^ t[i]; + } + + return 0; +} diff --git a/components/util/test/test_aes.c b/components/util/test/test_aes.c index e34ebc12..14e6b7c4 100644 --- a/components/util/test/test_aes.c +++ b/components/util/test/test_aes.c @@ -112,6 +112,95 @@ static const uint32_t s_aes_ctr_result[3][8] = { } }; +static const uint8_t aes_test_xts_key[][32] = { + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + + { + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 + }, + + { + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 + }, +}; + +static const uint8_t aes_test_xts_pt32[][32] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + + { + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 + }, + + { + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 + }, +}; + +static const uint8_t aes_test_xts_ct32[][32] = +{ + { + 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, + 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, + 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e + }, + + { + 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e, + 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b, + 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4, + 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 + }, + + { + 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a, + 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2, + 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53, + 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 + }, +}; + +static const uint8_t aes_test_xts_data_unit[][16] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + + { + 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + + { + 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, +}; + TEST_CASE("Test AES-ECB", "[AES]") { uint32_t buf[4]; @@ -451,3 +540,50 @@ TEST_CASE("Test AES-CTR", "[AES]") // align: AES-CRT test cost time totally encode 344845 us and decode 344421 us, once cost is about encode 336 us and decode 336 us // no align: AES-CRT test cost time totally encode 639256 us and decode 635343 us, once cost is about encode 624 us and decode 620 us + + + +TEST_CASE("Test AES-XTS", "[AES]") +{ + uint32_t encode_time = 0, decode_time = 0; + const int num_tests = sizeof(aes_test_xts_key) / sizeof(*aes_test_xts_key); + extern uint32_t esp_get_time(void); + + for (int cnt = 0; cnt < TEST_AES_COUNT; cnt++) { + for (int i = 0; i < num_tests; i++) { + const int len = sizeof(*aes_test_xts_ct32); + uint32_t buf[8]; + uint8_t key[32]; + const uint8_t *data_unit = aes_test_xts_data_unit[i]; + esp_aes_xts_t ctx_xts; + + memcpy(key, aes_test_xts_key[i], 32); + + TEST_ASSERT_TRUE(esp_aes_xts_set_encrypt_key(&ctx_xts, key, 256) == 0); + memcpy(buf, aes_test_xts_pt32[i], len); + + uint32_t tmp = esp_get_time(); + TEST_ASSERT_TRUE(esp_aes_crypt_xts(&ctx_xts, 1, len, data_unit, buf, buf) == 0); + encode_time += esp_get_time() - tmp; + + TEST_ASSERT_TRUE(memcmp(buf, aes_test_xts_ct32[i], len) == 0); + + TEST_ASSERT_TRUE(esp_aes_xts_set_decrypt_key(&ctx_xts, key, 256) == 0); + memcpy(buf, aes_test_xts_ct32[i], len); + + tmp = esp_get_time(); + TEST_ASSERT_TRUE(esp_aes_crypt_xts(&ctx_xts, 0, len, data_unit, buf, buf) == 0); + decode_time += esp_get_time() - tmp; + + TEST_ASSERT_TRUE(memcmp(buf, aes_test_xts_pt32[i], len) == 0); + } + } + +#if TEST_AES_DEBUG_TIME + printf("AES-XTS test cost time totally encode %u us and decode %u us, once cost is about encode %u us and decode %u us\n", + encode_time, decode_time, encode_time / TEST_AES_COUNT, decode_time / TEST_AES_COUNT); +#endif +} + +// align: AES-XTS test cost time totally encode 723197 us and decode 533441 us, once cost is about encode 706 us and decode 520 us +// no align: AES-XTS test cost time totally encode 675249 us and decode 645998 us, once cost is about encode 659 us and decode 630 us