使用openssl正确获取文件的sha-1

Zai*_*mir 3 c++ windows openssl cryptography file

我正在尝试为一些文件获取sha-1.我目前所做的是循环给定路径中的文件,分别打开和读取每个文件,并将内容加载到缓冲区中,然后将其发送到openssl的SHA函数以获取哈希值.代码看起来像这样:

    void ReadHashFile(LPCTSTR name)
{
 FILE * pFile;
 long lSize;
 char * buffer;
 size_t result;

 pFile = _tfopen ( name , L"rb" );
 if (pFile==NULL) {fputs ("File error",stderr); return;}

 // obtain file size:
 fseek (pFile , 0 , SEEK_END);
 lSize = ftell (pFile);
 rewind (pFile);

 if(lSize == -1){fputs ("Read Error",stderr);return;}

 // allocate memory to contain the whole file:
 buffer = (char*) malloc (sizeof(char)*lSize);
 if (buffer == NULL) {fputs ("Memory error",stderr); return;}

 // copy the file into the buffer:
 result = fread (buffer,1,lSize,pFile);
 if (result != lSize) {fputs ("Reading error",stderr); return;}

 /* the whole file is now loaded in the memory buffer. */

 // terminate
 fclose (pFile);

 //Do what ever with buffer
 unsigned char ibuf[] = "compute sha1";
 unsigned char obuf[20];

 SHA1((const unsigned char*)buffer, strlen((const char*)buffer), obuf);
 fwprintf(stderr, L"file %s\n", name);
 int i;
 for (i = 0; i < 20; i++) {
  printf("%02x ", obuf[i]);
 }
 printf("\n");


 free(buffer);
}
Run Code Online (Sandbox Code Playgroud)

有些文件似乎是不可读的,有些文件给我一个-1大小的其他文件我只能读取前2-3个字节,这给了很多文件相同的sha,即使它们是不同的.

如果有人可以帮助我,或者如果有人有文件散列经验,我将不胜感激.哦,有没有办法得到一个文件的sha1而不先将整个文件加载到内存中,我的意思是考虑大文件,这个解决方案不会工作.

问候

Tho*_*nin 16

如果您调用散列函数代码之前无法读取文件内容,那么您的问题与散列无关.

你应该使用标准fopen()函数,而不是_tfopen().在C中,通常最好避免以下划线字符开头的事物.特别是因为根据是否激活所谓的"unicode支持",_tfopen()似乎映射到任一fopen()或Windows特定_wfopen().或者,在纯Windows应用程序中,您可以依赖Win32等功能CreateFile().

在内存中读取整个文件然后散列它是粗糙的.例如,它将无法处理大于可用RAM的文件.此外,为了知道文件大小,你必须寻找它,这是不可靠的(可能有伪文件实际上是一些数据生成过程的管道,为此无法寻找).散列函数可以按块处理数据; 你应该使用一个小缓冲区(8 KB的是传统的大小),并采用了SHA1_Init(),SHA1_Update()SHA1_Final()功能.

fread()不一定要读取您请求的数据.这不是一个错误.

当你打电话时SHA1(),你strlen()在你的缓冲区上使用,这是假的.strlen()返回字符串的长度; 用简单的话说,直到下一个字节值为零的字节数.许多文件包含值为0的字节.如果文件没有,则无法保证缓冲区包含任何值为0的字节,因此调用strlen()可能最终会读取分配缓冲区之外的内存(这很糟糕) .既然你遇到了获取文件长度并分配大缓冲区的麻烦,你应该至少使用那个长度,而不是试图用一个不这样做的函数来重新计算它.

总结一下:你的代码看起来应该是那样的(未经测试):

/*
 * Hash a file, which name is given. Hash output is written out in
 * buffer "out[]". The hash output consists in exactly 20 bytes.
 * On success, 0 is returned; on error, returned value is -1 and
 * out[] is unaltered.
 */
int
do_sha1_file(char *name, unsigned char *out)
{
    FILE *f;
    unsigned char buf[8192];
    SHA_CTX sc;
    int err;

    f = fopen(name, "rb");
    if (f == NULL) {
        /* do something smart here: the file could not be opened */
        return -1;
    }
    SHA1_Init(&sc);
    for (;;) {
        size_t len;

        len = fread(buf, 1, sizeof buf, f);
        if (len == 0)
            break;
        SHA1_Update(&sc, buf, len);
    }
    err = ferror(f);
    fclose(f);
    if (err) {
        /* some I/O error was encountered; report the error */
        return -1;
    }
    SHA1_Final(out, &sc);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

并且不要忘记包含相关的文件头!(<stdio.h>sha.h来自OpenSSL)