HKDF实现

HKDF详细请见文章 https://blog.csdn.net/mrpre/article/details/79879392
本文给了一种python实现和三种C实现。

python程序(摘自wiki):

    #!/usr/bin/env python3
    import hashlib
    import hmac
    from math import ceil

    hash_len = 32
    def hmac_sha256(key, data):
        return hmac.new(key, data, hashlib.sha256).digest()

    def hkdf(length, ikm, salt=b"", info=b""):
        prk = hmac_sha256(salt, ikm)
        t = b""
        okm = b""
        for i in range(ceil(length / hash_len)):
            t = hmac_sha256(prk, t + info + bytes([1+i]))
            okm += t
        return okm[:length]

C程序:

OpenSSL_HKDF1() 直接调用了OPENSSL库函数计算完整的HKDF。
OpenSSL_HKDF2() 先调用extract,然后再调用expand,完成一次完整的HKDF。
my_HKDF() 是我按照RFC的逻辑实现的HKDF。

#include <openssl/ssl.h>
#include <openssl/kdf.h>
#include <string.h>
#define OUT_LEN 90
#define HASH_SIZE 32
#define MD_FUNC EVP_sha256()
#define INFO "test"
#define INFO_LEN 4

void OpenSSL_HKDF1()
{
    unsigned char secret[HASH_SIZE]={0};
    const EVP_MD *md = MD_FUNC;
    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);

    unsigned char out[OUT_LEN];
    size_t outlen = OUT_LEN, i, ret;

    ret = EVP_PKEY_derive_init(pctx) <= 0
          || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND) <= 0
          || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0
          || EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, HASH_SIZE) <= 0
          || EVP_PKEY_CTX_add1_hkdf_info(pctx, INFO, INFO_LEN) <= 0
          || EVP_PKEY_derive(pctx, out, &outlen) <= 0;

    EVP_PKEY_CTX_free(pctx);
    if (ret == 0)
    {
        printf("HKDF result:%d\n",outlen);
        for(i=0;i<outlen;i++)
            printf("%02X", out[i]);
        printf("\n");
    } 
}

void OpenSSL_HKDF2()
{
    unsigned char secret[HASH_SIZE]={0};
    const EVP_MD *md = MD_FUNC;
    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);

    unsigned char prk[HASH_SIZE], okm[OUT_LEN];
    size_t outlen = HASH_SIZE, i, ret;

    /*first do extract*/
    ret = EVP_PKEY_derive_init(pctx) <= 0
          || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) <= 0
          || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0
          || EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, HASH_SIZE) <= 0
          //|| EVP_PKEY_CTX_add1_hkdf_info(pctx, INFO, INFO_LEN) <= 0
          || EVP_PKEY_derive(pctx, prk, &outlen) <= 0;

    if (ret == 0)
    {
        printf("HKDF extract prk:%d\n",outlen);
        for(i=0;i<outlen;i++)
            printf("%02X", prk[i]);
        printf("\n");
    }
    EVP_PKEY_CTX_free(pctx); 

    /*second do expand, using prk as secret*/
    outlen = OUT_LEN;
    pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
    ret = EVP_PKEY_derive_init(pctx) <= 0
          || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0
          || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0
          || EVP_PKEY_CTX_set1_hkdf_key(pctx, prk, HASH_SIZE) <= 0
          || EVP_PKEY_CTX_add1_hkdf_info(pctx, INFO, INFO_LEN) <= 0
          || EVP_PKEY_derive(pctx, okm, &outlen) <= 0;

    if (ret == 0)
    {
        printf("HKDF expand okm:%d\n",outlen);
        for(i=0;i<outlen;i++)
            printf("%02X", okm[i]);
        printf("\n");
    }
    EVP_PKEY_CTX_free(pctx); 
}


void my_HKDF()
{
    unsigned char secret[HASH_SIZE]={0};
    const EVP_MD *md = MD_FUNC;
    unsigned char prk[HASH_SIZE], okm[OUT_LEN], T[HASH_SIZE]={0}, tmp[OUT_LEN];
    int outlen = HASH_SIZE, i, ret, tmplen;
    unsigned char *p;
    /*extract is a simple HMAC...
      Note:salt should be treated as hmac key and ikm should be treated as data
     */
    if (!HMAC(md, NULL, 0, secret, HASH_SIZE, prk, &outlen)) 
        return ;

    printf("HKDF extract prk:%d\n",outlen);
    for(i=0;i<outlen;i++)
        printf("%02X", prk[i]);
    printf("\n");

    /*do expand*/

    /*calc the round times*/
    ret = OUT_LEN/HASH_SIZE + !!(OUT_LEN%HASH_SIZE);

    tmplen = outlen;
    for (i = 0; i < ret; i++)
    {
        p = tmp;

        /*T(0) = empty string (zero length)*/
        if (i != 0)
        {
            memcpy(p, T, HASH_SIZE);
            p += HASH_SIZE;
        }

        memcpy(p, INFO, INFO_LEN);
        p += INFO_LEN;
        *p++ = i + 1;

        HMAC(md, prk, HASH_SIZE, tmp, (int)(p - tmp), T, &outlen);
        memcpy(okm + i*HASH_SIZE, T, tmplen < HASH_SIZE ? tmplen:HASH_SIZE);
        tmplen -= HASH_SIZE;
    }

    printf("HKDF expand okm:%d\n",OUT_LEN);
    for(i=0;i<OUT_LEN;i++)
        printf("%02X", okm[i]);
    printf("\n");
}

void main()
{
    my_HKDF();
}

猜你喜欢

转载自blog.csdn.net/mrpre/article/details/79881184