summaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_crypto.c
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2007-07-05 20:11:05 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2007-07-05 20:11:05 +0000
commite596c97fc8de1786820d37838908f918fedd1fdb (patch)
treea7d7a8cfeb64aac3c4c0beeff58a5c5b0ee42708 /sys/net80211/ieee80211_crypto.c
parentf3e070ecb201427560fb1594c75a10fa4566a016 (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.c299
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);
+}