Beispiel #1
0
/*
 *  hkdf
 *
 *  Description:
 *      This function will generate keying material using HKDF.
 *
 *  Parameters:
 *      whichSha: [in]
 *          One of SHA1, SHA224, SHA256, SHA384, SHA512
 *      salt[ ]: [in]
 *          The optional salt value (a non-secret random value);
 *          if not provided (salt == NULL), it is set internally
 *          to a string of HashLen(whichSha) zeros.
 *      salt_len: [in]
 *          The length of the salt value.  (Ignored if salt == NULL.)
 *      ikm[ ]: [in]
 *          Input keying material.
 *      ikm_len: [in]
 *          The length of the input keying material.
 *      info[ ]: [in]
 *          The optional context and application specific information.
 *          If info == NULL or a zero-length string, it is ignored.
 *      info_len: [in]
 *          The length of the optional context and application specific
 *          information.  (Ignored if info == NULL.)
 *      okm[ ]: [out]
 *          Where the HKDF is to be stored.
 *      okm_len: [in]
 *          The length of the buffer to hold okm.
 *          okm_len must be <= 255 * USHABlockSize(whichSha)
 *
 *  Notes:
 *      Calls hkdfExtract() and hkdfExpand().
 *
 *  Returns:
 *      sha Error Code.
 *
 */
int hkdf(SHAversion whichSha,
         const unsigned char *salt, int salt_len,
         const unsigned char *ikm, int ikm_len,
         const unsigned char *info, int info_len,
         uint8_t okm[ ], int okm_len)
{
    int result;
    uint8_t *prk = malloc(USHAMaxHashSize);
    result =  hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) ||
              hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
                         info_len, okm, okm_len);
    free(prk);
    return result;
}
Beispiel #2
0
/*
 *  hkdfReset
 *
 *  Description:
 *      This function will initialize the hkdfContext in preparation
 *      for key derivation using the modular HKDF interface for
 *      arbitrary length inputs.
 *
 *  Parameters:
 *      context: [in/out]
 *          The context to reset.
 *      whichSha: [in]
 *          One of SHA1, SHA224, SHA256, SHA384, SHA512
 *      salt[ ]: [in]
 *          The optional salt value (a non-secret random value);
 *          if not provided (salt == NULL), it is set internally
 *          to a string of HashLen(whichSha) zeros.
 *      salt_len: [in]
 *          The length of the salt value.  (Ignored if salt == NULL.)
 *
 *  Returns:
 *      sha Error Code.
 *
 */
int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
              const unsigned char *salt, int salt_len)
{
    unsigned char nullSalt[USHAMaxHashSize];
    if (!context) return shaNull;

    context->whichSha = whichSha;
    context->hashSize = USHAHashSize(whichSha);
    if (salt == 0) {
        salt = nullSalt;
        salt_len = context->hashSize;
        memset(nullSalt, '\0', salt_len);
    }

    return hmacReset(&context->hmacContext, whichSha, salt, salt_len);
}
Beispiel #3
0
/*
 *  hkdfExtract
 *
 *  Description:
 *      This function will perform HKDF extraction.
 *
 *  Parameters:
 *      whichSha: [in]
 *          One of SHA1, SHA224, SHA256, SHA384, SHA512
 *      salt[ ]: [in]
 *          The optional salt value (a non-secret random value);
 *          if not provided (salt == NULL), it is set internally
 *          to a string of HashLen(whichSha) zeros.
 *      salt_len: [in]
 *          The length of the salt value.  (Ignored if salt == NULL.)
 *      ikm[ ]: [in]
 *          Input keying material.
 *      ikm_len: [in]
 *          The length of the input keying material.
 *      prk[ ]: [out]
 *          Array where the HKDF extraction is to be stored.
 *          Must be larger than USHAHashSize(whichSha);
 *
 *  Returns:
 *      sha Error Code.
 *
 */
