From e088a9d0e988fb4e4c3938222d0e341e61e02549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kopy=C5=9Bci=C5=84ski?= Date: Fri, 9 Oct 2020 07:09:40 +0200 Subject: [PATCH] mesh: Refactor CCM Unifies the Mesh CCM implementation parts for encryption and decryption into a crypt and an auth step, reducing stack usage and code size. This change also brings several performance improvements, most notably reducing copying of the nonce and unrolling the 16 byte XOR operations. Performance for the Mesh worst case of a 382 byte payload with 16 bytes of additional data (full transport encrypt with virtual address) goes from an average of 889us to 780us on nRF52840 with default optimization flags. this is port of 234888095f440f0504d6794ffc16aadb339232c9 --- nimble/host/mesh/src/crypto.c | 351 ++++++++++++---------------------- 1 file changed, 123 insertions(+), 228 deletions(-) diff --git a/nimble/host/mesh/src/crypto.c b/nimble/host/mesh/src/crypto.c index b6a0ba21d..4bea800f4 100644 --- a/nimble/host/mesh/src/crypto.c +++ b/nimble/host/mesh/src/crypto.c @@ -194,83 +194,91 @@ int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16]) return bt_mesh_k1(n, 16, salt, id128, out); } -static int bt_mesh_ccm_decrypt(const u8_t key[16], u8_t nonce[13], - const u8_t *enc_msg, size_t msg_len, - const u8_t *aad, size_t aad_len, - u8_t *out_msg, size_t mic_size) +static inline void xor16(u8_t *dst, const u8_t *a, const u8_t *b) { - u8_t msg[16], pmsg[16], cmic[16], cmsg[16], Xn[16], mic[16]; - u16_t last_blk, blk_cnt; - size_t i, j; - int err; + dst[0] = a[0] ^ b[0]; + dst[1] = a[1] ^ b[1]; + dst[2] = a[2] ^ b[2]; + dst[3] = a[3] ^ b[3]; + dst[4] = a[4] ^ b[4]; + dst[5] = a[5] ^ b[5]; + dst[6] = a[6] ^ b[6]; + dst[7] = a[7] ^ b[7]; + dst[8] = a[8] ^ b[8]; + dst[9] = a[9] ^ b[9]; + dst[10] = a[10] ^ b[10]; + dst[11] = a[11] ^ b[11]; + dst[12] = a[12] ^ b[12]; + dst[13] = a[13] ^ b[13]; + dst[14] = a[14] ^ b[14]; + dst[15] = a[15] ^ b[15]; +} - if (msg_len < 1 || aad_len >= 0xff00) { - return -EINVAL; - } +/* pmsg is assumed to have the nonce already present in bytes 1-13 */ +static int ccm_calculate_X0(const u8_t key[16], const u8_t *aad, u8_t aad_len, + size_t mic_size, u8_t msg_len, u8_t b[16], + u8_t X0[16]) +{ + int i, j, err; - /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(0x0000, pmsg + 14); + /* X_0 = e(AppKey, flags || nonce || length) */ + b[0] = (((mic_size - 2) / 2) << 3) | ((!!aad_len) << 6) | 0x01; - err = bt_encrypt_be(key, pmsg, cmic); - if (err) { - return err; - } + sys_put_be16(msg_len, b + 14); - /* X_0 = e(AppKey, 0x09 || nonce || length) */ - if (mic_size == sizeof(u64_t)) { - pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00); - } else { - pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00); - } - - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(msg_len, pmsg + 14); - - err = bt_encrypt_be(key, pmsg, Xn); + err = bt_encrypt_be(key, b, X0); if (err) { return err; } /* If AAD is being used to authenticate, include it here */ if (aad_len) { - sys_put_be16(aad_len, pmsg); + sys_put_be16(aad_len, b); for (i = 0; i < sizeof(u16_t); i++) { - pmsg[i] = Xn[i] ^ pmsg[i]; + b[i] = X0[i] ^ b[i]; } j = 0; aad_len += sizeof(u16_t); while (aad_len > 16) { do { - pmsg[i] = Xn[i] ^ aad[j]; + b[i] = X0[i] ^ aad[j]; i++, j++; } while (i < 16); aad_len -= 16; i = 0; - err = bt_encrypt_be(key, pmsg, Xn); + err = bt_encrypt_be(key, b, X0); if (err) { return err; } } for (; i < aad_len; i++, j++) { - pmsg[i] = Xn[i] ^ aad[j]; + b[i] = X0[i] ^ aad[j]; } for (i = aad_len; i < 16; i++) { - pmsg[i] = Xn[i]; + b[i] = X0[i]; } - err = bt_encrypt_be(key, pmsg, Xn); + err = bt_encrypt_be(key, b, X0); if (err) { return err; } } + return 0; +} + +static int ccm_auth(const u8_t key[16], u8_t nonce[13], + const u8_t *cleartext_msg, size_t msg_len, const u8_t *aad, + size_t aad_len, u8_t *mic, size_t mic_size) +{ + u8_t b[16], Xn[16], s0[16]; + u16_t blk_cnt, last_blk; + int err, j, i; last_blk = msg_len % 16; blk_cnt = (msg_len + 15) / 16; @@ -278,72 +286,95 @@ static int bt_mesh_ccm_decrypt(const u8_t key[16], u8_t nonce[13], last_blk = 16; } + b[0] = 0x01; + memcpy(b + 1, nonce, 13); + + /* S[0] = e(AppKey, 0x01 || nonce || 0x0000) */ + sys_put_be16(0x0000, &b[14]); + + err = bt_encrypt_be(key, b, s0); + if (err) { + return err; + } + + ccm_calculate_X0(key, aad, aad_len, mic_size, msg_len, b, Xn); + for (j = 0; j < blk_cnt; j++) { + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ if (j + 1 == blk_cnt) { - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ for (i = 0; i < last_blk; i++) { - msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i]; + b[i] = Xn[i] ^ cleartext_msg[(j * 16) + i]; } - memcpy(out_msg + (j * 16), msg, last_blk); - - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < last_blk; i++) { - pmsg[i] = Xn[i] ^ msg[i]; - } - - for (i = last_blk; i < 16; i++) { - pmsg[i] = Xn[i] ^ 0x00; - } - - err = bt_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* MIC = C_mic ^ X_1 */ - for (i = 0; i < sizeof(mic); i++) { - mic[i] = cmic[i] ^ Xn[i]; - } + memcpy(&b[i], &Xn[i], 16 - i); } else { - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); + xor16(b, Xn, &cleartext_msg[j * 16]); + } - err = bt_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } + err = bt_encrypt_be(key, b, Xn); + if (err) { + return err; + } + } + /* MIC = C_mic ^ X_1 */ + for (i = 0; i < mic_size; i++) { + mic[i] = s0[i] ^ Xn[i]; + } - /* Encrypted = Payload[0-15] ^ C_1 */ - for (i = 0; i < 16; i++) { - msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i]; - } + return 0; +} - memcpy(out_msg + (j * 16), msg, 16); +static int ccm_crypt(const u8_t key[16], const u8_t nonce[13], + const u8_t *in_msg, u8_t *out_msg, size_t msg_len) +{ + u8_t a_i[16], s_i[16]; + u16_t last_blk, blk_cnt; + size_t i, j; + int err; - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < 16; i++) { - pmsg[i] = Xn[i] ^ msg[i]; - } + last_blk = msg_len % 16; + blk_cnt = (msg_len + 15) / 16; + if (!last_blk) { + last_blk = 16U; + } - err = bt_encrypt_be(key, pmsg, Xn); - if (err) { - return err; + a_i[0] = 0x01; + memcpy(&a_i[1], nonce, 13); + + for (j = 0; j < blk_cnt; j++) { + /* S_1 = e(AppKey, 0x01 || nonce || 0x0001) */ + sys_put_be16(j + 1, &a_i[14]); + err = bt_encrypt_be(key, a_i, s_i); + if (err) { + return err; + } + + /* Encrypted = Payload[0-15] ^ C_1 */ + if (j < blk_cnt - 1) { + xor16(&out_msg[j * 16], s_i, &in_msg[j * 16]); + } else { + for (i = 0; i < last_blk; i++) { + out_msg[(j * 16) + i] = + in_msg[(j * 16) + i] ^ s_i[i]; } } } + return 0; +} + +static int bt_mesh_ccm_decrypt(const u8_t key[16], u8_t nonce[13], + const u8_t *enc_msg, size_t msg_len, + const u8_t *aad, size_t aad_len, + u8_t *out_msg, size_t mic_size) +{ + u8_t mic[16]; + + if (msg_len == 0 || aad_len >= 0xff00) { + return -EINVAL; + } + ccm_crypt(key, nonce, enc_msg, out_msg, msg_len); + + ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size); if (memcmp(mic, enc_msg + msg_len, mic_size)) { return -EBADMSG; @@ -357,10 +388,7 @@ static int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13], const u8_t *aad, size_t aad_len, u8_t *out_msg, size_t mic_size) { - u8_t pmsg[16], cmic[16], cmsg[16], mic[16], Xn[16]; - u16_t blk_cnt, last_blk; - size_t i, j; - int err; + u8_t *mic = out_msg + msg_len; BT_DBG("key %s", bt_hex(key, 16)); BT_DBG("nonce %s", bt_hex(nonce, 13)); @@ -372,142 +400,9 @@ static int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13], return -EINVAL; } - /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(0x0000, pmsg + 14); + ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size); - err = bt_encrypt_be(key, pmsg, cmic); - if (err) { - return err; - } - - /* X_0 = e(AppKey, 0x09 || nonce || length) */ - if (mic_size == sizeof(u64_t)) { - pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00); - } else { - pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00); - } - - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(msg_len, pmsg + 14); - - err = bt_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* If AAD is being used to authenticate, include it here */ - if (aad_len) { - sys_put_be16(aad_len, pmsg); - - for (i = 0; i < sizeof(u16_t); i++) { - pmsg[i] = Xn[i] ^ pmsg[i]; - } - - j = 0; - aad_len += sizeof(u16_t); - while (aad_len > 16) { - do { - pmsg[i] = Xn[i] ^ aad[j]; - i++, j++; - } while (i < 16); - - aad_len -= 16; - i = 0; - - err = bt_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - for (; i < aad_len; i++, j++) { - pmsg[i] = Xn[i] ^ aad[j]; - } - - for (i = aad_len; i < 16; i++) { - pmsg[i] = Xn[i]; - } - - err = bt_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16; - } - - for (j = 0; j < blk_cnt; j++) { - if (j + 1 == blk_cnt) { - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < last_blk; i++) { - pmsg[i] = Xn[i] ^ msg[(j * 16) + i]; - } - for (i = last_blk; i < 16; i++) { - pmsg[i] = Xn[i] ^ 0x00; - } - - err = bt_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* MIC = C_mic ^ X_1 */ - for (i = 0; i < sizeof(mic); i++) { - mic[i] = cmic[i] ^ Xn[i]; - } - - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - for (i = 0; i < last_blk; i++) { - out_msg[(j * 16) + i] = - msg[(j * 16) + i] ^ cmsg[i]; - } - } else { - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < 16; i++) { - pmsg[i] = Xn[i] ^ msg[(j * 16) + i]; - } - - err = bt_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_N */ - for (i = 0; i < 16; i++) { - out_msg[(j * 16) + i] = - msg[(j * 16) + i] ^ cmsg[i]; - } - - } - } - - memcpy(out_msg + msg_len, mic, mic_size); + ccm_crypt(key, nonce, msg, out_msg, msg_len); return 0; }