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