Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6bd082af authored by Ivan Safonov's avatar Ivan Safonov Committed by Greg Kroah-Hartman
Browse files

staging:r8188eu: use lib80211 CCMP decrypt



Custom AES decrypt implementation replaced with lib80211 library.

Signed-off-by: default avatarIvan Safonov <insafonov@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a3d2ae04
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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.
+50 −216
Original line number Diff line number Diff line
@@ -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)
{
	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;

	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);
				key_idx = psecuritypriv->dot118021XGrpKeyid;
				key = psecuritypriv->dot118021XGrpKey[key_idx].skey;
			} else {
				key_idx = 0;
				key = stainfo->dot118021x_UncstKey.skey;
			}

			if (!crypto_ops) {
				res = _FAIL;
					goto exit;
				goto exit_lib80211_ccmp;
			}
			} else {
				prwskey = &stainfo->dot118021x_UncstKey.skey[0];

			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;
			}
			length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len;
			res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length);
			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;