hmac-sha1摘要算法以及C语言实现
最近在研究WPA2破解算法,里面涉及到了hmac-sha1摘要算法。 hmac算法是一种信息摘要算法,常常用于密码验证过程中。而hmac-sha1则是使用sha1作为具体摘要算法的。除了sha1外,还可以使用md5等。 各种信息摘要算法用于密码验证的基本流程如下: 1、客户端向服务器发出登录或其他操作请求; 2、服务器生成一个随机数,发送给客户端; 3、客户端把用户输入的密码和这个随机数通过某种算法,计算得到一个摘要值A,发送给服务器; 4、服务器端把存于数据库中的正确的密码和这个随机数通过该算法,计算得到一个摘要值B,如果A==B,那么服务器断定客户端有正确的密码。 上述过程就是一种密码质询(challenge)过程,其中提到的“某种算法”,可以有很多很多实现。一种比较简单的方法是,把密码与随机数串联后带入MD5算法,得到摘要值。 那么为什么需要hmac-sha1算法呢?个人的理解是这样的: 1、规范化质询算法; 2、提供更高强度的保护。 第一条很好理解。每个人都有自己的质询实现,比如我的质询方法是MD5(密码+随机数),而他的质询方法是MD5(随机数+密码),甚至MD5(密码+随机数*2)等等。规范化质询算法,有助于大家交流嘛~ 第二条,是因为传统的MD5等算法的强度正在逐渐衰减,所以需要更加复杂的算法来保护数据。 OK,讲了这么多,就来讲讲C语言的实现吧。 其实我不是自己实现的,而是在github上找到了现成的开源代码,在此感谢#HREF"https://github.com/Akagi201/hmac-sha1"#-HREF1Akagi201/hmac-sha1#-HREF2项目。不过,该项目可以通过宏来选择是使用openssl里面的sha1算法还是使用该项目自己实现的sha1算法。为了减少文件数量,我还是用了openssl,并且稍微简化了以下代码。 先给出一个使用的例子: main.c +++code #include <stdio.h> #include "hmac.h" int main() { uint8_t t_key[]={'k','e','y'}; uint8_t t_data[]={'h','e','l','l','o'}; uint8_t t_result[256]={0}; size_t t_len=sizeof(t_result); hmac_sha1(t_key,3,t_data,5,t_result,&t_len); int t_i; for(t_i=0;t_i<t_len;t_i++) printf("%x ",t_result[t_i]); return 0; } ---code 编译的makefile很简单: +++code main: main.o hmac_sha1.o gcc main.o hmac_sha1.o -lcrypto -o main main.o: main.c gcc -c main.c -o main.o hmac_sha1.o: hmac_sha1.c gcc -c hmac_sha1.c -o hmac_sha1.o ---code 运行结果是: +++code b3 4c ea c4 51 6f f2 3a 14 3e 61 d7 9d f a7 a4 fb e5 f2 66 ---code 以下就是该项目的源码,共hmac.h、hmac_sha1.c两个文件。 hmac.h +++code /** * @file re_hmac.h Interface to HMAC functions * * Copyright (C) 2010 Creytiv.com */ #ifndef HMAC_H_ #define HMAC_H_ (1) #include <stdint.h> void hmac_sha1(const uint8_t *k, /* secret key */ size_t lk, /* length of the key in bytes */ const uint8_t *d, /* data */ size_t ld, /* length of data in bytes */ uint8_t *out, /* output buffer, at least "t" bytes */ size_t *t); #endif // HMAC_H_ ---code hmac_sha1.c +++code /** * @file hmac_sha1.c Implements HMAC-SHA1 as of RFC 2202 * * Copyright (C) 2010 Creytiv.com */ #include <string.h> #include <stdint.h> #include <openssl/sha.h> #include <openssl/hmac.h> #include <openssl/err.h> #include "hmac.h" /** SHA-1 Block size */ #ifndef SHA_BLOCKSIZE #define SHA_BLOCKSIZE (64) #endif /** * Function to compute the digest * * @param k Secret key * @param lk Length of the key in bytes * @param d Data * @param ld Length of data in bytes * @param out Digest output * @param t Size of digest output */ void hmac_sha1(const uint8_t *k, /* secret key */ size_t lk, /* length of the key in bytes */ const uint8_t *d, /* data */ size_t ld, /* length of data in bytes */ uint8_t *out, /* output buffer, at least "t" bytes */ size_t *t) { #ifdef USE_OPENSSL if (!HMAC(EVP_sha1(), k, (int)lk, d, ld, out, t)) { ERR_clear_error(); } #else SHA_CTX ictx, octx; uint8_t isha[SHA_DIGEST_LENGTH], osha[SHA_DIGEST_LENGTH]; uint8_t key[SHA_DIGEST_LENGTH]; uint8_t buf[SHA_BLOCKSIZE]; size_t i; if (lk > SHA_BLOCKSIZE) { SHA_CTX tctx; SHA1_Init(&tctx); SHA1_Update(&tctx, k, lk); SHA1_Final(key, &tctx); k = key; lk = SHA_DIGEST_LENGTH; } /**** Inner Digest ****/ SHA1_Init(&ictx); /* Pad the key for inner digest */ for (i = 0; i < lk; ++i) { buf[i] = k[i] ^ 0x36; } for (i = lk; i < SHA_BLOCKSIZE; ++i) { buf[i] = 0x36; } SHA1_Update(&ictx, buf, SHA_BLOCKSIZE); SHA1_Update(&ictx, d, ld); SHA1_Final(isha, &ictx); /**** Outer Digest ****/ SHA1_Init(&octx); /* Pad the key for outter digest */ for (i = 0; i < lk; ++i) { buf[i] = k[i] ^ 0x5c; } for (i = lk; i < SHA_BLOCKSIZE; ++i) { buf[i] = 0x5c; } SHA1_Update(&octx, buf, SHA_BLOCKSIZE); SHA1_Update(&octx, isha, SHA_DIGEST_LENGTH); SHA1_Final(osha, &octx); /* truncate and print the results */ *t = *t > SHA_DIGEST_LENGTH ? SHA_DIGEST_LENGTH : *t; memcpy(out, osha, *t); #endif } ---code