2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2009-01-08 14:32:01 +03:00
/*
* AES - 128 - CMAC with TLen 16 for IEEE 802.11 w BIP
* Copyright 2008 , Jouni Malinen < j @ w1 . fi >
*/
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/crypto.h>
2012-11-07 13:13:58 +04:00
# include <linux/export.h>
2009-01-08 14:32:01 +03:00
# include <linux/err.h>
2011-07-07 00:02:14 +04:00
# include <crypto/aes.h>
2009-01-08 14:32:01 +03:00
# include <net/mac80211.h>
# include "key.h"
# include "aes_cmac.h"
# define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */
2015-01-24 20:52:08 +03:00
# define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */
2009-01-08 14:32:01 +03:00
# define AAD_LEN 20
2017-02-06 13:49:28 +03:00
static const u8 zero [ CMAC_TLEN_256 ] ;
2009-01-08 14:32:01 +03:00
2017-02-06 13:49:28 +03:00
void ieee80211_aes_cmac ( struct crypto_shash * tfm , const u8 * aad ,
2009-01-08 14:32:01 +03:00
const u8 * data , size_t data_len , u8 * mic )
{
2017-02-06 13:49:28 +03:00
SHASH_DESC_ON_STACK ( desc , tfm ) ;
u8 out [ AES_BLOCK_SIZE ] ;
2020-02-22 16:25:45 +03:00
const __le16 * fc ;
2009-01-08 14:32:01 +03:00
2017-02-06 13:49:28 +03:00
desc - > tfm = tfm ;
2009-01-08 14:32:01 +03:00
2017-02-06 13:49:28 +03:00
crypto_shash_init ( desc ) ;
crypto_shash_update ( desc , aad , AAD_LEN ) ;
2020-02-22 16:25:45 +03:00
fc = ( const __le16 * ) aad ;
if ( ieee80211_is_beacon ( * fc ) ) {
/* mask Timestamp field to zero */
crypto_shash_update ( desc , zero , 8 ) ;
crypto_shash_update ( desc , data + 8 , data_len - 8 - CMAC_TLEN ) ;
} else {
crypto_shash_update ( desc , data , data_len - CMAC_TLEN ) ;
}
2017-02-06 13:49:28 +03:00
crypto_shash_finup ( desc , zero , CMAC_TLEN , out ) ;
memcpy ( mic , out , CMAC_TLEN ) ;
2009-01-08 14:32:01 +03:00
}
2017-02-06 13:49:28 +03:00
void ieee80211_aes_cmac_256 ( struct crypto_shash * tfm , const u8 * aad ,
2015-01-24 20:52:08 +03:00
const u8 * data , size_t data_len , u8 * mic )
{
2017-02-06 13:49:28 +03:00
SHASH_DESC_ON_STACK ( desc , tfm ) ;
2020-02-22 16:25:45 +03:00
const __le16 * fc ;
2015-01-24 20:52:08 +03:00
2017-02-06 13:49:28 +03:00
desc - > tfm = tfm ;
2015-01-24 20:52:08 +03:00
2017-02-06 13:49:28 +03:00
crypto_shash_init ( desc ) ;
crypto_shash_update ( desc , aad , AAD_LEN ) ;
2020-02-22 16:25:45 +03:00
fc = ( const __le16 * ) aad ;
if ( ieee80211_is_beacon ( * fc ) ) {
/* mask Timestamp field to zero */
crypto_shash_update ( desc , zero , 8 ) ;
crypto_shash_update ( desc , data + 8 ,
data_len - 8 - CMAC_TLEN_256 ) ;
} else {
crypto_shash_update ( desc , data , data_len - CMAC_TLEN_256 ) ;
}
2017-02-06 13:49:28 +03:00
crypto_shash_finup ( desc , zero , CMAC_TLEN_256 , mic ) ;
2015-01-24 20:52:08 +03:00
}
2009-01-08 14:32:01 +03:00
2017-02-06 13:49:28 +03:00
struct crypto_shash * ieee80211_aes_cmac_key_setup ( const u8 key [ ] ,
size_t key_len )
2009-01-08 14:32:01 +03:00
{
2017-02-06 13:49:28 +03:00
struct crypto_shash * tfm ;
2009-01-08 14:32:01 +03:00
2017-02-06 13:49:28 +03:00
tfm = crypto_alloc_shash ( " cmac(aes) " , 0 , 0 ) ;
2010-08-01 20:37:03 +04:00
if ( ! IS_ERR ( tfm ) )
2017-02-06 13:49:28 +03:00
crypto_shash_setkey ( tfm , key , key_len ) ;
2009-01-08 14:32:01 +03:00
return tfm ;
}
2017-02-06 13:49:28 +03:00
void ieee80211_aes_cmac_key_free ( struct crypto_shash * tfm )
2009-01-08 14:32:01 +03:00
{
2017-02-06 13:49:28 +03:00
crypto_free_shash ( tfm ) ;
2009-01-08 14:32:01 +03:00
}