SAE: Add support for ECC group 21 (521-bit random ECP group)

In addition to the trivial change in adding the new group ientifier,
this required changes to KDF and random number generation to support
cases where the length of the prime in bits is not a multiple of eight.
The binary presentation of the value needs to be shifted so that the
unused most significant bits are the zero padding rather than the extra
bits in the end of the array.

Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2013-01-01 14:00:40 +02:00
parent bf14657b9f
commit cd9c2714e7
6 changed files with 88 additions and 14 deletions

View file

@ -63,15 +63,27 @@ static int val_zero(const u8 *val, size_t len)
}
static int sae_get_rand(const u8 *order, size_t prime_len, u8 *val)
static void buf_shift_right(u8 *buf, size_t len, size_t bits)
{
size_t i;
for (i = len - 1; i > 0; i--)
buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
buf[0] >>= bits;
}
static int sae_get_rand(const u8 *order, size_t prime_len_bits, u8 *val)
{
int iter = 0;
size_t prime_len = (prime_len_bits + 7) / 8;
do {
if (random_get_bytes(val, prime_len) < 0)
return -1;
if (iter++ > 100)
return -1;
if (random_get_bytes(val, prime_len) < 0)
return -1;
if (prime_len_bits % 8)
buf_shift_right(val, prime_len, 8 - prime_len_bits % 8);
} while (os_memcmp(val, order, prime_len) >= 0 ||
val_zero_or_one(val, prime_len));
@ -83,13 +95,14 @@ static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
{
u8 mask[SAE_MAX_PRIME_LEN], order[SAE_MAX_PRIME_LEN];
struct crypto_bignum *bn;
size_t prime_len_bits = crypto_ec_prime_len_bits(sae->ec);
if (crypto_bignum_to_bin(crypto_ec_get_order(sae->ec),
order, sizeof(order), sae->prime_len) < 0)
return NULL;
if (sae_get_rand(order, sae->prime_len, sae->sae_rand) < 0 ||
sae_get_rand(order, sae->prime_len, mask) < 0)
if (sae_get_rand(order, prime_len_bits, sae->sae_rand) < 0 ||
sae_get_rand(order, prime_len_bits, mask) < 0)
return NULL;
wpa_hexdump_key(MSG_DEBUG, "SAE: rand",
sae->sae_rand, sae->prime_len);
@ -120,6 +133,7 @@ static int sae_test_pwd_seed(struct sae_data *sae, const u8 *pwd_seed,
u8 pwd_value[SAE_MAX_PRIME_LEN], prime[SAE_MAX_PRIME_LEN];
struct crypto_bignum *x;
int y_bit;
size_t bits;
if (crypto_bignum_to_bin(crypto_ec_get_prime(sae->ec),
prime, sizeof(prime), sae->prime_len) < 0)
@ -128,8 +142,11 @@ static int sae_test_pwd_seed(struct sae_data *sae, const u8 *pwd_seed,
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
sha256_prf(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
prime, sae->prime_len, pwd_value, sae->prime_len);
bits = crypto_ec_prime_len_bits(sae->ec);
sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
prime, sae->prime_len, pwd_value, bits);
if (bits % 8)
buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
pwd_value, sae->prime_len);
@ -241,8 +258,10 @@ static int sae_derive_commit(struct sae_data *sae, struct crypto_ec_point *pwe)
int ret = -1;
mask = sae_get_rand_and_mask(sae);
if (mask == NULL)
if (mask == NULL) {
wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
return -1;
}
x = crypto_bignum_init();
bn_rand = crypto_bignum_init_set(sae->sae_rand, sae->prime_len);
@ -263,8 +282,10 @@ static int sae_derive_commit(struct sae_data *sae, struct crypto_ec_point *pwe)
crypto_ec_point_invert(sae->ec, elem) < 0 ||
crypto_ec_point_to_bin(sae->ec, elem, sae->own_commit_element,
sae->own_commit_element + sae->prime_len) <
0)
0) {
wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "SAE: commit-element x",
sae->own_commit_element, sae->prime_len);

View file

@ -1,6 +1,6 @@
/*
* Simultaneous authentication of equals
* Copyright (c) 2012, Jouni Malinen <j@w1.fi>
* Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -13,7 +13,7 @@
#define SAE_PMK_LEN 32
#define SAE_PMKID_LEN 16
#define SAE_KEYSEED_KEY_LEN 32
#define SAE_MAX_PRIME_LEN 48
#define SAE_MAX_PRIME_LEN 66
#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)

View file

@ -549,6 +549,13 @@ void crypto_ec_deinit(struct crypto_ec *e);
*/
size_t crypto_ec_prime_len(struct crypto_ec *e);
/**
* crypto_ec_prime_len_bits - Get length of the prime in bits
* @e: EC context from crypto_ec_init()
* Returns: Length of the prime defining the group in bits
*/
size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
/**
* crypto_ec_get_prime - Get prime defining an EC group
* @e: EC context from crypto_ec_init()

View file

@ -917,6 +917,9 @@ struct crypto_ec * crypto_ec_init(int group)
case 20:
nid = NID_secp384r1;
break;
case 21:
nid = NID_secp521r1;
break;
case 25:
nid = NID_X9_62_prime192v1;
break;
@ -972,6 +975,12 @@ size_t crypto_ec_prime_len(struct crypto_ec *e)
}
size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
{
return BN_num_bits(e->prime);
}
const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
{
return (const struct crypto_bignum *) e->prime;

View file

@ -1,6 +1,6 @@
/*
* SHA256-based PRF (IEEE 802.11r)
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -28,6 +28,29 @@
*/
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
}
/**
* sha256_prf_bits - IEEE Std 802.11-2012, 11.6.1.7.2 Key derivation function
* @key: Key for KDF
* @key_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
* @data: Extra data to bind into the key
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bits of key to generate
*
* This function is used to derive new, cryptographically separate keys from a
* given key. If the requested buf_len is not divisible by eight, the least
* significant 1-7 bits of the last octet in the output are not part of the
* requested output.
*/
void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits)
{
u16 counter = 1;
size_t pos, plen;
@ -35,6 +58,7 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *addr[4];
size_t len[4];
u8 counter_le[2], length_le[2];
size_t buf_len = (buf_len_bits + 7) / 8;
addr[0] = counter_le;
len[0] = 2;
@ -45,7 +69,7 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
addr[3] = length_le;
len[3] = sizeof(length_le);
WPA_PUT_LE16(length_le, buf_len * 8);
WPA_PUT_LE16(length_le, buf_len_bits);
pos = 0;
while (pos < buf_len) {
plen = buf_len - pos;
@ -57,8 +81,18 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
} else {
hmac_sha256_vector(key, key_len, 4, addr, len, hash);
os_memcpy(&buf[pos], hash, plen);
pos += plen;
break;
}
counter++;
}
/*
* Mask out unused bits in the last octet if it does not use all the
* bits.
*/
if (buf_len_bits % 8) {
u8 mask = 0xff << (8 - buf_len_bits % 8);
buf[pos - 1] &= mask;
}
}

View file

@ -1,6 +1,6 @@
/*
* SHA256 hash implementation and interface functions
* Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -17,6 +17,9 @@ int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits);
void tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);