diff options
author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2013-10-10 03:55:20 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-10-11 09:38:20 -0400 |
commit | 7ec7c4a9a686c608315739ab6a2b0527a240883c (patch) | |
tree | e3f5ecc10414b632be93bef3f4e0494733113795 /net/mac80211/aes_ccm.c | |
parent | fa1fb9cb1c734204018d2b4e6f38c4a9b4146612 (diff) |
mac80211: port CCMP to cryptoapi's CCM driver
Use the generic CCM aead chaining mode driver rather than a local
implementation that sits right on top of the core AES cipher.
This allows the use of accelerated implementations of either
CCM as a whole or the CTR mode which it encapsulates.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/aes_ccm.c')
-rw-r--r-- | net/mac80211/aes_ccm.c | 169 |
1 files changed, 56 insertions, 113 deletions
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index be7614b9ed27..7c7df475a401 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c | |||
@@ -2,6 +2,8 @@ | |||
2 | * Copyright 2003-2004, Instant802 Networks, Inc. | 2 | * Copyright 2003-2004, Instant802 Networks, Inc. |
3 | * Copyright 2005-2006, Devicescape Software, Inc. | 3 | * Copyright 2005-2006, Devicescape Software, Inc. |
4 | * | 4 | * |
5 | * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org> | ||
6 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | 7 | * 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 | 8 | * it under the terms of the GNU General Public License version 2 as |
7 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
@@ -17,134 +19,75 @@ | |||
17 | #include "key.h" | 19 | #include "key.h" |
18 | #include "aes_ccm.h" | 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; | 25 | struct scatterlist assoc, pt, ct[2]; |
23 | u8 *b_0, *aad, *b, *s_0; | 26 | struct { |
24 | 27 | struct aead_request req; | |
25 | b_0 = scratch + 3 * AES_BLOCK_SIZE; | 28 | u8 priv[crypto_aead_reqsize(tfm)]; |
26 | aad = scratch + 4 * AES_BLOCK_SIZE; | 29 | } aead_req; |
27 | b = scratch; | ||
28 | s_0 = scratch + AES_BLOCK_SIZE; | ||
29 | |||
30 | crypto_cipher_encrypt_one(tfm, b, b_0); | ||
31 | 30 | ||
32 | /* Extra Authenticate-only data (always two AES blocks) */ | 31 | memset(&aead_req, 0, sizeof(aead_req)); |
33 | for (i = 0; i < AES_BLOCK_SIZE; i++) | ||
34 | aad[i] ^= b[i]; | ||
35 | crypto_cipher_encrypt_one(tfm, b, aad); | ||
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++) | 39 | aead_request_set_tfm(&aead_req.req, tfm); |
40 | aad[i] ^= b[i]; | 40 | aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); |
41 | crypto_cipher_encrypt_one(tfm, a, aad); | 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 */ | 43 | crypto_aead_encrypt(&aead_req.req); |
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 | } | 44 | } |
51 | 45 | ||
52 | 46 | int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | |
53 | void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, | 47 | u8 *data, size_t data_len, u8 *mic) |
54 | u8 *data, size_t data_len, | ||
55 | u8 *cdata, u8 *mic) | ||
56 | { | 48 | { |
57 | int i, j, last_len, num_blocks; | 49 | struct scatterlist assoc, pt, ct[2]; |
58 | u8 *pos, *cpos, *b, *s_0, *e, *b_0; | 50 | struct { |
59 | 51 | struct aead_request req; | |
60 | b = scratch; | 52 | u8 priv[crypto_aead_reqsize(tfm)]; |
61 | s_0 = scratch + AES_BLOCK_SIZE; | 53 | } aead_req; |
62 | e = scratch + 2 * AES_BLOCK_SIZE; | 54 | |
63 | b_0 = scratch + 3 * AES_BLOCK_SIZE; | 55 | memset(&aead_req, 0, sizeof(aead_req)); |
64 | 56 | ||
65 | num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); | 57 | sg_init_one(&pt, data, data_len); |
66 | last_len = data_len % AES_BLOCK_SIZE; | 58 | sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); |
67 | aes_ccm_prepare(tfm, scratch, b); | 59 | sg_init_table(ct, 2); |
68 | 60 | sg_set_buf(&ct[0], data, data_len); | |
69 | /* Process payload blocks */ | 61 | sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); |
70 | pos = data; | 62 | |
71 | cpos = cdata; | 63 | aead_request_set_tfm(&aead_req.req, tfm); |
72 | for (j = 1; j <= num_blocks; j++) { | 64 | aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); |
73 | int blen = (j == num_blocks && last_len) ? | 65 | aead_request_set_crypt(&aead_req.req, ct, &pt, |
74 | last_len : AES_BLOCK_SIZE; | 66 | data_len + IEEE80211_CCMP_MIC_LEN, b_0); |
75 | 67 | ||
76 | /* Authentication followed by encryption */ | 68 | return crypto_aead_decrypt(&aead_req.req); |
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]; | ||
90 | } | 69 | } |
91 | 70 | ||
92 | 71 | struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]) | |
93 | int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, | ||
94 | u8 *cdata, size_t data_len, u8 *mic, u8 *data) | ||
95 | { | 72 | { |
96 | int i, j, last_len, num_blocks; | 73 | struct crypto_aead *tfm; |
97 | u8 *pos, *cpos, *b, *s_0, *a, *b_0; | 74 | int err; |
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 | } | ||
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[]) | 80 | err = crypto_aead_setkey(tfm, key, WLAN_KEY_LEN_CCMP); |
136 | { | 81 | if (!err) |
137 | struct crypto_cipher *tfm; | 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); | 86 | crypto_free_aead(tfm); |
140 | if (!IS_ERR(tfm)) | 87 | return ERR_PTR(err); |
141 | crypto_cipher_setkey(tfm, key, WLAN_KEY_LEN_CCMP); | ||
142 | |||
143 | return tfm; | ||
144 | } | 88 | } |
145 | 89 | ||
146 | 90 | void ieee80211_aes_key_free(struct crypto_aead *tfm) | |
147 | void ieee80211_aes_key_free(struct crypto_cipher *tfm) | ||
148 | { | 91 | { |
149 | crypto_free_cipher(tfm); | 92 | crypto_free_aead(tfm); |
150 | } | 93 | } |