kapil.gupta ad7cb5f5c1 wpa_supplicant: Write Crypto API based on mbedtls
This commit add following crypto changes

1. Update current crypto code with upstream supplicant code
2. Add a proper porting layer to use mbedtls APIs for all the crypto
   operations used by supplicant.

Internal crypto will be used when USE_MBEDLTS flag is disabled
in supplicant's menuconfig.

This commit also removes the clutter in crypto files due to partial
porting of some APIs to mbedtls, all the code from those files have
been removed and rewritten in a generic way, this is inspired from
current upstream code.

This also reduces the lib size significantly, supplicant's lib
size reduces around ~567kb after this change(NB: lib size doesn't
indicate reduction in final bin size).
2021-05-04 10:54:57 +00:00

209 lines
4.1 KiB
C

/*
* AES SIV (RFC 5297)
* Copyright (c) 2013 Cozybit, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
#include "aes_siv.h"
static const u8 zero[AES_BLOCK_SIZE];
static void dbl(u8 *pad)
{
int i, carry;
carry = pad[0] & 0x80;
for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
pad[AES_BLOCK_SIZE - 1] <<= 1;
if (carry)
pad[AES_BLOCK_SIZE - 1] ^= 0x87;
}
static void xor(u8 *a, const u8 *b)
{
int i;
for (i = 0; i < AES_BLOCK_SIZE; i++)
*a++ ^= *b++;
}
static void xorend(u8 *a, int alen, const u8 *b, int blen)
{
int i;
if (alen < blen)
return;
for (i = 0; i < blen; i++)
a[alen - blen + i] ^= b[i];
}
static void pad_block(u8 *pad, const u8 *addr, size_t len)
{
os_memset(pad, 0, AES_BLOCK_SIZE);
os_memcpy(pad, addr, len);
if (len < AES_BLOCK_SIZE)
pad[len] = 0x80;
}
static int aes_s2v(const u8 *key, size_t key_len,
size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
{
u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
u8 *buf = NULL;
int ret;
size_t i;
const u8 *data[1];
size_t data_len[1];
if (!num_elem) {
os_memcpy(tmp, zero, sizeof(zero));
tmp[AES_BLOCK_SIZE - 1] = 1;
data[0] = tmp;
data_len[0] = sizeof(tmp);
return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
}
data[0] = zero;
data_len[0] = sizeof(zero);
ret = omac1_aes_vector(key, key_len, 1, data, data_len, tmp);
if (ret)
return ret;
for (i = 0; i < num_elem - 1; i++) {
ret = omac1_aes_vector(key, key_len, 1, &addr[i], &len[i],
tmp2);
if (ret)
return ret;
dbl(tmp);
xor(tmp, tmp2);
}
if (len[i] >= AES_BLOCK_SIZE) {
buf = os_memdup(addr[i], len[i]);
if (!buf)
return -1;
xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
data[0] = buf;
ret = omac1_aes_vector(key, key_len, 1, data, &len[i], mac);
bin_clear_free(buf, len[i]);
return ret;
}
dbl(tmp);
pad_block(tmp2, addr[i], len[i]);
xor(tmp, tmp2);
data[0] = tmp;
data_len[0] = sizeof(tmp);
return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
}
int aes_siv_encrypt(const u8 *key, size_t key_len,
const u8 *pw, size_t pwlen,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *out)
{
const u8 *_addr[6];
size_t _len[6];
const u8 *k1, *k2;
u8 v[AES_BLOCK_SIZE];
size_t i;
u8 *iv, *crypt_pw;
if (num_elem > ARRAY_SIZE(_addr) - 1 ||
(key_len != 32 && key_len != 48 && key_len != 64))
return -1;
key_len /= 2;
k1 = key;
k2 = key + key_len;
for (i = 0; i < num_elem; i++) {
_addr[i] = addr[i];
_len[i] = len[i];
}
_addr[num_elem] = pw;
_len[num_elem] = pwlen;
if (aes_s2v(k1, key_len, num_elem + 1, _addr, _len, v))
return -1;
iv = out;
crypt_pw = out + AES_BLOCK_SIZE;
os_memcpy(iv, v, AES_BLOCK_SIZE);
os_memcpy(crypt_pw, pw, pwlen);
/* zero out 63rd and 31st bits of ctr (from right) */
v[8] &= 0x7f;
v[12] &= 0x7f;
return aes_ctr_encrypt(k2, key_len, v, crypt_pw, pwlen);
}
int aes_siv_decrypt(const u8 *key, size_t key_len,
const u8 *iv_crypt, size_t iv_c_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *out)
{
const u8 *_addr[6];
size_t _len[6];
const u8 *k1, *k2;
size_t crypt_len;
size_t i;
int ret;
u8 iv[AES_BLOCK_SIZE];
u8 check[AES_BLOCK_SIZE];
if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1 ||
(key_len != 32 && key_len != 48 && key_len != 64))
return -1;
crypt_len = iv_c_len - AES_BLOCK_SIZE;
key_len /= 2;
k1 = key;
k2 = key + key_len;
for (i = 0; i < num_elem; i++) {
_addr[i] = addr[i];
_len[i] = len[i];
}
_addr[num_elem] = out;
_len[num_elem] = crypt_len;
os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
iv[8] &= 0x7f;
iv[12] &= 0x7f;
ret = aes_ctr_encrypt(k2, key_len, iv, out, crypt_len);
if (ret)
return ret;
ret = aes_s2v(k1, key_len, num_elem + 1, _addr, _len, check);
if (ret)
return ret;
if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
return 0;
return -1;
}