Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
aes_ccm.c
Go to the documentation of this file.
1 /*
2  * Copyright 2003-2004, Instant802 Networks, Inc.
3  * Copyright 2005-2006, Devicescape Software, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9 
10 #include <linux/kernel.h>
11 #include <linux/types.h>
12 #include <linux/crypto.h>
13 #include <linux/err.h>
14 #include <crypto/aes.h>
15 
16 #include <net/mac80211.h>
17 #include "key.h"
18 #include "aes_ccm.h"
19 
20 static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a)
21 {
22  int i;
23  u8 *b_0, *aad, *b, *s_0;
24 
25  b_0 = scratch + 3 * AES_BLOCK_SIZE;
26  aad = scratch + 4 * AES_BLOCK_SIZE;
27  b = scratch;
28  s_0 = scratch + AES_BLOCK_SIZE;
29 
30  crypto_cipher_encrypt_one(tfm, b, b_0);
31 
32  /* Extra Authenticate-only data (always two AES blocks) */
33  for (i = 0; i < AES_BLOCK_SIZE; i++)
34  aad[i] ^= b[i];
35  crypto_cipher_encrypt_one(tfm, b, aad);
36 
37  aad += AES_BLOCK_SIZE;
38 
39  for (i = 0; i < AES_BLOCK_SIZE; i++)
40  aad[i] ^= b[i];
41  crypto_cipher_encrypt_one(tfm, a, aad);
42 
43  /* Mask out bits from auth-only-b_0 */
44  b_0[0] &= 0x07;
45 
46  /* S_0 is used to encrypt T (= MIC) */
47  b_0[14] = 0;
48  b_0[15] = 0;
49  crypto_cipher_encrypt_one(tfm, s_0, b_0);
50 }
51 
52 
53 void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
54  u8 *data, size_t data_len,
55  u8 *cdata, u8 *mic)
56 {
57  int i, j, last_len, num_blocks;
58  u8 *pos, *cpos, *b, *s_0, *e, *b_0;
59 
60  b = scratch;
61  s_0 = scratch + AES_BLOCK_SIZE;
62  e = scratch + 2 * AES_BLOCK_SIZE;
63  b_0 = scratch + 3 * AES_BLOCK_SIZE;
64 
65  num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
66  last_len = data_len % AES_BLOCK_SIZE;
67  aes_ccm_prepare(tfm, scratch, b);
68 
69  /* Process payload blocks */
70  pos = data;
71  cpos = cdata;
72  for (j = 1; j <= num_blocks; j++) {
73  int blen = (j == num_blocks && last_len) ?
74  last_len : AES_BLOCK_SIZE;
75 
76  /* Authentication followed by encryption */
77  for (i = 0; i < blen; i++)
78  b[i] ^= pos[i];
79  crypto_cipher_encrypt_one(tfm, b, b);
80 
81  b_0[14] = (j >> 8) & 0xff;
82  b_0[15] = j & 0xff;
83  crypto_cipher_encrypt_one(tfm, e, b_0);
84  for (i = 0; i < blen; i++)
85  *cpos++ = *pos++ ^ e[i];
86  }
87 
88  for (i = 0; i < CCMP_MIC_LEN; i++)
89  mic[i] = b[i] ^ s_0[i];
90 }
91 
92 
93 int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
94  u8 *cdata, size_t data_len, u8 *mic, u8 *data)
95 {
96  int i, j, last_len, num_blocks;
97  u8 *pos, *cpos, *b, *s_0, *a, *b_0;
98 
99  b = scratch;
100  s_0 = scratch + AES_BLOCK_SIZE;
101  a = scratch + 2 * AES_BLOCK_SIZE;
102  b_0 = scratch + 3 * AES_BLOCK_SIZE;
103 
104  num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
105  last_len = data_len % AES_BLOCK_SIZE;
106  aes_ccm_prepare(tfm, scratch, a);
107 
108  /* Process payload blocks */
109  cpos = cdata;
110  pos = data;
111  for (j = 1; j <= num_blocks; j++) {
112  int blen = (j == num_blocks && last_len) ?
113  last_len : AES_BLOCK_SIZE;
114 
115  /* Decryption followed by authentication */
116  b_0[14] = (j >> 8) & 0xff;
117  b_0[15] = j & 0xff;
118  crypto_cipher_encrypt_one(tfm, b, b_0);
119  for (i = 0; i < blen; i++) {
120  *pos = *cpos++ ^ b[i];
121  a[i] ^= *pos++;
122  }
123  crypto_cipher_encrypt_one(tfm, a, a);
124  }
125 
126  for (i = 0; i < CCMP_MIC_LEN; i++) {
127  if ((mic[i] ^ s_0[i]) != a[i])
128  return -1;
129  }
130 
131  return 0;
132 }
133 
134 
136 {
137  struct crypto_cipher *tfm;
138 
139  tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
140  if (!IS_ERR(tfm))
141  crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
142 
143  return tfm;
144 }
145 
146 
148 {
149  crypto_free_cipher(tfm);
150 }