|
2 | 2 | * Copyright 2003-2004, Instant802 Networks, Inc.
|
3 | 3 | * Copyright 2005-2006, Devicescape Software, Inc.
|
4 | 4 | *
|
| 5 | + * Rewrite: Copyright (C) 2013 Linaro Ltd <[email protected]> |
| 6 | + * |
5 | 7 | * This program is free software; you can redistribute it and/or modify
|
6 | 8 | * it under the terms of the GNU General Public License version 2 as
|
7 | 9 | * published by the Free Software Foundation.
|
|
17 | 19 | #include "key.h"
|
18 | 20 | #include "aes_ccm.h"
|
19 | 21 |
|
20 |
| -static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a) |
| 22 | +void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, |
| 23 | + u8 *data, size_t data_len, u8 *mic) |
21 | 24 | {
|
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); |
| 25 | + struct scatterlist assoc, pt, ct[2]; |
| 26 | + struct { |
| 27 | + struct aead_request req; |
| 28 | + u8 priv[crypto_aead_reqsize(tfm)]; |
| 29 | + } aead_req; |
31 | 30 |
|
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); |
| 31 | + memset(&aead_req, 0, sizeof(aead_req)); |
36 | 32 |
|
37 |
| - aad += AES_BLOCK_SIZE; |
| 33 | + sg_init_one(&pt, data, data_len); |
| 34 | + sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); |
| 35 | + sg_init_table(ct, 2); |
| 36 | + sg_set_buf(&ct[0], data, data_len); |
| 37 | + sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); |
38 | 38 |
|
39 |
| - for (i = 0; i < AES_BLOCK_SIZE; i++) |
40 |
| - aad[i] ^= b[i]; |
41 |
| - crypto_cipher_encrypt_one(tfm, a, aad); |
| 39 | + aead_request_set_tfm(&aead_req.req, tfm); |
| 40 | + aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); |
| 41 | + aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0); |
42 | 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); |
| 43 | + crypto_aead_encrypt(&aead_req.req); |
50 | 44 | }
|
51 | 45 |
|
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) |
| 46 | +int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, |
| 47 | + u8 *data, size_t data_len, u8 *mic) |
56 | 48 | {
|
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 < IEEE80211_CCMP_MIC_LEN; i++) |
89 |
| - mic[i] = b[i] ^ s_0[i]; |
| 49 | + struct scatterlist assoc, pt, ct[2]; |
| 50 | + struct { |
| 51 | + struct aead_request req; |
| 52 | + u8 priv[crypto_aead_reqsize(tfm)]; |
| 53 | + } aead_req; |
| 54 | + |
| 55 | + memset(&aead_req, 0, sizeof(aead_req)); |
| 56 | + |
| 57 | + sg_init_one(&pt, data, data_len); |
| 58 | + sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); |
| 59 | + sg_init_table(ct, 2); |
| 60 | + sg_set_buf(&ct[0], data, data_len); |
| 61 | + sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); |
| 62 | + |
| 63 | + aead_request_set_tfm(&aead_req.req, tfm); |
| 64 | + aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); |
| 65 | + aead_request_set_crypt(&aead_req.req, ct, &pt, |
| 66 | + data_len + IEEE80211_CCMP_MIC_LEN, b_0); |
| 67 | + |
| 68 | + return crypto_aead_decrypt(&aead_req.req); |
90 | 69 | }
|
91 | 70 |
|
92 |
| - |
93 |
| -int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, |
94 |
| - u8 *cdata, size_t data_len, u8 *mic, u8 *data) |
| 71 | +struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]) |
95 | 72 | {
|
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 < IEEE80211_CCMP_MIC_LEN; i++) { |
127 |
| - if ((mic[i] ^ s_0[i]) != a[i]) |
128 |
| - return -1; |
129 |
| - } |
130 |
| - |
131 |
| - return 0; |
132 |
| -} |
| 73 | + struct crypto_aead *tfm; |
| 74 | + int err; |
133 | 75 |
|
| 76 | + tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); |
| 77 | + if (IS_ERR(tfm)) |
| 78 | + return tfm; |
134 | 79 |
|
135 |
| -struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]) |
136 |
| -{ |
137 |
| - struct crypto_cipher *tfm; |
| 80 | + err = crypto_aead_setkey(tfm, key, WLAN_KEY_LEN_CCMP); |
| 81 | + if (!err) |
| 82 | + err = crypto_aead_setauthsize(tfm, IEEE80211_CCMP_MIC_LEN); |
| 83 | + if (!err) |
| 84 | + return tfm; |
138 | 85 |
|
139 |
| - tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); |
140 |
| - if (!IS_ERR(tfm)) |
141 |
| - crypto_cipher_setkey(tfm, key, WLAN_KEY_LEN_CCMP); |
142 |
| - |
143 |
| - return tfm; |
| 86 | + crypto_free_aead(tfm); |
| 87 | + return ERR_PTR(err); |
144 | 88 | }
|
145 | 89 |
|
146 |
| - |
147 |
| -void ieee80211_aes_key_free(struct crypto_cipher *tfm) |
| 90 | +void ieee80211_aes_key_free(struct crypto_aead *tfm) |
148 | 91 | {
|
149 |
| - crypto_free_cipher(tfm); |
| 92 | + crypto_free_aead(tfm); |
150 | 93 | }
|
0 commit comments