2
* Copyright 2003-2004, Instant802 Networks, Inc.
3
* Copyright 2005-2006, Devicescape Software, Inc.
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.
10
#include <linux/types.h>
11
#include <linux/crypto.h>
12
#include <linux/err.h>
13
#include <asm/scatterlist.h>
15
#include <net/mac80211.h>
16
#include "ieee80211_key.h"
20
static void ieee80211_aes_encrypt(struct crypto_cipher *tfm,
21
const u8 pt[16], u8 ct[16])
23
crypto_cipher_encrypt_one(tfm, ct, pt);
27
static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
28
u8 *b, u8 *s_0, u8 *a)
32
ieee80211_aes_encrypt(tfm, b_0, b);
34
/* Extra Authenticate-only data (always two AES blocks) */
35
for (i = 0; i < AES_BLOCK_LEN; i++)
37
ieee80211_aes_encrypt(tfm, aad, b);
41
for (i = 0; i < AES_BLOCK_LEN; i++)
43
ieee80211_aes_encrypt(tfm, aad, a);
45
/* Mask out bits from auth-only-b_0 */
48
/* S_0 is used to encrypt T (= MIC) */
51
ieee80211_aes_encrypt(tfm, b_0, s_0);
55
void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
56
u8 *b_0, u8 *aad, u8 *data, size_t data_len,
59
int i, j, last_len, num_blocks;
60
u8 *pos, *cpos, *b, *s_0, *e;
63
s_0 = scratch + AES_BLOCK_LEN;
64
e = scratch + 2 * AES_BLOCK_LEN;
66
num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
67
last_len = data_len % AES_BLOCK_LEN;
68
aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
70
/* Process payload blocks */
73
for (j = 1; j <= num_blocks; j++) {
74
int blen = (j == num_blocks && last_len) ?
75
last_len : AES_BLOCK_LEN;
77
/* Authentication followed by encryption */
78
for (i = 0; i < blen; i++)
80
ieee80211_aes_encrypt(tfm, b, b);
82
b_0[14] = (j >> 8) & 0xff;
84
ieee80211_aes_encrypt(tfm, b_0, e);
85
for (i = 0; i < blen; i++)
86
*cpos++ = *pos++ ^ e[i];
89
for (i = 0; i < CCMP_MIC_LEN; i++)
90
mic[i] = b[i] ^ s_0[i];
94
int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
95
u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
98
int i, j, last_len, num_blocks;
99
u8 *pos, *cpos, *b, *s_0, *a;
102
s_0 = scratch + AES_BLOCK_LEN;
103
a = scratch + 2 * AES_BLOCK_LEN;
105
num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
106
last_len = data_len % AES_BLOCK_LEN;
107
aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
109
/* Process payload blocks */
112
for (j = 1; j <= num_blocks; j++) {
113
int blen = (j == num_blocks && last_len) ?
114
last_len : AES_BLOCK_LEN;
116
/* Decryption followed by authentication */
117
b_0[14] = (j >> 8) & 0xff;
119
ieee80211_aes_encrypt(tfm, b_0, b);
120
for (i = 0; i < blen; i++) {
121
*pos = *cpos++ ^ b[i];
125
ieee80211_aes_encrypt(tfm, a, a);
128
for (i = 0; i < CCMP_MIC_LEN; i++) {
129
if ((mic[i] ^ s_0[i]) != a[i])
137
struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[])
139
struct crypto_cipher *tfm;
141
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
145
crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
151
void ieee80211_aes_key_free(struct crypto_cipher *tfm)
154
crypto_free_cipher(tfm);