From 6bd082af7e36cfeeaf2434a3cd0dbb3331cf6e1a Mon Sep 17 00:00:00 2001 From: Ivan Safonov Date: Fri, 23 Feb 2018 17:57:42 +0300 Subject: [PATCH] staging:r8188eu: use lib80211 CCMP decrypt Custom AES decrypt implementation replaced with lib80211 library. Signed-off-by: Ivan Safonov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/Kconfig | 1 + drivers/staging/rtl8188eu/core/rtw_security.c | 266 ++++-------------- 2 files changed, 51 insertions(+), 216 deletions(-) diff --git a/drivers/staging/rtl8188eu/Kconfig b/drivers/staging/rtl8188eu/Kconfig index d787a091d3c1..ff7832798a77 100644 --- a/drivers/staging/rtl8188eu/Kconfig +++ b/drivers/staging/rtl8188eu/Kconfig @@ -6,6 +6,7 @@ config R8188EU select WEXT_PRIV select LIB80211 select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_CCMP ---help--- This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N. If built as a module, it will be called r8188eu. diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c index 72da86fdd264..68e2c6790ee6 100644 --- a/drivers/staging/rtl8188eu/core/rtw_security.c +++ b/drivers/staging/rtl8188eu/core/rtw_security.c @@ -1275,217 +1275,24 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) return res; } -static int aes_decipher(u8 *key, uint hdrlen, - u8 *pframe, uint plen) +u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) { - static u8 message[MAX_MSG_SIZE]; - uint qc_exists, a4_exists, i, j, payload_remainder, - num_blocks, payload_index; - int res = _SUCCESS; - - u8 pn_vector[6]; - u8 mic_iv[16]; - u8 mic_header1[16]; - u8 mic_header2[16]; - u8 ctr_preload[16]; - - /* Intermediate Buffers */ - u8 chain_buffer[16]; - u8 aes_out[16]; - u8 padded_buffer[16]; - u8 mic[8]; - -/* uint offset = 0; */ - uint frtype = GetFrameType(pframe); - uint frsubtype = GetFrameSubType(pframe); - frsubtype >>= 4; - - memset(mic_iv, 0, 16); - memset(mic_header1, 0, 16); - memset(mic_header2, 0, 16); - memset(ctr_preload, 0, 16); - memset(chain_buffer, 0, 16); - memset(aes_out, 0, 16); - memset(padded_buffer, 0, 16); - - /* start to decrypt the payload */ - - num_blocks = (plen-8) / 16; /* plen including llc, payload_length and mic) */ - - payload_remainder = (plen-8) % 16; - - pn_vector[0] = pframe[hdrlen]; - pn_vector[1] = pframe[hdrlen+1]; - pn_vector[2] = pframe[hdrlen+4]; - pn_vector[3] = pframe[hdrlen+5]; - pn_vector[4] = pframe[hdrlen+6]; - pn_vector[5] = pframe[hdrlen+7]; - - if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) - a4_exists = 0; - else - a4_exists = 1; - - if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) || - (frtype == WIFI_DATA_CFACKPOLL)) { - qc_exists = 1; - if (hdrlen != WLAN_HDR_A3_QOS_LEN) - hdrlen += 2; - } else if ((frsubtype == 0x08) || (frsubtype == 0x09) || - (frsubtype == 0x0a) || (frsubtype == 0x0b)) { - if (hdrlen != WLAN_HDR_A3_QOS_LEN) - hdrlen += 2; - qc_exists = 1; - } else { - qc_exists = 0; - } - - /* now, decrypt pframe with hdrlen offset and plen long */ - - payload_index = hdrlen + 8; /* 8 is for extiv */ - - for (i = 0; i < num_blocks; i++) { - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1); - - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); - - for (j = 0; j < 16; j++) - pframe[payload_index++] = chain_buffer[j]; - } - - if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ - /* encrypt it and copy the unpadded part back */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1); - - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = pframe[payload_index+j]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < payload_remainder; j++) - pframe[payload_index++] = chain_buffer[j]; - } - - /* start to calculate the mic */ - if ((hdrlen+plen+8) <= MAX_MSG_SIZE) - memcpy(message, pframe, (hdrlen + plen+8)); /* 8 is for ext iv len */ - - pn_vector[0] = pframe[hdrlen]; - pn_vector[1] = pframe[hdrlen+1]; - pn_vector[2] = pframe[hdrlen+4]; - pn_vector[3] = pframe[hdrlen+5]; - pn_vector[4] = pframe[hdrlen+6]; - pn_vector[5] = pframe[hdrlen+7]; - construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, pn_vector); - - construct_mic_header1(mic_header1, hdrlen, message); - construct_mic_header2(mic_header2, message, a4_exists, qc_exists); - - payload_remainder = (plen-8) % 16; - num_blocks = (plen-8) / 16; - - /* Find start of payload */ - payload_index = hdrlen + 8; - - /* Calculate MIC */ - aes128k128d(key, mic_iv, aes_out); - bitwise_xor(aes_out, mic_header1, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - bitwise_xor(aes_out, mic_header2, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - - for (i = 0; i < num_blocks; i++) { - bitwise_xor(aes_out, &message[payload_index], chain_buffer); - - payload_index += 16; - aes128k128d(key, chain_buffer, aes_out); - } - - /* Add on the final payload block if it needs padding */ - if (payload_remainder > 0) { - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = message[payload_index++]; - bitwise_xor(aes_out, padded_buffer, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - } - - for (j = 0 ; j < 8; j++) - mic[j] = aes_out[j]; - - /* Insert MIC into payload */ - for (j = 0; j < 8; j++) - message[payload_index+j] = mic[j]; - - payload_index = hdrlen + 8; - for (i = 0; i < num_blocks; i++) { - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i+1); - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &message[payload_index], chain_buffer); - for (j = 0; j < 16; j++) - message[payload_index++] = chain_buffer[j]; - } - - if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ - /* encrypt it and copy the unpadded part back */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, num_blocks+1); - - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = message[payload_index+j]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < payload_remainder; j++) - message[payload_index++] = chain_buffer[j]; - } - - /* Encrypt the MIC */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0); - - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < 8; j++) - padded_buffer[j] = message[j+hdrlen+8+plen-8]; - - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < 8; j++) - message[payload_index++] = chain_buffer[j]; - - /* compare the mic */ - for (i = 0; i < 8; i++) { - if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, - ("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n", - i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i])); - DBG_88E("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n", - i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]); - res = _FAIL; - } - } - return res; -} - -u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) -{ /* exclude ICV */ - /* Intermediate Buffers */ - int length; - u8 *pframe, *prwskey; /* *payload,*iv */ - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - u32 res = _SUCCESS; + struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; + u32 res = _SUCCESS; - pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data; /* 4 start to encrypt each fragment */ if (prxattrib->encrypt == _AES_) { - stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); + struct sta_info *stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); + if (stainfo != NULL) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n")); + int key_idx; + const int key_length = 16, iv_len = 8, icv_len = 8; + struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt; + void *crypto_private = NULL; + u8 *key, *pframe = skb->data; + struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("CCMP"), "lib80211_crypt_ccmp"); + struct security_priv *psecuritypriv = &padapter->securitypriv; + char iv[8], icv[8]; if (IS_MCAST(prxattrib->ra)) { /* in concurrent we should use sw descrypt in group key, so we remove this message */ @@ -1494,18 +1301,45 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); goto exit; } - prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; - if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) { - DBG_88E("not match packet_index=%d, install_index=%d\n", - prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid); - res = _FAIL; - goto exit; - } + key_idx = psecuritypriv->dot118021XGrpKeyid; + key = psecuritypriv->dot118021XGrpKey[key_idx].skey; } else { - prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + key_idx = 0; + key = stainfo->dot118021x_UncstKey.skey; } - length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len; - res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); + + if (!crypto_ops) { + res = _FAIL; + goto exit_lib80211_ccmp; + } + + memcpy(iv, pframe + prxattrib->hdrlen, iv_len); + memcpy(icv, pframe + skb->len - icv_len, icv_len); + + crypto_private = crypto_ops->init(key_idx); + if (!crypto_private) { + res = _FAIL; + goto exit_lib80211_ccmp; + } + if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) { + res = _FAIL; + goto exit_lib80211_ccmp; + } + if (crypto_ops->decrypt_mpdu(skb, prxattrib->hdrlen, crypto_private)) { + res = _FAIL; + goto exit_lib80211_ccmp; + } + + memmove(pframe, pframe + iv_len, prxattrib->hdrlen); + skb_push(skb, iv_len); + skb_put(skb, icv_len); + + memcpy(pframe + prxattrib->hdrlen, iv, iv_len); + memcpy(pframe + skb->len - icv_len, icv, icv_len); + +exit_lib80211_ccmp: + if (crypto_ops && crypto_private) + crypto_ops->deinit(crypto_private); } else { RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n")); res = _FAIL; -- 2.45.2