来自不同文件的哈希始终相同

时间:2018-08-24 21:03:33

标签: c# .net-core

我正在构建一个API,该API具有通过POST请求接受文件的方法。 基于该文件,我需要在文件本身(而不是名称)上创建一个哈希,检查该哈希是否已经存在,并执行其他一些操作。

我的问题是,无论我将通过邮递员发送的文件是什么,每个文件的哈希值始终相同,这意味着每次我只获得1个被覆盖的文件。

这是我的方法

 private string GetHashFromImage(IFormFile file)
    {
        /* Creates a hash with the image as a parameter
         * with the SHA1 algorithm and returns the hash
         * as a string since the ComputeHash() method 
         * creates a byte array.
         */
         System.IO.MemoryStream image = new System.IO.MemoryStream();
         file.CopyTo(image);
         var hashedValue = System.Security.Cryptography.SHA1.Create().ComputeHash(image);
         var hashAsString = Convert.ToBase64String(hashedValue).Replace(@"/", @"");
         image.Seek(0, System.IO.SeekOrigin.Begin);

         return hashAsString;
        }
    }

我需要一个与操作系统无关的哈希方法,并且将在每个文件上返回相同的哈希值。

2 个答案:

答案 0 :(得分:0)

不是完全确定为什么您的解决方案无法正常工作,但是我认为我对如何实现所需目标有一个想法,它使用MD5而不是SHA1。让我们创建一个函数,该函数将接收IFormFile,计算其内容的MD5哈希值,然后将哈希值作为string返回。

using System;
using System.IO;
using System.Security.Cryptography;

private string GetMD5Hash(IFormFile file)
{
    // get stream from file then convert it to a MemoryStream
    MemoryStream stream = new MemoryStream();
    file.OpenReadStream().CopyTo(stream);

    byte[] bytes = MD5.Create().ComputeHash(stream.ToArray());
    return BitConverter.ToString(bytes).Replace("-",string.Empty).ToLower();
}

希望它对您有用!

答案 1 :(得分:0)

此行为的真正原因是计算出的流中的最后位置(与image.Seek(0, System.IO.SeekOrigin.End)之后的位置相同)。

CopyToComputeHash之类的流操作会更改序列的位置,因为它们必须遍历它们。 任何在末尾位置的流的最终哈希值始终相同-就像是空流或空数组的哈希值。

当然,将流转换为数组是可行的,因为将数组功能用于整个流(从position = 0开始),但这通常不是很优雅的解决方案,因为您必须将整个流复制到内存中(内存流也是如此) -数据也在内存中。)

直接使用流时,该函数(如从流中计算哈希)将按小块(如4096B)读取流,并迭代地计算哈希(.NET source code)。这意味着原始解决方案应该在哈希计算之前执行从头开始的查找操作时起作用。

实际上,您应该能够直接从输入流(在IFormFile中计算哈希,而无需将整个流复制到内存(数组或内存流)中,从而具有更好的性能,并且没有风险,例如OutOfMemoryException