mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-11-07 21:12:47 +00:00
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
This commit is contained in:
committed by
Łukasz Rymanowski
parent
07928f548a
commit
e088a9d0e9
+123
-228
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user