Linux-Bluetooth Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH BlueZ] unit: Add Mesh Crypto tests from Mesh Profile Spec
@ 2019-10-03 19:49 Brian Gix
  0 siblings, 0 replies; only message in thread
From: Brian Gix @ 2019-10-03 19:49 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, inga.stotland

This unit test will be grown over time to include tests formed from the
sample data in the Bluetooth Mesh Profile specification (Currently at
version v1.0.1).

Currently it includes test cases for the following nset of sample data:
Sections 8.1.1-6
Sections 8.2.1-6
Sections 8.3.1-11
Section 8.4.3
Section 8.6.2
---
 Makefile.am             |   10 +
 unit/test-mesh-crypto.c | 1998 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 2008 insertions(+)
 create mode 100644 unit/test-mesh-crypto.c

diff --git a/Makefile.am b/Makefile.am
index 938cfd9c0..2ac28b23d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -123,6 +123,7 @@ ell_headers = ell/util.h \
 			ell/main.h \
 			ell/strv.h \
 			ell/string.h \
+			ell/utf8.h \
 			ell/dbus.h \
 			ell/dbus-service.h \
 			ell/dbus-client.h
@@ -142,6 +143,7 @@ ell_sources = ell/private.h ell/missing.h \
 			ell/string.c \
 			ell/cipher.c \
 			ell/checksum.c \
+			ell/utf8.c \
 			ell/dbus-private.h \
 			ell/dbus.c \
 			ell/dbus-message.c \
@@ -518,6 +520,14 @@ unit_test_midi_LDADD = src/libshared-glib.la \
 			$(GLIB_LIBS) $(ALSA_LIBS)
 endif
 
+unit_tests += unit/test-mesh-crypto
+unit_test_mesh_crypto_CPPFLAGS = $(ell_cflags)
+unit_test_mesh_crypto_SOURCES = unit/test-mesh-crypto.c \
+				mesh/crypto.h ell/internal ell/ell.h \
+				$(ell_sources)
+unit_test_mesh_crypto_LDADD = src/libshared-ell.la \
+			$(ell_ldadd)
+
 if MAINTAINER_MODE
 noinst_PROGRAMS += $(unit_tests)
 endif
