diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2007-07-05 20:11:05 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2007-07-05 20:11:05 +0000 |
commit | e596c97fc8de1786820d37838908f918fedd1fdb (patch) | |
tree | a7d7a8cfeb64aac3c4c0beeff58a5c5b0ee42708 /sys/net80211/ieee80211_crypto.c | |
parent | f3e070ecb201427560fb1594c75a10fa4566a016 (diff) |
add the pseudo-random function (PRF) and various key derivation
functions defined in 802.11i.
Diffstat (limited to 'sys/net80211/ieee80211_crypto.c')
-rw-r--r-- | sys/net80211/ieee80211_crypto.c | 299 |
1 files changed, 296 insertions, 3 deletions
diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c index dc053db2a0d..6125b832e5b 100644 --- a/sys/net80211/ieee80211_crypto.c +++ b/sys/net80211/ieee80211_crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_crypto.c,v 1.12 2007/06/16 13:17:05 damien Exp $ */ +/* $OpenBSD: ieee80211_crypto.c,v 1.13 2007/07/05 20:11:04 damien Exp $ */ /* $NetBSD: ieee80211_crypto.c,v 1.5 2003/12/14 09:56:53 dyoung Exp $ */ /*- @@ -62,12 +62,41 @@ #include <dev/rndvar.h> #include <crypto/arc4.h> +#include <crypto/md5.h> +#include <crypto/sha1.h> #define arc4_ctxlen() sizeof (struct rc4_ctx) #define arc4_setkey(_c,_k,_l) rc4_keysetup(_c,_k,_l) #define arc4_encrypt(_c,_d,_s,_l) rc4_crypt(_c,_s,_d,_l) -void ieee80211_crc_init(void); +struct vector { + const void *base; + size_t len; +}; + +void ieee80211_crc_init(void); u_int32_t ieee80211_crc_update(u_int32_t, const u_int8_t *, int); +void ieee80211_hmac_md5_v(const struct vector *, int, const uint8_t *, + size_t, uint8_t digest[]); +void ieee80211_hmac_md5(const u_int8_t *, size_t, const uint8_t *, size_t, + uint8_t digest[]); +void ieee80211_hmac_sha1_v(const struct vector *, int, const uint8_t *, + size_t, uint8_t digest[]); +void ieee80211_hmac_sha1(const u_int8_t *, size_t, const uint8_t *, size_t, + uint8_t digest[]); +void ieee80211_prf(const u_int8_t *, size_t, struct vector *, int, + u_int8_t *, size_t); +void ieee80211_derive_ptk(const u_int8_t *, size_t, const u_int8_t *, + const u_int8_t *, const u_int8_t *, const u_int8_t *, u_int8_t *, + size_t); +void ieee80211_derive_pmkid(const u_int8_t *, size_t, const u_int8_t *, + const u_int8_t *, u_int8_t *); +void ieee80211_derive_gtk(const u_int8_t *, size_t, const u_int8_t *, + const u_int8_t *, u_int8_t *, size_t); +void ieee80211_derive_stk(const u_int8_t *, size_t, const u_int8_t *, + const u_int8_t *, const u_int8_t *, const u_int8_t *, u_int8_t *, + size_t); +void ieee80211_derive_smkid(const u_int8_t *, size_t, const u_int8_t *, + const u_int8_t *, const u_int8_t *, const u_int8_t *, u_int8_t *); void ieee80211_crypto_attach(struct ifnet *ifp) @@ -316,7 +345,6 @@ ieee80211_crc_init(void) * should be initialized to all 1's, and the transmitted value * is the 1's complement of the final running CRC */ - u_int32_t ieee80211_crc_update(u_int32_t crc, const u_int8_t *buf, int len) { @@ -326,3 +354,268 @@ ieee80211_crc_update(u_int32_t crc, const u_int8_t *buf, int len) crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); return crc; } + +void +ieee80211_hmac_md5_v(const struct vector *vec, int vcnt, const uint8_t *key, + size_t key_len, uint8_t digest[MD5_DIGEST_LENGTH]) +{ + MD5_CTX ctx; + uint8_t k_pad[MD5_BLOCK_LENGTH]; + uint8_t tk[MD5_DIGEST_LENGTH]; + int i; + + if (key_len > MD5_BLOCK_LENGTH) { + MD5Init(&ctx); + MD5Update(&ctx, (u_int8_t *)key, key_len); + MD5Final(tk, &ctx); + + key = tk; + key_len = MD5_DIGEST_LENGTH; + } + + bzero(k_pad, sizeof k_pad); + bcopy(key, k_pad, key_len); + for (i = 0; i < MD5_BLOCK_LENGTH; i++) + k_pad[i] ^= 0x36; + + MD5Init(&ctx); + MD5Update(&ctx, k_pad, MD5_BLOCK_LENGTH); + for (i = 0; i < vcnt; i++) + MD5Update(&ctx, (u_int8_t *)vec[i].base, vec[i].len); + MD5Final(digest, &ctx); + + bzero(k_pad, sizeof k_pad); + bcopy(key, k_pad, key_len); + for (i = 0; i < MD5_BLOCK_LENGTH; i++) + k_pad[i] ^= 0x5c; + + MD5Init(&ctx); + MD5Update(&ctx, k_pad, MD5_BLOCK_LENGTH); + MD5Update(&ctx, digest, MD5_DIGEST_LENGTH); + MD5Final(digest, &ctx); +} + +/* wrapper around ieee80211_hmac_md5_v */ +void +ieee80211_hmac_md5(const u_int8_t *text, size_t text_len, const uint8_t *key, + size_t key_len, uint8_t digest[MD5_DIGEST_LENGTH]) +{ + struct vector vec; + vec.base = text; + vec.len = text_len; + ieee80211_hmac_md5_v(&vec, 1, key, key_len, digest); +} + +void +ieee80211_hmac_sha1_v(const struct vector *vec, int vcnt, const uint8_t *key, + size_t key_len, uint8_t digest[SHA1_DIGEST_LENGTH]) +{ + SHA1_CTX ctx; + uint8_t k_pad[SHA1_BLOCK_LENGTH]; + uint8_t tk[SHA1_DIGEST_LENGTH]; + int i; + + if (key_len > SHA1_BLOCK_LENGTH) { + SHA1Init(&ctx); + SHA1Update(&ctx, (u_int8_t *)key, key_len); + SHA1Final(tk, &ctx); + + key = tk; + key_len = SHA1_DIGEST_LENGTH; + } + + bzero(k_pad, sizeof k_pad); + bcopy(key, k_pad, key_len); + for (i = 0; i < SHA1_BLOCK_LENGTH; i++) + k_pad[i] ^= 0x36; + + SHA1Init(&ctx); + SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); + for (i = 0; i < vcnt; i++) + SHA1Update(&ctx, (u_int8_t *)vec[i].base, vec[i].len); + SHA1Final(digest, &ctx); + + bzero(k_pad, sizeof k_pad); + bcopy(key, k_pad, key_len); + for (i = 0; i < SHA1_BLOCK_LENGTH; i++) + k_pad[i] ^= 0x5c; + + SHA1Init(&ctx); + SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); + SHA1Update(&ctx, digest, SHA1_DIGEST_LENGTH); + SHA1Final(digest, &ctx); +} + +/* wrapper around ieee80211_hmac_sha1_v */ +void +ieee80211_hmac_sha1(const u_int8_t *text, size_t text_len, const uint8_t *key, + size_t key_len, uint8_t digest[SHA1_DIGEST_LENGTH]) +{ + struct vector vec; + vec.base = text; + vec.len = text_len; + ieee80211_hmac_sha1_v(&vec, 1, key, key_len, digest); +} + +/* + * SHA1-based Pseudo-Random Function (see 8.5.1.1). + */ +void +ieee80211_prf(const u_int8_t *key, size_t key_len, struct vector *vec, + int vcnt, u_int8_t *output, size_t len) +{ + u_int8_t hash[SHA1_DIGEST_LENGTH]; + u_int8_t count = 0; + + /* single octet count, starts at 0 */ + vec[vcnt].base = &count; + vec[vcnt].len = 1; + vcnt++; + + while (len > SHA1_DIGEST_LENGTH) { + ieee80211_hmac_sha1_v(vec, vcnt, key, key_len, output); + count++; + + output += SHA1_DIGEST_LENGTH; + len -= SHA1_DIGEST_LENGTH; + } + if (len > 0) { + ieee80211_hmac_sha1_v(vec, vcnt, key, key_len, hash); + /* truncate HMAC-SHA1 to len bytes */ + memcpy(output, hash, len); + } +} + +/* + * Derive Pairwise Transient Key (PTK) (see 8.5.1.2). + */ +void +ieee80211_derive_ptk(const u_int8_t *pmk, size_t pmk_len, const u_int8_t *aa, + const u_int8_t *spa, const u_int8_t *anonce, const u_int8_t *snonce, + u_int8_t *ptk, size_t ptk_len) +{ + struct vector vec[6]; /* +1 for PRF */ + int ret; + + vec[0].base = "Pairwise key expansion"; + vec[0].len = 23; /* include trailing '\0' */ + + ret = memcmp(aa, spa, IEEE80211_ADDR_LEN) < 0; + /* Min(AA,SPA) */ + vec[1].base = ret ? aa : spa; + vec[1].len = IEEE80211_ADDR_LEN; + /* Max(AA,SPA) */ + vec[2].base = ret ? spa : aa; + vec[2].len = IEEE80211_ADDR_LEN; + + ret = memcmp(anonce, snonce, EAPOL_KEY_NONCE_LEN) < 0; + /* Min(ANonce,SNonce) */ + vec[3].base = ret ? anonce : snonce; + vec[3].len = EAPOL_KEY_NONCE_LEN; + /* Max(ANonce,SNonce) */ + vec[4].base = ret ? snonce : anonce; + vec[4].len = EAPOL_KEY_NONCE_LEN; + + ieee80211_prf(pmk, pmk_len, vec, 5, ptk, ptk_len); +} + +/* + * Derive Pairwise Master Key Identifier (PMKID) (see 8.5.1.2). + */ +void +ieee80211_derive_pmkid(const u_int8_t *pmk, size_t pmk_len, const u_int8_t *aa, + const u_int8_t *spa, u_int8_t *pmkid) +{ + struct vector vec[3]; + u_int8_t hash[SHA1_DIGEST_LENGTH]; + + vec[0].base = "PMK Name"; + vec[0].len = 8; /* does *not* include trailing '\0' */ + vec[1].base = aa; + vec[1].len = IEEE80211_ADDR_LEN; + vec[2].base = spa; + vec[2].len = IEEE80211_ADDR_LEN; + + ieee80211_hmac_sha1_v(vec, 3, pmk, pmk_len, hash); + /* use the first 128 bits of the HMAC-SHA1 */ + memcpy(pmkid, hash, IEEE80211_PMKID_LEN); +} + +/* + * Derive Group Temporal Key (GTK) (see 8.5.1.3). + */ +void +ieee80211_derive_gtk(const u_int8_t *gmk, size_t gmk_len, const u_int8_t *aa, + const u_int8_t *gnonce, u_int8_t *gtk, size_t gtk_len) +{ + struct vector vec[4]; /* +1 for PRF */ + + vec[0].base = "Group key expansion"; + vec[0].len = 20; /* include trailing '\0' */ + vec[1].base = aa; + vec[1].len = IEEE80211_ADDR_LEN; + vec[2].base = gnonce; + vec[2].len = EAPOL_KEY_NONCE_LEN; + + ieee80211_prf(gmk, gmk_len, vec, 3, gtk, gtk_len); +} + +/* + * Derive Station to Station Transient Key (STK) (see 8.5.1.4). + */ +void +ieee80211_derive_stk(const u_int8_t *smk, size_t smk_len, const u_int8_t *imac, + const u_int8_t *pmac, const u_int8_t *inonce, const u_int8_t *pnonce, + u_int8_t *stk, size_t stk_len) +{ + struct vector vec[6]; /* +1 for PRF */ + int ret; + + vec[0].base = "Peer key expansion"; + vec[0].len = 19; /* include trailing '\0' */ + + ret = memcmp(imac, pmac, IEEE80211_ADDR_LEN) < 0; + /* Min(MAC_I,MAC_P) */ + vec[1].base = ret ? imac : pmac; + vec[1].len = IEEE80211_ADDR_LEN; + /* Max(MAC_I,MAC_P) */ + vec[2].base = ret ? pmac : imac; + vec[2].len = IEEE80211_ADDR_LEN; + + ret = memcmp(inonce, pnonce, EAPOL_KEY_NONCE_LEN) < 0; + /* Min(INonce,PNonce) */ + vec[3].base = ret ? inonce : pnonce; + vec[3].len = EAPOL_KEY_NONCE_LEN; + /* Max(INonce,PNonce) */ + vec[4].base = ret ? pnonce : inonce; + vec[4].len = EAPOL_KEY_NONCE_LEN; + + ieee80211_prf(smk, smk_len, vec, 5, stk, stk_len); +} + +/* + * Derive Station to Station Master Key Identifier (SMKID) (see 8.5.1.4). + */ +void +ieee80211_derive_smkid(const u_int8_t *smk, size_t smk_len, + const u_int8_t *imac, const u_int8_t *pmac, const u_int8_t *inonce, + const u_int8_t *pnonce, u_int8_t *smkid) +{ + struct vector vec[5]; + u_int8_t hash[SHA1_DIGEST_LENGTH]; + + vec[0].base = "SMK Name"; + vec[0].len = 8; /* does *not* include trailing '\0' */ + vec[1].base = pnonce; + vec[1].len = EAPOL_KEY_NONCE_LEN; + vec[2].base = pmac; + vec[2].len = IEEE80211_ADDR_LEN; + vec[3].base = inonce; + vec[3].len = EAPOL_KEY_NONCE_LEN; + vec[4].base = imac; + vec[4].len = IEEE80211_ADDR_LEN; + + ieee80211_hmac_sha1_v(vec, 5, smk, smk_len, hash); + /* use the first 128 bits of the HMAC-SHA1 */ + memcpy(smkid, hash, IEEE80211_SMKID_LEN); +} |