mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-26 10:39:23 +01:00
eapol: Rework eapol_decrypt_key_data
802.11 uses AES Key Wrap and RC4 with the first 256 bytes skipped. The IV is also initialized into the RC4 key.
This commit is contained in:
parent
88d4b36663
commit
89e4538945
47
src/eapol.c
47
src/eapol.c
@ -30,6 +30,7 @@
|
|||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
|
#include "arc4.h"
|
||||||
#include "eapol.h"
|
#include "eapol.h"
|
||||||
|
|
||||||
#define VERIFY_IS_ZERO(field) \
|
#define VERIFY_IS_ZERO(field) \
|
||||||
@ -72,33 +73,57 @@ uint8_t *eapol_decrypt_key_data(const uint8_t *kek,
|
|||||||
const struct eapol_key *frame)
|
const struct eapol_key *frame)
|
||||||
{
|
{
|
||||||
size_t key_data_len = L_BE16_TO_CPU(frame->key_data_len);
|
size_t key_data_len = L_BE16_TO_CPU(frame->key_data_len);
|
||||||
struct l_cipher *cipher;
|
const uint8_t *key_data = frame->key_data;
|
||||||
|
size_t expected_len;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
bool ret;
|
|
||||||
|
|
||||||
switch (frame->key_descriptor_version) {
|
switch (frame->key_descriptor_version) {
|
||||||
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
|
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
|
||||||
/* TODO: This might require an IV from frame->eapol_key_iv */
|
expected_len = key_data_len;
|
||||||
cipher = l_cipher_new(L_CIPHER_ARC4, kek, 16);
|
|
||||||
break;
|
break;
|
||||||
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
|
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
|
||||||
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
|
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
|
||||||
cipher = l_cipher_new(L_CIPHER_AES, kek, 16);
|
expected_len = key_data_len - 8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
};
|
};
|
||||||
|
|
||||||
buf = l_new(uint8_t, key_data_len);
|
buf = l_new(uint8_t, expected_len);
|
||||||
ret = l_cipher_decrypt(cipher, frame->key_data, buf, key_data_len);
|
|
||||||
l_cipher_free(cipher);
|
|
||||||
|
|
||||||
if (!ret) {
|
switch (frame->key_descriptor_version) {
|
||||||
l_free(buf);
|
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
|
||||||
return NULL;
|
{
|
||||||
|
uint8_t key[32];
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
memcpy(key, frame->eapol_key_iv, 16);
|
||||||
|
memcpy(key + 16, kek, 16);
|
||||||
|
|
||||||
|
ret = arc4_skip(key, 32, 256, key_data, key_data_len, buf);
|
||||||
|
memset(key, 0, sizeof(key));
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
|
||||||
|
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
|
||||||
|
if (key_data_len < 8 || key_data_len % 8)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!aes_unwrap(kek, key_data, key_data_len, buf))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
|
error:
|
||||||
|
l_free(buf);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len)
|
const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len)
|
||||||
|
Loading…
Reference in New Issue
Block a user