summaryrefslogtreecommitdiff
path: root/mesh/crypto.c
diff options
context:
space:
mode:
authorInga Stotland <johan.hedberg@gmail.com>2018-06-21 23:32:00 -0700
committerMarcel Holtmann <marcel@holtmann.org>2018-07-06 13:03:33 +0200
commitef05f4957dce261ca4aa4def2d360015f8be6eed (patch)
tree9b50f62c2cfe1f61e359641e459772e800493a5a /mesh/crypto.c
parentf0d0c48e82e485d79393bcd30091cfdc5ee201e7 (diff)
downloadbluez-ef05f4957dce261ca4aa4def2d360015f8be6eed.tar.gz
tools: Move meshctl sources under tools/mesh directory
This is a temporary location until the unified mesh solution is provided
Diffstat (limited to 'mesh/crypto.c')
-rw-r--r--mesh/crypto.c1168
1 files changed, 0 insertions, 1168 deletions
diff --git a/mesh/crypto.c b/mesh/crypto.c
deleted file mode 100644
index efb9df8ac..000000000
--- a/mesh/crypto.c
+++ /dev/null
@@ -1,1168 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2017 Intel Corporation. All rights reserved.
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/socket.h>
-
-#include <linux/if_alg.h>
-
-#include <glib.h>
-
-#ifndef SOL_ALG
-#define SOL_ALG 279
-#endif
-
-#ifndef ALG_SET_AEAD_AUTHSIZE
-#define ALG_SET_AEAD_AUTHSIZE 5
-#endif
-
-#include "src/shared/util.h"
-#include "mesh/mesh-net.h"
-#include "mesh/crypto.h"
-
-static int alg_new(int fd, const void *keyval, socklen_t keylen,
- size_t mic_size)
-{
- if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, keyval, keylen) < 0) {
- g_printerr("key");
- return -1;
- }
-
- if (mic_size &&
- setsockopt(fd, SOL_ALG,
- ALG_SET_AEAD_AUTHSIZE, NULL, mic_size) < 0) {
- g_printerr("taglen");
- return -1;
- }
-
- /* 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;
- }
-
- 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;
-}
-
-/* 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,
- 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)
- 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;
-
- fd = aes_cmac_setup(N);
- return fd;
-}
-
-static bool aes_cmac_one(const uint8_t key[16], const void *msg,
- size_t msg_len, uint8_t res[16])
-{
- bool result;
- int fd;
-
- fd = aes_cmac_setup(key);
- if (fd < 0)
- return false;
-
- result = aes_cmac(fd, msg, msg_len, res);
-
- aes_cmac_destroy(fd);
-
- return result;
-}
-
-bool mesh_crypto_aes_cmac(const uint8_t key[16], const uint8_t *msg,
- size_t msg_len, uint8_t res[16])
-{
- return aes_cmac_one(key, msg, msg_len, res);
-}
-
-bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16],
- const uint8_t *aad, uint16_t aad_len,
- const uint8_t *msg, uint16_t msg_len,
- 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;
- bool result;
- size_t i, j;
- int fd;
-
- if (aad_len >= 0xff00) {
- g_printerr("Unsupported AAD size");
- 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);
- 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 == sizeof(uint64_t))
- pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
- else
- pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
-
- memcpy(pmsg + 1, nonce, 13);
- 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) {
- 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;
- }
-
- 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);
- 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);
- 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 sizeof(uint32_t):
- *(uint32_t *)out_mic = get_be32(mic);
- break;
- case sizeof(uint64_t):
- *(uint64_t *)out_mic = get_be64(mic);
- break;
- default:
- g_printerr("Unsupported MIC size");
- }
- }
-
-done:
- aes_ecb_destroy(fd);
-
- return result;
-}
-
-bool mesh_crypto_aes_ccm_decrypt(const uint8_t nonce[13], const uint8_t key[16],
- const uint8_t *aad, uint16_t aad_len,
- const uint8_t *enc_msg, uint16_t enc_msg_len,
- 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;
- bool result;
- size_t i, j;
- int fd;
-
- if (enc_msg_len < 5 || aad_len >= 0xff00)
- 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);
- 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 == sizeof(uint64_t))
- pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
- else
- pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
-
- memcpy(pmsg + 1, nonce, 13);
- 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) {
- 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;
- }
-
- 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) {
- /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
- pmsg[0] = 0x01;
- memcpy(pmsg + 1, nonce, 13);
- 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);
- 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;
- }
- }
-
- switch (mic_size) {
- case sizeof(uint32_t):
- if (out_mic)
- *(uint32_t *)out_mic = get_be32(mic);
- else if (get_be32(enc_msg + enc_msg_len - mic_size) !=
- get_be32(mic))
- result = false;
- break;
-
- case sizeof(uint64_t):
- if (out_mic)
- *(uint64_t *)out_mic = get_be64(mic);
- else if (get_be64(enc_msg + enc_msg_len - mic_size) !=
- get_be64(mic))
- result = false;
- break;
-
- default:
- g_printerr("Unsupported MIC size");
- result = false;
- }
-
-done:
- aes_ecb_destroy(fd);
-
- return result;
-}
-
-bool mesh_crypto_k1(const uint8_t ikm[16], const uint8_t salt[16],
- const void *info, size_t info_len, uint8_t okm[16])
-{
- uint8_t res[16];
-
- if (!aes_cmac_one(salt, ikm, 16, res))
- return false;
-
- return aes_cmac_one(res, info, info_len, okm);
-}
-
-bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
- uint8_t net_id[1],
- uint8_t enc_key[16],
- uint8_t priv_key[16])
-{
- int fd;
- uint8_t output[16];
- uint8_t t[16];
- uint8_t *stage;
- bool success = false;
-
- stage = g_malloc(sizeof(output) + p_len + 1);
- if (stage == NULL)
- return false;
-
- if (!mesh_crypto_s1("smk2", 4, stage))
- goto fail;
-
- if (!aes_cmac_one(stage, n, 16, t))
- goto fail;
-
- fd = aes_cmac_N_start(t);
- if (fd < 0)
- goto fail;
-
- memcpy(stage, p, p_len);
- stage[p_len] = 1;
-
- if(!aes_cmac(fd, stage, p_len + 1, output))
- goto done;
-
- net_id[0] = output[15] & 0x7f;
-
- memcpy(stage, output, 16);
- memcpy(stage + 16, p, p_len);
- stage[p_len + 16] = 2;
-
- if(!aes_cmac(fd, stage, p_len + 16 + 1, output))
- goto done;
-
- memcpy(enc_key, output, 16);
-
- memcpy(stage, output, 16);
- memcpy(stage + 16, p, p_len);
- stage[p_len + 16] = 3;
-
- if(!aes_cmac(fd, stage, p_len + 16 + 1, output))
- goto done;
-
- memcpy(priv_key, output, 16);
- success = true;
-
-done:
- aes_cmac_destroy(fd);
-fail:
- g_free(stage);
-
- return success;
-}
-
-static bool crypto_128(const uint8_t n[16], const char *s, uint8_t out128[16])
-{
- uint8_t id128[] = { 'i', 'd', '1', '2', '8', 0x01 };
- uint8_t salt[16];
-
- if (!mesh_crypto_s1(s, 4, salt))
- return false;
-
- return mesh_crypto_k1(n, salt, id128, sizeof(id128), out128);
-}
-
-bool mesh_crypto_nkik(const uint8_t n[16], uint8_t identity_key[16])
-{
- return crypto_128(n, "nkik", identity_key);
-}
-
-static bool identity_calc(const uint8_t net_key[16], uint16_t addr,
- bool check, uint8_t id[16])
-{
- uint8_t id_key[16];
- uint8_t tmp[16];
-
- if (!mesh_crypto_nkik(net_key, id_key))
- return false;
-
- memset(tmp, 0, sizeof(tmp));
- put_be16(addr, tmp + 14);
-
- if (check) {
- memcpy(tmp + 6, id + 8, 8);
- } else {
- mesh_get_random_bytes(tmp + 6, 8);
- memcpy(id + 8, tmp + 6, 8);
- }
-
- if (!aes_ecb_one(id_key, tmp, tmp))
- return false;
-
- if (check)
- return (memcmp(id, tmp + 8, 8) == 0);
-
- memcpy(id, tmp + 8, 8);
- return true;
-}
-
-bool mesh_crypto_identity(const uint8_t net_key[16], uint16_t addr,
- uint8_t id[16])
-{
- return identity_calc(net_key, addr, false, id);
-}
-
-bool mesh_crypto_identity_check(const uint8_t net_key[16], uint16_t addr,
- uint8_t id[16])
-{
- return identity_calc(net_key, addr, true, id);
-}
-
-bool mesh_crypto_nkbk(const uint8_t n[16], uint8_t beacon_key[16])
-{
- return crypto_128(n, "nkbk", beacon_key);
-}
-
-bool mesh_crypto_k3(const uint8_t n[16], uint8_t out64[8])
-{
- uint8_t tmp[16];
- uint8_t t[16];
- uint8_t id64[] = { 'i', 'd', '6', '4', 0x01 };
-
- if (!mesh_crypto_s1("smk3", 4, tmp))
- return false;
-
- if (!aes_cmac_one(tmp, n, 16, t))
- return false;
-
- if (!aes_cmac_one(t, id64, sizeof(id64), tmp))
- return false;
-
- memcpy(out64, tmp + 8, 8);
-
- return true;
-}
-
-bool mesh_crypto_k4(const uint8_t a[16], uint8_t out6[1])
-{
- uint8_t tmp[16];
- uint8_t t[16];
- uint8_t id6[] = { 'i', 'd', '6', 0x01 };
-
- if (!mesh_crypto_s1("smk4", 4, tmp))
- return false;
-
- if (!aes_cmac_one(tmp, a, 16, t))
- return false;
-
- if (!aes_cmac_one(t, id6, sizeof(id6), tmp))
- return false;
-
- out6[0] = tmp[15] & 0x3f;
- return true;
-}
-
-bool mesh_crypto_beacon_cmac(const uint8_t encryption_key[16],
- const uint8_t network_id[8],
- uint32_t iv_index, bool kr, bool iu,
- uint64_t *cmac)
-{
- uint8_t msg[13], tmp[16];
-
- if (!cmac)
- return false;
-
- msg[0] = kr ? 0x01 : 0x00;
- msg[0] |= iu ? 0x02 : 0x00;
- memcpy(msg + 1, network_id, 8);
- put_be32(iv_index, msg + 9);
-
- if (!aes_cmac_one(encryption_key, msg, 13, tmp))
- return false;
-
- *cmac = get_be64(tmp);
-
- return true;
-}
-
-bool mesh_crypto_network_nonce(bool ctl, uint8_t ttl, uint32_t seq,
- uint16_t src, uint32_t iv_index,
- uint8_t nonce[13])
-{
- nonce[0] = 0;
- nonce[1] = (ttl & TTL_MASK) | (ctl ? CTL : 0x00);
- nonce[2] = (seq >> 16) & 0xff;
- nonce[3] = (seq >> 8) & 0xff;
- nonce[4] = seq & 0xff;
-
- /* SRC */
- put_be16(src, nonce + 5);
-
- put_be16(0, nonce + 7);
-
- /* IV Index */
- put_be32(iv_index, nonce + 9);
-
- return true;
-}
-
-bool mesh_crypto_network_encrypt(bool ctl, uint8_t ttl,
- uint32_t seq, uint16_t src,
- uint32_t iv_index,
- const uint8_t net_key[16],
- const uint8_t *enc_msg, uint8_t enc_msg_len,
- uint8_t *out, void *net_mic)
-{
- uint8_t nonce[13];
-
- if (!mesh_crypto_network_nonce(ctl, ttl, seq, src, iv_index, nonce))
- return false;
-
- return mesh_crypto_aes_ccm_encrypt(nonce, net_key,
- NULL, 0, enc_msg,
- enc_msg_len, out,
- net_mic,
- ctl ? sizeof(uint64_t) : sizeof(uint32_t));
-}
-
-bool mesh_crypto_network_decrypt(bool ctl, uint8_t ttl,
- uint32_t seq, uint16_t src,
- uint32_t iv_index,
- const uint8_t net_key[16],
- const uint8_t *enc_msg, uint8_t enc_msg_len,
- uint8_t *out, void *net_mic, size_t mic_size)
-{
- uint8_t nonce[13];
-
- if (!mesh_crypto_network_nonce(ctl, ttl, seq, src, iv_index, nonce))
- return false;
-
- return mesh_crypto_aes_ccm_decrypt(nonce, net_key, NULL, 0,
- enc_msg, enc_msg_len, out,
- net_mic, mic_size);
-}
-
-bool mesh_crypto_application_nonce(uint32_t seq, uint16_t src,
- uint16_t dst, uint32_t iv_index,
- bool aszmic, uint8_t nonce[13])
-{
- nonce[0] = 0x01;
- nonce[1] = aszmic ? 0x80 : 0x00;
- nonce[2] = (seq & 0x00ff0000) >> 16;
- nonce[3] = (seq & 0x0000ff00) >> 8;
- nonce[4] = (seq & 0x000000ff);
- nonce[5] = (src & 0xff00) >> 8;
- nonce[6] = (src & 0x00ff);
- nonce[7] = (dst & 0xff00) >> 8;
- nonce[8] = (dst & 0x00ff);
- put_be32(iv_index, nonce + 9);
-
- return true;
-}
-
-bool mesh_crypto_device_nonce(uint32_t seq, uint16_t src,
- uint16_t dst, uint32_t iv_index,
- bool aszmic, uint8_t nonce[13])
-{
- nonce[0] = 0x02;
- nonce[1] = aszmic ? 0x80 : 0x00;
- nonce[2] = (seq & 0x00ff0000) >> 16;
- nonce[3] = (seq & 0x0000ff00) >> 8;
- nonce[4] = (seq & 0x000000ff);
- nonce[5] = (src & 0xff00) >> 8;
- nonce[6] = (src & 0x00ff);
- nonce[7] = (dst & 0xff00) >> 8;
- nonce[8] = (dst & 0x00ff);
- put_be32(iv_index, nonce + 9);
-
- return true;
-}
-
-bool mesh_crypto_application_encrypt(uint8_t key_id, uint32_t seq, uint16_t src,
- uint16_t dst, uint32_t iv_index,
- const uint8_t app_key[16],
- const uint8_t *aad, uint8_t aad_len,
- const uint8_t *msg, uint8_t msg_len,
- uint8_t *out, void *app_mic,
- size_t mic_size)
-{
- uint8_t nonce[13];
- bool aszmic = (mic_size == sizeof(uint64_t)) ? true : false;
-
- if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
- iv_index, aszmic, nonce))
- return false;
-
- if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
- iv_index, aszmic, nonce))
- return false;
-
- return mesh_crypto_aes_ccm_encrypt(nonce, app_key, aad, aad_len,
- msg, msg_len,
- out, app_mic, mic_size);
-}
-
-bool mesh_crypto_application_decrypt(uint8_t key_id, uint32_t seq, uint16_t src,
- uint16_t dst, uint32_t iv_index,
- const uint8_t app_key[16],
- const uint8_t *aad, uint8_t aad_len,
- const uint8_t *enc_msg, uint8_t enc_msg_len,
- uint8_t *out, void *app_mic, size_t mic_size)
-{
- uint8_t nonce[13];
- bool aszmic = (mic_size == sizeof(uint64_t)) ? true : false;
-
- if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
- iv_index, aszmic, nonce))
- return false;
-
- if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
- iv_index, aszmic, nonce))
- return false;
-
- return mesh_crypto_aes_ccm_decrypt(nonce, app_key,
- aad, aad_len, enc_msg,
- enc_msg_len, out,
- app_mic, mic_size);
-}
-
-bool mesh_crypto_session_key(const uint8_t secret[32],
- const uint8_t salt[16],
- uint8_t session_key[16])
-{
- const uint8_t prsk[4] = "prsk";
-
- if (!aes_cmac_one(salt, secret, 32, session_key))
- return false;
-
- return aes_cmac_one(session_key, prsk, 4, session_key);
-}
-
-bool mesh_crypto_nonce(const uint8_t secret[32],
- const uint8_t salt[16],
- uint8_t nonce[13])
-{
- const uint8_t prsn[4] = "prsn";
- uint8_t tmp[16];
- bool result;
-
- if (!aes_cmac_one(salt, secret, 32, tmp))
- return false;
-
- result = aes_cmac_one(tmp, prsn, 4, tmp);
-
- if (result)
- memcpy(nonce, tmp + 3, 13);
-
- return result;
-}
-
-bool mesh_crypto_s1(const void *info, size_t len, uint8_t salt[16])
-{
- const uint8_t zero[16] = {0};
-
- return aes_cmac_one(zero, info, len, salt);
-}
-
-bool mesh_crypto_prov_prov_salt(const uint8_t conf_salt[16],
- const uint8_t prov_rand[16],
- const uint8_t dev_rand[16],
- uint8_t prov_salt[16])
-{
- const uint8_t zero[16] = {0};
- uint8_t tmp[16 * 3];
-
- memcpy(tmp, conf_salt, 16);
- memcpy(tmp + 16, prov_rand, 16);
- memcpy(tmp + 32, dev_rand, 16);
-
- return aes_cmac_one(zero, tmp, sizeof(tmp), prov_salt);
-}
-
-bool mesh_crypto_prov_conf_key(const uint8_t secret[32],
- const uint8_t salt[16],
- uint8_t conf_key[16])
-{
- const uint8_t prck[4] = "prck";
-
- if (!aes_cmac_one(salt, secret, 32, conf_key))
- return false;
-
- return aes_cmac_one(conf_key, prck, 4, conf_key);
-}
-
-bool mesh_crypto_device_key(const uint8_t secret[32],
- const uint8_t salt[16],
- uint8_t device_key[16])
-{
- const uint8_t prdk[4] = "prdk";
-
- if (!aes_cmac_one(salt, secret, 32, device_key))
- return false;
-
- return aes_cmac_one(device_key, prdk, 4, device_key);
-}
-
-bool mesh_crypto_virtual_addr(const uint8_t virtual_label[16],
- uint16_t *addr)
-{
- uint8_t tmp[16];
-
- if (!mesh_crypto_s1("vtad", 4, tmp))
- return false;
-
- if (!addr || !aes_cmac_one(tmp, virtual_label, 16, tmp))
- return false;
-
- *addr = (get_be16(tmp + 14) & 0x3fff) | 0x8000;
-
- return true;
-}
-
-bool mesh_crypto_packet_encode(uint8_t *packet, uint8_t packet_len,
- const uint8_t network_key[16],
- uint32_t iv_index,
- const uint8_t privacy_key[16])
-{
- uint8_t network_nonce[13] = { 0x00, 0x00 };
- uint8_t privacy_counter[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
- uint8_t tmp[16];
- int i;
-
- /* Detect Proxy packet by CTL == true && DST == 0x0000 */
- if ((packet[1] & CTL) && get_be16(packet + 7) == 0)
- network_nonce[0] = 0x03;
- else
- /* CTL + TTL */
- network_nonce[1] = packet[1];
-
- /* Seq Num */
- network_nonce[2] = packet[2];
- network_nonce[3] = packet[3];
- network_nonce[4] = packet[4];
-
- /* SRC */
- network_nonce[5] = packet[5];
- network_nonce[6] = packet[6];
-
- /* DST not available */
- network_nonce[7] = 0;
- network_nonce[8] = 0;
-
- /* IV Index */
- put_be32(iv_index, network_nonce + 9);
-
- /* Check for Long net-MIC */
- if (packet[1] & CTL) {
- if (!mesh_crypto_aes_ccm_encrypt(network_nonce, network_key,
- NULL, 0,
- packet + 7, packet_len - 7 - 8,
- packet + 7, NULL, sizeof(uint64_t)))
- return false;
- } else {
- if (!mesh_crypto_aes_ccm_encrypt(network_nonce, network_key,
- NULL, 0,
- packet + 7, packet_len - 7 - 4,
- packet + 7, NULL, sizeof(uint32_t)))
- return false;
- }
-
- put_be32(iv_index, privacy_counter + 5);
- memcpy(privacy_counter + 9, packet + 7, 7);
-
- if (!aes_ecb_one(privacy_key, privacy_counter, tmp))
- return false;
-
- for (i = 0; i < 6; i++)
- packet[1 + i] ^= tmp[i];
-
- return true;
-}
-
-bool mesh_crypto_packet_decode(const uint8_t *packet, uint8_t packet_len,
- bool proxy, uint8_t *out, uint32_t iv_index,
- const uint8_t network_key[16],
- const uint8_t privacy_key[16])
-{
- uint8_t privacy_counter[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
- uint8_t network_nonce[13] = { 0x00, 0x00, };
- uint8_t tmp[16];
- uint16_t src;
- int i;
-
- if (packet_len < 14)
- return false;
-
- put_be32(iv_index, privacy_counter + 5);
- memcpy(privacy_counter + 9, packet + 7, 7);
-
- if (!aes_ecb_one(privacy_key, privacy_counter, tmp))
- return false;
-
- memcpy(out, packet, packet_len);
- for (i = 0; i < 6; i++)
- out[1 + i] ^= tmp[i];
-
- src = get_be16(out + 5);
-
- /* Pre-check SRC address for illegal values */
- if (!src || src >= 0x8000)
- return false;
-
- /* Detect Proxy packet by CTL == true && proxy == true */
- if ((out[1] & CTL) && proxy)
- network_nonce[0] = 0x03;
- else
- /* CTL + TTL */
- network_nonce[1] = out[1];
-
- /* Seq Num */
- network_nonce[2] = out[2];
- network_nonce[3] = out[3];
- network_nonce[4] = out[4];
-
- /* SRC */
- network_nonce[5] = out[5];
- network_nonce[6] = out[6];
-
- /* DST not available */
- network_nonce[7] = 0;
- network_nonce[8] = 0;
-
- /* IV Index */
- put_be32(iv_index, network_nonce + 9);
-
- /* Check for Long MIC */
- if (out[1] & CTL) {
- uint64_t mic;
-
- if (!mesh_crypto_aes_ccm_decrypt(network_nonce, network_key,
- NULL, 0, packet + 7, packet_len - 7,
- out + 7, &mic, sizeof(mic)))
- return false;
-
- mic ^= get_be64(out + packet_len - 8);
- put_be64(mic, out + packet_len - 8);
-
- if (mic)
- return false;
- } else {
- uint32_t mic;
-
- if (!mesh_crypto_aes_ccm_decrypt(network_nonce, network_key,
- NULL, 0, packet + 7, packet_len - 7,
- out + 7, &mic, sizeof(mic)))
- return false;
-
- mic ^= get_be32(out + packet_len - 4);
- put_be32(mic, out + packet_len - 4);
-
- if (mic)
- return false;
- }
-
- return true;
-}
-
-bool mesh_get_random_bytes(void *buf, size_t num_bytes)
-{
- ssize_t len;
- int fd;
-
- fd = open("/dev/urandom", O_RDONLY);
- if (fd < 0)
- return false;
-
- len = read(fd, buf, num_bytes);
-
- close(fd);
-
- if (len < 0)
- return false;
-
- return true;
-}