借用gcc源码中的sha1.c进行SHA1计算
Posted 失散糖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了借用gcc源码中的sha1.c进行SHA1计算相关的知识,希望对你有一定的参考价值。
起初打算用sha1校验进行密码比对,然后想找个能算SHA1校验码的C语言函数,想到这个算法很可能在开源代码中能找到,于是在gcc-4.9.2的源码中找到了一个名叫"sha1.c"的文件,在源码树的gcc-4.9.2\\libiberty目录下,就拿来用用看.
把该文件拷出来,拿到VC6下打开编译,自动建立了一个工程,但是第26行有个严重错误:
#include <config.h>
找不到config.h,这是一个很常见的错误,源码树下又搜不到这个文件,于是,要么新建一个空的文件命成这个名字,要么直接删掉这行包含语句.咱不想破坏源码文件,所以新建了一个空的config.h放在了工程目录下,但,重新编译还是提示找不到,大概是因为用尖括号包含的缘故.接下来修改工程配置,在C/C++的预处理路径中添加一个小数点,代表工程文件所在目录,重新编译,这回能找到了,但是出现了新的错误:在第28行:
#include "sha1.h"
回到源码树中搜索,在gcc-4.9.2\\include路径下找到了sha1.h,拷出来放到工程路径下,重新编译,于是在sha1.h的第29行:
#include "ansidecl.h"
继续搜,仍然在gcc-4.9.2\\include路径下,找到了这个ansidecl.h文件,拷出来放到工程路径下,重新编译,终于编译通过了.
分析下sha1.h文件,可以看出,sha1_buffer函数就是我们要找的计算SHA1的函数
很好,新建个测试文件,起名叫sha1_test.c,文件内容如下:
#include <stdio.h>
#include "sha1.h"
int main()
char buffer[64] = 0 ;
unsigned char resblock[20] = "";
size_t i = 0;
sha1_buffer (buffer, sizeof (buffer), resblock);
for (i = 0; i < 20; i++)
printf ("%02X", resblock[i]);
putchar ('\\n');
return 0;
代码很简单,只是给了一组数据,64个字节的零,计算其SHA1值,将计算结果以字节为单位,用十六进制打印出来,跑一下,结果如下:
C8D7D0EF0EEDFA82D2EA1AA592845B9A6D4B02B7
看起来挺像那么回事的.然后,因为VC6新建工程后,默认为Debug模式,咱把它切换到Release模式下跑跑看,这一跑,坏了,结果不一样了:
7076B3F1F5B3F7440BB4BFCC04C469EBD9FBC129
解决办法有两个:其一,修改工程配置,把sha1.c这个文件的优化关掉,重新编译,啊,这回结果变得和Debug下的结果一样了.
其二,用旧版本的gcc源码,比如gcc-4.7.2的源码,这个版本没有上述问题.
用文件对比工具(比如SVN)对比下两个版本的源码,发现只有一处差异,第303行,旧版本是
if (ctx->total[0] < len)
++ctx->total[1];
新版本是
ctx->total[1] += ((len >> 31) >> 1) + (ctx->total[0] < len);
果然新版本是把((len >> 31) >> 1)优化错了,据我猜测,新版本这么个改法,是为了在64位程序上,当内存中申请了超过2的32次方大小的内存后,对这块内存求SHA1校验码,((len >> 31) >> 1)才有意义.32位程序由于不存在如此大的buf所以旧版本的没有加.
手头没有条件测试这个情况,但是根据猜测,旧版本不加((len >> 31) >> 1),会导致对超过2的32次方大小的内存直接计算校验码出现错误吧.新版本之所以要加上这么个量,想必是为了防止这样的错误.但是禁止优化这种事情,很容易忘记,所以,最好的办法是利用config.h文件,在这个文件中加上这么一行:
#pragma optimize("",off)
强制关掉优化(仅在VC6下试过能用,其他编译环境请自行试验),OK了,有新版咱还是用新版比较安心什么的
PS:在源码树的gcc-4.9.2\\libiberty目录下,还能看到其他很多大概能用上的函数,像是md5.c什么的,拿来用用吧
以上是关于借用gcc源码中的sha1.c进行SHA1计算的主要内容,如果未能解决你的问题,请参考以下文章