/*FUNCTION:------------------------------------------------------
 *  NAME
 *      zbee_sec_decrypt_payload
 *  DESCRIPTION
 *      Creates a nonce and decrypts a secured payload.
 *  PARAMETERS
 *      gchar                *nonce  - Nonce Buffer.
 *      zbee_security_packet *packet - Security information.
 *  RETURNS
 *      void
 *---------------------------------------------------------------
 */
static gboolean
zbee_sec_decrypt_payload(zbee_security_packet *packet, const gchar *enc_buffer, const gchar offset, guint8 *dec_buffer,
        guint payload_len, guint mic_len, guint8 *key)
{
    guint8  nonce[ZBEE_SEC_CONST_NONCE_LEN];
    guint8  buffer[ZBEE_SEC_CONST_BLOCKSIZE+1];
    guint8 *key_buffer = buffer;

    switch (packet->key_id) {
        case ZBEE_SEC_KEY_NWK:
            /* Decrypt with the PAN's current network key */
        case ZBEE_SEC_KEY_LINK:
            /* Decrypt with the unhashed link key assigned by the trust center to this
             * source/destination pair */
            key_buffer = key;
            break;

        case ZBEE_SEC_KEY_TRANSPORT:
            /* Decrypt with a Key-Transport key, a hashed link key that protects network
             * keys sent from the trust center */
            zbee_sec_key_hash(key, 0x00, buffer);
            key_buffer = buffer;
            break;

        case ZBEE_SEC_KEY_LOAD:
            /* Decrypt with a Key-Load key, a hashed link key that protects link keys
             * sent from the trust center. */
            zbee_sec_key_hash(key, 0x02, buffer);
            key_buffer = buffer;
            break;

        default:
            break;
    } /* switch */

    /* Perform Decryption. */
    zbee_sec_make_nonce(packet, nonce);

    if ( zbee_sec_ccm_decrypt(key_buffer,   /* key */
                        nonce,              /* Nonce */
                        enc_buffer,         /* a, length l(a) */
                        enc_buffer+offset,  /* c, length l(c) = l(m) + M */
                        dec_buffer,         /* m, length l(m) */
                        offset,             /* l(a) */
                        payload_len,        /* l(m) */
                        mic_len) ) {        /* M */
        return TRUE;
    }
    else return FALSE;
}
Esempio n. 2
0
/*FUNCTION:------------------------------------------------------
 *  NAME
 *      dissect_zbee_secure
 *  DESCRIPTION
 *      Dissects and decrypts secured ZigBee frames.
 *
 *      Will return a valid tvbuff only if security processing was
 *      successful. If processing fails, then this function will
 *      handle internally and return NULL.
 *  PARAMETERS
 *      tvbuff_t    *tvb    - pointer to buffer containing raw packet.
 *      packet_into *pinfo  - pointer to packet information fields
 *      proto_tree  *tree   - pointer to data tree Wireshark uses to display packet.
 *      guint       offset  - pointer to the start of the auxilliary security header.
 *      guint64     src     - extended source address, or 0 if unknown.
 *  RETURNS
 *      tvbuff_t *
 *---------------------------------------------------------------
 */
tvbuff_t *
dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset, guint64 src)
{
    proto_tree *    sec_tree = NULL;
    proto_item *    sec_root;
    proto_tree *    field_tree;
    proto_item *    ti;

    zbee_security_packet    packet;
    guint           mic_len;
    guint           payload_len;
    tvbuff_t *      payload_tvb;

#ifdef HAVE_LIBGCRYPT
    const guint8 *  enc_buffer;
    guint8 *        dec_buffer;
    guint8 *        key_buffer;
    guint8          nonce[ZBEE_SEC_CONST_NONCE_LEN];
#endif

    /* Create a substree for the security information. */
    if (tree) {
        sec_root = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "ZigBee Security Header");
        sec_tree = proto_item_add_subtree(sec_root, ett_zbee_sec);
    }

    /*  Get and display the Security control field */
    packet.control  = tvb_get_guint8(tvb, offset);
    /* Patch the security level. */
    packet.control &= ~ZBEE_SEC_CONTROL_LEVEL;
    packet.control |= (ZBEE_SEC_CONTROL_LEVEL & gPREF_zbee_sec_level);
    /*
     * Eww, I think I just threw up a little...  ZigBee requires this field
     * to be patched before computing the MIC, but we don't have write-access
     * to the tvbuff. So we need to allocate a copy of the whole thing just
     * so we can fix these 3 bits.
     */
