// SPDX-License-Identifier: LGPL-2.1-or-later
/*
 *
 *  BlueZ - Bluetooth protocol stack for Linux
 *
 *  Copyright (C) 2019  Intel Corporation. All rights reserved.
 *
 *
 */

#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 (flooding)",
	.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 (flooding)",
	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.iv_index	= 0x12345678,

	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.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,

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.iv_index	= 0x12345678,

	.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",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.iv_index	= 0x12345678,

	.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_3_22 = {
	.name		= "8.3.22 Message #22",

	.app_key	= "63964771734fbd76e3b40519d1d94a48",
	.net_key	= "7dd7364cd842ad18c17c2b820c84c3d6",
	.dev_key	= "9d6dd0e96eb25dc19a40ed9914f8f03f",
	.iv_index	= 0x12345677,

	.net_nid	= 0x68,
	.net_ttl	= 0x03,
	.app_seq	= 0x07080b,
	.net_seq	= {0x07080b},
	.net_src	= 0x1234,
	.net_dst	= 0xb529,
	.uuid		= "0073e7e4d8b9440faf8415df4c56c0e1",
	.akf		= true,
	.key_aid	= 0x26,
	.app_msg	= "d50a0048656c6c6f",
	.enc_msg	= "3871b904d4315263",
	.app_mic32	= 0x16ca48a0,

	.enc_key	= "0953fa93e7caac9638f58820220a398e",
	.app_nonce	= "010007080b1234b52912345677",

	.priv_key	= "8b84eedec100067d670971dd2aa700cf",

	.net_nonce	= {"000307080b1234000012345677"},

	.priv_rand	= {"000000000012345677ed31f3fdcf88a4"},

	.trans_pkt	= {"663871b904d431526316ca48a0"},

	.net_msg	= {"ed31f3fdcf88a411135fea55df730b"},

	.net_mic32	= {0x6b28e255},

	.packet		= {"e8d85caecef1e3ed31f3fdcf88a411135fea55df730b6b28e255" },
};

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_4_6_1 = {
	.name		= "8.4.6.1 Private Beacon IVU",

	.net_key	= "f7a2a44f8e8a8029064f173ddc1e2b00",
	.iv_index	= 0x1010abcd,

	.enc_key	= "6be76842460b2d3a5850d4698409f1bb",
	.rand		= "435f18f85cf78a3121f58478a5",

	.beacon_type	= 0x02,
	.beacon_flags	= 0x02,
	.beacon_cmac	= "f3174f022a514741",
	.beacon	= "02435f18f85cf78a3121f58478a561e488e7cbf3174f022a514741",
};

static const struct mesh_crypto_test s8_4_6_2 = {
	.name		= "8.4.6.2 Private Beacon IVU Complete",

	.net_key	= "3bbb6f1fbd53e157417f308ce7aec58f",
	.iv_index	= 0x00000000,

	.enc_key	= "ca478cdac626b7a8522d7272dd124f26",
	.rand		= "1b998f82927535ea6f3076f422",

	.beacon_type	= 0x02,
	.beacon_flags	= 0x00,
	.beacon_cmac	= "2f0ffb94cf97f881",
	.beacon	= "021b998f82927535ea6f3076f422ce827408ab2f0ffb94cf97f881",
};

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 EXITCMP(a, b, l)	do { if (memcmp((a), (b), (l))) \
					exit(1); \
				} while (0)

#define EVALSTR(a, b)	(((a) && (b)) ? (strcmp((a), (b)) ? FAIL : PASS) \
								: INVAL)
#define EXITSTR(a, b)	do { if ((a) && (b)) { \
					if (strcmp((a), (b))) \
						exit(1); \
				} else \
					exit(1); \
			} while (0)

#define EVALNUM(a, b)	(((a) == (b)) ? PASS : FAIL)
#define EXITNUM(a, b)	do { if (a != b) exit(1); } while (0)

#define EVALBOOLNOTBOTH(a, b)	!(a && b) ? PASS : FAIL
#define EXITBOOLNOTBOTH(a, b)	do { if (!!(a && b)) exit(1); } while (0)

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));
	EXITSTR(sample, str);
	l_free(str);
}

static void verify_bool(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",
						EVALNUM(sample, data));
	EXITNUM(sample, data);
}

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));
	EXITBOOLNOTBOTH(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));
	EXITNUM(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));
	EXITNUM(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));
	EXITNUM(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));
	EXITNUM(sample, data);
}

