Browse Source

[digest] Add HMAC-SHA1 based pseudorandom function and PBKDF2

Both of these routines are used by 802.11 WPA, but they are generic
and could be needed by other protocols as well.

Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.0.0-rc1
Joshua Oreman 15 years ago
parent
commit
59b7d00c06
2 changed files with 174 additions and 0 deletions
  1. 165
    0
      src/crypto/sha1extra.c
  2. 9
    0
      src/include/gpxe/sha1.h

+ 165
- 0
src/crypto/sha1extra.c View File

@@ -0,0 +1,165 @@
1
+/*
2
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <gpxe/crypto.h>
22
+#include <gpxe/sha1.h>
23
+#include <gpxe/hmac.h>
24
+#include <stdint.h>
25
+#include <byteswap.h>
26
+
27
+/**
28
+ * SHA1 pseudorandom function for creating derived keys
29
+ *
30
+ * @v key	Master key with which this call is associated
31
+ * @v key_len	Length of key
32
+ * @v label	NUL-terminated ASCII string describing purpose of PRF data
33
+ * @v data	Further data that should be included in the PRF
34
+ * @v data_len	Length of further PRF data
35
+ * @v prf_len	Bytes of PRF to generate
36
+ * @ret prf	Pseudorandom function bytes
37
+ *
38
+ * This is the PRF variant used by 802.11, defined in IEEE 802.11-2007
39
+ * 8.5.5.1. EAP-FAST uses a different SHA1-based PRF, and TLS uses an
40
+ * MD5-based PRF.
41
+ */
42
+void prf_sha1 ( const void *key, size_t key_len, const char *label,
43
+		const void *data, size_t data_len, void *prf, size_t prf_len )
44
+{
45
+	u32 blk;
46
+	u8 keym[key_len];	/* modifiable copy of key */
47
+	u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
48
+	u8 *in_blknr;		/* pointer to last byte of in, block number */
49
+	u8 out[SHA1_SIZE];	/* HMAC-SHA1 result */
50
+	u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
51
+	const size_t label_len = strlen ( label );
52
+
53
+	/* The HMAC-SHA-1 is calculated using the given key on the
54
+	   message text `label', followed by a NUL, followed by one
55
+	   byte indicating the block number (0 for first). */
56
+
57
+	memcpy ( keym, key, key_len );
58
+
59
+	memcpy ( in, label, strlen ( label ) + 1 );
60
+	memcpy ( in + label_len + 1, data, data_len );
61
+	in_blknr = in + label_len + 1 + data_len;
62
+
63
+	for ( blk = 0 ;; blk++ ) {
64
+		*in_blknr = blk;
65
+
66
+		hmac_init ( &sha1_algorithm, sha1_ctx, keym, &key_len );
67
+		hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
68
+		hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );
69
+
70
+		if ( prf_len <= SHA1_SIZE ) {
71
+			memcpy ( prf, out, prf_len );
72
+			break;
73
+		}
74
+
75
+		memcpy ( prf, out, SHA1_SIZE );
76
+		prf_len -= SHA1_SIZE;
77
+		prf += SHA1_SIZE;
78
+	}
79
+}
80
+
81
+/**
82
+ * PBKDF2 key derivation function inner block operation
83
+ *
84
+ * @v passphrase	Passphrase from which to derive key
85
+ * @v pass_len		Length of passphrase
86
+ * @v salt		Salt to include in key
87
+ * @v salt_len		Length of salt
88
+ * @v iterations	Number of iterations of SHA1 to perform
89
+ * @v blocknr		Index of this block, starting at 1
90
+ * @ret block		SHA1_SIZE bytes of PBKDF2 data
91
+ *
92
+ * The operation of this function is described in RFC 2898.
93
+ */
94
+static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
95
+			    const void *salt, size_t salt_len,
96
+			    int iterations, u32 blocknr, u8 *block )
97
+{
98
+	u8 pass[pass_len];	/* modifiable passphrase */
99
+	u8 in[salt_len + 4];	/* input buffer to first round */
100
+	u8 last[SHA1_SIZE];	/* output of round N, input of N+1 */
101
+	u8 sha1_ctx[SHA1_CTX_SIZE];
102
+	u8 *next_in = in;	/* changed to `last' after first round */
103
+	int next_size = sizeof ( in );
104
+	int i, j;
105
+
106
+	blocknr = htonl ( blocknr );
107
+
108
+	memcpy ( pass, passphrase, pass_len );
109
+	memcpy ( in, salt, salt_len );
110
+	memcpy ( in + salt_len, &blocknr, 4 );
111
+	memset ( block, 0, SHA1_SIZE );
112
+
113
+	for ( i = 0; i < iterations; i++ ) {
114
+		hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
115
+		hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
116
+		hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );
117
+
118
+		for ( j = 0; j < SHA1_SIZE; j++ ) {
119
+			block[j] ^= last[j];
120
+		}
121
+
122
+		next_in = last;
123
+		next_size = SHA1_SIZE;
124
+	}
125
+}
126
+
127
+/**
128
+ * PBKDF2 key derivation function using SHA1
129
+ *
130
+ * @v passphrase	Passphrase from which to derive key
131
+ * @v pass_len		Length of passphrase
132
+ * @v salt		Salt to include in key
133
+ * @v salt_len		Length of salt
134
+ * @v iterations	Number of iterations of SHA1 to perform
135
+ * @v key_len		Length of key to generate
136
+ * @ret key		Generated key bytes
137
+ *
138
+ * This is used most notably in 802.11 WPA passphrase hashing, in
139
+ * which case the salt is the SSID, 4096 iterations are used, and a
140
+ * 32-byte key is generated that serves as the Pairwise Master Key for
141
+ * EAPOL authentication.
142
+ *
143
+ * The operation of this function is further described in RFC 2898.
144
+ */
145
+void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
146
+		   const void *salt, size_t salt_len,
147
+		   int iterations, void *key, size_t key_len )
148
+{
149
+	u32 blocks = ( key_len + SHA1_SIZE - 1 ) / SHA1_SIZE;
150
+	u32 blk;
151
+	u8 buf[SHA1_SIZE];
152
+
153
+	for ( blk = 1; blk <= blocks; blk++ ) {
154
+		pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len,
155
+				iterations, blk, buf );
156
+		if ( key_len <= SHA1_SIZE ) {
157
+			memcpy ( key, buf, key_len );
158
+			break;
159
+		}
160
+
161
+		memcpy ( key, buf, SHA1_SIZE );
162
+		key_len -= SHA1_SIZE;
163
+		key += SHA1_SIZE;
164
+	}
165
+}

+ 9
- 0
src/include/gpxe/sha1.h View File

@@ -12,4 +12,13 @@ struct digest_algorithm;
12 12
 
13 13
 extern struct digest_algorithm sha1_algorithm;
14 14
 
15
+/* SHA1-wrapping functions defined in sha1extra.c: */
16
+
17
+void prf_sha1 ( const void *key, size_t key_len, const char *label,
18
+		const void *data, size_t data_len, void *prf, size_t prf_len );
19
+
20
+void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
21
+		   const void *salt, size_t salt_len,
22
+		   int iterations, void *key, size_t key_len );
23
+
15 24
 #endif /* _GPXE_SHA1_H */

Loading…
Cancel
Save