summaryrefslogtreecommitdiff
path: root/mesh/crypto.c
diff options
context:
space:
mode:
authorBrian Gix <brian.gix@intel.com>2019-05-29 10:28:18 -0700
committerBrian Gix <brian.gix@intel.com>2019-05-31 16:46:34 -0700
commitdfed4839463fc54106cd182d312147ff112d5366 (patch)
treefc824a1bbb5c0944a1792ff44b49d2aaf74d22b8 /mesh/crypto.c
parent75cd5b382e44d78e664f339e677efb44e6e21808 (diff)
downloadbluez-dfed4839463fc54106cd182d312147ff112d5366.tar.gz
mesh: Convert crypto to use ELL wrappers
Use ELL implementations of aead-ccm(aes), ecb(aes) and cmac(aes). These standard encryption and hashing routines are provided by ELL.
Diffstat (limited to 'mesh/crypto.c')
-rw-r--r--mesh/crypto.c518
1 files changed, 54 insertions, 464 deletions
diff --git a/mesh/crypto.c b/mesh/crypto.c
index 085e72798..3fa0df246 100644
--- a/mesh/crypto.c
+++ b/mesh/crypto.c
@@ -44,193 +44,52 @@
/* Multiply used Zero array */
static const uint8_t zero[16] = { 0, };
-static int alg_new(int fd, const void *keyval, socklen_t keylen,
- size_t mic_size)
+static bool aes_ecb_one(const uint8_t key[16], const uint8_t in[16],
+ uint8_t out[16])
{
- if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, keyval, keylen) < 0)
- return -1;
+ void *cipher;
+ bool result = false;
- if (mic_size &&
- setsockopt(fd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE,
- NULL, mic_size) < 0)
- return -1;
+ cipher = l_cipher_new(L_CIPHER_AES, key, 16);
- /* FIXME: This should use accept4() with SOCK_CLOEXEC */
- return accept(fd, NULL, 0);
-}
-
-static bool alg_encrypt(int fd, const void *inbuf, size_t inlen,
- void *outbuf, size_t outlen)
-{
- __u32 alg_op = ALG_OP_ENCRYPT;
- char cbuf[CMSG_SPACE(sizeof(alg_op))];
- struct cmsghdr *cmsg;
- struct msghdr msg;
- struct iovec iov;
- ssize_t len;
-
- memset(cbuf, 0, sizeof(cbuf));
- memset(&msg, 0, sizeof(msg));
-
- msg.msg_control = cbuf;
- msg.msg_controllen = sizeof(cbuf);
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_ALG;
- cmsg->cmsg_type = ALG_SET_OP;
- cmsg->cmsg_len = CMSG_LEN(sizeof(alg_op));
- memcpy(CMSG_DATA(cmsg), &alg_op, sizeof(alg_op));
-
- iov.iov_base = (void *) inbuf;
- iov.iov_len = inlen;
-
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- len = sendmsg(fd, &msg, 0);
- if (len < 0)
- return false;
-
- len = read(fd, outbuf, outlen);
- if (len < 0)
- return false;
-
- return true;
-}
-
-static int aes_ecb_setup(const uint8_t key[16])
-{
- struct sockaddr_alg salg;
- int fd, nfd;
-
- fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
- if (fd < 0)
- return -1;
-
- memset(&salg, 0, sizeof(salg));
- salg.salg_family = AF_ALG;
- strcpy((char *) salg.salg_type, "skcipher");
- strcpy((char *) salg.salg_name, "ecb(aes)");
-
- if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
- close(fd);
- return -1;
+ if (cipher) {
+ result = l_cipher_encrypt(cipher, in, out, 16);
+ l_cipher_free(cipher);
}
- nfd = alg_new(fd, key, 16, 0);
-
- close(fd);
-
- return nfd;
-}
-
-static bool aes_ecb(int fd, const uint8_t plaintext[16], uint8_t encrypted[16])
-{
- return alg_encrypt(fd, plaintext, 16, encrypted, 16);
-}
-
-static void aes_ecb_destroy(int fd)
-{
- close(fd);
-}
-
-static bool aes_ecb_one(const uint8_t key[16],
- const uint8_t plaintext[16], uint8_t encrypted[16])
-{
- bool result;
- int fd;
-
- fd = aes_ecb_setup(key);
- if (fd < 0)
- return false;
-
- result = aes_ecb(fd, plaintext, encrypted);
-
- aes_ecb_destroy(fd);
-
return result;
}
-bool mesh_aes_ecb_one(const uint8_t key[16],
- const uint8_t plaintext[16], uint8_t encrypted[16])
-{
- return aes_ecb_one(key, plaintext, encrypted);
-}
-
-/* Maximum message length that can be passed to aes_cmac */
-#define CMAC_MSG_MAX (64 + 64 + 17)
-
-static int aes_cmac_setup(const uint8_t key[16])
-{
- struct sockaddr_alg salg;
- int fd, nfd;
-
- fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
- if (fd < 0)
- return -1;
-
- memset(&salg, 0, sizeof(salg));
- salg.salg_family = AF_ALG;
- strcpy((char *) salg.salg_type, "hash");
- strcpy((char *) salg.salg_name, "cmac(aes)");
-
- if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
- close(fd);
- return -1;
- }
-
- nfd = alg_new(fd, key, 16, 0);
-
- close(fd);
-
- return nfd;
-}
-
-static bool aes_cmac(int fd, const uint8_t *msg,
+static bool aes_cmac(void *checksum, const uint8_t *msg,
size_t msg_len, uint8_t res[16])
{
- ssize_t len;
-
- if (msg_len > CMAC_MSG_MAX)
- return false;
-
- len = send(fd, msg, msg_len, 0);
- if (len < 0)
- return false;
-
- len = read(fd, res, 16);
- if (len < 0)
+ if (!l_checksum_update(checksum, msg, msg_len))
return false;
- return true;
-}
-
-static void aes_cmac_destroy(int fd)
-{
- close(fd);
-}
-
-static int aes_cmac_N_start(const uint8_t N[16])
-{
- int fd;
+ if (16 == l_checksum_get_digest(checksum, res, 16))
+ return true;
- fd = aes_cmac_setup(N);
- return fd;
+ return false;
}
static bool aes_cmac_one(const uint8_t key[16], const void *msg,
size_t msg_len, uint8_t res[16])
{
+ void *checksum;
bool result;
- int fd;
- fd = aes_cmac_setup(key);
- if (fd < 0)
+ checksum = l_checksum_new_cmac_aes(key, 16);
+ if (!checksum)
return false;
- result = aes_cmac(fd, msg, msg_len, res);
+ result = l_checksum_update(checksum, msg, msg_len);
- aes_cmac_destroy(fd);
+ if (result) {
+ ssize_t len = l_checksum_get_digest(checksum, res, 16);
+ result = !!(len == 16);
+ }
+
+ l_checksum_free(checksum);
return result;
}
@@ -247,161 +106,22 @@ bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16],
uint8_t *out_msg,
void *out_mic, size_t mic_size)
{
- uint8_t pmsg[16], cmic[16], cmsg[16];
- uint8_t mic[16], Xn[16];
- uint16_t blk_cnt, last_blk;
+ void *cipher;
bool result;
- size_t i, j;
- int fd;
-
- /* Mesh limits AAD length to 16 */
- if (aad_len > 16)
- return false;
-
- fd = aes_ecb_setup(key);
- if (fd < 0)
- return false;
-
- /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
- pmsg[0] = 0x01;
- memcpy(pmsg + 1, nonce, 13);
- l_put_be16(0x0000, pmsg + 14);
-
- result = aes_ecb(fd, pmsg, cmic);
- if (!result)
- goto done;
-
- /* X_0 = e(AppKey, 0x09 || nonce || length) */
- if (mic_size == 8)
- pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
- else
- pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
-
- memcpy(pmsg + 1, nonce, 13);
- l_put_be16(msg_len, pmsg + 14);
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
-
- /* If AAD is being used to authenticate, include it here */
- if (aad_len) {
- l_put_be16(aad_len, pmsg);
-
- for (i = 0; i < sizeof(uint16_t); i++)
- pmsg[i] = Xn[i] ^ pmsg[i];
- j = 0;
- aad_len += sizeof(uint16_t);
- while (aad_len > 16) {
- do {
- pmsg[i] = Xn[i] ^ aad[j];
- i++, j++;
- } while (i < 16);
+ cipher = l_aead_cipher_new(L_AEAD_CIPHER_AES_CCM, key, 16, mic_size);
- aad_len -= 16;
- i = 0;
+ result = l_aead_cipher_encrypt(cipher, msg, msg_len, aad, aad_len,
+ nonce, 13, out_msg, msg_len + mic_size);
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
- }
-
- for (i = 0; i < aad_len; i++, j++)
- pmsg[i] = Xn[i] ^ aad[j];
-
- for (i = aad_len; i < 16; i++)
- pmsg[i] = Xn[i];
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
- }
-
- 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;
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
-
- /* 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);
- l_put_be16(j + 1, pmsg + 14);
-
- result = aes_ecb(fd, pmsg, cmsg);
- if (!result)
- goto done;
-
- if (out_msg) {
- /* 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];
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
-
- /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
- pmsg[0] = 0x01;
- memcpy(pmsg + 1, nonce, 13);
- l_put_be16(j + 1, pmsg + 14);
-
- result = aes_ecb(fd, pmsg, cmsg);
- if (!result)
- goto done;
-
- if (out_msg) {
- /* Encrypted = Payload[0-15] ^ C_N */
- for (i = 0; i < 16; i++)
- out_msg[(j * 16) + i] =
- msg[(j * 16) + i] ^ cmsg[i];
- }
-
- }
- }
-
- if (out_msg)
- memcpy(out_msg + msg_len, mic, mic_size);
-
- if (out_mic) {
- switch (mic_size) {
- case 4:
- *(uint32_t *)out_mic = l_get_be32(mic);
- break;
- case 8:
- *(uint64_t *)out_mic = l_get_be64(mic);
- break;
- default:
- /* Unsupported MIC size */
- result = false;
- }
+ if (result && out_mic) {
+ if (mic_size == 4)
+ *(uint32_t *)out_mic = l_get_be32(out_msg + msg_len);
+ else
+ *(uint64_t *)out_mic = l_get_be64(out_msg + msg_len);
}
-done:
- aes_ecb_destroy(fd);
+ l_aead_cipher_free(cipher);
return result;
}
@@ -412,156 +132,26 @@ bool mesh_crypto_aes_ccm_decrypt(const uint8_t nonce[13], const uint8_t key[16],
uint8_t *out_msg,
void *out_mic, size_t mic_size)
{
- uint8_t msg[16], pmsg[16], cmic[16], cmsg[16], Xn[16];
- uint8_t mic[16];
- uint16_t msg_len = enc_msg_len - mic_size;
- uint16_t last_blk, blk_cnt;
+ void *cipher;
bool result;
- size_t i, j;
- int fd;
-
- if (enc_msg_len < 5 || aad_len > 16)
- return false;
-
- fd = aes_ecb_setup(key);
- if (fd < 0)
- return false;
-
- /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
- pmsg[0] = 0x01;
- memcpy(pmsg + 1, nonce, 13);
- l_put_be16(0x0000, pmsg + 14);
-
- result = aes_ecb(fd, pmsg, cmic);
- if (!result)
- goto done;
-
- /* X_0 = e(AppKey, 0x09 || nonce || length) */
- if (mic_size == 8)
- pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
- else
- pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
+ size_t out_msg_len = enc_msg_len - mic_size;
- memcpy(pmsg + 1, nonce, 13);
- l_put_be16(msg_len, pmsg + 14);
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
-
- /* If AAD is being used to authenticate, include it here */
- if (aad_len) {
- l_put_be16(aad_len, pmsg);
-
- for (i = 0; i < sizeof(uint16_t); i++)
- pmsg[i] = Xn[i] ^ pmsg[i];
-
- j = 0;
- aad_len += sizeof(uint16_t);
- while (aad_len > 16) {
- do {
- pmsg[i] = Xn[i] ^ aad[j];
- i++, j++;
- } while (i < 16);
-
- aad_len -= 16;
- i = 0;
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
- }
+ cipher = l_aead_cipher_new(L_AEAD_CIPHER_AES_CCM, key, 16, mic_size);
- for (i = 0; i < aad_len; i++, j++)
- pmsg[i] = Xn[i] ^ aad[j];
+ result = l_aead_cipher_decrypt(cipher, enc_msg, enc_msg_len,
+ aad, aad_len, nonce, 13,
+ out_msg, out_msg_len);
- for (i = aad_len; i < 16; i++)
- pmsg[i] = Xn[i];
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
- }
-
- 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) {
- /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
- pmsg[0] = 0x01;
- memcpy(pmsg + 1, nonce, 13);
- l_put_be16(j + 1, pmsg + 14);
-
- result = aes_ecb(fd, pmsg, cmsg);
- if (!result)
- goto done;
-
- /* Encrypted = Payload[0-15] ^ C_1 */
- for (i = 0; i < last_blk; i++)
- msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
-
- if (out_msg)
- 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;
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
-
- /* MIC = C_mic ^ X_1 */
- for (i = 0; i < sizeof(mic); i++)
- mic[i] = cmic[i] ^ Xn[i];
- } else {
- /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
- pmsg[0] = 0x01;
- memcpy(pmsg + 1, nonce, 13);
- l_put_be16(j + 1, pmsg + 14);
-
- result = aes_ecb(fd, pmsg, cmsg);
- if (!result)
- goto done;
-
- /* Encrypted = Payload[0-15] ^ C_1 */
- for (i = 0; i < 16; i++)
- msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
-
- if (out_msg)
- memcpy(out_msg + (j * 16), msg, 16);
-
- /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
- for (i = 0; i < 16; i++)
- pmsg[i] = Xn[i] ^ msg[i];
-
- result = aes_ecb(fd, pmsg, Xn);
- if (!result)
- goto done;
- }
- }
-
- if (out_mic) {
- switch (mic_size) {
- case 4:
- *(uint32_t *)out_mic = l_get_be32(mic);
- break;
- case 8:
- *(uint64_t *)out_mic = l_get_be64(mic);
- break;
- default:
- /* Unsupported MIC size */
- result = false;
- }
+ if (result && out_mic) {
+ if (mic_size == 4)
+ *(uint32_t *)out_mic =
+ l_get_be32(enc_msg + enc_msg_len - mic_size);
+ else
+ *(uint64_t *)out_mic =
+ l_get_be64(enc_msg + enc_msg_len - mic_size);
}
-done:
- aes_ecb_destroy(fd);
+ l_aead_cipher_free(cipher);
return result;
}
@@ -582,7 +172,7 @@ bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
uint8_t enc_key[16],
uint8_t priv_key[16])
{
- int fd;
+ void *checksum;
uint8_t output[16];
uint8_t t[16];
uint8_t *stage;
@@ -598,14 +188,14 @@ bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
if (!aes_cmac_one(stage, n, 16, t))
goto fail;
- fd = aes_cmac_N_start(t);
- if (fd < 0)
+ checksum = l_checksum_new_cmac_aes(t, 16);
+ if (!checksum)
goto fail;
memcpy(stage, p, p_len);
stage[p_len] = 1;
- if (!aes_cmac(fd, stage, p_len + 1, output))
+ if (!aes_cmac(checksum, stage, p_len + 1, output))
goto done;
net_id[0] = output[15] & 0x7f;
@@ -614,7 +204,7 @@ bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
memcpy(stage + 16, p, p_len);
stage[p_len + 16] = 2;
- if (!aes_cmac(fd, stage, p_len + 16 + 1, output))
+ if (!aes_cmac(checksum, stage, p_len + 16 + 1, output))
goto done;
memcpy(enc_key, output, 16);
@@ -623,14 +213,14 @@ bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
memcpy(stage + 16, p, p_len);
stage[p_len + 16] = 3;
- if (!aes_cmac(fd, stage, p_len + 16 + 1, output))
+ if (!aes_cmac(checksum, stage, p_len + 16 + 1, output))
goto done;
memcpy(priv_key, output, 16);
success = true;
done:
- aes_cmac_destroy(fd);
+ l_checksum_free(checksum);
fail:
l_free(stage);