【问题标题】:Correctly getting sha-1 for files using openssl使用 openssl 正确获取文件的 sha-1
【发布时间】:2011-03-28 21:10:03
【问题描述】:

我正在尝试为多个文件获取 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);
}

有些文件似乎无法读取,有些文件大小为 -1,而有些文件的大小我只能读取前 2-3 个字节,这使得许多文件具有相同的 sha,即使它们不同。

如果有人可以帮助我,或者如果有人有文件散列方面的经验,我将不胜感激。哦,有没有办法在不先将整个文件加载到内存中的情况下获取文件的 sha1,我的意思是考虑到大文件,这个解决方案不起作用。

问候

【问题讨论】:

    标签: c++ windows file cryptography openssl


    【解决方案1】:

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

    您应该使用标准的fopen() 函数,而不是_tfopen()。在 C 中,通常最好避免以下划线字符开头的内容。特别是因为_tfopen() 似乎映射到fopen() 或特定于Windows 的_wfopen(),这取决于是否激活了所谓的“unicode 支持”。或者,在纯 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;
    }
    

    不要忘记包含相关的文件头! (&lt;stdio.h&gt;,以及来自 OpenSSL 的 sha.h

    【讨论】:

      猜你喜欢
      • 2013-04-29
      • 1970-01-01
      • 2023-03-12
      • 2018-01-11
      • 2012-04-10
      • 2013-08-30
      • 1970-01-01
      • 2020-06-22
      • 2022-01-07
      相关资源
      最近更新 更多