hackedteam/vector-ipa

View on GitHub
src/encryption_ccmp.c

Summary

Maintainability
Test Coverage
/*
    MODULE -- encryption function

    Copyright (C) Alberto Ornaghi

    $Id: encryption_ccmp.c 2910 2010-09-23 09:40:28Z alor $
*/

#include <main.h>
#include <encryption.h>
#include <checksum.h>
#include <threads.h>

#include <openssl/aes.h>

/* globals */

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

/* protos */

int wpa_ccmp_decrypt(u_char *mac, u_char *data, size_t len, struct wpa_sa sa);
static inline void get_PN(u_char *PN, u_char *data);
static inline void get_B0(u_char *B0, u_char *mac, u_char *PN, size_t len);
static inline void get_AAD(u_char *AAD, u_char *mac, u_char *B0);
static int ccmp_decrypt(u_char *enc, u_char *B0, u_char *B, u_char *A, u_char *mic, size_t len, AES_KEY *ctx);

/*******************************************/

/*
 * IEEE-802.11i-2004  8.3.3.1
 */
int wpa_ccmp_decrypt(u_char *mac, u_char *data, size_t len, struct wpa_sa sa)
{
   u_char mic[WPA_CCMP_TRAILER];
   u_char PN[6]; /* 48 bit Packet Number */
   size_t data_len = len - sizeof(struct wpa_header);
   u_char AAD[AES_BLOCK_SIZE*2];
   u_char B0[AES_BLOCK_SIZE], A[AES_BLOCK_SIZE], B[AES_BLOCK_SIZE];
   u_char decbuf[len];
   AES_KEY aes_ctx;

   /* init the AES with the decryption key from SA */
   AES_set_encrypt_key(sa.decryption_key, 128, &aes_ctx);

   /* get the Packet Number */
   get_PN(PN, data);

   /* get the B0 */
   memset(B0, 0, sizeof(B0));
   get_B0(B0, mac, PN, data_len);

   /* get the Additional Authentication Data */
   memset(AAD, 0, sizeof(AAD));
   get_AAD(AAD, mac, B0);

   /* Start with the first block and AAD */
   AES_encrypt(B0, A, &aes_ctx);
   XOR_BLOCK(A, AAD, AES_BLOCK_SIZE);
   AES_encrypt(A, A, &aes_ctx);
   XOR_BLOCK(A, AAD + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
   AES_encrypt(A, A, &aes_ctx);

   B0[0] &= 0x07;
   B0[14] = B0[15] = 0;
   AES_encrypt(B0, B, &aes_ctx);

   /* get the MIC trailer. it is after the end of our packet */
   memcpy(mic, data + len, WPA_CCMP_TRAILER);

   XOR_BLOCK(mic, B, WPA_CCMP_TRAILER);

   /* copy the encrypted data to the decryption buffer (skipping the wpa parameters) */
   memcpy(decbuf, data + sizeof(struct wpa_header), len);

   /* decrypt the packet */
   if (ccmp_decrypt(decbuf, B0, B, A, mic, len, &aes_ctx) != 0) {
      DEBUG_MSG(D_VERBOSE, "WPA (CCMP) decryption failed, packet was skipped");
      return -ENOTHANDLED;
   }

   /*
    * copy the decrypted packet over the original one
    * overwriting the wpa header. this way the packet is
    * identical to a non-WPA one.
    */
   memcpy(data, decbuf, len);

   /*
    * wipe out the remaining bytes at the end of the packets
    * we have moved the data over the wpa header and the MIC was left
    * at the end of the packet.
    */
   memset(data + len - WPA_CCMP_TRAILER, 0, WPA_CCMP_TRAILER);

   return ESUCCESS;
}


/*
 * IEEE-802.11i-2004  8.3.3.2
 *
 * ----------------------------------------
 * |PN0|PN1|Reserved|KeyId|PN2|PN3|PN4|PN5|
 * ----------------------------------------
 */
static inline void get_PN(u_char *PN, u_char *data)
{
   PN[0] = data[0];
   PN[1] = data[1];
   /* skip the reserved */
   PN[2] = data[4];
   PN[3] = data[5];
   PN[4] = data[6];
   PN[5] = data[7];
}


static inline void get_B0(u_char *B0, u_char *mac, u_char *PN, size_t len)
{
   B0[0] = 0x59;
   B0[1] = 0; /* this will be set later by the callee */

   memcpy(B0 + 2, mac + 10, ETH_ADDR_LEN);

   B0[8]  = PN[5];
   B0[9]  = PN[4];
   B0[10] = PN[3];
   B0[11] = PN[2];
   B0[12] = PN[1];
   B0[13] = PN[0];

   B0[14] = ( len >> 8 ) & 0xFF;
   B0[15] = ( len & 0xFF );
}

static inline void get_AAD(u_char *AAD, u_char *mac, u_char *B0)
{
   AAD[0] = 0; /* AAD length >> 8 */
   AAD[1] = 0; /* this will be set below */
   AAD[2] = mac[0] & 0x8f;
   AAD[3] = mac[1] & 0xc7;
   /* we know 3 addresses are contiguous */
   memcpy(AAD + 4, mac + 4, 3 * ETH_ADDR_LEN);
   AAD[22] = mac[22] & 0x0F;
   AAD[23] = 0; /* all bits masked */

   /* XXX - implement the case of AP to AP 4 addresses wifi header */

   /* if WIFI_DATA | WIFI_BACON, we have a QoS Packet */
   if ( (mac[0] & (0x80 | 0x08)) == 0x88 ) {
      AAD[24] = mac[24] & 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;
   }
}


static int ccmp_decrypt(u_char *enc, u_char *B0, u_char *B, u_char *A, u_char *mic, size_t len, AES_KEY *ctx)
{
   int i = 1;

   /* remove the trailer from the length */
   len -= WPA_CCMP_TRAILER;

   while (len >= AES_BLOCK_SIZE) {
      CCMP_DECRYPT(i, B, B0, enc, A, AES_BLOCK_SIZE, ctx);

      enc += AES_BLOCK_SIZE;
      len -= AES_BLOCK_SIZE;
      i++;
   }

   /* last block */
   if (len != 0) {
      CCMP_DECRYPT(i, B, B0, enc, A, len, ctx);
   }

   return memcmp(mic, A, WPA_CCMP_TRAILER);
}

/* EOF */

// vim:ts=3:expandtab