| // 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->relay, 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->relay, 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->relay, 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, 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); |
| |
| 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, 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, 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, NULL, 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(); |
| |
| /* 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; |
| } |