1 /* 2 * Copyright (c) 2009 Joshua Oreman <oremanj (at) 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 } 166