Logo Search packages:      
Sourcecode: wireshark version File versions  Download package

airpdcap_ccmp.c
/* airpdcap_ccmp.c
 *
 * $Id: airpdcap_ccmp.c 22104 2007-06-14 22:09:14Z gerald $
 *
 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
 * Copyright (c) 2006 CACE Technologies, Davis (California)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Note: This file was derived from the FreeBSD source code, RELENG 6,
 *          sys/net80211/ieee80211_crypto_ccmp.c
 */

/****************************************************************************/
/* File includes                                            */

#include "airpdcap_system.h"
#include "airpdcap_int.h"

#include "airpdcap_rijndael.h"

#include "airpdcap_debug.h"

/****************************************************************************/
/*    Internal definitions                                        */

#define AES_BLOCK_LEN 16

/* Note: copied from net80211/ieee80211.h                         */
#define AIRPDCAP_FC1_DIR_MASK                  0x03
#define AIRPDCAP_FC1_DIR_DSTODS                0x03    /* AP ->AP  */
#define AIRPDCAP_FC0_SUBTYPE_QOS               0x80
#define AIRPDCAP_FC0_TYPE_DATA                 0x08
#define AIRPDCAP_FC0_TYPE_MASK                 0x0c
#define AIRPDCAP_SEQ_FRAG_MASK                 0x000f
#define AIRPDCAP_QOS_HAS_SEQ(wh) \
      (((wh)->fc[0] & \
      (AIRPDCAP_FC0_TYPE_MASK | AIRPDCAP_FC0_SUBTYPE_QOS)) == \
      (AIRPDCAP_FC0_TYPE_DATA | AIRPDCAP_FC0_SUBTYPE_QOS))

/****************************************************************************/
/* Internal macros                                                */

#define CCMP_DECRYPT(_i, _b, _b0, _pos, _a, _len) {         \
      /* Decrypt, with counter */                             \
      _b0[14] = (UINT8)((_i >> 8) & 0xff);                    \
      _b0[15] = (UINT8)(_i & 0xff);                           \
      rijndael_encrypt(&key, _b0, _b);                  \
      XOR_BLOCK(_pos, _b, _len);                      \
      /* Authentication */                            \
      XOR_BLOCK(_a, _pos, _len);                      \
      rijndael_encrypt(&key, _a, _a);                       \
}

#define READ_6(b0, b1, b2, b3, b4, b5) \
      ((((UINT64)((UINT16)((b4 << 0) | (b5 << 8)))) << 32) | \
          ((UINT32)((b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24))))

#define AIRPDCAP_ADDR_COPY(dst,src)    memcpy(dst,src,AIRPDCAP_MAC_LEN)

/****************************************************************************/
/* Internal function prototypes declarations                            */

static void ccmp_init_blocks(
      rijndael_ctx *ctx,
        PAIRPDCAP_MAC_FRAME wh,
      UINT64 pn,
      size_t dlen,
      UINT8 b0[AES_BLOCK_LEN],
      UINT8 aad[2 * AES_BLOCK_LEN],
      UINT8 a[AES_BLOCK_LEN],
      UINT8 b[AES_BLOCK_LEN])
      ;

/****************************************************************************/
/* Function definitions                                     */