#ifdef HAVE_LIBGCRYPT
    enc_buffer = ep_tvb_memdup(tvb, 0, tvb_length(tvb));
    /*
     * Override the const qualifiers and patch the security level field, we
     * know it is safe to overide the const qualifiers because we just
     * allocated this memory via ep_tvb_memdup().
     */
    ((guint8 *)(enc_buffer))[offset] = packet.control;
#endif /* HAVE_LIBGCRYPT */
    packet.level    = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_LEVEL);
    packet.key      = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY);
    packet.nonce    = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_NONCE);
    if (tree) {
        ti = proto_tree_add_text(sec_tree, tvb, offset, sizeof(guint8), "Security Control Field");
        field_tree = proto_item_add_subtree(ti, ett_zbee_sec_control);

        proto_tree_add_uint(field_tree, hf_zbee_sec_key, tvb, offset, sizeof(guint8), packet.control & ZBEE_SEC_CONTROL_KEY);
        proto_tree_add_boolean(field_tree, hf_zbee_sec_nonce, tvb, offset, sizeof(guint8), packet.control & ZBEE_SEC_CONTROL_NONCE);
    }
    offset += sizeof(guint8);

    /* Get and display the frame counter field. */
    packet.counter = tvb_get_letohl(tvb, offset);
    if (tree) {
        proto_tree_add_uint(sec_tree, hf_zbee_sec_counter, tvb, offset, sizeof(guint32), packet.counter);
    }
    offset += sizeof(guint32);

    if (packet.nonce) {
        /* Get and display the source address. */
        packet.src = tvb_get_letoh64(tvb, offset);
        if (tree) {
            proto_tree_add_eui64(sec_tree, hf_zbee_sec_src, tvb, offset, sizeof(guint64), packet.src);
        }
        offset += sizeof(guint64);
    }
    else {
        /* This field is required in the security decryption process, so
         * fill it in in case the higher layer provided it.
         */
        packet.src = src;
    }

    if (packet.key == ZBEE_SEC_KEY_NWK) {
        /* Get and display the key sequence number. */
        packet.key_seqno = tvb_get_guint8(tvb, offset);
        if (tree) {
            proto_tree_add_uint(sec_tree, hf_zbee_sec_key_seqno, tvb, offset, sizeof(guint8), packet.key_seqno);
        }
        offset += sizeof(guint8);
    }

    /* Determine the length of the MIC. */
    switch (packet.level){
        case ZBEE_SEC_ENC:
        case ZBEE_SEC_NONE:
        default:
            mic_len=0;
            break;

        case ZBEE_SEC_ENC_MIC32:
        case ZBEE_SEC_MIC32:
            mic_len=4;
            break;

        case ZBEE_SEC_ENC_MIC64:
        case ZBEE_SEC_MIC64:
            mic_len=8;
            break;

        case ZBEE_SEC_ENC_MIC128:
        case ZBEE_SEC_MIC128:
            mic_len=16;
            break;
    } /* switch */

    /* Ensure that the payload exists (length >= 1) for this length. */
    payload_len = tvb_ensure_length_remaining(tvb, offset+mic_len+1)+1;

    /* Get and display the MIC. */
    if (mic_len) {
        /* Display the MIC. */
        if (tree) {
            ti = proto_tree_add_bytes(sec_tree, hf_zbee_sec_mic, tvb, tvb_length(tvb)-mic_len, mic_len, ep_tvb_memdup(tvb, tvb_length(tvb)-mic_len, mic_len));
        }
    }

    /**********************************************
     *  Perform Security Operations on the Frame  *
     **********************************************
     */
    if ((packet.level == ZBEE_SEC_NONE) ||
        (packet.level == ZBEE_SEC_MIC32) ||
        (packet.level == ZBEE_SEC_MIC64) ||
        (packet.level == ZBEE_SEC_MIC128)) {
        /* Payload is only integrity protected. Just return the sub-tvbuff. */
        return tvb_new_subset(tvb, offset, payload_len, payload_len);
    }

