mac80211: aes-cmac: switch to shash CMAC driver
Instead of open coding the CMAC algorithm in the mac80211 driver using byte wide xors and calls into the crypto layer for each block of data, instantiate a cmac(aes) synchronous hash and pass all the data into it directly. This does not only simplify the code, it also allows the use of more efficient and more secure implementations, especially on platforms where SIMD ciphers have a considerable setup cost. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
fe8de3da13
commit
26717828b7
3 changed files with 32 additions and 107 deletions
|
@ -22,126 +22,50 @@
|
|||
#define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */
|
||||
#define AAD_LEN 20
|
||||
|
||||
static const u8 zero[CMAC_TLEN_256];
|
||||
|
||||
void gf_mulx(u8 *pad)
|
||||
{
|
||||
int i, carry;
|
||||
|
||||
carry = pad[0] & 0x80;
|
||||
for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
|
||||
pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
|
||||
pad[AES_BLOCK_SIZE - 1] <<= 1;
|
||||
if (carry)
|
||||
pad[AES_BLOCK_SIZE - 1] ^= 0x87;
|
||||
}
|
||||
|
||||
void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac,
|
||||
size_t mac_len)
|
||||
{
|
||||
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
|
||||
const u8 *pos, *end;
|
||||
size_t i, e, left, total_len;
|
||||
|
||||
memset(cbc, 0, AES_BLOCK_SIZE);
|
||||
|
||||
total_len = 0;
|
||||
for (e = 0; e < num_elem; e++)
|
||||
total_len += len[e];
|
||||
left = total_len;
|
||||
|
||||
e = 0;
|
||||
pos = addr[0];
|
||||
end = pos + len[0];
|
||||
|
||||
while (left >= AES_BLOCK_SIZE) {
|
||||
for (i = 0; i < AES_BLOCK_SIZE; i++) {
|
||||
cbc[i] ^= *pos++;
|
||||
if (pos >= end) {
|
||||
e++;
|
||||
pos = addr[e];
|
||||
end = pos + len[e];
|
||||
}
|
||||
}
|
||||
if (left > AES_BLOCK_SIZE)
|
||||
crypto_cipher_encrypt_one(tfm, cbc, cbc);
|
||||
left -= AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memset(pad, 0, AES_BLOCK_SIZE);
|
||||
crypto_cipher_encrypt_one(tfm, pad, pad);
|
||||
gf_mulx(pad);
|
||||
|
||||
if (left || total_len == 0) {
|
||||
for (i = 0; i < left; i++) {
|
||||
cbc[i] ^= *pos++;
|
||||
if (pos >= end) {
|
||||
e++;
|
||||
pos = addr[e];
|
||||
end = pos + len[e];
|
||||
}
|
||||
}
|
||||
cbc[left] ^= 0x80;
|
||||
gf_mulx(pad);
|
||||
}
|
||||
|
||||
for (i = 0; i < AES_BLOCK_SIZE; i++)
|
||||
pad[i] ^= cbc[i];
|
||||
crypto_cipher_encrypt_one(tfm, pad, pad);
|
||||
memcpy(mac, pad, mac_len);
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
|
||||
void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad,
|
||||
const u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
u8 zero[CMAC_TLEN];
|
||||
SHASH_DESC_ON_STACK(desc, tfm);
|
||||
u8 out[AES_BLOCK_SIZE];
|
||||
|
||||
memset(zero, 0, CMAC_TLEN);
|
||||
addr[0] = aad;
|
||||
len[0] = AAD_LEN;
|
||||
addr[1] = data;
|
||||
len[1] = data_len - CMAC_TLEN;
|
||||
addr[2] = zero;
|
||||
len[2] = CMAC_TLEN;
|
||||
desc->tfm = tfm;
|
||||
|
||||
aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN);
|
||||
crypto_shash_init(desc);
|
||||
crypto_shash_update(desc, aad, AAD_LEN);
|
||||
crypto_shash_update(desc, data, data_len - CMAC_TLEN);
|
||||
crypto_shash_finup(desc, zero, CMAC_TLEN, out);
|
||||
|
||||
memcpy(mic, out, CMAC_TLEN);
|
||||
}
|
||||
|
||||
void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad,
|
||||
void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad,
|
||||
const u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
u8 zero[CMAC_TLEN_256];
|
||||
SHASH_DESC_ON_STACK(desc, tfm);
|
||||
|
||||
memset(zero, 0, CMAC_TLEN_256);
|
||||
addr[0] = aad;
|
||||
len[0] = AAD_LEN;
|
||||
addr[1] = data;
|
||||
len[1] = data_len - CMAC_TLEN_256;
|
||||
addr[2] = zero;
|
||||
len[2] = CMAC_TLEN_256;
|
||||
desc->tfm = tfm;
|
||||
|
||||
aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256);
|
||||
crypto_shash_init(desc);
|
||||
crypto_shash_update(desc, aad, AAD_LEN);
|
||||
crypto_shash_update(desc, data, data_len - CMAC_TLEN_256);
|
||||
crypto_shash_finup(desc, zero, CMAC_TLEN_256, mic);
|
||||
}
|
||||
|
||||
struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[],
|
||||
size_t key_len)
|
||||
struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[],
|
||||
size_t key_len)
|
||||
{
|
||||
struct crypto_cipher *tfm;
|
||||
struct crypto_shash *tfm;
|
||||
|
||||
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
||||
tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
|
||||
if (!IS_ERR(tfm))
|
||||
crypto_cipher_setkey(tfm, key, key_len);
|
||||
crypto_shash_setkey(tfm, key, key_len);
|
||||
|
||||
return tfm;
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm)
|
||||
void ieee80211_aes_cmac_key_free(struct crypto_shash *tfm)
|
||||
{
|
||||
crypto_free_cipher(tfm);
|
||||
crypto_free_shash(tfm);
|
||||
}
|
||||
|
|
|
@ -10,13 +10,14 @@
|
|||
#define AES_CMAC_H
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[],
|
||||
size_t key_len);
|
||||
void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
|
||||
struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[],
|
||||
size_t key_len);
|
||||
void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad,
|
||||
const u8 *data, size_t data_len, u8 *mic);
|
||||
void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad,
|
||||
void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad,
|
||||
const u8 *data, size_t data_len, u8 *mic);
|
||||
void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm);
|
||||
void ieee80211_aes_cmac_key_free(struct crypto_shash *tfm);
|
||||
|
||||
#endif /* AES_CMAC_H */
|
||||
|
|
|
@ -93,7 +93,7 @@ struct ieee80211_key {
|
|||
} ccmp;
|
||||
struct {
|
||||
u8 rx_pn[IEEE80211_CMAC_PN_LEN];
|
||||
struct crypto_cipher *tfm;
|
||||
struct crypto_shash *tfm;
|
||||
u32 replays; /* dot11RSNAStatsCMACReplays */
|
||||
u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
|
||||
} aes_cmac;
|
||||
|
|
Loading…
Reference in a new issue