static void ccmp_init_blocks(
      rijndael_ctx *ctx,
        PAIRPDCAP_MAC_FRAME wh,
      UINT64 pn,
      size_t dlen,
      UINT8 b0[AES_BLOCK_LEN],
      UINT8 aad[2 * AES_BLOCK_LEN],
      UINT8 a[AES_BLOCK_LEN],
      UINT8 b[AES_BLOCK_LEN])
{
#define IS_4ADDRESS(wh) \
      ((wh->fc[1] & AIRPDCAP_FC1_DIR_MASK) == AIRPDCAP_FC1_DIR_DSTODS)
#define IS_QOS_DATA(wh) AIRPDCAP_QOS_HAS_SEQ(wh)

      memset(aad, 0, 2*AES_BLOCK_LEN);

      /* CCM Initial Block:
      * Flag (Include authentication header, M=3 (8-octet MIC),
      *       L=1 (2-octet Dlen))
      * Nonce: 0x00 | A2 | PN
      * Dlen */
      b0[0] = 0x59;
      /* NB: b0[1] set below */
      AIRPDCAP_ADDR_COPY(b0 + 2, wh->addr2);
      b0[8] = (UINT8)(pn >> 40);
      b0[9] = (UINT8)(pn >> 32);
      b0[10] = (UINT8)(pn >> 24);
      b0[11] = (UINT8)(pn >> 16);
      b0[12] = (UINT8)(pn >> 8);
      b0[13] = (UINT8)(pn >> 0);
      b0[14] = (UINT8)((UINT8)(dlen >> 8) & 0xff);
      b0[15] = (UINT8)(dlen & 0xff);

      /* AAD:
      * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
      * A1 | A2 | A3
      * SC with bits 4..15 (seq#) masked to zero
      * A4 (if present)
      * QC (if present)
      */
      aad[0] = 0;     /* AAD length >> 8 */
      /* NB: aad[1] set below */
      aad[2] = (UINT8)(wh->fc[0] & 0x8f);    /* XXX magic #s */
      aad[3] = (UINT8)(wh->fc[1] & 0xc7);    /* XXX magic #s */
      /* NB: we know 3 addresses are contiguous */
      memcpy(aad + 4, wh->addr1, 3 * AIRPDCAP_MAC_LEN);
      aad[22] = (UINT8)(wh->seq[0] & AIRPDCAP_SEQ_FRAG_MASK);
      aad[23] = 0; /* all bits masked */
      /*
      * Construct variable-length portion of AAD based
      * on whether this is a 4-address frame/QOS frame.
      * We always zero-pad to 32 bytes before running it
      * through the cipher.
      *
      * We also fill in the priority bits of the CCM
      * initial block as we know whether or not we have
      * a QOS frame.
      */
      if (IS_4ADDRESS(wh)) {
            AIRPDCAP_ADDR_COPY(aad + 24,
                  ((PAIRPDCAP_MAC_FRAME_ADDR4)wh)->addr4);
            if (IS_QOS_DATA(wh)) {
                  PAIRPDCAP_MAC_FRAME_ADDR4_QOS qwh4 =
                        (PAIRPDCAP_MAC_FRAME_ADDR4_QOS) wh;
                  aad[30] = (UINT8)(qwh4->qos[0] & 0x0f);/* just priority bits */
                  aad[31] = 0;
                  b0[1] = aad[30];
                  aad[1] = 22 + AIRPDCAP_MAC_LEN + 2;
            } else {
                  memset(&aad[30], 0, 2);
                  b0[1] = 0;
                  aad[1] = 22 + AIRPDCAP_MAC_LEN;
            }
      } else {
            if (IS_QOS_DATA(wh)) {
                  PAIRPDCAP_MAC_FRAME_QOS qwh =
                        (PAIRPDCAP_MAC_FRAME_QOS) wh;
                  aad[24] = (UINT8)(qwh->qos[0] & 0x0f); /* just priority bits */
                  aad[25] = 0;
                  b0[1] = aad[24];
                  aad[1] = 22 + 2;
            } else {
                  memset(&aad[24], 0, 2);
                  b0[1] = 0;
                  aad[1] = 22;
            }
            memset(&aad[26], 0, 4);
      }

      /* Start with the first block and AAD */
      rijndael_encrypt(ctx, b0, a);
      XOR_BLOCK(a, aad, AES_BLOCK_LEN);
      rijndael_encrypt(ctx, a, a);
      XOR_BLOCK(a, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
      rijndael_encrypt(ctx, a, a);
      b0[0] &= 0x07;
      b0[14] = b0[15] = 0;
      rijndael_encrypt(ctx, b0, b);

      /** //XOR( m + len - 8, b, 8 ); **/
#undef  IS_QOS_DATA
#undef  IS_4ADDRESS
}

INT AirPDcapCcmpDecrypt(
      UINT8 *m,
        gint mac_header_len,
      INT len,
      UCHAR TK1[16])
{
      PAIRPDCAP_MAC_FRAME wh;
      UINT8 aad[2 * AES_BLOCK_LEN];
      UINT8 b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], a[AES_BLOCK_LEN];
      UINT8 mic[AES_BLOCK_LEN];
      size_t data_len;
      UINT i;
      UINT8 *pos;
      UINT space;
      INT z = mac_header_len;
      rijndael_ctx key;
      UINT64 PN;
      UINT8 *ivp=m+z;

      PN = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);

      /* freebsd  */
      rijndael_set_key(&key, TK1, 128);
      wh = (PAIRPDCAP_MAC_FRAME )m;
      data_len = len - (z + AIRPDCAP_CCMP_HEADER+AIRPDCAP_CCMP_TRAILER);
      if (data_len < 1)
          return 0;
      ccmp_init_blocks(&key, wh, PN, data_len, b0, aad, a, b);
      memcpy(mic, m+len-AIRPDCAP_CCMP_TRAILER, AIRPDCAP_CCMP_TRAILER);
      XOR_BLOCK(mic, b, AIRPDCAP_CCMP_TRAILER);

      i = 1;
      pos = (UINT8 *)m + z + AIRPDCAP_CCMP_HEADER;
      space = len - (z + AIRPDCAP_CCMP_HEADER);

      if (space > data_len)
            space = (UINT)data_len;
      while (space >= AES_BLOCK_LEN) {
            CCMP_DECRYPT(i, b, b0, pos, a, AES_BLOCK_LEN);
            pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
            data_len -= AES_BLOCK_LEN;
            i++;
      }

      if (space != 0)         /* short last block */
            CCMP_DECRYPT(i, b, b0, pos, a, space);

      /*    MIC Key ?= MIC                                                                                                                      */
      if (memcmp(mic, a, AIRPDCAP_CCMP_TRAILER) == 0) {
            return 0;
      }

      /* TODO replay check    (IEEE 802.11i-2004, pg. 62)               */
      /* TODO PN must be incremental (IEEE 802.11i-2004, pg. 62)        */

      return 1;
}

Generated by  Doxygen 1.6.0   Back to index