diff --git a/unit/test-mesh-crypto.c b/unit/test-mesh-crypto.c
new file mode 100644
index 000000000..27e21176d
--- /dev/null
+++ b/unit/test-mesh-crypto.c
@@ -0,0 +1,1998 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2019  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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "client/display.h"
+
+#include "mesh/crypto.c"
+
+struct mesh_crypto_test {
+	const char *name;
+
+	const char *dev_key;
+	const char *app_key;
+	const char *net_key;
+	const char *uuid;
+	uint32_t iv_index;
+
+	uint8_t net_nid;
+	uint8_t key_aid;
+	bool md[32];
+	bool szmic;
+	bool frnd;
+	bool ctl;
+	bool segmented;
+	bool relay;
+	bool akf;
+	bool kr;
+	bool ivu;
+	bool network_only;
+	uint8_t seg_max;
+	uint8_t seg_num;
+	uint8_t opcode;
+	uint8_t net_ttl;
+	uint16_t seqZero;
+	uint32_t app_seq;
+	uint32_t net_seq[32];
+	uint16_t net_src;
+	uint16_t net_dst;
+	const char *app_msg;
+
+	const char *ikm;
+	const char *okm;
+	const char *info;
+	const char *salt;
+	const char *salt_out;
+	const char *nid;
+	const char *lpn_addr;
+	const char *lpn_cntr;
+	const char *fn_addr;
+	const char *fn_cntr;
+	const char *p;
+	const char *short_net_id;
+	const char *net_key_id;
+	const char *aid;
+
+	const char *enc_key;
+	const char *net_id;
+	const char *net_nonce[32];
+	const char *app_nonce;
+	const char *priv_key;
+	const char *priv_rand[32];
+
+	const char *enc_msg;
+	uint32_t app_mic32;
+	uint64_t app_mic64;
+
+	const char *trans_pkt[32];
+	const char *net_msg[32];
+	uint32_t net_mic32[32];
+	uint64_t net_mic64;
+
+	const char *packet[32];
+
+	uint8_t beacon_type;
+	uint8_t beacon_flags;
+	const char *beacon_cmac;
+	const char *beacon;
+
+	const char *rand;
+	const char *ident_res_key;
+	const char *hash_input;
+	const char *mesh_id_hash;
+	const char *identity_hash;
+};
+
+static const struct mesh_crypto_test s8_1_1 = {
+	.name		= "8.1.1 s1 SALT generation function",
+	.salt		= "test",
+	.salt_out	= "b73cefbd641ef2ea598c2b6efb62f79c",
+};
+
+static const struct mesh_crypto_test s8_1_2 = {
+	.name		= "8.1.2 k1 function",
+	.ikm		= "3216d1509884b533248541792b877f98",
+	.salt		= "salt",
+	.info		= "info",
+	.okm		= "f6ed15a8934afbe7d83e8dcb57fcf5d7",
+};
+
+static const struct mesh_crypto_test s8_1_3 = {
+	.name		= "8.1.3 k2 function (master)",
+	.net_key	= "f7a2a44f8e8a8029064f173ddc1e2b00",
+	.p		= "00",
+	.nid		= "7f",
+	.enc_key	= "9f589181a0f50de73c8070c7a6d27f46",
+	.priv_key	= "4c715bd4a64b938f99b453351653124f",
+};
+
+static const struct mesh_crypto_test s8_1_4 = {
+	.name		= "8.1.4 k2 function (friendship)",
+	.frnd		= true,
+	.lpn_addr	= "0203",
+	.fn_addr	= "0405",
+	.lpn_cntr	= "0607",
+	.fn_cntr	= "0809",
+	.net_key	= "f7a2a44f8e8a8029064f173ddc1e2b00",
+	.p		= "010203040506070809",
+	.nid		= "73",
+	.enc_key	= "11efec0642774992510fb5929646df49",
+	.priv_key	= "d4d7cc0dfa772d836a8df9df5510d7a7",
+};
+
+static const struct mesh_crypto_test s8_1_5 = {
+	.name		= "8.1.5 k3 function",
+	.net_key	= "f7a2a44f8e8a8029064f173ddc1e2b00",
+	.salt		= "smk3",
+	.info		= "id64\01",
+	.short_net_id	= "ff046958233db014",
+};
+
+static const struct mesh_crypto_test s8_1_6 = {
+	.name		= "8.1.6 k4 function",
+	.app_key	= "3216d1509884b533248541792b877f98",
+	.salt		= "smk4",
+	.info		= "id6\01",
+	.aid		= "38",
+};
+
+
+static const struct mesh_crypto_test s8_2_1 = {
+	.name		= "8.2.1 Application key AID",
+	.app_key	= "63964771734fbd76e3b40519d1d94a48",
+	.salt		= "smk4",
+	.info		= "id6\01",
+	.aid		= "26",
+};
+
+static const struct mesh_crypto_test s8_2_2 = {
+	.name		= "8.2.2 Encryption and privacy keys (Master)",
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.p		= "00",
+	.nid		= "68",
+	.enc_key	= "0953fa93e7caac9638f58820220a398e",
+	.priv_key	= "8b84eedec100067d670971dd2aa700cf",
+};
+
+static const struct mesh_crypto_test s8_2_3 = {
+	.name		= "8.2.3 Encryption and privacy keys (Friendship)",
+	.frnd		= true,
+	.lpn_addr	= "1201",
+	.fn_addr	= "2345",
+	.lpn_cntr	= "0000",
+	.fn_cntr	= "072f",
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.p		= "01120123450000072f",
+	.nid		= "5e",
+	.enc_key	= "be635105434859f484fc798e043ce40e",
+	.priv_key	= "5d396d4b54d3cbafe943e051fe9a4eb8",
+};
+
+static const struct mesh_crypto_test s8_2_4 = {
+	.name		= "8.2.4 Network ID",
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.salt		= "smk3",
+	.info		= "id64\01",
+	.short_net_id	= "3ecaff672f673370",
+};
+
+static const struct mesh_crypto_test s8_2_5 = {
+	.name		= "8.2.5 Identity Key",
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.salt		= "nkik",
+	.info		= "id128\01",
+	.enc_key	= "84396c435ac48560b5965385253e210c",
+};
+
+static const struct mesh_crypto_test s8_2_6 = {
+	.name		= "8.2.6 Beacon Key",
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.salt		= "nkbk",
+	.info		= "id128\01",
+	.enc_key	= "5423d967da639a99cb02231a83f7d254",
+};
+
+static const struct mesh_crypto_test s8_3_1 = {
+	.name		= "8.3.1 Message #1",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.iv_index	= 0x12345678,
+
+	.net_ttl	= 0x00,
+	.net_seq	= {0x000001},
+	.net_src	= 0x1201,
+	.net_dst	= 0xfffd,
+	.opcode		= NET_OP_FRND_REQUEST,
+	.trans_pkt	= {"034b50057e400000010000"},
+	.net_nid	= 0x68,
+
+
+	.ctl		= true,
+	.enc_key	= "0953fa93e7caac9638f58820220a398e",
+	.net_nonce	= {"00800000011201000012345678"},
+	.priv_key	= "8b84eedec100067d670971dd2aa700cf",
+	.priv_rand	= {"000000000012345678b5e5bfdacbaf6c"},
+
+	.net_msg	= {"b5e5bfdacbaf6cb7fb6bff871f"},
+	.net_mic64	= 0x035444ce83a670df,
+
+	.packet		= {"68eca487516765b5e5bfdacbaf6cb7fb6bff871f035444ce83a670df"},
+};
+
+static const struct mesh_crypto_test s8_3_2 = {
+	.name		= "8.3.2 Message #2",
+
+	.iv_index	= 0x12345678,
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+
+	.ctl		= true,
+	.net_ttl	= 0x00,
+	.net_seq	= {0x014820},
+	.net_src	= 0x2345,
+	.net_dst	= 0x1201,
+	.trans_pkt	= {"04320308ba072f"},
+	.net_nid	= 0x68,
+
+
+	.opcode		= NET_OP_FRND_OFFER,
+	.enc_key	= "0953fa93e7caac9638f58820220a398e",
+	.net_nonce	= {"00800148202345000012345678"},
+	.priv_key	= "8b84eedec100067d670971dd2aa700cf",
+
+	.net_msg	= {"79d7dbc0c9b4d43eeb"},
+	.net_mic64	= 0xec129d20a620d01e,
+
+	.priv_rand	= {"00000000001234567879d7dbc0c9b4d4"},
+	.packet		= {"68d4c826296d7979d7dbc0c9b4d43eebec129d20a620d01e"},
+};
+
+static const struct mesh_crypto_test s8_3_3 = {
+	.name		= "8.3.3 Message #3",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.iv_index	= 0x12345678,
+
+	.ctl		= true,
+	.net_ttl	= 0x00,
+	.net_seq	= {0x2b3832},
+	.net_dst	= 0x1201,
+	.net_src	= 0x2fe3,
+	.trans_pkt	= {"04fa0205a6000a"},
+	.net_nid	= 0x68,
+
+
+	.opcode		= NET_OP_FRND_OFFER,
+	.enc_key	= "0953fa93e7caac9638f58820220a398e",
+	.net_nonce	= {"00802b38322fe3000012345678"},
+	.priv_key	= "8b84eedec100067d670971dd2aa700cf",
+	.priv_rand	= {"00000000001234567853273086b8c5ee"},
+
+	.net_msg	= {"53273086b8c5ee00bd"},
+	.net_mic64	= 0xd9cfcc62a2ddf572,
+
+	.packet		= {"68da062bc96df253273086b8c5ee00bdd9cfcc62a2ddf572"},
+};
+
+static const struct mesh_crypto_test s8_3_4 = {
+	.name		= "8.3.4 Message #4",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.iv_index	= 0x12345678,
+
+	.net_nid	= 0x5e,
+	.net_ttl	= 0x00,
+	.net_seq	= {0x000002},
+	.net_dst	= 0x2345,
+	.net_src	= 0x1201,
+	.trans_pkt	= {"0100"},
+
+	.frnd		= true,
+	.lpn_addr	= "1201",
+	.fn_addr	= "2345",
+	.lpn_cntr	= "0000",
+	.fn_cntr	= "072f",
+	.p		= "01120123450000072f",
+
+	.ctl		= true,
+	.opcode		= NET_OP_FRND_POLL,
+	.enc_key	= "be635105434859f484fc798e043ce40e",
+	.net_nonce	= {"00800000021201000012345678"},
+	.priv_key	= "5d396d4b54d3cbafe943e051fe9a4eb8",
+	.priv_rand	= {"000000000012345678b0e5d0ad970d57"},
+
+	.net_msg	= {"b0e5d0ad"},
+	.net_mic64	= 0x970d579a4e88051c,
+
+	.packet		= {"5e84eba092380fb0e5d0ad970d579a4e88051c"},
+};
+
+static const struct mesh_crypto_test s8_3_5 = {
+	.name		= "8.3.5 Message #5",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.iv_index	= 0x12345678,
+
+	.net_nid	= 0x5e,
+	.net_ttl	= 0x00,
+	.net_seq	= {0x014834},
+	.net_src	= 0x2345,
+	.net_dst	= 0x1201,
+	.trans_pkt	= {"02001234567800"},
+
+	.frnd		= true,
+	.lpn_addr	= "1201",
+	.fn_addr	= "2345",
+	.lpn_cntr	= "0000",
+	.fn_cntr	= "072f",
+	.p		= "01120123450000072f",
+
+	.ctl		= true,
+	.opcode		= NET_OP_FRND_UPDATE,
+	.enc_key	= "be635105434859f484fc798e043ce40e",
+	.net_nonce	= {"00800148342345000012345678"},
+	.priv_key	= "5d396d4b54d3cbafe943e051fe9a4eb8",
+	.priv_rand	= {"0000000000123456785c39da1792b1fe"},
+
+	.net_msg	= {"5c39da1792b1fee9ec"},
+	.net_mic64	= 0x74b786c56d3a9dee,
+
+	.packet		= {"5eafd6f53c43db5c39da1792b1fee9ec74b786c56d3a9dee"},
+};
+
+static const struct mesh_crypto_test s8_3_6 = {
+	.name		= "8.3.6 Message #6",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
+	.iv_index	= 0x12345678,
+
+	.segmented	= true,
+	.net_nid	= 0x68,
+	.net_ttl	= 0x04,
+	.app_seq	= 0x3129ab,
+	.net_seq	= {0x3129ab,
+			   0x3129ac},
+	.net_src	= 0x0003,
+	.net_dst	= 0x1201,
+	.app_msg	= "0056341263964771734fbd76e3b40519d1d94a48",
+	.enc_msg	= "ee9dddfd2169326d23f3afdfcfdc18c52fdef772",
+	.app_mic32	= 0xe0e17308,
+
+	.enc_key	= "0953fa93e7caac9638f58820220a398e",
+	.app_nonce	= "02003129ab0003120112345678",
+
+	.priv_key	= "8b84eedec100067d670971dd2aa700cf",
+
+	.net_nonce	= {"00043129ab0003000012345678",
+	                   "00043129ac0003000012345678"},
+
+	.priv_rand	= {"0000000000123456780afba8c63d4e68",
+	                   "0000000000123456786cae0c032bf074"},
+
+	.trans_pkt	= {"8026ac01ee9dddfd2169326d23f3afdf",
+			   "8026ac21cfdc18c52fdef772e0e17308"},
+
+	.net_msg	= {"0afba8c63d4e686364979deaf4fd40961145",
+	                   "6cae0c032bf0746f44f1b8cc8ce5edc57e55"},
+
+	.net_mic32	= {0x939cda0e,
+	                   0xbeed49c0},
+
+	.packet		= {"68cab5c5348a230afba8c63d4e686364979deaf4fd40961145939cda0e",
+	                   "681615b5dd4a846cae0c032bf0746f44f1b8cc8ce5edc57e55beed49c0"},
+};
+
+static const struct mesh_crypto_test s8_3_7 = {
+	.name		= "8.3.7 Message #7",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.iv_index	= 0x12345678,
+
+	.net_nid	= 0x68,
+	.relay		= true,
+	.ctl		= true,
+	.net_ttl	= 0x0b,
+	.net_seq	= {0x014835},
+	.net_src	= 0x2345,
+	.net_dst	= 0x0003,
+	.opcode		= NET_OP_SEG_ACKNOWLEDGE,
+	.seqZero	= 0x09ab,
+	.trans_pkt	= {"00a6ac00000002"},
+
+
+	.enc_key	= "0953fa93e7caac9638f58820220a398e",
+	.net_nonce	= {"008b0148352345000012345678"},
+	.priv_key	= "8b84eedec100067d670971dd2aa700cf",
+	.priv_rand	= {"0000000000123456780d0d730f94d7f3"},
+
+	.net_msg	= {"0d0d730f94d7f3509d"},
+	.net_mic64	= 0xf987bb417eb7c05f,
+
+	.packet		= {"68e476b5579c980d0d730f94d7f3509df987bb417eb7c05f"},
+};
+
+static const struct mesh_crypto_test s8_3_8 = {
+	.name		= "8.3.8 Message #8",
+	.network_only	= true,  /* Test has incomplete Access Payload */
+	.seg_max	= 1,
+	.seg_num	= 0,
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.iv_index	= 0x12345678,
+
+	.net_nid	= 0x68,
+	.relay		= true,
+	.net_ttl	= 0x04,
+	.net_seq	= {0x3129ad},
+	.net_src	= 0x0003,
+	.net_dst	= 0x1201,
+	.segmented	= true,
+	.seqZero	= 0x09ab,
+	.trans_pkt	= {"8026ac01ee9dddfd2169326d23f3afdf"},
+
+
+	.enc_key	= "0953fa93e7caac9638f58820220a398e",
+	.net_nonce	= {"00043129ad0003000012345678"},
+	.priv_key	= "8b84eedec100067d670971dd2aa700cf",
+	.priv_rand	= {"0000000000123456780e2f91add6f06e"},
+
+	.net_msg	= {"0e2f91add6f06e66006844cec97f973105ae"},
+	.net_mic32	= {0x2534f958},
+
+	.packet		= {"684daa6267c2cf0e2f91add6f06e66006844cec97f973105ae2534f958"},
+};
+
+
+static const struct mesh_crypto_test s8_3_9 = {
+	.name		= "8.3.9 Message #9",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.iv_index	= 0x12345678,
+
+	.net_nid	= 0x68,
+	.relay		= true,
+	.ctl		= true,
+	.net_ttl	= 0x0b,
+	.net_seq	= {0x014836},
+	.net_src	= 0x2345,
+	.net_dst	= 0x0003,
+	.opcode		= NET_OP_SEG_ACKNOWLEDGE,
+	.seqZero	= 0x09ab,
+	.trans_pkt	= {"00a6ac00000003"},
+
+
+	.enc_key	= "0953fa93e7caac9638f58820220a398e",
+	.net_nonce	= {"008b0148362345000012345678"},
+	.priv_key	= "8b84eedec100067d670971dd2aa700cf",
+	.priv_rand	= {"000000000012345678d85d806bbed248"},
+
+	.net_msg	= {"d85d806bbed248614f"},
+	.net_mic64	= 0x938067b0d983bb7b,
+
+	.packet		= {"68aec467ed4901d85d806bbed248614f938067b0d983bb7b"},
+};
+
+static const struct mesh_crypto_test s8_3_10 = {
+	.name		= "8.3.10 Message #10",
+
+	.iv_index	= 0x12345678,
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+
+	.net_nid	= 0x5e,
+	.net_ttl	= 0x00,
+	.net_seq	= {0x000003},
+	.net_src	= 0x1201,
+	.net_dst	= 0x2345,
+	.trans_pkt	= {"0101"},
+
+	.frnd		= true,
+	.lpn_addr	= "1201",
+	.fn_addr	= "2345",
+	.lpn_cntr	= "0000",
+	.fn_cntr	= "072f",
+	.p		= "01120123450000072f",
+
+	.ctl		= true,
+	.opcode		= NET_OP_FRND_POLL,
+	.enc_key	= "be635105434859f484fc798e043ce40e",
+	.net_nonce	= {"00800000031201000012345678"},
+	.priv_key	= "5d396d4b54d3cbafe943e051fe9a4eb8",
+	.priv_rand	= {"0000000000123456787777ed355afaf6"},
+
+	.net_msg	= {"7777ed35"},
+	.net_mic64	= 0x5afaf66d899c1e3d,
+
+	.packet		= {"5e7b786568759f7777ed355afaf66d899c1e3d"},
+};
+
+static const struct mesh_crypto_test s8_3_11 = {
+	.name		= "8.3.11 Message #11",
+
+	/* Test has incomplete Access Payload */
+	.network_only	= true,
+	.seg_max	= 1,
+	.seg_num	= 0,
+
+	.frnd		= true,
+	.lpn_addr	= "1201",
+	.fn_addr	= "2345",
+	.lpn_cntr	= "0000",
+	.fn_cntr	= "072f",
+	.p		= "01120123450000072f",
+
+	.iv_index	= 0x12345678,
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+
+	.net_nid	= 0x5e,
+	.net_ttl	= 0x03,
+	.net_seq	= {0x3129ad},
+	.net_src	= 0x0003,
+	.net_dst	= 0x1201,
+	.akf		= true,
+	.key_aid	= 0x00,
+	.segmented	= true,
+	.seqZero	= 0x09ab,
+	.trans_pkt	= {"c026ac01ee9dddfd2169326d23f3afdf"},
+
+	.enc_key	= "be635105434859f484fc798e043ce40e",
+	.net_nonce	= {"00033129ad0003000012345678"},
+	.priv_key	= "5d396d4b54d3cbafe943e051fe9a4eb8",
+	.priv_rand	= {"000000000012345678d5e748a20ecfd9"},
+
+	.net_msg	= {"d5e748a20ecfd98ddfd32de80befb400213d"},
+	.net_mic32	= {0x113813b5},
+
+	.packet		= {"5e6ebfc021edf5d5e748a20ecfd98ddfd32de80befb400213d113813b5"},
+};
+
+static const struct mesh_crypto_test s8_4_3 = {
+	.name		= "8.4.3 Secure Network Beacon",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.iv_index	= 0x12345678,
+
+	.enc_key	= "5423d967da639a99cb02231a83f7d254",
+	.net_id		= "3ecaff672f673370",
+
+	.beacon_type	= 0x01,
+	.beacon_flags	= 0x00,
+	.beacon_cmac	= "8ea261582f364f6f",
+	.beacon		= "01003ecaff672f673370123456788ea261582f364f6f",
+};
+
+static const struct mesh_crypto_test s8_6_2 = {
+	.name		= "8.6.2 Service Data using Node Identity",
+
+	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
+	.net_src	= 0x1201,
+	.rand		= "34ae608fbbc1f2c6",
+	.ident_res_key	= "84396c435ac48560b5965385253e210c",
+
+	.hash_input	= "00000000000034ae608fbbc1f2c61201",
+	.identity_hash	= "00861765aefcc57b",
+	.beacon 	= "0100861765aefcc57b34ae608fbbc1f2c6",
+};
+
+#define PASS	COLOR_GREEN "PASS" COLOR_OFF
+#define FAIL	COLOR_RED "FAIL" COLOR_OFF
+#define INVAL	COLOR_YELLOW "INVALID" COLOR_OFF
+
+#define EVALCMP(a, b, l)	memcmp((a), (b), (l)) ? FAIL : PASS
+#define EVALSTR(a, b)		(a) && (b) ? (strcmp((a), (b)) ? FAIL : PASS) : INVAL
+#define EVALNUM(a, b)		a == b ? PASS : FAIL
+#define EVALBOOLNOTBOTH(a, b)	!(a && b) ? PASS : FAIL
+
+static void verify_data(const char *label, unsigned int indent,
+			const char *sample, const uint8_t *data, size_t size)
+{
+	char *str;
+
+	str = l_util_hexstring(data, size);
+	l_info("%-20s =%*c%s", label, 1 + (indent * 2), ' ', sample);
+	l_info("%-20s  %*c%s => %s", "", 1 + (indent * 2), ' ', str,
+							EVALSTR(sample, str));
+	l_free(str);
+}
+
+static void verify_bool_not_both(const char *label, unsigned int indent,
+						bool sample, bool data)
+{
+	l_info("%-20s =%*c%s", label, 1 + (indent * 2), ' ',
+						sample ? "true" : "false");
+	l_info("%-20s  %*c%s => %s", "", 1 + (indent * 2), ' ',
+						data ? "true" : "false",
+						EVALBOOLNOTBOTH(sample, data));
+}
+
+static void verify_uint8(const char *label, unsigned int indent,
+						uint8_t sample, uint8_t data)
+{
+	l_info("%-20s =%*c%02x", label, 1 + (indent * 2), ' ', sample);
+	l_info("%-20s  %*c%02x => %s", "", 1 + (indent * 2), ' ', data,
+							EVALNUM(sample, data));
+}
+
+static void verify_uint16(const char *label, unsigned int indent,
+						uint16_t sample, uint16_t data)
+{
+	l_info("%-20s =%*c%04x", label, 1 + (indent * 2), ' ', sample);
+	l_info("%-20s  %*c%04x => %s", "", 1 + (indent * 2), ' ', data,
+							EVALNUM(sample, data));
+}
+
+static void verify_uint24(const char *label, unsigned int indent,
+						uint32_t sample, uint32_t data)
+{
+	l_info("%-20s =%*c%06x", label, 1 + (indent * 2), ' ', sample);
+	l_info("%-20s  %*c%06x => %s", "", 1 + (indent * 2), ' ', data,
+							EVALNUM(sample, data));
+}
+
+static void verify_uint32(const char *label, unsigned int indent,
+						uint32_t sample, uint32_t data)
+{
+	l_info("%-20s =%*c%08x", label, 1 + (indent * 2), ' ', sample);
+	l_info("%-20s  %*c%08x => %s", "", 1 + (indent * 2), ' ', data,
+							EVALNUM(sample, data));
+}
+
+static void verify_uint64(const char *label, unsigned int indent,
+						uint64_t sample, uint64_t data)
+{
+	l_info("%-20s =%*c%16lx", label, 1 + (indent * 2), ' ', sample);
+	l_info("%-20s  %*c%16lx => %s", "", 1 + (indent * 2), ' ', data,
+							EVALNUM(sample, data));
+}
+
+static void show_str(const char *label, unsigned int indent,
+						const char *sample)
+{
+	char *printable = l_malloc(strlen(sample) + 1);
+	char *tmp = printable;
+
+	while (*sample) {
+		if (l_ascii_isprint(*sample))
+			*tmp++ = *sample++;
+		else {
+			*tmp++ = '?';
+			sample++;
+		}
+	}
+
+	*tmp = '\0';
+
+	l_info("%-20s =%*c%s", label, 1 + (indent * 2), ' ', printable);
+	l_free(printable);
+}
+
+static void show_data(const char *label, unsigned int indent,
+						const void *data, size_t size)
+{
+	char *str;
+
+	str = l_util_hexstring(data, size);
+	l_info("%-20s =%*c%s", label, 1 + (indent * 2), ' ', str);
+	l_free(str);
+}
+
+static void show_uint8(const char *label, unsigned int indent, uint8_t data)
+{
+	l_info("%-20s =%*c%2.2x", label, 1 + (indent * 2), ' ', data);
+}
+
+static void show_uint32(const char *label, unsigned int indent, uint32_t data)
+{
+	l_info("%-20s =%*c%8.8x", label, 1 + (indent * 2), ' ', data);
+}
+
+
+static void check_encrypt_segment(const struct mesh_crypto_test *keys,
+				uint16_t seg, uint16_t seg_max,
+				uint8_t *enc_msg, size_t len,
+				uint8_t *enc_key, uint8_t *priv_key,
+				uint8_t nid)
+{
+	uint8_t net_nonce[13];
+	uint8_t priv_rand[16];
+	uint8_t packet[29];
+	uint8_t packet_len;
+	uint64_t net_mic64;
+	uint32_t hdr, net_mic32;
+	size_t net_msg_len;
+	uint8_t key_aid = keys->key_aid | (keys->akf ? KEY_ID_AKF : 0x00);
+
+	if (keys->ctl) {
+		mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+				keys->net_seq[0],
+				keys->net_src, keys->net_dst,
+				keys->opcode,
+				keys->segmented, key_aid,
+				keys->szmic, keys->relay, keys->seqZero,
+				seg, seg_max,
+				enc_msg, len,
+				packet, &packet_len);
+	} else {
+		mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+				keys->net_seq[0],
+				keys->net_src, keys->net_dst,
+				keys->opcode,
+				keys->segmented, key_aid,
+				keys->szmic, keys->relay, keys->seqZero,
+				seg, seg_max,
+				enc_msg, len,
+				packet, &packet_len);
+	}
+
+	l_info(COLOR_YELLOW "Segment-%d" COLOR_OFF, seg);
+
+	hdr = l_get_be32(packet + 9);
+	verify_uint8("SEG", 9, keys->segmented << (SEG_HDR_SHIFT % 8),
+			packet[9] & (1 << (SEG_HDR_SHIFT % 8)));
+
+	if (keys->ctl) {
+		verify_uint8("Opcode", 9,
+				keys->opcode << (OPCODE_HDR_SHIFT % 8),
+				(packet[9] & OPCODE_MASK) <<
+				(OPCODE_HDR_SHIFT % 8));
+	} else {
+		verify_uint8("AKF", 9, keys->akf << (AKF_HDR_SHIFT % 8),
+				packet[9] & (1 << (AKF_HDR_SHIFT % 8)));
+		verify_uint8("AID", 9,
+				keys->key_aid << (KEY_HDR_SHIFT % 8),
+				(packet[9] & KEY_AID_MASK) <<
+						(KEY_HDR_SHIFT % 8));
+	}
+
+	verify_uint8("SZMIC", 10,
+			keys->szmic << (SZMIC_HDR_SHIFT % 8),
+			packet[10] & (1 << (SZMIC_HDR_SHIFT % 8)));
+
+	/* Awkward shift-by-two for correct display */
+	verify_uint16("SeqZero", 10,
+			(keys->seqZero & SEQ_ZERO_MASK) << 2,
+			((hdr >> SEQ_ZERO_HDR_SHIFT) & SEQ_ZERO_MASK)
+			<< 2);
+	verify_uint16("SegO", 11,
+			(seg & SEG_MASK) << SEGO_HDR_SHIFT,
+			hdr & (SEG_MASK << SEGO_HDR_SHIFT));
+	verify_uint8("SegN", 12,
+			(seg_max & SEG_MASK) << SEGN_HDR_SHIFT,
+			hdr & (SEG_MASK << SEGN_HDR_SHIFT));
+	show_data("Payload", 13, enc_msg, len);
+		len += 4;
+
+
+	mesh_crypto_network_nonce(keys->ctl, keys->net_ttl,
+					keys->net_seq[0], keys->net_src,
+					keys->iv_index, net_nonce);
+
+	verify_data("TransportData", 9, keys->trans_pkt[0],
+			packet + 9, len);
+
+	verify_uint16("DST", 7, keys->net_dst, l_get_be16(packet + 7));
+	net_msg_len = len + 2;
+	show_data("TransportPayload", 7, packet + 7, net_msg_len);
+
+	mesh_crypto_network_encrypt(keys->ctl,
+			keys->net_ttl, keys->net_seq[0],
+			keys->net_src,
+			keys->iv_index, enc_key,
+			packet + 7, len + 2, packet + 7,
+			keys->ctl ? (void *)&net_mic64 :
+			(void *)&net_mic32);
+
+	mesh_crypto_privacy_counter(keys->iv_index, packet + 7, priv_rand);
+
+	l_info("");
+	show_uint32("IVindex", 0, keys->iv_index);
+	verify_data("NetworkNonce", 0, keys->net_nonce[0], net_nonce, 13);
+	verify_data("PrivacyRandom", 0, keys->priv_rand[0], priv_rand, 16);
+
+	show_uint8("INI", 0, (keys->iv_index & 0x01) << 7);
+	verify_uint8("NID", 0, keys->net_nid, nid);
+	verify_uint8("CTL", 1, keys->ctl << 7, packet[1] & 0x80);
+	verify_uint8("TTL", 1, keys->net_ttl, packet[1] & 0x7f);
+	verify_uint24("SEQ", 2, keys->net_seq[0],
+			l_get_be32(packet + 1) & SEQ_MASK);
+	verify_uint16("SRC", 5, keys->net_src, l_get_be16(packet + 5));
+
+	verify_data("EncNetworkPayload", 7, keys->net_msg[0],
+			packet + 7, net_msg_len);
+	if (keys->ctl) {
+		verify_uint64("NetworkMIC", 7 + net_msg_len,
+				keys->net_mic64, net_mic64);
+		net_msg_len += 8;
+	} else {
+		verify_uint32("NetworkMIC", 7 + net_msg_len,
+				keys->net_mic32[0], net_mic32);
+		net_msg_len += 4;
+	}
+
+	show_data("PreObsPayload", 1, packet + 1, 6 + net_msg_len);
+	mesh_crypto_network_obfuscate(priv_key, priv_rand,
+			keys->ctl,
+			keys->net_ttl, keys->net_seq[0],
+			keys->net_src, packet + 1);
+	show_data("PostObsPayload", 1, packet + 1, 6 + net_msg_len);
+
+	packet[0] = (keys->iv_index & 0x01) << 7 | nid;
+	packet_len = 7 + net_msg_len;
+
+	verify_data("Packet", 0, keys->packet[0], packet, packet_len);
+	l_info("");
+
+}
+
+static void check_encrypt(const struct mesh_crypto_test *keys)
+{
+	uint8_t *dev_key;
+	uint8_t *app_key;
+	uint8_t *net_key;
+	uint8_t nid;
+	uint8_t enc_key[16];
+	uint8_t priv_key[16];
+	uint8_t net_nonce[13];
+	uint8_t app_nonce[13];
+	uint8_t priv_rand[16];
+	uint8_t p[9];
+	size_t p_len;
+	size_t aad_len = 0;
+	uint8_t *aad;
+	size_t app_msg_len;
+	uint8_t *app_msg = NULL;
+	uint8_t *enc_msg;
+	uint32_t app_mic32;
+	uint64_t app_mic64;
+	size_t net_msg_len;
+	uint32_t net_mic32;
+	uint64_t net_mic64;
+	uint8_t key_aid;
+	uint8_t packet[29];
+	uint8_t packet_len;
+	uint16_t i, seg_max, seg_len = 0;
+	uint32_t seqZero, hdr;
+
+	l_info(COLOR_BLUE "[Encrypt %s]" COLOR_OFF, keys->name);
+	verify_bool_not_both("CTL && Segmented", 0, keys->ctl, keys->segmented);
+
+	dev_key = l_util_from_hexstring(keys->dev_key, NULL);
+	app_key = l_util_from_hexstring(keys->app_key, NULL);
+	net_key = l_util_from_hexstring(keys->net_key, NULL);
+	aad = l_util_from_hexstring(keys->uuid, &aad_len);
+
+	show_data("NetworkKey", 0, net_key, 16);
+
+	if (keys->akf) {
+		mesh_crypto_k4(app_key, &key_aid);
+		key_aid |= KEY_ID_AKF;
+	} else {
+		key_aid = 0;
+	}
+
+	if (keys->frnd) {
+		uint8_t *lpn_addr, *fn_addr, *lpn_cntr, *fn_cntr;
+
+		lpn_addr = l_util_from_hexstring(keys->lpn_addr, NULL);
+		fn_addr = l_util_from_hexstring(keys->fn_addr, NULL);
+		lpn_cntr = l_util_from_hexstring(keys->lpn_cntr, NULL);
+		fn_cntr = l_util_from_hexstring(keys->fn_cntr, NULL);
+
+		show_data("LPN Address", 0, lpn_addr, 2);
+		show_data("Friend Address", 0, fn_addr, 2);
+		show_data("LPN Counter", 0, lpn_cntr, 2);
+		show_data("Friend Counter", 0, fn_cntr, 2);
+		l_info("");
+
+		p[0] = 1;
+		l_put_be16(l_get_be16(lpn_addr), p + 1);
+		l_put_be16(l_get_be16(fn_addr), p + 3);
+		l_put_be16(l_get_be16(lpn_cntr), p + 5);
+		l_put_be16(l_get_be16(fn_cntr), p + 7);
+		p_len = 9;
+
+		l_free(fn_cntr);
+		l_free(lpn_cntr);
+		l_free(fn_addr);
+		l_free(lpn_addr);
+	} else {
+		p[0] = 0;
+		p_len = 1;
+	}
+
+	if (p_len > 1) verify_data("P", 0, keys->p, p, p_len);
+
+	mesh_crypto_k2(net_key, p, p_len, &nid, enc_key, priv_key);
+
+	verify_data("EncryptionKey", 0, keys->enc_key, enc_key,
+							sizeof(enc_key));
+	verify_data("PrivacyKey", 0, keys->priv_key, priv_key,
+							sizeof(priv_key));
+	verify_uint8("NID", 0, keys->net_nid, nid);
+
+	if (keys->network_only) {
+		enc_msg = l_util_from_hexstring(keys->trans_pkt[0],
+							&app_msg_len);
+		check_encrypt_segment(keys, keys->seg_num, keys->seg_max,
+				enc_msg + 4, app_msg_len - 4,
+				enc_key, priv_key, nid);
+		goto done;
+	}
+
+	if (keys->akf)
+		mesh_crypto_application_nonce(keys->app_seq, keys->net_src,
+						keys->net_dst, keys->iv_index,
+						keys->szmic, app_nonce);
+	else
+		mesh_crypto_device_nonce(keys->app_seq, keys->net_src,
+						keys->net_dst, keys->iv_index,
+						keys->szmic, app_nonce);
+
+	seqZero = keys->app_seq;
+
+	if (!keys->ctl) {
+		app_msg = l_util_from_hexstring(keys->app_msg, &app_msg_len);
+
+		if (keys->szmic) {
+			seg_max = SEG_MAX(app_msg_len + 8);
+			enc_msg = l_malloc(app_msg_len + 8);
+			mesh_crypto_application_encrypt(key_aid, keys->app_seq,
+					keys->net_src, keys->net_dst,
+					keys->iv_index,
+					keys->akf ? app_key : dev_key,
+					aad, aad_len,
+					app_msg, app_msg_len,
+					enc_msg, &app_mic64, sizeof(app_mic64));
+			l_put_be64(app_mic64, enc_msg + app_msg_len);
+		} else {
+			seg_max = SEG_MAX(app_msg_len + 4);
+			enc_msg = l_malloc(app_msg_len + 4);
+			mesh_crypto_application_encrypt(key_aid, keys->app_seq,
+					keys->net_src, keys->net_dst,
+					keys->iv_index,
+					keys->akf ? app_key : dev_key,
+					aad, aad_len,
+					app_msg, app_msg_len,
+					enc_msg, &app_mic32, sizeof(app_mic32));
+			l_put_be32(app_mic32, enc_msg + app_msg_len);
+		}
+
+		if (keys->dev_key && !keys->akf)
+			show_data("DeviceKey", 0, dev_key, 16);
+
+		if (keys->app_key && keys->akf)
+			show_data("ApplicationKey", 0, app_key, 16);
+
+		if (aad) show_data("UUID", 0, aad, 16);
+
+		verify_data("EncryptionKey", 0, keys->enc_key, enc_key, 16);
+		verify_data("ApplicationNonce", 0, keys->app_nonce,
+								app_nonce, 13);
+		verify_data("PrivacyKey", 0, keys->priv_key, priv_key, 16);
+
+		show_data("AppPayload", 0, app_msg, app_msg_len);
+		verify_data("EncryptedAppPayload", 0, keys->enc_msg, enc_msg,
+								app_msg_len);
+		if (keys->szmic) {
+			verify_uint64("ApplicationMIC", app_msg_len,
+						keys->app_mic64, app_mic64);
+			app_msg_len += 8;
+		} else {
+			verify_uint32("ApplicationMIC", app_msg_len,
+						keys->app_mic32, app_mic32);
+			app_msg_len += 4;
+		}
+	} else {
+		enc_msg = l_util_from_hexstring(keys->trans_pkt[0],
+								&app_msg_len);
+		seg_max = 0;
+		app_msg_len--;
+	}
+
+	for (i = 0; i <= seg_max; i++) {
+		if (seg_max) {
+			if (i < seg_max || !(app_msg_len % 12))
+				seg_len = 12;
+			else
+				seg_len = app_msg_len % 12;
+		} else {
+			seg_len = app_msg_len;
+		}
+
+		if (keys->ctl) {
+			mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+					keys->net_seq[i],
+					keys->net_src, keys->net_dst,
+					keys->opcode,
+					keys->segmented, key_aid,
+					keys->szmic, keys->relay, keys->seqZero,
+					i, seg_max,
+					enc_msg + 1, seg_len,
+					packet, &packet_len);
+		} else {
+			mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+					keys->net_seq[i],
+					keys->net_src, keys->net_dst,
+					keys->opcode,
+					keys->segmented, key_aid,
+					keys->szmic, keys->relay, seqZero,
+					i, seg_max,
+					enc_msg + (i * 12), seg_len,
+					packet, &packet_len);
+		}
+
+		if (seg_max) l_info(COLOR_YELLOW "Segment-%d" COLOR_OFF, i);
+
+		hdr = l_get_be32(packet + 9);
+		verify_uint8("SEG", 9, keys->segmented << (SEG_HDR_SHIFT % 8),
+					packet[9] & (1 << (SEG_HDR_SHIFT % 8)));
+
+		if (keys->ctl) {
+			verify_uint8("Opcode", 9,
+				keys->opcode << (OPCODE_HDR_SHIFT % 8),
+				(packet[9] & OPCODE_MASK) <<
+							(OPCODE_HDR_SHIFT % 8));
+		} else {
+			verify_uint8("AKF", 9, keys->akf << (AKF_HDR_SHIFT % 8),
+				packet[9] & (1 << (AKF_HDR_SHIFT % 8)));
+			verify_uint8("AID", 9,
+				keys->key_aid << (KEY_HDR_SHIFT % 8),
+				(packet[9] & KEY_AID_MASK) <<
+							(KEY_HDR_SHIFT % 8));
+		}
+
+		if (seg_max == 0) {
+			if (!keys->ctl) {
+				show_data("Payload", 10, app_msg, seg_len - 4);
+				show_data("EncryptedPayload", 10, packet + 10,
+								seg_len);
+			} else if (keys->opcode == NET_OP_SEG_ACKNOWLEDGE) {
+				verify_uint8("Relay", 10,
+					keys->relay << (RELAY_HDR_SHIFT % 8),
+					packet[10] &
+						(1 << (RELAY_HDR_SHIFT % 8)));
+
+				/* Awkward shift-by-two for correct display */
+				verify_uint16("SeqZero", 10,
+					(keys->seqZero & SEQ_ZERO_MASK) << 2,
+					((hdr >> SEQ_ZERO_HDR_SHIFT) &
+							SEQ_ZERO_MASK) << 2);
+
+				show_data("Payload", 12, packet + 12, seg_len);
+			} else {
+				show_data("Payload", 10, packet + 10, seg_len);
+			}
+			seg_len += 1;
+		} else {
+
+			verify_uint8("SZMIC", 10,
+				keys->szmic << (SZMIC_HDR_SHIFT % 8),
+				packet[10] & (1 << (SZMIC_HDR_SHIFT % 8)));
+
+			/* Awkward shift-by-two for correct display */
+			verify_uint16("SeqZero", 10,
+				(keys->app_seq & SEQ_ZERO_MASK) << 2,
+				((hdr >> SEQ_ZERO_HDR_SHIFT) & SEQ_ZERO_MASK)
+									<< 2);
+			verify_uint16("SegO", 11,
+					(i & SEG_MASK) << SEGO_HDR_SHIFT,
+					hdr & (SEG_MASK << SEGO_HDR_SHIFT));
+			verify_uint8("SegN", 12,
+					(seg_max & SEG_MASK) << SEGN_HDR_SHIFT,
+					hdr & (SEG_MASK << SEGN_HDR_SHIFT));
+			show_data("Payload", 13, enc_msg + (i * 12), seg_len);
+			seg_len += 4;
+		}
+
+
+		mesh_crypto_network_nonce(keys->ctl, keys->net_ttl,
+					keys->net_seq[i], keys->net_src,
+					keys->iv_index, net_nonce);
+
+			verify_data("TransportData", 9, keys->trans_pkt[i],
+							packet + 9, seg_len);
+
+		verify_uint16("DST", 7, keys->net_dst, l_get_be16(packet + 7));
+		net_msg_len = seg_len + 2;
+		show_data("TransportPayload", 7, packet + 7, net_msg_len);
+
+		mesh_crypto_network_encrypt(keys->ctl,
+				keys->net_ttl, keys->net_seq[i],
+				keys->net_src,
+				keys->iv_index, enc_key,
+				packet + 7, seg_len + 2, packet + 7,
+				keys->ctl ? (void *)&net_mic64 :
+							(void *)&net_mic32);
+
+		mesh_crypto_privacy_counter(keys->iv_index, packet + 7,
+								priv_rand);
+
+		l_info("");
+		show_uint32("IVindex", 0, keys->iv_index);
+		verify_data("NetworkNonce", 0, keys->net_nonce[i],
+								net_nonce, 13);
+		verify_data("PrivacyRandom", 0, keys->priv_rand[i],
+								priv_rand, 16);
+
+		show_uint8("INI", 0, (keys->iv_index & 0x01) << 7);
+		verify_uint8("NID", 0, keys->net_nid, nid);
+		verify_uint8("CTL", 1, keys->ctl << 7, packet[1] & 0x80);
+		verify_uint8("TTL", 1, keys->net_ttl, packet[1] & 0x7f);
+		verify_uint24("SEQ", 2, keys->net_seq[i],
+					l_get_be32(packet + 1) & SEQ_MASK);
+		verify_uint16("SRC", 5, keys->net_src, l_get_be16(packet + 5));
+
+		verify_data("EncNetworkPayload", 7, keys->net_msg[i],
+						packet + 7, net_msg_len);
+		if (keys->ctl) {
+			verify_uint64("NetworkMIC", 7 + net_msg_len,
+						keys->net_mic64, net_mic64);
+			net_msg_len += 8;
+		} else {
+			verify_uint32("NetworkMIC", 7 + net_msg_len,
+						keys->net_mic32[i], net_mic32);
+			net_msg_len += 4;
+		}
+
+		show_data("PreObsPayload", 1, packet + 1, 6 + net_msg_len);
+		mesh_crypto_network_obfuscate(priv_key, priv_rand,
+				keys->ctl,
+				keys->net_ttl, keys->net_seq[i],
+				keys->net_src, packet + 1);
+		show_data("PostObsPayload", 1, packet + 1, 6 + net_msg_len);
+
+		packet[0] = (keys->iv_index & 0x01) << 7 | nid;
+		packet_len = 7 + net_msg_len;
+
+		verify_data("Packet", 0, keys->packet[i], packet, packet_len);
+		l_info("");
+	}
+
+done:
+	l_free(dev_key);
+	l_free(app_key);
+	l_free(aad);
+	l_free(net_key);
+	l_free(app_msg);
+	l_free(enc_msg);
+}
+
+static void check_decrypt_segment(const struct mesh_crypto_test *keys,
+				uint16_t seg, uint16_t seg_max,
+				const uint8_t *pkt, uint8_t pkt_len,
+				const uint8_t *msg, uint8_t msg_len,
+				uint8_t *enc_key, uint8_t *priv_key,
+				uint8_t nid)
+{
+	uint8_t net_clr[29];
+	uint64_t net_mic64, calc_net_mic64;
+	uint32_t hdr, net_mic32, calc_net_mic32;
+	bool ctl, segmented, relay, szmic, key_akf;
+	uint8_t ttl, opcode, key_aid, segO, segN;
+	uint32_t seq;
+	uint16_t src, dst, seqZero;
+
+	memcpy(net_clr, pkt, pkt_len);
+	show_data("NetworkMessage", 0, pkt, pkt_len);
+	mesh_crypto_packet_decode(pkt, pkt_len,
+				false, net_clr, keys->iv_index,
+				enc_key, priv_key);
+	show_data("Decoded", 0, net_clr, pkt_len);
+
+	mesh_crypto_packet_parse(net_clr, pkt_len,
+			&ctl, &ttl, &seq,
+			&src, &dst,
+			NULL, &opcode,
+			&segmented, &key_aid,
+			&szmic, &relay, &seqZero,
+			&segO, &segN,
+			&msg, &msg_len);
+
+	if (ctl) {
+		net_mic64 = l_get_be64(pkt + pkt_len - 8);
+		show_data("EncryptedPayload", 7, pkt + 7, pkt_len - 7 - 8);
+		mesh_crypto_network_decrypt(ctl, ttl, seq,
+				src, keys->iv_index, enc_key,
+				pkt + 7, pkt_len - 7, net_clr + 7,
+				&calc_net_mic64,
+				sizeof(calc_net_mic64));
+		verify_uint64("NetworkMIC", pkt_len - 8, net_mic64,
+				calc_net_mic64);
+		show_data("DecryptedPayload", 7, net_clr + 7, pkt_len - 7 - 8);
+	} else {
+		net_mic32 = l_get_be32(pkt + pkt_len - 4);
+		show_data("EncryptedPayload", 7, pkt + 7, pkt_len - 7 - 4);
+
+		mesh_crypto_network_decrypt(ctl, ttl, seq,
+				src, keys->iv_index, enc_key,
+				pkt + 7, pkt_len - 7, net_clr + 7,
+				&calc_net_mic32,
+				sizeof(calc_net_mic32));
+
+		verify_uint32("NetworkMIC", pkt_len - 4, net_mic32,
+				calc_net_mic32);
+		show_data("DecryptedPayload", 7, net_clr + 7, pkt_len - 7 - 4);
+	}
+
+	hdr = l_get_be32(net_clr + 9);
+
+	segmented = !!((hdr >> SEG_HDR_SHIFT) & 1);
+	if (ctl) {
+		opcode = (hdr >> OPCODE_HDR_SHIFT) & OPCODE_MASK;
+		if (opcode == NET_OP_SEG_ACKNOWLEDGE) {
+			relay = !!((hdr >> RELAY_HDR_SHIFT) & 1);
+			seqZero = (hdr >> SEQ_ZERO_HDR_SHIFT) & SEQ_ZERO_MASK;
+			verify_uint24("SeqZero", 9,
+					((keys->seqZero) & SEQ_ZERO_MASK)
+					<< (SEQ_ZERO_HDR_SHIFT - 8),
+					seqZero << (SEQ_ZERO_HDR_SHIFT - 8));
+			verify_uint24("Relay", 9,
+					keys->relay << (RELAY_HDR_SHIFT - 8),
+					relay << (RELAY_HDR_SHIFT - 8));
+			verify_uint24("Opcode", 9,
+					keys->opcode << (OPCODE_HDR_SHIFT - 8),
+					opcode << (OPCODE_HDR_SHIFT - 8));
+			verify_uint24("SEGMENTED", 9,
+					keys->segmented << (SEG_HDR_SHIFT - 8),
+					segmented << (SEG_HDR_SHIFT - 8));
+		} else {
+			verify_uint8("Opcode", 9,
+					keys->opcode << (OPCODE_HDR_SHIFT % 8),
+					opcode << (OPCODE_HDR_SHIFT % 8));
+			verify_uint8("SEGMENTED", 9,
+					keys->segmented << (SEG_HDR_SHIFT % 8),
+					segmented << (SEG_HDR_SHIFT % 8));
+		}
+	} else {
+		key_akf = !!((hdr >> AKF_HDR_SHIFT) & 1);
+		key_aid = (hdr >> KEY_HDR_SHIFT) & KEY_AID_MASK;
+		if (segmented) {
+			show_data("EncryptedApp", 13, net_clr + 13,
+					pkt_len - 13 - 4);
+			segN = (hdr >> SEGN_HDR_SHIFT) & SEG_MASK;
+			segO = (hdr >> SEGO_HDR_SHIFT) & SEG_MASK;
+			seqZero =  ((hdr >> SEQ_ZERO_HDR_SHIFT) &
+					SEQ_ZERO_MASK);
+
+			verify_uint32("SegN", 9,
+					seg_max << SEGN_HDR_SHIFT,
+					segN << SEGN_HDR_SHIFT);
+			verify_uint32("SegO", 9, seg << SEGO_HDR_SHIFT,
+					segO << SEGO_HDR_SHIFT);
+			verify_uint32("SeqZero", 9,
+					(keys->seqZero & SEQ_ZERO_MASK)
+						<< SEQ_ZERO_HDR_SHIFT,
+					(seqZero & SEQ_ZERO_MASK)
+						<< SEQ_ZERO_HDR_SHIFT);
+			verify_uint32("AID", 9,
+					keys->key_aid << KEY_HDR_SHIFT,
+					key_aid << KEY_HDR_SHIFT);
+			verify_uint32("AKF", 9,
+					keys->akf << AKF_HDR_SHIFT,
+					key_akf << AKF_HDR_SHIFT);
+			verify_uint32("SEGMENTED", 9,
+					keys->segmented << SEG_HDR_SHIFT,
+					segmented << SEG_HDR_SHIFT);
+		} else {
+			show_data("EncryptedApp", 10, msg + 3, pkt_len - 3);
+			verify_uint8("AID", 9,
+					keys->key_aid << (KEY_HDR_SHIFT % 8),
+					key_aid << (KEY_HDR_SHIFT % 8));
+			verify_uint8("AKF", 9,
+					keys->akf << (AKF_HDR_SHIFT % 8),
+					key_aid << (AKF_HDR_SHIFT % 8));
+			verify_uint8("SEGMENTED", 9,
+					keys->segmented << (SEG_HDR_SHIFT % 8),
+					segmented << (SEG_HDR_SHIFT % 8));
+		}
+	}
+
+	dst = l_get_be16(net_clr + 7);
+
+	verify_uint16("DST", 7, keys->net_dst, dst);
+	verify_uint16("SRC", 5, keys->net_src, src);
+	verify_uint24("SEQ", 2, keys->net_seq[0], seq);
+	verify_uint8("TTL", 1, keys->net_ttl, ttl);
+	verify_uint8("CTL", 1, keys->ctl << 7, ctl << 7);
+	verify_uint8("NID", 0, keys->net_nid, net_clr[0] & 0x7f);
+	verify_uint8("INI", 0, (keys->iv_index & 0x01) << 7, net_clr[0] & 0x80);
+}
+
+static void check_decrypt(const struct mesh_crypto_test *keys)
+{
+	uint8_t *dev_key;
+	uint8_t *app_key;
+	uint8_t *net_key;
+	uint8_t enc_key[16];
+	uint8_t net_nonce[13];
+	uint8_t app_nonce[13];
+	uint8_t priv_key[16];
+	uint8_t priv_rand[16];
+	uint8_t p[9];
+	size_t p_len;
+	uint8_t *packet;
+	size_t packet_len;
+	const uint8_t *net_hdr;
+	uint8_t *net_msg;
+	uint8_t net_msg_len;
+	uint16_t app_msg_len = 0;
+	uint32_t calc_net_mic32, net_mic32 = 0;
+	uint64_t calc_net_mic64, net_mic64 = 0;
+	bool net_ctl, net_segmented, net_rly, net_akf;
+	uint8_t net_aid, net_ttl, nid, net_segO, net_segN = 0;
+	uint32_t net_seq, hdr, seqZero = 0;
+	uint16_t net_src, net_dst;
+	uint32_t calc_app_mic32;
+	uint64_t calc_app_mic64;
+	uint32_t app_mic32;
+	uint64_t app_mic64;
+	uint8_t *app_msg;
+	uint8_t *aad;
+	uint8_t *payload;
+	size_t trans_msg_len, payload_len, aad_len = 0;
+	uint8_t pkt_len, hdr_len, net_op = 0;
+	uint16_t i, seg_max;
+	uint8_t keys_aid = 0;
+
+	l_info(COLOR_BLUE "[Decrypt %s]" COLOR_OFF, keys->name);
+	verify_bool_not_both("CTL && Segmented", 0, keys->ctl, keys->segmented);
+	dev_key = l_util_from_hexstring(keys->dev_key, NULL);
+	app_key = l_util_from_hexstring(keys->app_key, NULL);
+	net_key = l_util_from_hexstring(keys->net_key, NULL);
+	aad = l_util_from_hexstring(keys->uuid, &aad_len);
+
+	if (keys->frnd) {
+		uint8_t *lpn_addr, *fn_addr, *lpn_cntr, *fn_cntr;
+
+		lpn_addr = l_util_from_hexstring(keys->lpn_addr, NULL);
+		fn_addr = l_util_from_hexstring(keys->fn_addr, NULL);
+		lpn_cntr = l_util_from_hexstring(keys->lpn_cntr, NULL);
+		fn_cntr = l_util_from_hexstring(keys->fn_cntr, NULL);
+
+		show_data("LPN Address", 0, lpn_addr, 2);
+		show_data("Friend Address", 0, fn_addr, 2);
+		show_data("LPN Counter", 0, lpn_cntr, 2);
+		show_data("Friend Counter", 0, fn_cntr, 2);
+		l_info("");
+
+		p[0] = 1;
+		l_put_be16(l_get_be16(lpn_addr), p + 1);
+		l_put_be16(l_get_be16(fn_addr), p + 3);
+		l_put_be16(l_get_be16(lpn_cntr), p + 5);
+		l_put_be16(l_get_be16(fn_cntr), p + 7);
+		p_len = 9;
+
+		l_free(fn_cntr);
+		l_free(lpn_cntr);
+		l_free(fn_addr);
+		l_free(lpn_addr);
+	} else {
+		p[0] = 0;
+		p_len = 1;
+	}
+
+	if (p_len > 1) verify_data("P", 0, keys->p, p, p_len);
+	mesh_crypto_k2(net_key, p, p_len, &nid, enc_key, priv_key);
+
+
+	if (keys->network_only) {
+		app_msg = l_util_from_hexstring(keys->trans_pkt[0],
+							&trans_msg_len);
+		packet = l_util_from_hexstring(keys->packet[0], &packet_len);
+		check_decrypt_segment(keys, keys->seg_num, keys->seg_max,
+				packet, packet_len,
+				app_msg + 4, trans_msg_len - 4,
+				enc_key, priv_key, nid);
+		goto done;
+	}
+
+	mesh_crypto_application_nonce(keys->app_seq, keys->net_src,
+						keys->net_dst, keys->iv_index,
+						keys->szmic, app_nonce);
+	app_msg = l_malloc(384);
+
+	seg_max = (sizeof(keys->packet) / sizeof(keys->packet[0])) - 1;
+
+	/* Calculate number of segments in sample data */
+	while (keys->packet[seg_max] == NULL && seg_max) seg_max--;
+
+	for (i = 0; i <= seg_max; i++) {
+		if (keys->segmented)
+			l_info(COLOR_YELLOW "Segment-%d" COLOR_OFF, i);
+
+		mesh_crypto_network_nonce(keys->frnd, keys->net_ttl,
+				keys->net_seq[i], keys->net_src, keys->iv_index,
+				net_nonce);
+		packet = l_util_from_hexstring(keys->packet[i], &packet_len);
+
+		net_hdr = packet + 1;
+		net_msg = packet + 7;
+		net_msg_len = packet_len - 7;
+
+		mesh_crypto_privacy_counter(keys->iv_index, net_msg, priv_rand);
+
+		mesh_crypto_network_clarify(priv_key, priv_rand, net_hdr,
+				&net_ctl, &net_ttl, &net_seq, &net_src);
+
+		show_str("Packet", 0, keys->packet[i]);
+
+		if (net_ctl) {
+			net_mic64 = l_get_be64(packet + packet_len - 8);
+			show_data("NetworkMessage", 7, net_msg,
+							net_msg_len - 8);
+			mesh_crypto_network_decrypt(net_ctl, net_ttl, net_seq,
+					net_src, keys->iv_index, enc_key,
+					net_msg, net_msg_len, net_msg,
+					&calc_net_mic64,
+					sizeof(calc_net_mic64));
+			net_msg_len -= 8;
+			verify_uint64("NetworkMIC", 7 + net_msg_len, net_mic64,
+								calc_net_mic64);
+			show_data("DecryptedNetwork", 7, net_msg, net_msg_len);
+		} else {
+			net_mic32 = l_get_be32(packet + packet_len - 4);
+			show_data("NetworkMessage", 7, net_msg,
+							net_msg_len - 4);
+
+			mesh_crypto_network_decrypt(net_ctl, net_ttl, net_seq,
+					net_src, keys->iv_index, enc_key,
+					net_msg, net_msg_len, net_msg,
+					&calc_net_mic32,
+					sizeof(calc_net_mic32));
+
+			net_msg_len -= 4;
+			verify_uint32("NetworkMIC", 7 + net_msg_len, net_mic32,
+								calc_net_mic32);
+			show_data("DecryptedNetwork", 7, net_msg, net_msg_len);
+		}
+
+
+		hdr = l_get_be32(packet + 9);
+
+		net_segmented = !!((hdr >> SEG_HDR_SHIFT) & 1);
+		if (net_ctl) {
+			net_op = (hdr >> OPCODE_HDR_SHIFT) & OPCODE_MASK;
+			hdr_len = 1;
+			if (net_op == NET_OP_SEG_ACKNOWLEDGE) {
+				net_rly = !!((hdr >> RELAY_HDR_SHIFT) & 1);
+				seqZero = (hdr >> SEQ_ZERO_HDR_SHIFT) &
+								SEQ_ZERO_MASK;
+				verify_uint24("SeqZero", 9,
+					((keys->seqZero) & SEQ_ZERO_MASK)
+						<< (SEQ_ZERO_HDR_SHIFT - 8),
+					seqZero << (SEQ_ZERO_HDR_SHIFT - 8));
+				verify_uint24("Relay", 9,
+					keys->relay << (RELAY_HDR_SHIFT - 8),
+					net_rly << (RELAY_HDR_SHIFT - 8));
+				verify_uint24("Opcode", 9,
+					keys->opcode << (OPCODE_HDR_SHIFT - 8),
+					net_op << (OPCODE_HDR_SHIFT - 8));
+				verify_uint24("SEGMENTED", 9,
+					keys->segmented << (SEG_HDR_SHIFT - 8),
+					net_segmented << (SEG_HDR_SHIFT - 8));
+			} else {
+				verify_uint8("Opcode", 9,
+					keys->opcode << (OPCODE_HDR_SHIFT % 8),
+					net_op << (OPCODE_HDR_SHIFT % 8));
+				verify_uint8("SEGMENTED", 9,
+					keys->segmented << (SEG_HDR_SHIFT % 8),
+					net_segmented << (SEG_HDR_SHIFT % 8));
+			}
+		} else {
+			net_akf = !!((hdr >> AKF_HDR_SHIFT) & 1);
+			net_aid = (hdr >> KEY_HDR_SHIFT) & KEY_AID_MASK;
+			if (net_segmented) {
+				hdr_len = 4;
+				show_data("EncryptedApp", 13, net_msg + 6,
+							net_msg_len - 6);
+				memcpy(app_msg + (12 * i), net_msg + 6,
+							net_msg_len - 6);
+				app_msg_len += net_msg_len - 6;
+				net_segN = (hdr >> SEGN_HDR_SHIFT) & SEG_MASK;
+				net_segO = (hdr >> SEGO_HDR_SHIFT) & SEG_MASK;
+				seqZero =  ((hdr >> SEQ_ZERO_HDR_SHIFT)
+							& SEQ_ZERO_MASK) |
+						(net_seq & ~SEQ_ZERO_MASK);
+
+				if (seqZero > net_seq) seqZero -=
+							(SEQ_ZERO_MASK + 1);
+				verify_uint32("SegN", 9,
+						seg_max << SEGN_HDR_SHIFT,
+						net_segN << SEGN_HDR_SHIFT);
+				verify_uint32("SegO", 9, i << SEGO_HDR_SHIFT,
+						net_segO << SEGO_HDR_SHIFT);
+				verify_uint32("SeqZero", 9,
+					(keys->app_seq & SEQ_ZERO_MASK)
+							<< SEQ_ZERO_HDR_SHIFT,
+					(seqZero & SEQ_ZERO_MASK)
+							<< SEQ_ZERO_HDR_SHIFT);
+				verify_uint32("AID", 9,
+					keys->key_aid << KEY_HDR_SHIFT,
+					net_aid << KEY_HDR_SHIFT);
+				verify_uint32("AKF", 9,
+					keys->akf << AKF_HDR_SHIFT,
+					net_akf << AKF_HDR_SHIFT);
+				verify_uint32("SEGMENTED", 9,
+					keys->segmented << SEG_HDR_SHIFT,
+					net_segmented << SEG_HDR_SHIFT);
+			} else {
+				hdr_len = 1;
+				show_data("EncryptedApp", 10, net_msg + 3,
+							net_msg_len - 3);
+				memcpy(app_msg + (12 * i), net_msg + 3,
+							net_msg_len - 3);
+				app_msg_len += net_msg_len - 3;
+				seqZero = net_seq;
+				verify_uint8("AID", 9,
+				keys->key_aid << (KEY_HDR_SHIFT % 8),
+				net_aid << (KEY_HDR_SHIFT % 8));
+				verify_uint8("AKF", 9,
+				keys->akf << (AKF_HDR_SHIFT % 8),
+				net_akf << (AKF_HDR_SHIFT % 8));
+				verify_uint8("SEGMENTED", 9,
+				keys->segmented << (SEG_HDR_SHIFT % 8),
+				net_segmented << (SEG_HDR_SHIFT % 8));
+			}
+		}
+
+		net_dst = l_get_be16(net_msg);
+
+		verify_uint16("DST", 7, keys->net_dst, net_dst);
+		verify_uint16("SRC", 5, keys->net_src, net_src);
+		verify_uint24("SEQ", 2, keys->net_seq[i], net_seq);
+		verify_uint8("TTL", 1, keys->net_ttl, net_ttl);
+		verify_uint8("CTL", 1, keys->ctl << 7, net_ctl << 7);
+		verify_uint8("NID", 0, keys->net_nid, nid);
+		verify_uint8("INI", 0, (keys->iv_index & 0x01) << 7,
+							packet[0] & 0x80);
+
+		payload = l_util_from_hexstring(keys->trans_pkt[i],
+								&payload_len);
+		memset(packet, 0, packet_len);
+
+		mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+				keys->net_seq[i], keys->net_src,
+				keys->net_dst, net_op,
+				keys->segmented,
+				keys->key_aid | (keys->akf ? KEY_ID_AKF : 0),
+				keys->szmic, keys->relay, seqZero,
+				i, seg_max,
+				payload + hdr_len, payload_len - hdr_len,
+				packet, &pkt_len);
+		verify_data("TransportData", 9, keys->trans_pkt[i], packet + 9,
+								payload_len);
+		mesh_crypto_packet_encode(packet, pkt_len, enc_key,
+						keys->iv_index, priv_key);
+		mesh_crypto_packet_label(packet, pkt_len, keys->iv_index, nid);
+
+		verify_data("Encoded-Packet", 0, keys->packet[i], packet,
+								pkt_len);
+
+		l_free(payload);
+
+		l_info("");
+		mesh_crypto_packet_decode(packet, pkt_len, false, packet,
+					keys->iv_index, enc_key, priv_key);
+		show_data("Decoded-Packet", 0, packet, pkt_len);
+		l_info("");
+	}
+
+	if (keys->segmented && keys->szmic) {
+		verify_data("EncryptedPayload", 0, keys->enc_msg, app_msg,
+							app_msg_len - 8);
+		app_mic64 = l_get_be64(app_msg + app_msg_len - 8);
+
+		mesh_crypto_application_decrypt(
+				keys_aid | (keys->akf ? KEY_ID_AKF : 0),
+				seqZero, net_src,
+				net_dst, keys->iv_index,
+				keys->akf ? app_key : dev_key,
+				aad, aad_len,
+				app_msg, app_msg_len,
+				app_msg, &calc_app_mic64,
+				sizeof(calc_app_mic64));
+
+		verify_data("Payload", 0, keys->app_msg, app_msg,
+							app_msg_len - 8);
+		verify_uint64("ApplicationMIC", app_msg_len - 8, app_mic64,
+								calc_app_mic64);
+	} else if (!keys->ctl) {
+		verify_data("EncryptedPayload", 0, keys->enc_msg, app_msg,
+							app_msg_len - 4);
+		app_mic32 = l_get_be32(app_msg + app_msg_len - 4);
+
+		mesh_crypto_application_decrypt(
+				keys_aid | (keys->akf ? KEY_ID_AKF : 0),
+				seqZero, net_src,
+				net_dst, keys->iv_index,
+				keys->akf ? app_key : dev_key,
+				aad, aad_len,
+				app_msg, app_msg_len,
+				app_msg, &calc_app_mic32,
+				sizeof(calc_app_mic32));
+
+		verify_data("Payload", 0, keys->app_msg, app_msg,
+							app_msg_len - 4);
+		verify_uint32("ApplicationMIC", app_msg_len - 4, app_mic32,
+								calc_app_mic32);
+	}
+
+done:
+
+	l_info("");
+
+	l_free(dev_key);
+	l_free(aad);
+	l_free(app_key);
+	l_free(net_key);
+	l_free(app_msg);
+	l_free(packet);
+}
+
+static void check_beacon(const struct mesh_crypto_test *keys)
+{
+	uint8_t *net_key;
+	uint8_t *beacon_cmac;
+	uint8_t beacon[22];
+	uint8_t enc_key[16];
+	uint8_t net_id[8];
+	uint8_t cmac[8];
+	uint64_t cmac_tmp;
+
+	net_key = l_util_from_hexstring(keys->net_key, NULL);
+	beacon_cmac = l_util_from_hexstring(keys->beacon_cmac, NULL);
+
+	mesh_crypto_nkbk(net_key, enc_key);
+	mesh_crypto_k3(net_key, net_id);
+
+	l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
+
+	verify_data("NetworkKey", 0, keys->net_key, net_key, 16);
+	show_uint32("IVindex", 0, keys->iv_index);
+
+	verify_data("BeaconKey", 0, keys->enc_key, enc_key, 16);
+	verify_data("NetworkID", 0, keys->net_id, net_id, 8);
+
+	beacon[0] = keys->beacon_type;
+	beacon[1] = keys->beacon_flags;
+	memcpy(beacon + 2, net_id, 8);
+	l_put_be32(keys->iv_index, beacon + 10);
+	mesh_crypto_beacon_cmac(enc_key, net_id, keys->iv_index,
+					!!(keys->beacon_flags & 0x01),
+					!!(keys->beacon_flags & 0x02),
+					&cmac_tmp);
+
+	l_put_be64(cmac_tmp, cmac);
+	l_put_be64(cmac_tmp, beacon + 14);
+	verify_data("BeaconCMAC", 0, keys->beacon_cmac, cmac, 8);
+	verify_data("Beacon", 0, keys->beacon, beacon, sizeof(beacon));
+
+	l_info("");
+
+	l_free(beacon_cmac);
+	l_free(net_key);
+}
+
+static void check_id_beacon(const struct mesh_crypto_test *keys)
+{
+	uint8_t *net_key;
+	uint8_t *rand;
+	uint8_t identity_key[16];
+	uint8_t hash_input[16];
+	uint8_t hash[16];
+	uint8_t beacon[17];
+
+	net_key = l_util_from_hexstring(keys->net_key, NULL);
+	rand = l_util_from_hexstring(keys->rand, NULL);
+
+	mesh_crypto_nkik(net_key, identity_key);
+
+	l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
+
+	verify_data("ID Resolving Key", 0, keys->ident_res_key,
+							identity_key, 16);
+	memset(hash_input, 0, 6);
+	memcpy(hash_input + 6, rand, 8);
+	l_put_be16(keys->net_src, hash_input + 6 + 8);
+
+	verify_data("Hash Input", 0, keys->hash_input, hash_input, 16);
+	aes_ecb_one(identity_key, hash_input, hash);
+
+	verify_data("Hash", 0, keys->identity_hash, hash + 8, 8);
+
+	beacon[0] = 0x01;
+	memcpy(beacon + 1, hash + 8, 8);
+	memcpy(beacon + 9, rand, 8);
+
+	verify_data("Mesh ID Beacon", 0, keys->beacon, beacon, 17);
+
+	l_info("");
+
+	l_free(net_key);
+}
+
+static void check_s1(const struct mesh_crypto_test *keys)
+{
+	uint8_t salt_out[16];
+
+	l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
+
+	show_str("Salt Input", 0, keys->salt);
+	show_data("Salt Input", 0, keys->salt, strlen(keys->salt));
+	mesh_crypto_s1(keys->salt, strlen(keys->salt), salt_out);
+
+	verify_data("s1(Salt)", 0, keys->salt_out, salt_out, 16);
+	l_info("");
+}
+
+static void check_k128(const struct mesh_crypto_test *keys)
+{
+	uint8_t salt[16];
+	uint8_t t[16];
+	uint8_t enc_key[16];
+	uint8_t *net_key;
+
+	l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
+
+	net_key = l_util_from_hexstring(keys->net_key, NULL);
+	show_data("NetKey", 0, net_key, 16);
+	l_info("");
+
+	show_str("Salt Input", 0, keys->salt);
+	show_data("Salt Input", 0, keys->salt, strlen(keys->salt));
+	mesh_crypto_s1(keys->salt, strlen(keys->salt), salt);
+	show_data("s1(Salt)", 0, salt, 16);
+	l_info("");
+
+	show_str("Info", 0, keys->info);
+	show_data("Info", 0, keys->info, strlen(keys->info));
+	l_info("");
+
+	mesh_crypto_aes_cmac(salt, net_key, 16, t);
+	show_data("T", 0, t, 16);
+	l_info("");
+
+	if (memcmp(keys->salt, "nkbk", 4) == 0)
+		mesh_crypto_nkbk(net_key, enc_key);
+	else if (memcmp(keys->salt, "nkpk", 4) == 0)
+		mesh_crypto_nkpk(net_key, enc_key);
+	else if (memcmp(keys->salt, "nkik", 4) == 0)
+		mesh_crypto_nkik(net_key, enc_key);
+
+	verify_data("k1(N, salt, info)", 0, keys->enc_key, enc_key, 16);
+
+	l_info("");
+}
+
+static void check_k1(const struct mesh_crypto_test *keys)
+{
+	uint8_t salt[16];
+	uint8_t info[16];
+	uint8_t t[16];
+	uint8_t okm[16];
+	uint8_t *ikm;
+
+	l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
+
+	ikm = l_util_from_hexstring(keys->ikm, NULL);
+	show_data("IKM", 0, ikm, 16);
+	l_info("");
+
+	show_str("Salt Input", 0, keys->salt);
+	show_data("Salt Input", 0, keys->salt, strlen(keys->salt));
+	mesh_crypto_s1(keys->salt, strlen(keys->salt), salt);
+	show_data("s1(Salt)", 0, salt, 16);
+	l_info("");
+
+	show_str("Info Input", 0, keys->info);
+	show_data("Info Input", 0, keys->info, strlen(keys->info));
+	mesh_crypto_s1(keys->info, strlen(keys->info), info);
+	show_data("s1(Info)", 0, info, 16);
+	l_info("");
+
+	mesh_crypto_aes_cmac(salt, ikm, 16, t);
+	show_data("T", 0, t, 16);
+	l_info("");
+
+	mesh_crypto_k1(ikm, salt, info, 16, okm);
+
+	verify_data("k1(ikm, salt, info)", 0, keys->okm, okm, 16);
+
+	l_free(ikm);
+	l_info("");
+}
+
+static void check_k2(const struct mesh_crypto_test *keys)
+{
+	uint8_t *net_key;
+	uint8_t p[9];
+	size_t  p_len;
+	uint8_t nid;
+	uint8_t enc_key[16];
+	uint8_t priv_key[16];
+
+	l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
+
+	net_key = l_util_from_hexstring(keys->net_key, NULL);
+	show_data("NetKey", 0, net_key, 16);
+	l_info("");
+
+	if (keys->frnd) {
+		uint8_t *lpn_addr, *fn_addr, *lpn_cntr, *fn_cntr;
+
+		lpn_addr = l_util_from_hexstring(keys->lpn_addr, NULL);
+		fn_addr = l_util_from_hexstring(keys->fn_addr, NULL);
+		lpn_cntr = l_util_from_hexstring(keys->lpn_cntr, NULL);
+		fn_cntr = l_util_from_hexstring(keys->fn_cntr, NULL);
+
+		show_data("LPN Address", 0, lpn_addr, 2);
+		show_data("Friend Address", 0, fn_addr, 2);
+		show_data("LPN Counter", 0, lpn_cntr, 2);
+		show_data("Friend Counter", 0, fn_cntr, 2);
+		l_info("");
+
+		p[0] = 1;
+		l_put_be16(l_get_be16(lpn_addr), p + 1);
+		l_put_be16(l_get_be16(fn_addr), p + 3);
+		l_put_be16(l_get_be16(lpn_cntr), p + 5);
+		l_put_be16(l_get_be16(fn_cntr), p + 7);
+		p_len = 9;
+
+		l_free(fn_cntr);
+		l_free(lpn_cntr);
+		l_free(fn_addr);
+		l_free(lpn_addr);
+	} else {
+		p[0] = 0;
+		p_len = 1;
+	}
+
+	mesh_crypto_k2(net_key, p, p_len, &nid, enc_key, priv_key);
+	verify_data("P", 0, keys->p, p, p_len);
+	l_info("");
+	verify_data("NID", 0, keys->nid, &nid, 1);
+	verify_data("EncryptionKey", 0, keys->enc_key, enc_key, 16);
+	verify_data("PrivacyKey", 0, keys->priv_key, priv_key, 16);
+	l_free(net_key);
+	l_info("");
+}
+
+static void check_k3(const struct mesh_crypto_test *keys)
+{
+	uint8_t *net_key;
+	uint8_t tmp[16];
+	uint8_t short_net_id[8];
+
+	l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
+
+	net_key = l_util_from_hexstring(keys->net_key, NULL);
+
+	show_data("NetKey", 0, net_key, 16);
+	l_info("");
+
+	show_str("Salt Input", 0, keys->salt);
+	show_data("Salt Input", 0, keys->salt, strlen(keys->salt));
+	mesh_crypto_s1(keys->salt, strlen(keys->salt), tmp);
+	show_data("s1(Salt)", 0, tmp, 16);
+	l_info("");
+
+	show_str("Info", 0, keys->info);
+	show_data("Info", 0, keys->info, strlen(keys->info));
+	l_info("");
+
+	mesh_crypto_aes_cmac(tmp, net_key, 16, tmp);
+	show_data("T", 0, tmp, 16);
+	l_info("");
+
+	mesh_crypto_k3(net_key, short_net_id);
+	verify_data("k3(NetKey)", 0, keys->short_net_id, short_net_id, 8);
+	l_free(net_key);
+	l_info("");
+}
+
+static void check_k4(const struct mesh_crypto_test *keys)
+{
+	uint8_t *app_key;
+	uint8_t tmp[16];
+	uint8_t aid;
+
+	l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
+
+	app_key = l_util_from_hexstring(keys->app_key, NULL);
+
+	show_data("AppKey", 0, app_key, 16);
+	l_info("");
+
+	show_str("Salt Input", 0, keys->salt);
+	show_data("Salt Input", 0, keys->salt, strlen(keys->salt));
+	mesh_crypto_s1(keys->salt, strlen(keys->salt), tmp);
+	show_data("s1(Salt)", 0, tmp, 16);
+	l_info("");
+
+	show_str("Info", 0, keys->info);
+	show_data("Info", 0, keys->info, strlen(keys->info));
+	l_info("");
+
+	mesh_crypto_aes_cmac(tmp, app_key, 16, tmp);
+	show_data("T", 0, tmp, 16);
+	l_info("");
+
+	mesh_crypto_k4(app_key, &aid);
+	verify_data("k4(AppKey)", 0, keys->aid, &aid, 1);
+	l_free(app_key);
+	l_info("");
+}
+
+int main(int argc, char *argv[])
+{
+	l_log_set_stderr();
+
+	/* Section 8.1 Sample Data Tests */
+	check_s1(&s8_1_1);
+	check_k1(&s8_1_2);
+	check_k2(&s8_1_3);
+	check_k2(&s8_1_4);
+	check_k3(&s8_1_5);
+	check_k4(&s8_1_6);
+
+	/* Section 8.2 Sample Data Tests */
+	check_k4(&s8_2_1);
+	check_k2(&s8_2_2);
+	check_k2(&s8_2_3);
+	check_k3(&s8_2_4);
+	check_k128(&s8_2_5);
+	check_k128(&s8_2_6);
+
+	/* Section 8.3 Sample Data Tests */
+	check_encrypt(&s8_3_1);
+	check_decrypt(&s8_3_1);
+	check_encrypt(&s8_3_2);
+	check_decrypt(&s8_3_2);
+	check_encrypt(&s8_3_3);
+	check_decrypt(&s8_3_3);
+	check_encrypt(&s8_3_4);
+	check_decrypt(&s8_3_4);
+	check_encrypt(&s8_3_5);
+	check_decrypt(&s8_3_5);
+	check_encrypt(&s8_3_6);
+	check_decrypt(&s8_3_6);
+	check_encrypt(&s8_3_7);
+	check_decrypt(&s8_3_7);
+	check_encrypt(&s8_3_8); /* Single segment tester unavailable */
+	check_decrypt(&s8_3_8); /* Single segment tester unavailable */
+	check_encrypt(&s8_3_9);
+	check_decrypt(&s8_3_9);
+	check_encrypt(&s8_3_10);
+	check_decrypt(&s8_3_10);
+	check_encrypt(&s8_3_11); /* Single segment tester unavailable */
+	check_decrypt(&s8_3_11); /* Single segment tester unavailable */
+
+	/* Section 8.4 Beacon Sample Data */
+	check_beacon(&s8_4_3);
+
+	/* Section 8.6 Mesh Proxy Service sample data */
+	check_id_beacon(&s8_6_2);
+
+	return 0;
+}
-- 
2.21.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, back to index

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-03 19:49 [PATCH BlueZ] unit: Add Mesh Crypto tests from Mesh Profile Spec Brian Gix

Linux-Bluetooth Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-bluetooth/0 linux-bluetooth/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-bluetooth linux-bluetooth/ https://lore.kernel.org/linux-bluetooth \
		linux-bluetooth@vger.kernel.org linux-bluetooth@archiver.kernel.org
	public-inbox-index linux-bluetooth

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-bluetooth


AGPL code for this site: git clone https://public-inbox.org/ public-inbox