#ifdef HAVE_LIBGCRYPT
    /* Ensure we have enough security material to decrypt this payload. */
    switch (packet.key) {
        /* Network Keys use the shared network key. */
        case ZBEE_SEC_KEY_NWK:
            if (!zbee_sec_have_nwk_key) {
                /* Without a key we can't decrypt (if we could what good would security be?)*/
                goto decrypt_failed;
            }
            if (packet.src == 0) {
                /* Without the extended source address, we can't create the nonce. */
                goto decrypt_failed;
            }
            /* The key, is the network key. */
            key_buffer = zbee_sec_nwk_key;
            break;

        /* Link Key might use the trust center link key. */
        case ZBEE_SEC_KEY_LINK:
            if (!zbee_sec_have_tclink_key) {
                /* Without a key we can't decrypt. */
                goto decrypt_failed;
            }
            if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){
                /* Without the extended source address, we can't create the nonce. */
                goto decrypt_failed;
            }
            else if (packet.src == 0) {
                packet.src = zbee_sec_tcaddr;
            }
            key_buffer = zbee_sec_tclink_key;
            break;

        /* Key-Transport Key should use the trust center link key. */
        case ZBEE_SEC_KEY_TRANSPORT:
            if (!zbee_sec_have_tclink_key) {
                /* Without a key we can't decrypt. */
                goto decrypt_failed;
            }
            if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){
                /* Without the extended source address, we can't create the nonce. */
                goto decrypt_failed;
            }
            else if (packet.src == 0) {
                packet.src = zbee_sec_tcaddr;
            }
            key_buffer = zbee_sec_key_hash(zbee_sec_tclink_key, 0x00, pinfo);
            break;

        /* Key-Load Key should use the trust center link key. */
        case ZBEE_SEC_KEY_LOAD:
            if (!zbee_sec_have_tclink_key) {
                /* Without a key we can't decrypt. */
                goto decrypt_failed;
            }
            if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){
                /* Without the extended source address, we can't create the nonce. */
                goto decrypt_failed;
            }
            else if (packet.src == 0) {
                packet.src = zbee_sec_tcaddr;
            }
            key_buffer = zbee_sec_key_hash(zbee_sec_tclink_key, 0x02, pinfo);
            break;

        default:
            goto decrypt_failed;
    } /* switch */

    /* Create the nonce. */
    zbee_sec_make_nonce(nonce, &packet);
    /* Allocate memory to decrypt the payload into. */
    dec_buffer = g_malloc(payload_len);
    /* Perform Decryption. */
    if (!zbee_sec_ccm_decrypt(key_buffer, /* key */
                nonce,              /* Nonce */
                enc_buffer,         /* a, length l(a) */
                enc_buffer+offset,  /* c, length l(c) = l(m) + M */
                dec_buffer,         /* m, length l(m) */
                offset,             /* l(a) */
                payload_len,        /* l(m) */
                mic_len)) {         /* M */
        /* Decryption Failed! */
        g_free(dec_buffer);
        goto decrypt_failed;
    }

    /* Setup the new tvbuff_t and return */
    payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len);
    add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload");
    /* Done! */
    return payload_tvb;

decrypt_failed:
#endif /* HAVE_LIBGCRYPT */

    /* Add expert info. */
    expert_add_info_format(pinfo, sec_tree, PI_UNDECODED, PI_WARN, "Encrypted Payload");
    /* Create a buffer for the undecrypted payload. */
    payload_tvb = tvb_new_subset(tvb, offset, payload_len, -1);
    /* Dump the payload to the data dissector. */
    call_dissector(data_handle, payload_tvb, pinfo, tree);
    /* Couldn't decrypt, so return NULL. */
    return NULL;

} /* dissect_zbee_secure */