借用gcc源码中的sha1.c计算HMAC_SHA1

之前的文章介绍了如何用gcc源码中的sha1.c来计算SHA1值,也介绍了如何用M4的HASH模块进行硬件计算SHA1及其HMAC,并且将原始数据的精度提升到了bit。现在,为了验证提升之后的计算结果的正确,顺便纠正datasheet上的笔误,在PC上进行软件计算。

再重新介绍下HMAC的概念:

HMAC(message) = Hash[((key | pad) XOR 0x5C) | Hash(((key | pad) XOR 0x36) | message)]

用sha1_buffer函数即可计算SHA1的值,为了方便显示,包装成如下的函数:

inline static void sha1_bytes( char ref_hash[41], const void *buffer, size_t len )
{
    if (ref_hash != 0 && (buffer != 0 || len == 0))
    {
        unsigned char resblock[21] = "";
        size_t i = 0;
        
        sha1_buffer ((const char *)buffer, len, resblock);

        for (i = 0; i < 20; i++)
        {
            const char *hex = "0123456789ABCDEF";
            unsigned char ch = resblock[i];
            ref_hash[i * 2 + 0] = hex[(ch >> 4U) & 0x0F];
            ref_hash[i * 2 + 1] = hex[(ch >> 0U) & 0x0F];
        }
        
        ref_hash[40] = 0;
    }

    return;
}
然后根据HMAC的概念,写出HMAC_SHA1的函数,考虑到计算时,需要将key和message拼接起来,所以并不直接用 sha1_buffer函数,而是使用sha1_init_ctx、sha1_process_bytes、sha1_finish_ctx系列函数来计算。我们看一下sha1_buffer函数的源码:

/* Compute SHA1 message digest for LEN bytes beginning at BUFFER.  The
   result is always in little endian byte order, so that a byte-wise
   output yields to the wanted ASCII representation of the message
   digest.  */
void *
sha1_buffer (const char *buffer, size_t len, void *resblock)
{
  struct sha1_ctx ctx;

  /* Initialize the computation context.  */
  sha1_init_ctx (&ctx);

  /* Process whole buffer but last len % 64 bytes.  */
  sha1_process_bytes (buffer, len, &ctx);

  /* Put result in desired memory area.  */
  return sha1_finish_ctx (&ctx, resblock);
}
基本上就明白这组函数的用法了,没错,把sha1_process_bytes函数重复调用两次,分别传入带拼接起来的两部分,即可。 HMAC函数如下:

inline static void hmac_sha1_bytes( char ref_hash[41],
    const void *key, size_t key_len,
    const void *msg, size_t msg_len )
{
    struct sha1_ctx ctx = { 0 };
    
    enum { HASH_LEN = 20 };
    enum { BLOCK_LEN = 64 };
    unsigned char hash[HASH_LEN] = { 0 };
    unsigned char key_pad[BLOCK_LEN] = { 0 };
    
    if (key_len > BLOCK_LEN)
    {
        ::sha1_buffer ((const char *)key, key_len, key_pad);
    }
    else
    {
        ::memcpy (key_pad, key, key_len);
    }
    
    unsigned char hash_temp[HASH_LEN] = { 0 };
    unsigned char key_pad_temp[BLOCK_LEN] = { 0 };
    size_t i = 0;
    for (i = 0; i < BLOCK_LEN; i++)
    {
        key_pad_temp[i] = key_pad[i] ^ 0x36;
        key_pad[i] ^= 0x5C;
    }
    
    ::sha1_init_ctx (&ctx);
    ::sha1_process_bytes (key_pad_temp, BLOCK_LEN, &ctx);
    ::sha1_process_bytes (msg, msg_len, &ctx);
    ::sha1_finish_ctx (&ctx, hash_temp);
    
    ::sha1_init_ctx (&ctx);
    ::sha1_process_bytes (key_pad, BLOCK_LEN, &ctx);
    ::sha1_process_bytes (hash_temp, HASH_LEN, &ctx);
    ::sha1_finish_ctx (&ctx, hash);
    
    for (i = 0; i < HASH_LEN; i++)
    {
        const char *hex = "0123456789ABCDEF";
        unsigned char ch = hash[i];
        ref_hash[i * 2 + 0] = hex[(ch >> 4U) & 0x0F];
        ref_hash[i * 2 + 1] = hex[(ch >> 0U) & 0x0F];
    }
    
    ref_hash[40] = 0;
    
    return;
}
不过,这两个函数,就原始数据来说,包括HMAC算法的key,都是以byte为单位的。虽然不知道实际应用中有没有需要处理以bit为单位的情况,但是从SHA1的定义来看,其本身就是处理bit的。只不过,平时PC上常见的都是给文件进行校验,所以以byte为单位也就习以为常了。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值