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/types.h>
11#include <linux/crypto.h>
12#include <linux/err.h>
13#include <asm/scatterlist.h>
14
15#include <net/mac80211.h>
16#include "ieee80211_key.h"
17#include "aes_ccm.h"
18
19
20static void ieee80211_aes_encrypt(struct crypto_cipher *tfm,
21				  const u8 pt[16], u8 ct[16])
22{
23	crypto_cipher_encrypt_one(tfm, ct, pt);
24}
25
26
27static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
28				   u8 *b, u8 *s_0, u8 *a)
29{
30	int i;
31
32	ieee80211_aes_encrypt(tfm, b_0, b);
33
34	/* Extra Authenticate-only data (always two AES blocks) */
35	for (i = 0; i < AES_BLOCK_LEN; i++)
36		aad[i] ^= b[i];
37	ieee80211_aes_encrypt(tfm, aad, b);
38
39	aad += AES_BLOCK_LEN;
40
41	for (i = 0; i < AES_BLOCK_LEN; i++)
42		aad[i] ^= b[i];
43	ieee80211_aes_encrypt(tfm, aad, a);
44
45	/* Mask out bits from auth-only-b_0 */
46	b_0[0] &= 0x07;
47
48	/* S_0 is used to encrypt T (= MIC) */
49	b_0[14] = 0;
50	b_0[15] = 0;
51	ieee80211_aes_encrypt(tfm, b_0, s_0);
52}
53
54
55void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
56			       u8 *b_0, u8 *aad, u8 *data, size_t data_len,
57			       u8 *cdata, u8 *mic)
58{
59	int i, j, last_len, num_blocks;
60	u8 *pos, *cpos, *b, *s_0, *e;
61
62	b = scratch;
63	s_0 = scratch + AES_BLOCK_LEN;
64	e = scratch + 2 * AES_BLOCK_LEN;
65
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);
69
70	/* Process payload blocks */
71	pos = data;
72	cpos = cdata;
73	for (j = 1; j <= num_blocks; j++) {
74		int blen = (j == num_blocks && last_len) ?
75			last_len : AES_BLOCK_LEN;
76
77		/* Authentication followed by encryption */
78		for (i = 0; i < blen; i++)
79			b[i] ^= pos[i];
80		ieee80211_aes_encrypt(tfm, b, b);
81
82		b_0[14] = (j >> 8) & 0xff;
83		b_0[15] = j & 0xff;
84		ieee80211_aes_encrypt(tfm, b_0, e);
85		for (i = 0; i < blen; i++)
86			*cpos++ = *pos++ ^ e[i];
87	}
88
89	for (i = 0; i < CCMP_MIC_LEN; i++)
90		mic[i] = b[i] ^ s_0[i];
91}
92
93
94int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
95			      u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
96			      u8 *mic, u8 *data)
97{
98	int i, j, last_len, num_blocks;
99	u8 *pos, *cpos, *b, *s_0, *a;
100
101	b = scratch;
102	s_0 = scratch + AES_BLOCK_LEN;
103	a = scratch + 2 * AES_BLOCK_LEN;
104
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);
108
109	/* Process payload blocks */
110	cpos = cdata;
111	pos = data;
112	for (j = 1; j <= num_blocks; j++) {
113		int blen = (j == num_blocks && last_len) ?
114			last_len : AES_BLOCK_LEN;
115
116		/* Decryption followed by authentication */
117		b_0[14] = (j >> 8) & 0xff;
118		b_0[15] = j & 0xff;
119		ieee80211_aes_encrypt(tfm, b_0, b);
120		for (i = 0; i < blen; i++) {
121			*pos = *cpos++ ^ b[i];
122			a[i] ^= *pos++;
123		}
124
125		ieee80211_aes_encrypt(tfm, a, a);
126	}
127
128	for (i = 0; i < CCMP_MIC_LEN; i++) {
129		if ((mic[i] ^ s_0[i]) != a[i])
130			return -1;
131	}
132
133	return 0;
134}
135
136
137struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[])
138{
139	struct crypto_cipher *tfm;
140
141	tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
142	if (IS_ERR(tfm))
143		return NULL;
144
145	crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
146
147	return tfm;
148}
149
150
151void ieee80211_aes_key_free(struct crypto_cipher *tfm)
152{
153	if (tfm)
154		crypto_free_cipher(tfm);
155}
156