static void verify_uint64(const char *label, unsigned int indent,
						uint64_t sample, uint64_t data)
{
	l_info("%-20s =%*c%16llx", label, 1 + (indent * 2), ' ',
					(long long unsigned int) sample);
	l_info("%-20s  %*c%16llx => %s", "", 1 + (indent * 2), ' ',
						(long long unsigned int) data,
						EVALNUM(sample, data));
	EXITNUM(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;
	uint32_t hdr;
	uint64_t net_mic64, net_mic32;
	size_t net_msg_len;
	bool status;
	uint8_t key_aid = keys->key_aid | (keys->akf ? KEY_ID_AKF : 0x00);

	if (keys->ctl) {
		status = 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->seqZero, seg, seg_max,
				enc_msg, len,
				packet, &packet_len);
	} else {
		status = 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->seqZero, seg, seg_max,
				enc_msg, len,
				packet, &packet_len);
	}

	l_info(COLOR_YELLOW "Segment-%d" COLOR_OFF, seg);

	verify_bool("Crypto packet build", 0, true, status);
	if (!status)
		return;

	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);

	status = mesh_crypto_packet_encrypt(packet, packet_len,
						enc_key,
						keys->iv_index, false,
						keys->ctl, keys->net_ttl,
						keys->net_seq[0],
						keys->net_src);

	verify_bool("Crypto packet encrypt", 0, true, status);
	if (!status)
		return;

	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) {
		net_mic64 = l_get_be64(packet + 7 + net_msg_len);
		verify_uint64("NetworkMIC", 7 + net_msg_len,
						keys->net_mic64, net_mic64);
		net_msg_len += 8;
	} else {
		net_mic32 = l_get_be32(packet + 7 + net_msg_len);
		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);
	status = mesh_crypto_network_obfuscate(packet, priv_key,
					keys->iv_index,
					keys->ctl, keys->net_ttl,
					keys->net_seq[0], keys->net_src);

	verify_bool("Crypto network obfuscate", 0, true, status);
	if (!status)
		return;

	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 = 0;
	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;
	bool status;

	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(keys->segmented, app_msg_len + 8);
			enc_msg = l_malloc(app_msg_len + 8);

			status = mesh_crypto_payload_encrypt(aad, app_msg,
					enc_msg, app_msg_len,
					keys->net_src, keys->net_dst, key_aid,
					keys->app_seq, keys->iv_index,
					keys->szmic,
					keys->akf ? app_key : dev_key);
		} else {
			seg_max = SEG_MAX(keys->segmented, app_msg_len + 4);
			enc_msg = l_malloc(app_msg_len + 4);

			status = mesh_crypto_payload_encrypt(aad, app_msg,
					enc_msg, app_msg_len,
					keys->net_src, keys->net_dst, key_aid,
					keys->app_seq, keys->iv_index,
					keys->szmic,
					keys->akf ? app_key : dev_key);
		}

		verify_bool("Crypto payload encrypt", 0, true, status);
		if (!status)
			return;

		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) {
			app_mic64 = l_get_be64(enc_msg + app_msg_len);
			verify_uint64("ApplicationMIC", app_msg_len,
						keys->app_mic64, app_mic64);
			app_msg_len += 8;
		} else {
			app_mic32 = l_get_be32(enc_msg + app_msg_len);
			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) {
			status = 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->seqZero, i, seg_max,
					enc_msg + 1, seg_len,
					packet, &packet_len);
		} else {
			status = 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, 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);

		verify_bool("Crypto packet build", 0, true, status);
		if (!status)
			return;

		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);

		status = mesh_crypto_packet_encrypt(packet, packet_len, enc_key,
						keys->iv_index, false,
						keys->ctl, keys->net_ttl,
						keys->net_seq[i],
						keys->net_src);

		verify_bool("Crypto packet encrypt", 0, true, status);
		if (!status)
			return;

		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) {
			net_mic64 = l_get_be64(packet + packet_len - 8);
			verify_uint64("NetworkMIC", 7 + net_msg_len,
						keys->net_mic64, net_mic64);
			net_msg_len += 8;
		} else {
			net_mic32 = l_get_be32(packet + packet_len - 4);
			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);
		status = mesh_crypto_network_obfuscate(packet, priv_key,
					keys->iv_index,
					keys->ctl, keys->net_ttl,
					keys->net_seq[i], keys->net_src);

		verify_bool("Crypto network obfuscate", 0, true, status);
		if (!status)
			return;

		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,
				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, status;
	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);
	status = 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);

	if (status)
		status = 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);

	verify_bool("Crypto Decode-Parse", 0, true, status);
	if (!status)
		return;

	if (ctl) {
		net_mic64 = l_get_be64(pkt + pkt_len - 8);
		show_data("EncryptedPayload", 7, pkt + 7, pkt_len - 7 - 8);

		mesh_crypto_packet_decrypt(pkt, pkt_len,
							enc_key,
							keys->iv_index, false,
							ctl, ttl, seq,
							src);
		calc_net_mic64 = l_get_be64(pkt + pkt_len - 8);

		verify_uint64("NetworkMIC", pkt_len - 8, net_mic64,
						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_packet_decrypt(pkt, pkt_len,
							enc_key,
							keys->iv_index, false,
							ctl, ttl, seq,
							src);
		calc_net_mic32 = l_get_be32(pkt + pkt_len - 4);

		verify_uint32("NetworkMIC", pkt_len - 4, net_mic32,
						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 priv_key[16];
	uint8_t p[9];
	size_t p_len;
	uint8_t *packet = NULL;
	size_t packet_len;
	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, status;
	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;
	}

	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);

		l_free(packet);
		packet = l_util_from_hexstring(keys->packet[i], &packet_len);

		net_msg = packet + 7;
		net_msg_len = packet_len - 7;

		status = mesh_crypto_network_clarify(packet, priv_key,
				keys->iv_index, &net_ctl, &net_ttl, &net_seq,
				&net_src);

		verify_bool("Crypto Clarify", 0, true, status);
		if (!status)
			return;


		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_packet_decrypt(packet, packet_len,
						enc_key,
						keys->iv_index, false,
						net_ctl, net_ttl,
						net_seq,
						net_src);
			calc_net_mic64 = l_get_be64(packet + packet_len - 8);
			net_msg_len -= 8;
			verify_uint64("NetworkMIC", 7 + net_msg_len, net_mic64,
						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_packet_decrypt(packet, packet_len,
						enc_key,
						keys->iv_index, false,
						net_ctl, net_ttl,
						net_seq,
						net_src);
			calc_net_mic32 = l_get_be32(packet + packet_len - 4);
			net_msg_len -= 4;
			verify_uint32("NetworkMIC", 7 + net_msg_len, net_mic32,
						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, 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, keys->iv_index,
							enc_key, 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_payload_decrypt(
				aad, aad_len,
				app_msg, app_msg_len,
				true,
				net_src, net_dst,
				keys->akf ? keys_aid | KEY_ID_AKF : APP_AID_DEV,
				seqZero,
				keys->iv_index,
				app_msg,
				keys->akf ? app_key : dev_key);

		calc_app_mic64 = l_get_be64(app_msg + app_msg_len - 8);

		verify_data("Payload", 0, keys->app_msg, app_msg,
							app_msg_len - 8);
		verify_uint64("ApplicationMIC", app_msg_len - 8, app_mic64,
						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_payload_decrypt(
				aad, aad_len,
				app_msg, app_msg_len,
				false,
				net_src, net_dst,
				keys->akf ? keys_aid | KEY_ID_AKF : APP_AID_DEV,
				seqZero,
				keys->iv_index,
				app_msg,
				keys->akf ? app_key : dev_key);

		calc_app_mic32 = l_get_be32(app_msg + app_msg_len - 4);

		verify_data("Payload", 0, keys->app_msg, app_msg,
							app_msg_len - 4);
		verify_uint32("ApplicationMIC", app_msg_len - 4, app_mic32,
						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 *random = NULL;
	uint8_t beacon[29];
	uint8_t enc_key[16];
	uint8_t net_id[8];
	uint8_t cmac[8];
	uint64_t cmac_tmp = 0;

	if (keys->beacon_type < 1 || keys->beacon_type > 2)
		verify_uint8("Unknown Beacon", 0, true,
			(keys->beacon_type >= 1 || keys->beacon_type <= 2));

	net_key = l_util_from_hexstring(keys->net_key, NULL);
	beacon_cmac = l_util_from_hexstring(keys->beacon_cmac, NULL);

	if (keys->beacon_type == 1) {
		mesh_crypto_nkbk(net_key, enc_key);
	} else {
		mesh_crypto_nkpk(net_key, enc_key);
		random = l_util_from_hexstring(keys->rand, NULL);
	}

	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_uint8("Beacon Flags", 0, keys->beacon_flags);
	show_uint32("IVindex", 0, keys->iv_index);

	verify_data("BeaconKey", 0, keys->enc_key, enc_key, 16);

	beacon[0] = keys->beacon_type;
	if (keys->beacon_type == 1) {
		verify_data("NetworkID", 0, keys->net_id, net_id, 8);
		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("SNBeacon", 0, keys->beacon, beacon, 22);
	} else {
		show_data("Random", 0, random, sizeof(random));
		memcpy(beacon + 1, random, 13);
		beacon[14] = keys->beacon_flags;
		l_put_be32(keys->iv_index, beacon + 15);
		mesh_crypto_aes_ccm_encrypt(random, enc_key, NULL, 0,
							beacon + 14, 5,
							beacon + 14, 8);
		verify_data("BeaconMIC", 0, keys->beacon_cmac, beacon + 19, 8);
		verify_data("PrivBeacon", 0, keys->beacon, beacon, 27);
	}

	l_info("");

	l_free(random);
	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(rand);
	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_free(net_key);
	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();

	if (!mesh_crypto_check_avail())
		return 77;

	/* 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 */
	check_encrypt(&s8_3_22);
	check_decrypt(&s8_3_22);

	/* Section 8.4 Beacon Sample Data */
	check_beacon(&s8_4_3);
	check_beacon(&s8_4_6_1);
	check_beacon(&s8_4_6_2);

	/* Section 8.6 Mesh Proxy Service sample data */
	check_id_beacon(&s8_6_2);

	return 0;
}
