Skip to content

Commit

Permalink
[digest] Add HMAC-SHA1 based pseudorandom function and PBKDF2
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
rwcr authored and Marty Connor committed Jan 5, 2010
1 parent 05d3be1 commit 59b7d00
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 0 deletions.
165 changes: 165 additions & 0 deletions src/crypto/sha1extra.c
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

FILE_LICENCE ( GPL2_OR_LATER );

#include <gpxe/crypto.h>
#include <gpxe/sha1.h>
#include <gpxe/hmac.h>
#include <stdint.h>
#include <byteswap.h>

/**
* SHA1 pseudorandom function for creating derived keys
*
* @v key Master key with which this call is associated
* @v key_len Length of key
* @v label NUL-terminated ASCII string describing purpose of PRF data
* @v data Further data that should be included in the PRF
* @v data_len Length of further PRF data
* @v prf_len Bytes of PRF to generate
* @ret prf Pseudorandom function bytes
*
* This is the PRF variant used by 802.11, defined in IEEE 802.11-2007
* 8.5.5.1. EAP-FAST uses a different SHA1-based PRF, and TLS uses an
* MD5-based PRF.
*/
void prf_sha1 ( const void *key, size_t key_len, const char *label,
const void *data, size_t data_len, void *prf, size_t prf_len )
{
u32 blk;
u8 keym[key_len]; /* modifiable copy of key */
u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
u8 *in_blknr; /* pointer to last byte of in, block number */
u8 out[SHA1_SIZE]; /* HMAC-SHA1 result */
u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
const size_t label_len = strlen ( label );

/* The HMAC-SHA-1 is calculated using the given key on the
message text `label', followed by a NUL, followed by one
byte indicating the block number (0 for first). */

memcpy ( keym, key, key_len );

memcpy ( in, label, strlen ( label ) + 1 );
memcpy ( in + label_len + 1, data, data_len );
in_blknr = in + label_len + 1 + data_len;

for ( blk = 0 ;; blk++ ) {
*in_blknr = blk;

hmac_init ( &sha1_algorithm, sha1_ctx, keym, &key_len );
hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );

if ( prf_len <= SHA1_SIZE ) {
memcpy ( prf, out, prf_len );
break;
}

memcpy ( prf, out, SHA1_SIZE );
prf_len -= SHA1_SIZE;
prf += SHA1_SIZE;
}
}

/**
* PBKDF2 key derivation function inner block operation
*
* @v passphrase Passphrase from which to derive key
* @v pass_len Length of passphrase
* @v salt Salt to include in key
* @v salt_len Length of salt
* @v iterations Number of iterations of SHA1 to perform
* @v blocknr Index of this block, starting at 1
* @ret block SHA1_SIZE bytes of PBKDF2 data
*
* The operation of this function is described in RFC 2898.
*/
static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
const void *salt, size_t salt_len,
int iterations, u32 blocknr, u8 *block )
{
u8 pass[pass_len]; /* modifiable passphrase */
u8 in[salt_len + 4]; /* input buffer to first round */
u8 last[SHA1_SIZE]; /* output of round N, input of N+1 */
u8 sha1_ctx[SHA1_CTX_SIZE];
u8 *next_in = in; /* changed to `last' after first round */
int next_size = sizeof ( in );
int i, j;

blocknr = htonl ( blocknr );

memcpy ( pass, passphrase, pass_len );
memcpy ( in, salt, salt_len );
memcpy ( in + salt_len, &blocknr, 4 );
memset ( block, 0, SHA1_SIZE );

for ( i = 0; i < iterations; i++ ) {
hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );

for ( j = 0; j < SHA1_SIZE; j++ ) {
block[j] ^= last[j];
}

next_in = last;
next_size = SHA1_SIZE;
}
}

/**
* PBKDF2 key derivation function using SHA1
*
* @v passphrase Passphrase from which to derive key
* @v pass_len Length of passphrase
* @v salt Salt to include in key
* @v salt_len Length of salt
* @v iterations Number of iterations of SHA1 to perform
* @v key_len Length of key to generate
* @ret key Generated key bytes
*
* This is used most notably in 802.11 WPA passphrase hashing, in
* which case the salt is the SSID, 4096 iterations are used, and a
* 32-byte key is generated that serves as the Pairwise Master Key for
* EAPOL authentication.
*
* The operation of this function is further described in RFC 2898.
*/
void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
const void *salt, size_t salt_len,
int iterations, void *key, size_t key_len )
{
u32 blocks = ( key_len + SHA1_SIZE - 1 ) / SHA1_SIZE;
u32 blk;
u8 buf[SHA1_SIZE];

for ( blk = 1; blk <= blocks; blk++ ) {
pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len,
iterations, blk, buf );
if ( key_len <= SHA1_SIZE ) {
memcpy ( key, buf, key_len );
break;
}

memcpy ( key, buf, SHA1_SIZE );
key_len -= SHA1_SIZE;
key += SHA1_SIZE;
}
}
9 changes: 9 additions & 0 deletions src/include/gpxe/sha1.h
Expand Up @@ -12,4 +12,13 @@ struct digest_algorithm;

extern struct digest_algorithm sha1_algorithm;

/* SHA1-wrapping functions defined in sha1extra.c: */

void prf_sha1 ( const void *key, size_t key_len, const char *label,
const void *data, size_t data_len, void *prf, size_t prf_len );

void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
const void *salt, size_t salt_len,
int iterations, void *key, size_t key_len );

#endif /* _GPXE_SHA1_H */

0 comments on commit 59b7d00

Please sign in to comment.