"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.2/libcanlock/test/hkdf.c" (23 Aug 2021, 10574 Bytes) of package /linux/misc/tin-2.6.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. See also the last Fossies "Diffs" side-by-side code changes report for "hkdf.c": 2.4.5_vs_2.6.0.

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