1 /* packet-zbee-security.c
2 * Dissector helper routines for encrypted ZigBee frames.
3 * By Owen Kirby <osk@exegin.com>; portions by Fred Fierling <fff@exegin.com>
4 * Copyright 2009 Exegin Technologies Limited
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include <epan/packet.h>
33 #include <epan/exceptions.h>
35 #include <epan/prefs.h>
36 #include <epan/expert.h>
37 #include <epan/emem.h>
40 /* We require libgcrpyt in order to decrypt ZigBee packets. Without it the best
41 * we can do is parse the security header and give up.
44 #include <wsutil/wsgcrypt.h>
45 #endif /* HAVE_LIBGCRYPT */
47 #include "packet-ieee802154.h"
48 #include "packet-zbee.h"
49 #include "packet-zbee-nwk.h"
50 #include "packet-zbee-security.h"
52 /* Helper Functions */
54 static gboolean
zbee_sec_ccm_decrypt(const gchar
*, const gchar
*, const gchar
*, const gchar
*, gchar
*,
56 static guint8
* zbee_sec_key_hash(guint8
*, guint8
, guint8
*);
57 static void zbee_sec_make_nonce (zbee_security_packet
*, guint8
*);
58 static gboolean
zbee_sec_decrypt_payload(zbee_security_packet
*, const gchar
*, const gchar
, guint8
*,
59 guint
, guint
, guint8
*);
61 static gboolean
zbee_security_parse_key(const gchar
*, guint8
*, gboolean
);
62 static void proto_init_zbee_security(void);
65 static int hf_zbee_sec_key_id
= -1;
66 static int hf_zbee_sec_nonce
= -1;
67 static int hf_zbee_sec_counter
= -1;
68 static int hf_zbee_sec_src64
= -1;
69 static int hf_zbee_sec_key_seqno
= -1;
70 static int hf_zbee_sec_mic
= -1;
71 static int hf_zbee_sec_key_origin
= -1;
73 /* Subtree pointers. */
74 static gint ett_zbee_sec
= -1;
75 static gint ett_zbee_sec_control
= -1;
77 static expert_field ei_zbee_sec_encrypted_payload
= EI_INIT
;
79 static dissector_handle_t data_handle
;
81 static const value_string zbee_sec_key_names
[] = {
82 { ZBEE_SEC_KEY_LINK
, "Link Key" },
83 { ZBEE_SEC_KEY_NWK
, "Network Key" },
84 { ZBEE_SEC_KEY_TRANSPORT
, "Key-Transport Key" },
85 { ZBEE_SEC_KEY_LOAD
, "Key-Load Key" },
90 /* These aren't really used anymore, as ZigBee no longer includes them in the
91 * security control field. If we were to display them all we would ever see is
94 static const value_string zbee_sec_level_names
[] = {
95 { ZBEE_SEC_NONE
, "None" },
96 { ZBEE_SEC_MIC32
, "No Encryption, 32-bit MIC" },
97 { ZBEE_SEC_MIC64
, "No Encryption, 64-bit MIC" },
98 { ZBEE_SEC_MIC128
, "No Encryption, 128-bit MIC" },
99 { ZBEE_SEC_ENC
, "Encryption, No MIC" },
100 { ZBEE_SEC_ENC_MIC32
, "Encryption, 32-bit MIC" },
101 { ZBEE_SEC_ENC_MIC64
, "Encryption, 64-bit MIC" },
102 { ZBEE_SEC_ENC_MIC128
, "Encryption, 128-bit MIC" },
107 /* The ZigBee security level, in enum_val_t for the security preferences. */
108 static const enum_val_t zbee_sec_level_enums
[] = {
109 { "None", "No Security", ZBEE_SEC_NONE
},
110 { "MIC32", "No Encryption, 32-bit Integrity Protection", ZBEE_SEC_MIC32
},
111 { "MIC64", "No Encryption, 64-bit Integrity Protection", ZBEE_SEC_MIC64
},
112 { "MIC128", "No Encryption, 128-bit Integrity Protection", ZBEE_SEC_MIC128
},
113 { "ENC", "AES-128 Encryption, No Integrity Protection", ZBEE_SEC_ENC
},
114 { "ENC-MIC32", "AES-128 Encryption, 32-bit Integrity Protection", ZBEE_SEC_ENC_MIC32
},
115 { "ENC-MIC64", "AES-128 Encryption, 64-bit Integrity Protection", ZBEE_SEC_ENC_MIC64
},
116 { "ENC-MIC128", "AES-128 Encryption, 128-bit Integrity Protection", ZBEE_SEC_ENC_MIC128
},
120 static gint gPREF_zbee_sec_level
= ZBEE_SEC_ENC_MIC32
;
121 static uat_t
*zbee_sec_key_table_uat
;
123 static const value_string byte_order_vals
[] = {
130 typedef struct _uat_key_record_t
{
134 guint8 key
[ZBEE_SEC_CONST_KEYSIZE
];
138 static uat_key_record_t
*uat_key_records
= NULL
;
139 static guint num_uat_key_records
= 0;
141 static void* uat_key_record_copy_cb(void* n
, const void* o
, size_t siz _U_
) {
142 uat_key_record_t
* new_key
= (uat_key_record_t
*)n
;
143 const uat_key_record_t
* old_key
= (uat_key_record_t
*)o
;
145 if (old_key
->string
) {
146 new_key
->string
= g_strdup(old_key
->string
);
148 new_key
->string
= NULL
;
151 if (old_key
->label
) {
152 new_key
->label
= g_strdup(old_key
->label
);
154 new_key
->label
= NULL
;
160 static void uat_key_record_update_cb(void* r
, const char** err
) {
161 uat_key_record_t
* rec
= (uat_key_record_t
*)r
;
163 if (rec
->string
== NULL
) {
164 *err
= g_strdup("Key can't be blank");
166 g_strstrip(rec
->string
);
168 if (rec
->string
[0] != 0) {
170 if ( !zbee_security_parse_key(rec
->string
, rec
->key
, rec
->byte_order
) ) {
171 *err
= g_strdup_printf("Expecting %d hexadecimal bytes or\n"
172 "a %d character double-quoted string", ZBEE_SEC_CONST_KEYSIZE
, ZBEE_SEC_CONST_KEYSIZE
);
175 *err
= g_strdup("Key can't be blank");
180 static void uat_key_record_free_cb(void*r
) {
181 uat_key_record_t
* key
= (uat_key_record_t
*)r
;
183 if (key
->string
) g_free(key
->string
);
184 if (key
->label
) g_free(key
->label
);
187 UAT_CSTRING_CB_DEF(uat_key_records
, string
, uat_key_record_t
)
188 UAT_VS_DEF(uat_key_records
, byte_order
, uat_key_record_t
, guint8
, 0, "Normal")
189 UAT_CSTRING_CB_DEF(uat_key_records
, label
, uat_key_record_t
)
191 static GSList
*zbee_pc_keyring
= NULL
;
194 * Enable this macro to use libgcrypt's CBC_MAC mode for the authentication
195 * phase. Unfortunately, this is broken, and I don't know why. However, using
196 * the messier EBC mode (to emulate CCM*) still works fine.
199 #define ZBEE_SEC_USE_GCRYPT_CBC_MAC
201 /*FUNCTION:------------------------------------------------------
203 * zbee_security_register
205 * Called by proto_register_zbee_nwk() to initialize the security
208 * module_t zbee_prefs - Prefs module to load preferences under.
211 *---------------------------------------------------------------
213 void zbee_security_register(module_t
*zbee_prefs
, int proto
)
215 static hf_register_info hf
[] = {
216 { &hf_zbee_sec_key_id
,
217 { "Key Id", "zbee.sec.key", FT_UINT8
, BASE_HEX
, VALS(zbee_sec_key_names
),
218 ZBEE_SEC_CONTROL_KEY
, NULL
, HFILL
}},
220 { &hf_zbee_sec_nonce
,
221 { "Extended Nonce", "zbee.sec.ext_nonce", FT_BOOLEAN
, 8, NULL
, ZBEE_SEC_CONTROL_NONCE
,
224 { &hf_zbee_sec_counter
,
225 { "Frame Counter", "zbee.sec.counter", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
228 { &hf_zbee_sec_src64
,
229 { "Extended Source", "zbee.sec.src64", FT_EUI64
, BASE_NONE
, NULL
, 0x0,
232 { &hf_zbee_sec_key_seqno
,
233 { "Key Sequence Number", "zbee.sec.key_seqno", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
237 { "Message Integrity Code", "zbee.sec.mic", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
240 { &hf_zbee_sec_key_origin
,
241 { "Key Origin", "zbee.sec.key.origin", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
245 static gint
*ett
[] = {
247 &ett_zbee_sec_control
250 static ei_register_info ei
[] = {
251 { &ei_zbee_sec_encrypted_payload
, { "zbee_sec.encrypted_payload", PI_UNDECODED
, PI_WARN
, "Encrypted Payload", EXPFILL
}},
254 expert_module_t
* expert_zbee_sec
;
256 static uat_field_t key_uat_fields
[] = {
257 UAT_FLD_CSTRING(uat_key_records
, string
, "Key",
258 "A 16-byte key in hexadecimal with optional dash-,\n"
259 "colon-, or space-separator characters, or a\n"
260 "a 16-character string in double-quotes."),
261 UAT_FLD_VS(uat_key_records
, byte_order
, "Byte Order", byte_order_vals
,
262 "Byte order of key."),
263 UAT_FLD_LSTRING(uat_key_records
, label
, "Label", "User label for key."),
267 /* If no prefs module was supplied, register our own. */
268 if (zbee_prefs
== NULL
) {
269 zbee_prefs
= prefs_register_protocol(proto
, NULL
);
272 /* Register preferences */
273 prefs_register_enum_preference(zbee_prefs
, "seclevel", "Security Level",
274 "Specifies the security level to use in the\n"
275 "decryption process. This value is ignored\n"
276 "for ZigBee 2004 and unsecured networks.",
277 &gPREF_zbee_sec_level
, zbee_sec_level_enums
, FALSE
);
279 zbee_sec_key_table_uat
= uat_new("Pre-configured Keys",
280 sizeof(uat_key_record_t
),
283 (void**) &uat_key_records
,
284 &num_uat_key_records
,
285 UAT_AFFECTS_DISSECTION
, /* affects dissection of packets, but not set of named fields */
286 NULL
, /* TODO: ptr to help manual? */
287 uat_key_record_copy_cb
,
288 uat_key_record_update_cb
,
289 uat_key_record_free_cb
,
290 NULL
, /* TODO: post_update */
293 prefs_register_uat_preference(zbee_prefs
,
295 "Pre-configured Keys",
296 "Pre-configured link or network keys.",
297 zbee_sec_key_table_uat
);
299 proto_register_field_array(proto
, hf
, array_length(hf
));
300 proto_register_subtree_array(ett
, array_length(ett
));
301 expert_zbee_sec
= expert_register_protocol(proto
);
302 expert_register_field_array(expert_zbee_sec
, ei
, array_length(ei
));
304 /* Register the init routine. */
305 register_init_routine(proto_init_zbee_security
);
306 } /* zbee_security_register */
308 /*FUNCTION:------------------------------------------------------
310 * zbee_security_parse_key
312 * Parses a key string from left to right into a buffer with
313 * increasing (normal byte order) or decreasing (reverse byte
316 * const gchar *key_str - pointer to the string
317 * guint8 *key_buf - destination buffer in memory
318 * gboolean big_end - fill key_buf with incrementing address
321 *---------------------------------------------------------------
324 zbee_security_parse_key(const gchar
*key_str
, guint8
*key_buf
, gboolean byte_order
)
328 gboolean string_mode
= FALSE
;
331 memset(key_buf
, 0, ZBEE_SEC_CONST_KEYSIZE
);
332 if (key_str
== NULL
) {
337 * Attempt to parse the key string. The key string must
338 * be at least 16 pairs of hexidecimal digits with the
339 * following optional separators: ':', '-', " ", or 16
340 * alphanumeric characters after a double-quote.
342 if ( (temp
= *key_str
++) == '"') {
347 j
= byte_order
?ZBEE_SEC_CONST_KEYSIZE
-1:0;
348 for (i
=ZBEE_SEC_CONST_KEYSIZE
-1; i
>=0; i
--) {
350 if ( g_ascii_isprint(temp
) ) {
358 /* If this character is a separator, skip it. */
359 if ( (temp
== ':') || (temp
== '-') || (temp
== ' ') ) temp
= *(key_str
++);
361 /* Process a nibble. */
362 if ( g_ascii_isxdigit (temp
) ) key_buf
[j
] = g_ascii_xdigit_value(temp
)<<4;
365 /* Get the next nibble. */
368 /* Process another nibble. */
369 if ( g_ascii_isxdigit (temp
) ) key_buf
[j
] |= g_ascii_xdigit_value(temp
);
372 /* Get the next nibble. */
376 /* Move key_buf pointer */
385 /* If we get this far, then the key was good. */
387 } /* zbee_security_parse_key */
389 /*FUNCTION:------------------------------------------------------
391 * zbee_security_handoff
393 * Hands off the security dissector.
398 *---------------------------------------------------------------
401 zbee_security_handoff(void)
403 /* Lookup the data dissector. */
404 data_handle
= find_dissector("data");
405 } /* zbee_security_handoff */
407 /*FUNCTION:------------------------------------------------------
409 * dissect_zbee_secure
411 * Dissects and decrypts secured ZigBee frames.
413 * Will return a valid tvbuff only if security processing was
414 * successful. If processing fails, then this function will
415 * handle internally and return NULL.
417 * tvbuff_t *tvb - pointer to buffer containing raw packet.
418 * packet_info *pinfo - pointer to packet information fields
419 * proto_tree *tree - pointer to data tree Wireshark uses to display packet.
420 * guint offset - pointer to the start of the auxilliary security header.
421 * guint64 src64 - extended source address, or 0 if unknown.
424 *---------------------------------------------------------------
427 dissect_zbee_secure(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
* tree
, guint offset
)
429 proto_tree
*sec_tree
= NULL
;
430 proto_item
*sec_root
;
431 proto_tree
*field_tree
;
434 zbee_security_packet packet
;
437 tvbuff_t
*payload_tvb
;
439 #ifdef HAVE_LIBGCRYPT
443 GSList
**nwk_keyring
;
445 key_record_t
*key_rec
= NULL
;
447 zbee_nwk_hints_t
*nwk_hints
;
448 ieee802154_hints_t
*ieee_hints
;
449 ieee802154_map_rec
*map_rec
= NULL
;
452 memset(&packet
, 0, sizeof(zbee_security_packet
));
454 /* Get pointers to any useful frame data from lower layers */
455 nwk_hints
= (zbee_nwk_hints_t
*)p_get_proto_data(pinfo
->fd
,
456 proto_get_id_by_filter_name(ZBEE_PROTOABBREV_NWK
), 0);
457 ieee_hints
= (ieee802154_hints_t
*)p_get_proto_data(pinfo
->fd
,
458 proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN
), 0);
460 /* Create a subtree for the security information. */
462 sec_root
= proto_tree_add_text(tree
, tvb
, offset
, tvb_length_remaining(tvb
, offset
), "ZigBee Security Header");
463 sec_tree
= proto_item_add_subtree(sec_root
, ett_zbee_sec
);
466 /* Get and display the Security control field */
467 packet
.control
= tvb_get_guint8(tvb
, offset
);
469 /* Patch the security level. */
470 packet
.control
&= ~ZBEE_SEC_CONTROL_LEVEL
;
471 packet
.control
|= (ZBEE_SEC_CONTROL_LEVEL
& gPREF_zbee_sec_level
);
474 * Eww, I think I just threw up a little... ZigBee requires this field
475 * to be patched before computing the MIC, but we don't have write-access
476 * to the tvbuff. So we need to allocate a copy of the whole thing just
477 * so we can fix these 3 bits. Memory allocated by tvb_memdup(wmem_packet_scope(),...)
478 * is automatically freed before the next packet is processed.
480 #ifdef HAVE_LIBGCRYPT
481 enc_buffer
= (guint8
*)tvb_memdup(wmem_packet_scope(), tvb
, 0, tvb_length(tvb
));
483 * Override the const qualifiers and patch the security level field, we
484 * know it is safe to overide the const qualifiers because we just
485 * allocated this memory via tvb_memdup(wmem_packet_scope(),...).
487 enc_buffer
[offset
] = packet
.control
;
488 #endif /* HAVE_LIBGCRYPT */
489 packet
.level
= zbee_get_bit_field(packet
.control
, ZBEE_SEC_CONTROL_LEVEL
);
490 packet
.key_id
= zbee_get_bit_field(packet
.control
, ZBEE_SEC_CONTROL_KEY
);
491 packet
.nonce
= zbee_get_bit_field(packet
.control
, ZBEE_SEC_CONTROL_NONCE
);
493 ti
= proto_tree_add_text(sec_tree
, tvb
, offset
, 1, "Security Control Field");
494 field_tree
= proto_item_add_subtree(ti
, ett_zbee_sec_control
);
496 proto_tree_add_uint(field_tree
, hf_zbee_sec_key_id
, tvb
, offset
, 1,
497 packet
.control
& ZBEE_SEC_CONTROL_KEY
);
498 proto_tree_add_boolean(field_tree
, hf_zbee_sec_nonce
, tvb
, offset
, 1,
499 packet
.control
& ZBEE_SEC_CONTROL_NONCE
);
503 /* Get and display the frame counter field. */
504 packet
.counter
= tvb_get_letohl(tvb
, offset
);
506 proto_tree_add_uint(sec_tree
, hf_zbee_sec_counter
, tvb
, offset
, 4, packet
.counter
);
511 /* Get and display the source address of the device that secured this payload. */
512 packet
.src64
= tvb_get_letoh64(tvb
, offset
);
514 proto_tree_add_item(sec_tree
, hf_zbee_sec_src64
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
517 if (!pinfo
->fd
->flags
.visited
) {
518 switch ( packet
.key_id
) {
519 case ZBEE_SEC_KEY_LINK
:
520 if (nwk_hints
&& ieee_hints
) {
521 /* Map this long address with the nwk layer short address. */
522 nwk_hints
->map_rec
= ieee802154_addr_update(&zbee_nwk_map
, nwk_hints
->src
,
523 ieee_hints
->src_pan
, packet
.src64
, pinfo
->current_proto
, pinfo
->fd
->num
);
527 case ZBEE_SEC_KEY_NWK
:
529 /* Map this long address with the ieee short address. */
530 ieee_hints
->map_rec
= ieee802154_addr_update(&zbee_nwk_map
, ieee_hints
->src16
,
531 ieee_hints
->src_pan
, packet
.src64
, pinfo
->current_proto
, pinfo
->fd
->num
);
535 /* We ignore the extended source addresses used to encrypt payloads with these
536 * types of keys, because they can emerge from APS tunnels created by nodes whose
537 * short address is not recorded in the packet. */
538 case ZBEE_SEC_KEY_TRANSPORT
:
539 case ZBEE_SEC_KEY_LOAD
:
547 /* Look for a source address in hints */
548 switch ( packet
.key_id
) {
549 case ZBEE_SEC_KEY_NWK
:
550 /* use the ieee extended source address for NWK decryption */
551 if ( ieee_hints
&& (map_rec
= ieee_hints
->map_rec
) )
552 packet
.src64
= map_rec
->addr64
;
554 proto_tree_add_text(sec_tree
, tvb
, 0, 0, "[Extended Source: Unknown]");
558 /* use the nwk extended source address for APS decryption */
559 if ( nwk_hints
&& (map_rec
= nwk_hints
->map_rec
) )
560 packet
.src64
= map_rec
->addr64
;
562 proto_tree_add_text(sec_tree
, tvb
, 0, 0, "[Extended Source: Unknown]");
567 if (packet
.key_id
== ZBEE_SEC_KEY_NWK
) {
568 /* Get and display the key sequence number. */
569 packet
.key_seqno
= tvb_get_guint8(tvb
, offset
);
571 proto_tree_add_uint(sec_tree
, hf_zbee_sec_key_seqno
, tvb
, offset
, 1, packet
.key_seqno
);
576 /* Determine the length of the MIC. */
577 switch (packet
.level
) {
584 case ZBEE_SEC_ENC_MIC32
:
589 case ZBEE_SEC_ENC_MIC64
:
594 case ZBEE_SEC_ENC_MIC128
:
595 case ZBEE_SEC_MIC128
:
600 /* Get and display the MIC. */
602 /* Display the MIC. */
604 proto_tree_add_item(sec_tree
, hf_zbee_sec_mic
, tvb
, (gint
)(tvb_length(tvb
)-mic_len
),
609 /* Check for null payload. */
610 if ( !(payload_len
= tvb_reported_length_remaining(tvb
, offset
+mic_len
)) ) {
612 } else if ( payload_len
< 0 ) {
613 THROW(ReportedBoundsError
);
616 /**********************************************
617 * Perform Security Operations on the Frame *
618 **********************************************
620 if ((packet
.level
== ZBEE_SEC_NONE
) ||
621 (packet
.level
== ZBEE_SEC_MIC32
) ||
622 (packet
.level
== ZBEE_SEC_MIC64
) ||
623 (packet
.level
== ZBEE_SEC_MIC128
)) {
625 /* Payload is only integrity protected. Just return the sub-tvbuff. */
626 return tvb_new_subset(tvb
, offset
, payload_len
, payload_len
);
629 #ifdef HAVE_LIBGCRYPT
630 /* Allocate memory to decrypt the payload into. */
631 dec_buffer
= (guint8
*)g_malloc(payload_len
);
634 if ( packet
.src64
) {
635 if (pinfo
->fd
->flags
.visited
) {
637 /* Use previously found key */
638 switch ( packet
.key_id
) {
639 case ZBEE_SEC_KEY_NWK
:
640 if ( (key_rec
= nwk_hints
->nwk
) ) {
641 decrypted
= zbee_sec_decrypt_payload( &packet
, enc_buffer
, offset
, dec_buffer
,
642 payload_len
, mic_len
, nwk_hints
->nwk
->key
);
647 if ( (key_rec
= nwk_hints
->link
) ) {
648 decrypted
= zbee_sec_decrypt_payload( &packet
, enc_buffer
, offset
, dec_buffer
,
649 payload_len
, mic_len
, nwk_hints
->link
->key
);
654 } /* ( !pinfo->fd->flags.visited ) */
656 /* We only search for sniffed keys in the first pass,
657 * to save time, and because decrypting with keys
658 * transported in future packets is cheating */
660 /* Lookup NWK and link key in hash for this pan. */
661 /* This overkill approach is a placeholder for a hash that looks up
662 * a key ring for a link key associated with a pair of devices.
665 nwk_keyring
= (GSList
**)g_hash_table_lookup(zbee_table_nwk_keyring
, &nwk_hints
->src_pan
);
668 GSList_i
= *nwk_keyring
;
669 while ( GSList_i
&& !decrypted
) {
670 decrypted
= zbee_sec_decrypt_payload( &packet
, enc_buffer
, offset
, dec_buffer
,
671 payload_len
, mic_len
, ((key_record_t
*)(GSList_i
->data
))->key
);
674 /* save pointer to the successful key record */
675 switch (packet
.key_id
) {
676 case ZBEE_SEC_KEY_NWK
:
677 key_rec
= nwk_hints
->nwk
= (key_record_t
*)(GSList_i
->data
);
681 key_rec
= nwk_hints
->link
= (key_record_t
*)(GSList_i
->data
);
685 GSList_i
= g_slist_next(GSList_i
);
690 /* Loop through user's password table for preconfigured keys, our last resort */
691 GSList_i
= zbee_pc_keyring
;
692 while ( GSList_i
&& !decrypted
) {
693 decrypted
= zbee_sec_decrypt_payload( &packet
, enc_buffer
, offset
, dec_buffer
,
694 payload_len
, mic_len
, ((key_record_t
*)(GSList_i
->data
))->key
);
697 /* save pointer to the successful key record */
698 switch (packet
.key_id
) {
699 case ZBEE_SEC_KEY_NWK
:
700 key_rec
= nwk_hints
->nwk
= (key_record_t
*)(GSList_i
->data
);
704 key_rec
= nwk_hints
->link
= (key_record_t
*)(GSList_i
->data
);
708 GSList_i
= g_slist_next(GSList_i
);
712 } /* ( ! pinfo->fd->flags.visited ) */
713 } /* ( packet.src64 ) */
716 if ( tree
&& key_rec
) {
717 if ( key_rec
->frame_num
== ZBEE_SEC_PC_KEY
) {
718 ti
= proto_tree_add_text(sec_tree
, tvb
, 0, 0, "Decryption Key: %s", key_rec
->label
);
720 ti
= proto_tree_add_uint(sec_tree
, hf_zbee_sec_key_origin
, tvb
, 0, 0,
723 PROTO_ITEM_SET_GENERATED(ti
);
726 /* Found a key that worked, setup the new tvbuff_t and return */
727 payload_tvb
= tvb_new_child_real_data(tvb
, dec_buffer
, payload_len
, payload_len
);
728 tvb_set_free_cb(payload_tvb
, g_free
); /* set up callback to free dec_buffer */
729 add_new_data_source(pinfo
, payload_tvb
, "Decrypted ZigBee Payload");
736 #endif /* HAVE_LIBGCRYPT */
738 /* Add expert info. */
739 expert_add_info(pinfo
, sec_tree
, &ei_zbee_sec_encrypted_payload
);
740 /* Create a buffer for the undecrypted payload. */
741 payload_tvb
= tvb_new_subset(tvb
, offset
, payload_len
, -1);
742 /* Dump the payload to the data dissector. */
743 call_dissector(data_handle
, payload_tvb
, pinfo
, tree
);
744 /* Couldn't decrypt, so return NULL. */
746 } /* dissect_zbee_secure */
748 #ifdef HAVE_LIBGCRYPT
749 /*FUNCTION:------------------------------------------------------
751 * zbee_sec_decrypt_payload
753 * Creates a nonce and decrypts a secured payload.
755 * gchar *nonce - Nonce Buffer.
756 * zbee_security_packet *packet - Security information.
759 *---------------------------------------------------------------
762 zbee_sec_decrypt_payload(zbee_security_packet
*packet
, const gchar
*enc_buffer
, const gchar offset
, guint8
*dec_buffer
,
763 guint payload_len
, guint mic_len
, guint8
*key
)
765 guint8 nonce
[ZBEE_SEC_CONST_NONCE_LEN
];
766 guint8 buffer
[ZBEE_SEC_CONST_BLOCKSIZE
+1];
767 guint8
*key_buffer
= buffer
;
769 switch (packet
->key_id
) {
770 case ZBEE_SEC_KEY_NWK
:
771 /* Decrypt with the PAN's current network key */
772 case ZBEE_SEC_KEY_LINK
:
773 /* Decrypt with the unhashed link key assigned by the trust center to this
774 * source/destination pair */
778 case ZBEE_SEC_KEY_TRANSPORT
:
779 /* Decrypt with a Key-Transport key, a hashed link key that protects network
780 * keys sent from the trust center */
781 zbee_sec_key_hash(key
, 0x00, buffer
);
785 case ZBEE_SEC_KEY_LOAD
:
786 /* Decrypt with a Key-Load key, a hashed link key that protects link keys
787 * sent from the trust center. */
788 zbee_sec_key_hash(key
, 0x02, buffer
);
796 /* Perform Decryption. */
797 zbee_sec_make_nonce(packet
, nonce
);
799 if ( zbee_sec_ccm_decrypt(key_buffer
, /* key */
801 enc_buffer
, /* a, length l(a) */
802 enc_buffer
+offset
, /* c, length l(c) = l(m) + M */
803 dec_buffer
, /* m, length l(m) */
805 payload_len
, /* l(m) */
812 /*FUNCTION:------------------------------------------------------
814 * zbee_sec_make_nonce
816 * Fills in the ZigBee security nonce from the provided security
819 * zbee_security_packet *packet - Security information.
820 * gchar *nonce - Nonce Buffer.
823 *---------------------------------------------------------------
826 zbee_sec_make_nonce(zbee_security_packet
*packet
, guint8
*nonce
)
828 /* First 8 bytes are the extended source address (little endian). */
829 *(nonce
++) = (guint8
)((packet
->src64
)>>0 & 0xff);
830 *(nonce
++) = (guint8
)((packet
->src64
)>>8 & 0xff);
831 *(nonce
++) = (guint8
)((packet
->src64
)>>16 & 0xff);
832 *(nonce
++) = (guint8
)((packet
->src64
)>>24 & 0xff);
833 *(nonce
++) = (guint8
)((packet
->src64
)>>32 & 0xff);
834 *(nonce
++) = (guint8
)((packet
->src64
)>>40 & 0xff);
835 *(nonce
++) = (guint8
)((packet
->src64
)>>48 & 0xff);
836 *(nonce
++) = (guint8
)((packet
->src64
)>>56 & 0xff);
837 /* Next 4 bytes are the frame counter (little endian). */
838 *(nonce
++) = (guint8
)((packet
->counter
)>>0 & 0xff);
839 *(nonce
++) = (guint8
)((packet
->counter
)>>8 & 0xff);
840 *(nonce
++) = (guint8
)((packet
->counter
)>>16 & 0xff);
841 *(nonce
++) = (guint8
)((packet
->counter
)>>24 & 0xff);
842 /* Next byte is the security control field. */
843 *(nonce
) = packet
->control
;
844 } /* zbee_sec_make_nonce */
847 #ifdef HAVE_LIBGCRYPT
848 /*FUNCTION:------------------------------------------------------
850 * zbee_sec_ccm_decrypt
852 * Performs the Reverse CCM* Transformation (specified in
853 * section A.3 of ZigBee Specification (053474r17).
855 * The length of parameter c (l(c)) is derived from the length
856 * of the payload and length of the MIC tag. Input buffer a
857 * will NOT be modified.
859 * When l_m is 0, then there is no payload to encrypt (ie: the
860 * payload is in plaintext), and this function will perform
861 * MIC verification only. When l_m is 0, m may be NULL.
863 * gchar *key - ZigBee Security Key (must be ZBEE_SEC_CONST_KEYSIZE) in length.
864 * gchar *nonce - ZigBee CCM* Nonce (must be ZBEE_SEC_CONST_NONCE_LEN) in length.
865 * gchar *a - CCM* Parameter a (must be l(a) in length). Additional data covered
866 * by the authentication process.
867 * gchar *c - CCM* Parameter c (must be l(c) = l(m) + M in length). Encrypted
868 * payload + encrypted authentication tag U.
869 * gchar *m - CCM* Output (must be l(m) in length). Decrypted Payload.
870 * guint l_a - l(a), length of CCM* parameter a.
871 * guint l_m - l(m), length of expected payload.
872 * guint M - M, length of CCM* authentication tag.
874 * gboolean - TRUE if successful.
875 *---------------------------------------------------------------
878 zbee_sec_ccm_decrypt(const gchar
*key
, /* Input */
879 const gchar
*nonce
, /* Input */
880 const gchar
*a
, /* Input */
881 const gchar
*c
, /* Input */
882 gchar
*m
, /* Output */
883 guint l_a
, /* sizeof(a) */
884 guint l_m
, /* sizeof(m) */
885 guint M
) /* sizeof(c) - sizeof(m) = sizeof(MIC) */
887 guint8 cipher_in
[ZBEE_SEC_CONST_BLOCKSIZE
];
888 guint8 cipher_out
[ZBEE_SEC_CONST_BLOCKSIZE
];
889 guint8 decrypted_mic
[ZBEE_SEC_CONST_BLOCKSIZE
];
891 /* Cipher Instance. */
892 gcry_cipher_hd_t cipher_hd
;
895 if (M
> ZBEE_SEC_CONST_BLOCKSIZE
) return FALSE
;
897 * The CCM* counter is L bytes in length, ensure that the payload
898 * isn't long enough to overflow it.
900 if ((1 + (l_a
/ZBEE_SEC_CONST_BLOCKSIZE
)) > (1<<(ZBEE_SEC_CONST_L
*8))) return FALSE
;
902 /******************************************************
903 * Step 1: Encryption/Decryption Transformation
904 ******************************************************
906 /* Create the CCM* counter block A0 */
907 memset(cipher_in
, 0, ZBEE_SEC_CONST_BLOCKSIZE
);
908 cipher_in
[0] = ZBEE_SEC_CCM_FLAG_L
;
909 memcpy(cipher_in
+ 1, nonce
, ZBEE_SEC_CONST_NONCE_LEN
);
911 * The encryption/decryption process of CCM* works in CTR mode. Open a CTR
912 * mode cipher for this phase. NOTE: The 'counter' part of the CCM* counter
913 * block is the last two bytes, and is big-endian.
915 if (gcry_cipher_open(&cipher_hd
, GCRY_CIPHER_AES128
, GCRY_CIPHER_MODE_CTR
, 0)) {
919 if (gcry_cipher_setkey(cipher_hd
, key
, ZBEE_SEC_CONST_KEYSIZE
)) {
920 gcry_cipher_close(cipher_hd
);
923 /* Set the counter. */
924 if (gcry_cipher_setctr(cipher_hd
, cipher_in
, ZBEE_SEC_CONST_BLOCKSIZE
)) {
925 gcry_cipher_close(cipher_hd
);
929 * Copy the MIC into the stack buffer. We need to feed the cipher a full
930 * block when decrypting the MIC (so that the payload starts on the second
931 * block). However, the MIC may be less than a full block so use a fixed
932 * size buffer to store the MIC, letting the CTR cipher overstep the MIC
935 memset(decrypted_mic
, 0, ZBEE_SEC_CONST_BLOCKSIZE
);
936 memcpy(decrypted_mic
, c
+ l_m
, M
);
937 /* Encrypt/Decrypt the MIC in-place. */
938 if (gcry_cipher_encrypt(cipher_hd
, decrypted_mic
, ZBEE_SEC_CONST_BLOCKSIZE
, decrypted_mic
, ZBEE_SEC_CONST_BLOCKSIZE
)) {
939 gcry_cipher_close(cipher_hd
);
942 /* Encrypt/Decrypt the payload. */
943 if (gcry_cipher_encrypt(cipher_hd
, m
, l_m
, c
, l_m
)) {
944 gcry_cipher_close(cipher_hd
);
947 /* Done with the CTR Cipher. */
948 gcry_cipher_close(cipher_hd
);
950 /******************************************************
951 * Step 3: Authentication Transformation
952 ******************************************************
955 /* There is no authentication tag. We're done! */
959 * The authentication process in CCM* operates in CBC-MAC mode, but
960 * unfortunately, the input to the CBC-MAC process needs some substantial
961 * transformation and padding before we can feed it into the CBC-MAC
962 * algorithm. Instead we will operate in ECB mode and perform the
963 * transformation and padding on the fly.
965 * I also think that libgcrypt requires the input to be memory-aligned
966 * when using CBC-MAC mode, in which case can't just feed it with data
967 * from the packet buffer. All things considered it's just a lot easier
968 * to use ECB mode and do CBC-MAC manually.
970 /* Re-open the cipher in ECB mode. */
971 if (gcry_cipher_open(&cipher_hd
, GCRY_CIPHER_AES128
, GCRY_CIPHER_MODE_ECB
, 0)) {
974 /* Re-load the key. */
975 if (gcry_cipher_setkey(cipher_hd
, key
, ZBEE_SEC_CONST_KEYSIZE
)) {
976 gcry_cipher_close(cipher_hd
);
979 /* Generate the first cipher block B0. */
980 cipher_in
[0] = ZBEE_SEC_CCM_FLAG_M(M
) |
981 ZBEE_SEC_CCM_FLAG_ADATA(l_a
) |
983 memcpy(cipher_in
+sizeof(gchar
), nonce
, ZBEE_SEC_CONST_NONCE_LEN
);
984 for (i
=0;i
<ZBEE_SEC_CONST_L
; i
++) {
985 cipher_in
[(ZBEE_SEC_CONST_BLOCKSIZE
-1)-i
] = (l_m
>> (8*i
)) & 0xff;
987 /* Generate the first cipher block, X1 = E(Key, 0^128 XOR B0). */
988 if (gcry_cipher_encrypt(cipher_hd
, cipher_out
, ZBEE_SEC_CONST_BLOCKSIZE
, cipher_in
, ZBEE_SEC_CONST_BLOCKSIZE
)) {
989 gcry_cipher_close(cipher_hd
);
993 * We avoid mallocing() big chunks of memory by recycling small stack
994 * buffers for the encryption process. Throughout this process, j is always
995 * pointed to the position within the current buffer.
998 /* AuthData = L(a) || a || Padding || m || Padding
1000 * - an empty string if l(a) == 0.
1001 * - 2-octet encoding of l(a) if 0 < l(a) < (2^16 - 2^8)
1002 * - 0xff || 0xfe || 4-octet encoding of l(a) if (2^16 - 2^8) <= l(a) < 2^32
1003 * - 0xff || 0xff || 8-octet encoding of l(a)
1004 * But for ZigBee, the largest packet size we should ever see is 2^7, so we
1005 * are only really concerned with the first two cases.
1007 * To generate the MIC tag CCM* operates similar to CBC-MAC mode. Each block
1008 * of AuthData is XOR'd with the last block of cipher output to produce the
1009 * next block of cipher output. Padding sections have the minimum non-negative
1010 * length such that the padding ends on a block boundary. Padded bytes are 0.
1013 /* Process L(a) into the cipher block. */
1014 cipher_in
[j
] = cipher_out
[j
] ^ ((l_a
>> 8) & 0xff);
1016 cipher_in
[j
] = cipher_out
[j
] ^ ((l_a
>> 0) & 0xff);
1018 /* Process a into the cipher block. */
1019 for (i
=0;i
<l_a
;i
++,j
++) {
1020 if (j
>=ZBEE_SEC_CONST_BLOCKSIZE
) {
1021 /* Generate the next cipher block. */
1022 if (gcry_cipher_encrypt(cipher_hd
, cipher_out
, ZBEE_SEC_CONST_BLOCKSIZE
, cipher_in
,
1023 ZBEE_SEC_CONST_BLOCKSIZE
)) {
1024 gcry_cipher_close(cipher_hd
);
1027 /* Reset j to point back to the start of the new cipher block. */
1030 /* Cipher in = cipher_out ^ a */
1031 cipher_in
[j
] = cipher_out
[j
] ^ a
[i
];
1033 /* Process padding into the cipher block. */
1034 for (;j
<ZBEE_SEC_CONST_BLOCKSIZE
;j
++)
1035 cipher_in
[j
] = cipher_out
[j
];
1037 /* Process m into the cipher block. */
1038 for (i
=0; i
<l_m
; i
++, j
++) {
1039 if (j
>=ZBEE_SEC_CONST_BLOCKSIZE
) {
1040 /* Generate the next cipher block. */
1041 if (gcry_cipher_encrypt(cipher_hd
, cipher_out
, ZBEE_SEC_CONST_BLOCKSIZE
, cipher_in
,
1042 ZBEE_SEC_CONST_BLOCKSIZE
)) {
1043 gcry_cipher_close(cipher_hd
);
1046 /* Reset j to point back to the start of the new cipher block. */
1049 /* Cipher in = cipher out ^ m */
1050 cipher_in
[j
] = cipher_out
[j
] ^ m
[i
];
1053 for (;j
<ZBEE_SEC_CONST_BLOCKSIZE
;j
++)
1054 cipher_in
[j
] = cipher_out
[j
];
1055 /* Generate the last cipher block, which will be the MIC tag. */
1056 if (gcry_cipher_encrypt(cipher_hd
, cipher_out
, ZBEE_SEC_CONST_BLOCKSIZE
, cipher_in
, ZBEE_SEC_CONST_BLOCKSIZE
)) {
1057 gcry_cipher_close(cipher_hd
);
1060 /* Done with the Cipher. */
1061 gcry_cipher_close(cipher_hd
);
1063 /* Compare the MIC's */
1064 return (memcmp(cipher_out
, decrypted_mic
, M
) == 0);
1065 } /* zbee_ccm_decrypt */
1067 /*FUNCTION:------------------------------------------------------
1071 * ZigBee Cryptographic Hash Function, described in ZigBee
1072 * specification sections B.1.3 and B.6.
1074 * This is a Matyas-Meyer-Oseas hash function using the AES-128
1075 * cipher. We use the ECB mode of libgcrypt to get a raw block
1078 * Input may be any length, and the output must be exactly 1-block in length.
1080 * Implements the function:
1081 * Hash(text) = Hash[t];
1082 * Hash[0] = 0^(blocksize).
1083 * Hash[i] = E(Hash[i-1], M[i]) XOR M[j];
1084 * M[i] = i'th block of text, with some padding and flags concatenated.
1086 * guint8 * input - Hash Input (any length).
1087 * guint8 input_len - Hash Input Length.
1088 * guint8 * output - Hash Output (exactly one block in length).
1091 *---------------------------------------------------------------
1094 zbee_sec_hash(guint8
*input
, guint input_len
, guint8
*output
)
1096 guint8 cipher_in
[ZBEE_SEC_CONST_BLOCKSIZE
];
1098 /* Cipher Instance. */
1099 gcry_cipher_hd_t cipher_hd
;
1101 /* Clear the first hash block (Hash0). */
1102 memset(output
, 0, ZBEE_SEC_CONST_BLOCKSIZE
);
1103 /* Create the cipher instance in ECB mode. */
1104 if (gcry_cipher_open(&cipher_hd
, GCRY_CIPHER_AES128
, GCRY_CIPHER_MODE_ECB
, 0)) {
1105 return; /* Failed. */
1107 /* Create the subsequent hash blocks using the formula: Hash[i] = E(Hash[i-1], M[i]) XOR M[i]
1109 * because we can't garauntee that M will be exactly a multiple of the
1110 * block size, we will need to copy it into local buffers and pad it.
1112 * Note that we check for the next cipher block at the end of the loop
1113 * rather than the start. This is so that if the input happens to end
1114 * on a block boundary, the next cipher block will be generated for the
1115 * start of the padding to be placed into.
1119 while (i
<input_len
) {
1120 /* Copy data into the cipher input. */
1121 cipher_in
[j
++] = input
[i
++];
1122 /* Check if this cipher block is done. */
1123 if (j
>= ZBEE_SEC_CONST_BLOCKSIZE
) {
1124 /* We have reached the end of this block. Process it with the
1125 * cipher, note that the Key input to the cipher is actually
1126 * the previous hash block, which we are keeping in output.
1128 (void)gcry_cipher_setkey(cipher_hd
, output
, ZBEE_SEC_CONST_BLOCKSIZE
);
1129 (void)gcry_cipher_encrypt(cipher_hd
, output
, ZBEE_SEC_CONST_BLOCKSIZE
, cipher_in
, ZBEE_SEC_CONST_BLOCKSIZE
);
1130 /* Now we have to XOR the input into the hash block. */
1131 for (j
=0;j
<ZBEE_SEC_CONST_BLOCKSIZE
;j
++) output
[j
] ^= cipher_in
[j
];
1132 /* Reset j to start again at the beginning at the next block. */
1136 /* Need to append the bit '1', followed by '0' padding long enough to end
1137 * the hash input on a block boundary. However, because 'n' is 16, and 'l'
1138 * will be a multiple of 8, the padding will be >= 7-bits, and we can just
1139 * append the byte 0x80.
1141 cipher_in
[j
++] = 0x80;
1142 /* Pad with '0' until the the current block is exactly 'n' bits from the
1145 while (j
!=(ZBEE_SEC_CONST_BLOCKSIZE
-2)) {
1146 if (j
>= ZBEE_SEC_CONST_BLOCKSIZE
) {
1147 /* We have reached the end of this block. Process it with the
1148 * cipher, note that the Key input to the cipher is actually
1149 * the previous hash block, which we are keeping in output.
1151 (void)gcry_cipher_setkey(cipher_hd
, output
, ZBEE_SEC_CONST_BLOCKSIZE
);
1152 (void)gcry_cipher_encrypt(cipher_hd
, output
, ZBEE_SEC_CONST_BLOCKSIZE
, cipher_in
, ZBEE_SEC_CONST_BLOCKSIZE
);
1153 /* Now we have to XOR the input into the hash block. */
1154 for (j
=0;j
<ZBEE_SEC_CONST_BLOCKSIZE
;j
++) output
[j
] ^= cipher_in
[j
];
1155 /* Reset j to start again at the beginning at the next block. */
1158 /* Pad the input with 0. */
1159 cipher_in
[j
++] = 0x00;
1161 /* Add the 'n'-bit representation of 'l' to the end of the block. */
1162 cipher_in
[j
++] = ((input_len
* 8) >> 8) & 0xff;
1163 cipher_in
[j
] = ((input_len
* 8) >> 0) & 0xff;
1164 /* Process the last cipher block. */
1165 (void)gcry_cipher_setkey(cipher_hd
, output
, ZBEE_SEC_CONST_BLOCKSIZE
);
1166 (void)gcry_cipher_encrypt(cipher_hd
, output
, ZBEE_SEC_CONST_BLOCKSIZE
, cipher_in
, ZBEE_SEC_CONST_BLOCKSIZE
);
1167 /* XOR the last input block back into the cipher output to get the hash. */
1168 for (j
=0;j
<ZBEE_SEC_CONST_BLOCKSIZE
;j
++) output
[j
] ^= cipher_in
[j
];
1169 /* Cleanup the cipher. */
1170 gcry_cipher_close(cipher_hd
);
1172 } /* zbee_sec_hash */
1174 /*FUNCTION:------------------------------------------------------
1178 * ZigBee Keyed Hash Function. Described in ZigBee specification
1179 * section B.1.4, and in FIPS Publication 198. Strictly speaking
1180 * there is nothing about the Keyed Hash Function which restricts
1181 * it to only a single byte input, but that's all ZigBee ever uses.
1183 * This function implements the hash function:
1184 * Hash(Key, text) = H((Key XOR opad) || H((Key XOR ipad) || text));
1185 * ipad = 0x36 repeated.
1186 * opad = 0x5c repeated.
1187 * H() = ZigBee Cryptographic Hash (B.1.3 and B.6).
1189 * The output of this function is an ep_alloced buffer containing
1190 * the key-hashed output, and is garaunteed never to return NULL.
1192 * guint8 *key - ZigBee Security Key (must be ZBEE_SEC_CONST_KEYSIZE) in length.
1193 * guint8 input - ZigBee CCM* Nonce (must be ZBEE_SEC_CONST_NONCE_LEN) in length.
1194 * packet_info *pinfo - pointer to packet information fields
1197 *---------------------------------------------------------------
1200 zbee_sec_key_hash(guint8
*key
, guint8 input
, guint8
*hash_out
)
1202 guint8 hash_in
[2*ZBEE_SEC_CONST_BLOCKSIZE
];
1204 static const guint8 ipad
= 0x36;
1205 static const guint8 opad
= 0x5c;
1207 /* Copy the key into hash_in and XOR with opad to form: (Key XOR opad) */
1208 for (i
=0; i
<ZBEE_SEC_CONST_KEYSIZE
; i
++) hash_in
[i
] = key
[i
] ^ opad
;
1209 /* Copy the Key into hash_out and XOR with ipad to form: (Key XOR ipad) */
1210 for (i
=0; i
<ZBEE_SEC_CONST_KEYSIZE
; i
++) hash_out
[i
] = key
[i
] ^ ipad
;
1211 /* Append the input byte to form: (Key XOR ipad) || text. */
1212 hash_out
[ZBEE_SEC_CONST_BLOCKSIZE
] = input
;
1213 /* Hash the contents of hash_out and append the contents to hash_in to
1214 * form: (Key XOR opad) || H((Key XOR ipad) || text).
1216 zbee_sec_hash(hash_out
, ZBEE_SEC_CONST_BLOCKSIZE
+1, hash_in
+ZBEE_SEC_CONST_BLOCKSIZE
);
1217 /* Hash the contents of hash_in to get the final result. */
1218 zbee_sec_hash(hash_in
, 2*ZBEE_SEC_CONST_BLOCKSIZE
, hash_out
);
1220 } /* zbee_sec_key_hash */
1221 #endif /* HAVE_LIBGCRYPT */
1223 /*FUNCTION:------------------------------------------------------
1225 * proto_init_zbee_security
1227 * Init routine for the
1232 *---------------------------------------------------------------
1235 proto_init_zbee_security(void)
1238 key_record_t key_record
;
1240 /* empty the key ring */
1241 if (zbee_pc_keyring
) {
1242 g_slist_free(zbee_pc_keyring
);
1243 zbee_pc_keyring
= NULL
;
1246 /* Load the pre-configured slist from the UAT. */
1247 for (i
=0; (uat_key_records
) && (i
<num_uat_key_records
) ; i
++) {
1248 key_record
.frame_num
= ZBEE_SEC_PC_KEY
; /* means it's a user PC key */
1249 key_record
.label
= se_strdup(uat_key_records
[i
].label
);
1250 memcpy(&key_record
.key
, &uat_key_records
[i
].key
, ZBEE_SEC_CONST_KEYSIZE
);
1252 zbee_pc_keyring
= g_slist_prepend(zbee_pc_keyring
, se_memdup(&key_record
, sizeof(key_record_t
)));
1254 } /* proto_init_zbee_security */