int hkdfExtract(SHAversion whichSha,
                const unsigned char *salt, int salt_len,
                const unsigned char *ikm, int ikm_len,
                uint8_t prk[USHAMaxHashSize])
{
    int result;
    unsigned char *nullSalt = malloc(USHAMaxHashSize);
    if(nullSalt == 0) return shaNull;
    if (salt == 0) {
        salt = nullSalt;
        salt_len = USHAHashSize(whichSha);
        memset(nullSalt, '\0', salt_len);
    } else if (salt_len < 0) {
        free(nullSalt);
        return shaBadParam;
    }
    result = hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
    free(nullSalt);
    return result;
}
Beispiel #4
0
/*
 *  hkdfExpand
 *
 *  Description:
 *      This function will perform HKDF expansion.
 *
 *  Parameters:
 *      whichSha: [in]
 *          One of SHA1, SHA224, SHA256, SHA384, SHA512
 *      prk[ ]: [in]
 *          The pseudo-random key to be expanded; either obtained
 *          directly from a cryptographically strong, uniformly
 *          distributed pseudo-random number generator, or as the
 *          output from hkdfExtract().
 *      prk_len: [in]
 *          The length of the pseudo-random key in prk;
 *          should at least be equal to USHAHashSize(whichSHA).
 *      info[ ]: [in]
 *          The optional context and application specific information.
 *          If info == NULL or a zero-length string, it is ignored.
 *      info_len: [in]
 *          The length of the optional context and application specific
 *          information.  (Ignored if info == NULL.)
 *      okm[ ]: [out]
 *          Where the HKDF is to be stored.
 *      okm_len: [in]
 *          The length of the buffer to hold okm.
 *          okm_len must be <= 255 * USHABlockSize(whichSha)
 *
 *  Returns:
 *      sha Error Code.
 *
 */
int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], int prk_len,
               const unsigned char *info, int info_len,
               uint8_t okm[ ], int okm_len)
{
    int hash_len, N;
    unsigned char T[USHAMaxHashSize];
    int Tlen, where, i;

    if (info == 0) {
        info = (const unsigned char *)"";
        info_len = 0;
    } else if (info_len < 0) {
        return shaBadParam;
    }
    if (okm_len <= 0) return shaBadParam;
    if (!okm) return shaBadParam;

    hash_len = USHAHashSize(whichSha);
    if (prk_len < hash_len) return shaBadParam;
    N = okm_len / hash_len;
    if ((okm_len % hash_len) != 0) N++;
    if (N > 255) return shaBadParam;

    Tlen = 0;
    where = 0;
    for (i = 1; i <= N; i++) {
        HMACContext context;
        unsigned char c = i;
        int ret = hmacReset(&context, whichSha, prk, prk_len) ||
                  hmacInput(&context, T, Tlen) ||
                  hmacInput(&context, info, info_len) ||
                  hmacInput(&context, &c, 1) ||
                  hmacResult(&context, T);
        if (ret != shaSuccess) return ret;
        memcpy(okm + where, T,
               (i != N) ? hash_len : (okm_len - where));
        where += hash_len;
        Tlen = hash_len;
    }
    return shaSuccess;
}
/*
*  hmacReset
*
*  Description:
*      This function will initialize the hmacContext in preparation
*      for computing a new HMAC message digest.
*
*  Parameters:
*      context: [in/out]
*          The context to reset.
*      whichSha: [in]
*          One of SHA1, SHA224, SHA256, SHA384, SHA512
*      key: [in]
*          The secret shared key.
*      key_len: [in]
*          The length of the secret shared key.
*
*  Returns:
*      sha Error Code.
*
*/
int hmacReset(HMACContext *ctx, enum SHAversion whichSha,
    const unsigned char *key, int key_len)
{
    int i, blocksize, hashsize;

    /* inner padding - key XORd with ipad */
    unsigned char k_ipad[USHA_Max_Message_Block_Size];

    /* temporary buffer when keylen > blocksize */
    unsigned char tempkey[USHAMaxHashSize];

    if (!ctx) return shaNull;

    blocksize = ctx->blockSize = USHABlockSize(whichSha);
    hashsize = ctx->hashSize = USHAHashSize(whichSha);

    ctx->whichSha = whichSha;

    /*
    * If key is longer than the hash blocksize,
    * reset it to key = HASH(key).
    */
    if (key_len > blocksize) {
        USHAContext tctx;
        int err = USHAReset(&tctx, whichSha) ||
            USHAInput(&tctx, key, key_len) ||
            USHAResult(&tctx, tempkey);
        if (err != shaSuccess) return err;

        key = tempkey;
        key_len = hashsize;
    }

    /*
    * The HMAC transform looks like:
    *
    * SHA(K XOR opad, SHA(K XOR ipad, text))
    *
    * where K is an n byte key.
    * ipad is the byte 0x36 repeated blocksize times
    * opad is the byte 0x5c repeated blocksize times
    * and text is the data being protected.
    */

    /* store key into the pads, XOR'd with ipad and opad values */
    for (i = 0; i < key_len; i++) {
        k_ipad[i] = key[i] ^ 0x36;
        ctx->k_opad[i] = key[i] ^ 0x5c;
    }
    /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
    for (; i < blocksize; i++) {
        k_ipad[i] = 0x36;
        ctx->k_opad[i] = 0x5c;
    }

    /* perform inner hash */
    /* init context for 1st pass */
    return USHAReset(&ctx->shaContext, whichSha) ||
        /* and start with inner pad */
        USHAInput(&ctx->shaContext, k_ipad, blocksize);
}