Home | History | Annotate | Download | only in crypto
      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