【问题标题】:OpenSSL SHA256 generates different sum for the same fileOpenSSL SHA256 为同一个文件生成不同的总和
【发布时间】:2023-02-05 04:05:21
【问题描述】:

我以前从未使用过 SHA256。最近,我一直在尝试实现 SHA256 校验和,以查看库是否已被篡改。

有趣的是,OpenSSL SHA256 根据其位置为完全相同的库生成不同的总和。如果它位于另一个文件夹中,则总和不同。

无论文件位于何处,我都可以做些什么来获得相同的总和?我提供了代码 sn-ps 和我得到的总和。

unsigned char* getsum( char* filename ) {
    std::ifstream pFile( filename, std::ios::binary );
    SHA256_CTX sContext;
    char pBuffer[ 1024*16 ];
    unsigned char pSum[SHA256_DIGEST_LENGTH];

    SHA256_Init( &sContext );
    while( pFile.good() ) {
        pFile.read( pBuffer, sizeof(pBuffer) );
        SHA256_Update( &sContext, pBuffer, pFile.gcount() );
    }
    SHA256_Final( pSum, &sContext );
    return pSum;
}

...

char* cl_sum = new char[256];
sprintf( cl_sum, "%02x", getsum("library.dll") );
MessageBoxA( NULL, cl_sum , NULL, NULL );
delete[] cl_sum;
exit( -1 );

我还尝试使用 SHA256() 函数而不是整个 SHA256 上下文、SHA256_Init()、Update & Final thing,但结果仍然相同。

【问题讨论】:

  • 这看起来很可疑:while( pFile.good() )
  • 这是错误的:sprintf( cl_sum, "%02x", getsum("library.dll") ); 编译器应该对此发出警告。

标签: c++


【解决方案1】:

您正在返回指向局部变量 pSum 的指针,这是未定义的行为 (UB)。

对不同输出的解释可能是因为数组位于堆栈上,所以调用 sprintfMessageBoxA 等未来函数可能会用自己的变量覆盖数组。但是在 UB 之后任何事情都可能发生。

请改用并返回 std::vector<unsigned char>

也不要使用new,而是std::array或另一个std::vector更安全。

最后,我强烈建议为您的编译器打开编译器警告,它应该警告上述问题。

【讨论】:

  • 感谢您的建议,我一定会尝试的,但问题是如果库(以及与此相关的整个应用程序)在同一个文件夹中,总和是相同的,它永远不会改变,但如果我将它移动到其他地方它确实改变了
  • @stuck 好的,这是可能的,但争论 UB 是徒劳的,首先修复代码并检查它是否解决了问题。
【解决方案2】:

您的代码有很多基本错误:

sprintf( cl_sum, "%02x", getsum("library.dll") );

格式字符串表示“打印我的 int 值”,getsum 返回 char *!这是错误的,如果您使用编译器警告,它应该可以解释问题。

返回值也是错误的:

unsigned char* getsum( char* filename ) {
....
    char pBuffer[ 1024*16 ];
....
    return pSum;
}

您正在返回一个指向本地对象的指针,该对象的生命周期在函数返回时结束。

while( pFile.good() ) {

这是常见的错误。你应该这样做:

    while(pFile.read(pBuffer, sizeof(pBuffer))) {
        SHA256_Update( &sContext, pBuffer, pFile.gcount() );
    }

【讨论】:

    【解决方案3】:

    您的代码输出取决于 getsum 返回的值。 getsum返回的值是栈上的一个地址。所以你的代码的输出取决于堆栈所在的位置。

    在代码的某处,您应该将 SHA256 运算的结果保存在某种缓冲区中,并且您应该输出内容那个缓冲区。您的代码不会执行这两件事。

    如果您认为将 SHA256 运算的输出保存在某种缓冲区中,您认为该缓冲区分配在哪里。您使用的唯一缓冲区是pBuffer,它分配在getsum 中的堆栈上,因此在getsum 返回时不存在。

    如果您认为您实际上在某处查看缓冲区,您认为该代码在哪里?你的sprintf 电话永远看不到缓冲区,它只是输出一个十六进制指针。

    【讨论】:

      【解决方案4】:

      您的代码有几个问题:

      • 您的函数返回一个指向局部变量的指针。当您的函数退出时,变量被销毁,返回的指针悬空。

      • 您正在打印指针本身的值,而不是它指向的 SHA 数据。这就是您看到显示相同值的原因。您看到的是局部变量的内存地址,函数的多次调用可能会重用相同的内存。

      • 在调用 SHA256_Update() 之前,您的阅读循环无法确保 read() 成功。

      尝试更像这样的东西:

      using Sha256Digest = std::array<unsigned char, SHA256_DIGEST_LENGTH>;
      
      Sha256Digest getsum( const char* filename ) {
          std::ifstream file( filename, std::ios::binary );
          SHA256_CTX sContext;
          char buffer[ 1024*16 ];   
          Sha256Digest sum;
      
          SHA256_Init( &sContext );
          while( file.read( buffer, sizeof(buffer) ) ) {
              SHA256_Update( &sContext, buffer, pFile.gcount() );
          }
          SHA256_Final( sum.data(), &sContext );
      
          return sum;
      }
      
      ...
      
      Sha256Digest sum = getsum("library.dll");
      std::ostringstream cl_sum;
      for (auto ch : sum) {
          cl_sum << std::hex << std::setw(2) << std::setfill('0') << ch;
      }
      MessageBoxA( NULL, cl_sum.str().c_str(), NULL, NULL );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-14
        • 2012-11-05
        • 1970-01-01
        • 1970-01-01
        • 2011-01-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多