"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.2/libcanlock/test/hkdf.c" (9 Mar 2017, 10182 Bytes) of package /linux/misc/tin-2.4.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /**************************** hkdf.c ***************************/
    2 /***************** See RFC 6234 for details. *******************/
    3 /* Copyright (c) 2011 IETF Trust and the persons identified as */
    4 /* authors of the code.  All rights reserved.                  */
    5 /* See sha.h for terms of use and redistribution.              */
    6 
    7 /*
    8  *  Description:
    9  *      This file implements the HKDF algorithm (HMAC-based
   10  *      Extract-and-Expand Key Derivation Function, RFC 5869),
   11  *      expressed in terms of the various SHA algorithms.
   12  */
   13 
   14 #include "sha.h"
   15 #include <string.h>
   16 #include <stdlib.h>
   17 
   18 /*
   19  *  hkdf
   20  *
   21  *  Description:
   22  *      This function will generate keying material using HKDF.
   23  *
   24  *  Parameters:
   25  *      whichSha: [in]
   26  *          One of SHA1, SHA224, SHA256, SHA384, SHA512
   27  *      salt[ ]: [in]
   28  *          The optional salt value (a non-secret random value);
   29  *          if not provided (salt == NULL), it is set internally
   30  *          to a string of HashLen(whichSha) zeros.
   31  *      salt_len: [in]
   32  *          The length of the salt value.  (Ignored if salt == NULL.)
   33  *      ikm[ ]: [in]
   34  *          Input keying material.
   35  *      ikm_len: [in]
   36  *          The length of the input keying material.
   37  *      info[ ]: [in]
   38  *          The optional context and application specific information.
   39  *          If info == NULL or a zero-length string, it is ignored.
   40  *      info_len: [in]
   41  *          The length of the optional context and application specific
   42  *          information.  (Ignored if info == NULL.)
   43  *      okm[ ]: [out]
   44  *          Where the HKDF is to be stored.
   45  *      okm_len: [in]
   46  *          The length of the buffer to hold okm.
   47  *          okm_len must be <= 255 * USHABlockSize(whichSha)
   48  *
   49  *  Notes:
   50  *      Calls hkdfExtract() and hkdfExpand().
   51  *
   52  *  Returns:
   53  *      sha Error Code.
   54  *
   55  */
   56 int hkdf(SHAversion whichSha,
   57     const unsigned char *salt, int salt_len,
   58     const unsigned char *ikm, int ikm_len,
   59     const unsigned char *info, int info_len,
   60     uint8_t okm[ ], int okm_len)
   61 {
   62   uint8_t prk[USHAMaxHashSize];
   63   return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) ||
   64          hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
   65                     info_len, okm, okm_len);
   66 }
   67 
   68 /*
   69  *  hkdfExtract
   70  *
   71  *  Description:
   72  *      This function will perform HKDF extraction.
   73  *
   74  *  Parameters:
   75  *      whichSha: [in]
   76  *          One of SHA1, SHA224, SHA256, SHA384, SHA512
   77  *      salt[ ]: [in]
   78  *          The optional salt value (a non-secret random value);
   79  *          if not provided (salt == NULL), it is set internally
   80  *          to a string of HashLen(whichSha) zeros.
   81  *      salt_len: [in]
   82  *          The length of the salt value.  (Ignored if salt == NULL.)
   83  *      ikm[ ]: [in]
   84  *          Input keying material.
   85  *      ikm_len: [in]
   86  *          The length of the input keying material.
   87  *      prk[ ]: [out]
   88  *          Array where the HKDF extraction is to be stored.
   89  *          Must be larger than USHAHashSize(whichSha);
   90  *
   91  *  Returns:
   92  *      sha Error Code.
   93  *
   94  */
   95 int hkdfExtract(SHAversion whichSha,
   96     const unsigned char *salt, int salt_len,
   97     const unsigned char *ikm, int ikm_len,
   98     uint8_t prk[USHAMaxHashSize])
   99 {
  100   unsigned char nullSalt[USHAMaxHashSize];
  101   if (salt == 0) {
  102     salt = nullSalt;
  103     salt_len = USHAHashSize(whichSha);
  104     memset(nullSalt, '\0', salt_len);
  105   } else if (salt_len < 0) {
  106     return shaBadParam;
  107   }
  108   return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
  109 }
  110 
  111 /*
  112  *  hkdfExpand
  113  *
  114  *  Description:
  115  *      This function will perform HKDF expansion.
  116  *
  117  *  Parameters:
  118  *      whichSha: [in]
  119  *          One of SHA1, SHA224, SHA256, SHA384, SHA512
  120  *      prk[ ]: [in]
  121  *          The pseudo-random key to be expanded; either obtained
  122  *          directly from a cryptographically strong, uniformly
  123  *          distributed pseudo-random number generator, or as the
  124  *          output from hkdfExtract().
  125  *      prk_len: [in]
  126  *          The length of the pseudo-random key in prk;
  127  *          should at least be equal to USHAHashSize(whichSHA).
  128  *      info[ ]: [in]
  129  *          The optional context and application specific information.
  130  *          If info == NULL or a zero-length string, it is ignored.
  131  *      info_len: [in]
  132  *          The length of the optional context and application specific
  133  *          information.  (Ignored if info == NULL.)
  134  *      okm[ ]: [out]
  135  *          Where the HKDF is to be stored.
  136  *      okm_len: [in]
  137  *          The length of the buffer to hold okm.
  138  *          okm_len must be <= 255 * USHABlockSize(whichSha)
  139  *
  140  *  Returns:
  141  *      sha Error Code.
  142  *
  143  */
  144 int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], int prk_len,
  145     const unsigned char *info, int info_len,
  146     uint8_t okm[ ], int okm_len)
  147 {
  148   int hash_len, N;
  149   unsigned char T[USHAMaxHashSize];
  150   int Tlen, where, i;
  151 
  152   if (info == 0) {
  153     info = (const unsigned char *)"";
  154     info_len = 0;
  155   } else if (info_len < 0) {
  156     return shaBadParam;
  157   }
  158   if (okm_len <= 0) return shaBadParam;
  159   if (!okm) return shaBadParam;
  160 
  161   hash_len = USHAHashSize(whichSha);
  162   if (prk_len < hash_len) return shaBadParam;
  163   N = okm_len / hash_len;
  164   if ((okm_len % hash_len) != 0) N++;
  165   if (N > 255) return shaBadParam;
  166 
  167   Tlen = 0;
  168   where = 0;
  169   for (i = 1; i <= N; i++) {
  170     HMACContext context;
  171     unsigned char c = i;
  172     int ret = hmacReset(&context, whichSha, prk, prk_len) ||
  173               hmacInput(&context, T, Tlen) ||
  174               hmacInput(&context, info, info_len) ||
  175               hmacInput(&context, &c, 1) ||
  176               hmacResult(&context, T);
  177     if (ret != shaSuccess) return ret;
  178     memcpy(okm + where, T,
  179            (i != N) ? hash_len : (okm_len - where));
  180     where += hash_len;
  181     Tlen = hash_len;
  182   }
  183   return shaSuccess;
  184 }
  185 
  186 /*
  187  *  hkdfReset
  188  *
  189  *  Description:
  190  *      This function will initialize the hkdfContext in preparation
  191  *      for key derivation using the modular HKDF interface for
  192  *      arbitrary length inputs.
  193  *
  194  *  Parameters:
  195  *      context: [in/out]
  196  *          The context to reset.
  197  *      whichSha: [in]
  198  *          One of SHA1, SHA224, SHA256, SHA384, SHA512
  199  *      salt[ ]: [in]
  200  *          The optional salt value (a non-secret random value);
  201  *          if not provided (salt == NULL), it is set internally
  202  *          to a string of HashLen(whichSha) zeros.
  203  *      salt_len: [in]
  204  *          The length of the salt value.  (Ignored if salt == NULL.)
  205  *
  206  *  Returns:
  207  *      sha Error Code.
  208  *
  209  */
  210 int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
  211               const unsigned char *salt, int salt_len)
  212 {
  213   unsigned char nullSalt[USHAMaxHashSize];
  214   if (!context) return shaNull;
  215 
  216   context->whichSha = whichSha;
  217   context->hashSize = USHAHashSize(whichSha);
  218   if (salt == 0) {
  219     salt = nullSalt;
  220     salt_len = context->hashSize;
  221     memset(nullSalt, '\0', salt_len);
  222   }
  223 
  224   return hmacReset(&context->hmacContext, whichSha, salt, salt_len);
  225 }
  226 
  227 /*
  228  *  hkdfInput
  229  *
  230  *  Description:
  231  *      This function accepts an array of octets as the next portion
  232  *      of the input keying material.  It may be called multiple times.
  233  *
  234  *  Parameters:
  235  *      context: [in/out]
  236  *          The HKDF context to update.
  237  *      ikm[ ]: [in]
  238  *          An array of octets representing the next portion of
  239  *          the input keying material.
  240  *      ikm_len: [in]
  241  *          The length of ikm.
  242  *
  243  *  Returns:
  244  *      sha Error Code.
  245  *
  246  */
  247 int hkdfInput(HKDFContext *context, const unsigned char *ikm,
  248               int ikm_len)
  249 {
  250   if (!context) return shaNull;
  251   if (context->Corrupted) return context->Corrupted;
  252   if (context->Computed) return context->Corrupted = shaStateError;
  253   return hmacInput(&context->hmacContext, ikm, ikm_len);
  254 }
  255 
  256 /*
  257  * hkdfFinalBits
  258  *
  259  * Description:
  260  *   This function will add in any final bits of the
  261  *   input keying material.
  262  *
  263  * Parameters:
  264  *   context: [in/out]
  265  *     The HKDF context to update
  266  *   ikm_bits: [in]
  267  *     The final bits of the input keying material, in the upper
  268  *     portion of the byte.  (Use 0b###00000 instead of 0b00000###
  269  *     to input the three bits ###.)
  270  *   ikm_bit_count: [in]
  271  *     The number of bits in message_bits, between 1 and 7.
  272  *
  273  * Returns:
  274  *   sha Error Code.
  275  */
  276 int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
  277                   unsigned int ikm_bit_count)
  278 {
  279   if (!context) return shaNull;
  280   if (context->Corrupted) return context->Corrupted;
  281   if (context->Computed) return context->Corrupted = shaStateError;
  282   return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
  283 }
  284 
  285 /*
  286  * hkdfResult
  287  *
  288  * Description:
  289  *   This function will finish the HKDF extraction and perform the
  290  *   final HKDF expansion.
  291  *
  292  * Parameters:
  293  *   context: [in/out]
  294  *     The HKDF context to use to calculate the HKDF hash.
  295  *   prk[ ]: [out]
  296  *     An optional location to store the HKDF extraction.
  297  *     Either NULL, or pointer to a buffer that must be
  298  *     larger than USHAHashSize(whichSha);
  299  *   info[ ]: [in]
  300  *     The optional context and application specific information.
  301  *     If info == NULL or a zero-length string, it is ignored.
  302  *   info_len: [in]
  303  *     The length of the optional context and application specific
  304  *     information.  (Ignored if info == NULL.)
  305  *   okm[ ]: [out]
  306  *     Where the HKDF is to be stored.
  307  *   okm_len: [in]
  308  *     The length of the buffer to hold okm.
  309  *     okm_len must be <= 255 * USHABlockSize(whichSha)
  310  *
  311  * Returns:
  312  *   sha Error Code.
  313  *
  314  */
  315 int hkdfResult(HKDFContext *context,
  316                uint8_t prk[USHAMaxHashSize],
  317                const unsigned char *info, int info_len,
  318                uint8_t okm[ ], int okm_len)
  319 {
  320   uint8_t prkbuf[USHAMaxHashSize];
  321   int ret;
  322 
  323   if (!context) return shaNull;
  324   if (context->Corrupted) return context->Corrupted;
  325   if (context->Computed) return context->Corrupted = shaStateError;
  326   if (!okm) return context->Corrupted = shaBadParam;
  327   if (!prk) prk = prkbuf;
  328 
  329   ret = hmacResult(&context->hmacContext, prk) ||
  330         hkdfExpand(context->whichSha, prk, context->hashSize, info,
  331                    info_len, okm, okm_len);
  332   context->Computed = 1;
  333   return context->Corrupted = ret;
  334 }