1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AES-128-CMAC with TLen 16 for IEEE 802.11w BIP 4 * Copyright 2008, Jouni Malinen <j@w1.fi> 5 * Copyright (C) 2020 Intel Corporation 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/types.h> 10 #include <linux/crypto.h> 11 #include <linux/export.h> 12 #include <linux/err.h> 13 #include <crypto/aes.h> 14 15 #include <net/mac80211.h> 16 #include "key.h" 17 #include "aes_cmac.h" 18 19 #define AAD_LEN 20 20 21 static const u8 zero[IEEE80211_CMAC_256_MIC_LEN]; 22 23 int ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad, 24 const u8 *data, size_t data_len, u8 *mic, 25 unsigned int mic_len) 26 { 27 int err; 28 SHASH_DESC_ON_STACK(desc, tfm); 29 u8 out[AES_BLOCK_SIZE]; 30 const __le16 *fc; 31 32 desc->tfm = tfm; 33 34 err = crypto_shash_init(desc); 35 if (err) 36 return err; 37 err = crypto_shash_update(desc, aad, AAD_LEN); 38 if (err) 39 return err; 40 fc = (const __le16 *)aad; 41 if (ieee80211_is_beacon(*fc)) { 42 /* mask Timestamp field to zero */ 43 err = crypto_shash_update(desc, zero, 8); 44 if (err) 45 return err; 46 err = crypto_shash_update(desc, data + 8, 47 data_len - 8 - mic_len); 48 if (err) 49 return err; 50 } else { 51 err = crypto_shash_update(desc, data, data_len - mic_len); 52 if (err) 53 return err; 54 } 55 err = crypto_shash_finup(desc, zero, mic_len, out); 56 if (err) 57 return err; 58 memcpy(mic, out, mic_len); 59 60 return 0; 61 } 62 63 struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[], 64 size_t key_len) 65 { 66 struct crypto_shash *tfm; 67 68 tfm = crypto_alloc_shash("cmac(aes)", 0, 0); 69 if (!IS_ERR(tfm)) { 70 int err = crypto_shash_setkey(tfm, key, key_len); 71 72 if (err) { 73 crypto_free_shash(tfm); 74 return ERR_PTR(err); 75 } 76 } 77 78 return tfm; 79 } 80 81 void ieee80211_aes_cmac_key_free(struct crypto_shash *tfm) 82 { 83 crypto_free_shash(tfm); 84 } 85