iPXE
hmac_drbg.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  *
00023  * Alternatively, you may distribute this code in source or binary
00024  * form, with or without modification, provided that the following
00025  * conditions are met:
00026  *
00027  *  1. Redistributions of source code must retain the above copyright
00028  *     notice, this list of conditions and the above disclaimer.
00029  *
00030  *  2. Redistributions in binary form must reproduce the above
00031  *     copyright notice, this list of conditions and the above
00032  *     disclaimer in the documentation and/or other materials provided
00033  *     with the distribution.
00034  */
00035 
00036 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00037 
00038 /** @file
00039  *
00040  * HMAC_DRBG algorithm
00041  *
00042  * This algorithm is designed to comply with ANS X9.82 Part 3-2007
00043  * Section 10.2.2.2.  This standard is not freely available, but most
00044  * of the text appears to be shared with NIST SP 800-90, which can be
00045  * downloaded from
00046  *
00047  *     http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
00048  *
00049  * Where possible, references are given to both documents.  In the
00050  * case of any disagreement, ANS X9.82 takes priority over NIST SP
00051  * 800-90.  (In particular, note that some algorithms that are
00052  * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
00053  */
00054 
00055 #include <stdint.h>
00056 #include <string.h>
00057 #include <errno.h>
00058 #include <assert.h>
00059 #include <ipxe/crypto.h>
00060 #include <ipxe/hmac.h>
00061 #include <ipxe/hmac_drbg.h>
00062 
00063 /**
00064  * Update the HMAC_DRBG key
00065  *
00066  * @v hash              Underlying hash algorithm
00067  * @v state             HMAC_DRBG internal state
00068  * @v data              Provided data
00069  * @v len               Length of provided data
00070  * @v single            Single byte used in concatenation
00071  *
00072  * This function carries out the operation
00073  *
00074  *     K = HMAC ( K, V || single || provided_data )
00075  *
00076  * as used by hmac_drbg_update()
00077  */
00078 static void hmac_drbg_update_key ( struct digest_algorithm *hash,
00079                                    struct hmac_drbg_state *state,
00080                                    const void *data, size_t len,
00081                                    const uint8_t single ) {
00082         uint8_t context[ hash->ctxsize ];
00083         size_t out_len = hash->digestsize;
00084 
00085         DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state );
00086         DBGC_HDA ( state, 0, data, len );
00087 
00088         /* Sanity checks */
00089         assert ( hash != NULL );
00090         assert ( state != NULL );
00091         assert ( ( data != NULL ) || ( len == 0 ) );
00092         assert ( ( single == 0x00 ) || ( single == 0x01 ) );
00093 
00094         /* K = HMAC ( K, V || single || provided_data ) */
00095         hmac_init ( hash, context, state->key, &out_len );
00096         assert ( out_len == hash->digestsize );
00097         hmac_update ( hash, context, state->value, out_len );
00098         hmac_update ( hash, context, &single, sizeof ( single ) );
00099         hmac_update ( hash, context, data, len );
00100         hmac_final ( hash, context, state->key, &out_len, state->key );
00101         assert ( out_len == hash->digestsize );
00102 
00103         DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || "
00104                "provided_data ) :\n", hash->name, state, single );
00105         DBGC_HDA ( state, 0, state->key, out_len );
00106 }
00107 
00108 /**
00109  * Update the HMAC_DRBG value
00110  *
00111  * @v hash              Underlying hash algorithm
00112  * @v state             HMAC_DRBG internal state
00113  * @v data              Provided data
00114  * @v len               Length of provided data
00115  * @v single            Single byte used in concatenation
00116  *
00117  * This function carries out the operation
00118  *
00119  *     V = HMAC ( K, V )
00120  *
00121  * as used by hmac_drbg_update() and hmac_drbg_generate()
00122  */
00123 static void hmac_drbg_update_value ( struct digest_algorithm *hash,
00124                                      struct hmac_drbg_state *state ) {
00125         uint8_t context[ hash->ctxsize ];
00126         size_t out_len = hash->digestsize;
00127 
00128         /* Sanity checks */
00129         assert ( hash != NULL );
00130         assert ( state != NULL );
00131 
00132         /* V = HMAC ( K, V ) */
00133         hmac_init ( hash, context, state->key, &out_len );
00134         assert ( out_len == hash->digestsize );
00135         hmac_update ( hash, context, state->value, out_len );
00136         hmac_final ( hash, context, state->key, &out_len, state->value );
00137         assert ( out_len == hash->digestsize );
00138 
00139         DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n",
00140                hash->name, state );
00141         DBGC_HDA ( state, 0, state->value, out_len );
00142 }
00143 
00144 /**
00145  * Update HMAC_DRBG internal state
00146  *
00147  * @v hash              Underlying hash algorithm
00148  * @v state             HMAC_DRBG internal state
00149  * @v data              Provided data
00150  * @v len               Length of provided data
00151  *
00152  * This is the HMAC_DRBG_Update function defined in ANS X9.82 Part
00153  * 3-2007 Section 10.2.2.2.2 (NIST SP 800-90 Section 10.1.2.2).
00154  *
00155  * The key and value are updated in-place within the HMAC_DRBG
00156  * internal state.
00157  */
00158 static void hmac_drbg_update ( struct digest_algorithm *hash,
00159                                struct hmac_drbg_state *state,
00160                                const void *data, size_t len ) {
00161 
00162         DBGC ( state, "HMAC_DRBG_%s %p update\n", hash->name, state );
00163 
00164         /* Sanity checks */
00165         assert ( hash != NULL );
00166         assert ( state != NULL );
00167         assert ( ( data != NULL ) || ( len == 0 ) );
00168 
00169         /* 1.  K = HMAC ( K, V || 0x00 || provided_data ) */
00170         hmac_drbg_update_key ( hash, state, data, len, 0x00 );
00171 
00172         /* 2.  V = HMAC ( K, V ) */
00173         hmac_drbg_update_value ( hash, state );
00174 
00175         /* 3.  If ( provided_data = Null ), then return K and V */
00176         if ( ! len )
00177                 return;
00178 
00179         /* 4.  K = HMAC ( K, V || 0x01 || provided_data ) */
00180         hmac_drbg_update_key ( hash, state, data, len, 0x01 );
00181 
00182         /* 5.  V = HMAC ( K, V ) */
00183         hmac_drbg_update_value ( hash, state );
00184 
00185         /* 6.  Return K and V */
00186 }
00187 
00188 /**
00189  * Instantiate HMAC_DRBG
00190  *
00191  * @v hash              Underlying hash algorithm
00192  * @v state             HMAC_DRBG internal state to be initialised
00193  * @v entropy           Entropy input
00194  * @v entropy_len       Length of entropy input
00195  * @v personal          Personalisation string
00196  * @v personal_len      Length of personalisation string
00197  *
00198  * This is the HMAC_DRBG_Instantiate_algorithm function defined in ANS
00199  * X9.82 Part 3-2007 Section 10.2.2.2.3 (NIST SP 800-90 Section
00200  * 10.1.2.3).
00201  *
00202  * The nonce must be included within the entropy input (i.e. the
00203  * entropy input must contain at least 3/2 * security_strength bits of
00204  * entropy, as per ANS X9.82 Part 3-2007 Section 8.4.2 (NIST SP 800-90
00205  * Section 8.6.7).
00206  *
00207  * The key, value and reseed counter are updated in-place within the
00208  * HMAC_DRBG internal state.
00209  */
00210 void hmac_drbg_instantiate ( struct digest_algorithm *hash,
00211                              struct hmac_drbg_state *state,
00212                              const void *entropy, size_t entropy_len,
00213                              const void *personal, size_t personal_len ){
00214         size_t out_len = hash->digestsize;
00215 
00216         DBGC ( state, "HMAC_DRBG_%s %p instantiate\n", hash->name, state );
00217 
00218         /* Sanity checks */
00219         assert ( hash != NULL );
00220         assert ( state != NULL );
00221         assert ( entropy != NULL );
00222         assert ( ( personal != NULL ) || ( personal_len == 0 ) );
00223 
00224         /* 1.  seed_material = entropy_input || nonce ||
00225          *     personalisation_string
00226          */
00227 
00228         /* 2.  Key = 0x00 00..00 */
00229         memset ( state->key, 0x00, out_len );
00230 
00231         /* 3.  V = 0x01 01...01 */
00232         memset ( state->value, 0x01, out_len );
00233 
00234         /* 4.  ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V )
00235          * 5.  reseed_counter = 1
00236          * 6.  Return V, Key and reseed_counter as the
00237          *     initial_working_state
00238          */
00239         hmac_drbg_reseed ( hash, state, entropy, entropy_len,
00240                            personal, personal_len );
00241 }
00242 
00243 /**
00244  * Reseed HMAC_DRBG
00245  *
00246  * @v hash              Underlying hash algorithm
00247  * @v state             HMAC_DRBG internal state
00248  * @v entropy           Entropy input
00249  * @v entropy_len       Length of entropy input
00250  * @v additional        Additional input
00251  * @v additional_len    Length of additional input
00252  *
00253  * This is the HMAC_DRBG_Reseed_algorithm function defined in ANS X9.82
00254  * Part 3-2007 Section 10.2.2.2.4 (NIST SP 800-90 Section 10.1.2.4).
00255  *
00256  * The key, value and reseed counter are updated in-place within the
00257  * HMAC_DRBG internal state.
00258  */
00259 void hmac_drbg_reseed ( struct digest_algorithm *hash,
00260                         struct hmac_drbg_state *state,
00261                         const void *entropy, size_t entropy_len,
00262                         const void *additional, size_t additional_len ) {
00263         uint8_t seed_material[ entropy_len + additional_len ];
00264 
00265         DBGC ( state, "HMAC_DRBG_%s %p (re)seed\n", hash->name, state );
00266 
00267         /* Sanity checks */
00268         assert ( hash != NULL );
00269         assert ( state != NULL );
00270         assert ( entropy != NULL );
00271         assert ( ( additional != NULL ) || ( additional_len == 0 ) );
00272 
00273         /* 1.  seed_material = entropy_input || additional_input */
00274         memcpy ( seed_material, entropy, entropy_len );
00275         memcpy ( ( seed_material + entropy_len ), additional, additional_len );
00276         DBGC ( state, "HMAC_DRBG_%s %p seed material :\n", hash->name, state );
00277         DBGC_HDA ( state, 0, seed_material, sizeof ( seed_material ) );
00278 
00279         /* 2.  ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) */
00280         hmac_drbg_update ( hash, state, seed_material,
00281                            sizeof ( seed_material ) );
00282 
00283         /* 3.  reseed_counter = 1 */
00284         state->reseed_counter = 1;
00285 
00286         /* 4.  Return V, Key and reseed_counter as the new_working_state */
00287 }
00288 
00289 /**
00290  * Generate pseudorandom bits using HMAC_DRBG
00291  *
00292  * @v hash              Underlying hash algorithm
00293  * @v state             HMAC_DRBG internal state
00294  * @v additional        Additional input
00295  * @v additional_len    Length of additional input
00296  * @v data              Output buffer
00297  * @v len               Length of output buffer
00298  * @ret rc              Return status code
00299  *
00300  * This is the HMAC_DRBG_Generate_algorithm function defined in ANS X9.82
00301  * Part 3-2007 Section 10.2.2.2.5 (NIST SP 800-90 Section 10.1.2.5).
00302  *
00303  * Requests must be for an integral number of bytes.
00304  *
00305  * The key, value and reseed counter are updated in-place within the
00306  * HMAC_DRBG internal state.
00307  *
00308  * Note that the only permitted error is "reseed required".
00309  */
00310 int hmac_drbg_generate ( struct digest_algorithm *hash,
00311                          struct hmac_drbg_state *state,
00312                          const void *additional, size_t additional_len,
00313                          void *data, size_t len ) {
00314         size_t out_len = hash->digestsize;
00315         void *orig_data = data;
00316         size_t orig_len = len;
00317         size_t frag_len;
00318 
00319         DBGC ( state, "HMAC_DRBG_%s %p generate\n", hash->name, state );
00320 
00321         /* Sanity checks */
00322         assert ( hash != NULL );
00323         assert ( state != NULL );
00324         assert ( data != NULL );
00325         assert ( ( additional != NULL ) || ( additional_len == 0 ) );
00326 
00327         /* 1.  If reseed_counter > reseed_interval, then return an
00328          *     indication that a reseed is required
00329          */
00330         if ( state->reseed_counter > HMAC_DRBG_RESEED_INTERVAL ) {
00331                 DBGC ( state, "HMAC_DRBG_%s %p reseed interval exceeded\n",
00332                        hash->name, state );
00333                 return -ESTALE;
00334         }
00335 
00336         /* 2.  If additional_input != Null, then
00337          *     ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V )
00338          */
00339         if ( additional_len )
00340                 hmac_drbg_update ( hash, state, additional, additional_len );
00341 
00342         /* 3.  temp = Null
00343          * 4.  While ( len ( temp ) < requested_number_of_bits ) do:
00344          */
00345         while ( len ) {
00346 
00347                 /* 4.1  V = HMAC ( Key, V ) */
00348                 hmac_drbg_update_value ( hash, state );
00349 
00350                 /* 4.2.  temp = temp || V
00351                  * 5.    returned_bits = Leftmost requested_number_of_bits
00352                  *       of temp
00353                  */
00354                 frag_len = len;
00355                 if ( frag_len > out_len )
00356                         frag_len = out_len;
00357                 memcpy ( data, state->value, frag_len );
00358                 data += frag_len;
00359                 len -= frag_len;
00360         }
00361 
00362         /* 6.  ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */
00363         hmac_drbg_update ( hash, state, additional, additional_len );
00364 
00365         /* 7.  reseed_counter = reseed_counter + 1 */
00366         state->reseed_counter++;
00367 
00368         DBGC ( state, "HMAC_DRBG_%s %p generated :\n", hash->name, state );
00369         DBGC_HDA ( state, 0, orig_data, orig_len );
00370 
00371         /* 8.  Return SUCCESS, returned_bits, and the new values of
00372          *     Key, V and reseed_counter as the new_working_state
00373          */
00374         return 0;
00375 }