上传图片创建MD5哈希值

3
我正在尝试从用户在我的网络应用程序上传的图像的字节数组中创建MD5字符串。这是因为我希望这些图像分散在不同的文件夹中。这样,我就不必使用userID作为文件夹名称,看起来更专业。
结果会类似于:
/images/ 'first-two-char-of-md5' / 'the-complete-md5-string'.[jpg,png,bmp....]

这个方案是否是处理图片的好方法?

那么,以下是我从互联网上找到的代码:

protected void btnUpload_Click(object sender, EventArgs e)
    {
        if (FileUpload1.HasFile)
        {
            if (CheckFileType(FileUpload1.FileName))
            {
                const int BUFFER_SIZE = 255;
                Byte[] Buffer = new Byte[BUFFER_SIZE];

                Stream theStream = FileUpload1.PostedFile.InputStream;
                nBytesRead = theStream.Read(Buffer, 0, BUFFER_SIZE);

                System.Text.ASCIIEncoding ASCIIEncoding = new ASCIIEncoding();
                System.Text.UTF8Encoding utf8 = new UTF8Encoding();
                //Just trying some stuff to see the output...
                Label1.Text =  ASCIIEncoding.GetString(CalculateMD5(theStream)) + "<br>" + utf8.GetString(CalculateMD5(theStream)) + "<br>" + Convert.ToBase64String(CalculateMD5(theStream));
             }
       }
  }


private static byte[] _emptyBuffer = new byte[0];

    public static byte[] CalculateMD5(Stream stream)
    {
        return CalculateMD5(stream, 64 * 1024);
    }

    public static byte[] CalculateMD5(Stream stream, int bufferSize)
    {
        MD5 md5Hasher = MD5.Create();

        byte[] buffer = new byte[bufferSize];
        int readBytes;

        while ((readBytes = stream.Read(buffer, 0, bufferSize)) > 0)
        {
            md5Hasher.TransformBlock(buffer, 0, readBytes, buffer, 0);
        }

        md5Hasher.TransformFinalBlock(_emptyBuffer, 0, 0);

        return md5Hasher.Hash;
    }

结果。我从"calculateMD5()"得到一些输出,但当我尝试将其放入label1中以查看发生了什么时,只有一堆奇怪的字符。

我在这里做错了什么?我希望它是htmlsafe的...只有a-z、A-Z、0-9。

4个回答

7

哈希值以字节数组的形式返回。您需要将其转换为人类可读的形式,例如 73868cb1848a216984dca1b6b0ee37bc。您可以使用以下代码:

var s = new StringBuilder();
foreach (byte b in md5Hasher.Hash)
    s.Append(b.ToString("x2").ToLower());
return s.ToString();

这会遍历哈希操作返回的字节列表并将每个字节转换为十六进制。有关可用于MSDN上byte类型的格式字符串的更多信息,请访问此处
回答您问题的第一部分:
这应该是足够的,但如果两个用户上传相同的图像,则会导致相同的哈希值。您可以尝试使用用户名和时间戳对数据进行加盐来缓解此问题。
您还需要进行一些检查,因为即使概率极小,您可能会为不同的图像/用户生成相同的哈希值('碰撞'),而您不希望一个用户覆盖另一个用户的图像。您可以通过生成图像的哈希值、检查其是否已经存在,如果存在,则在预处理的数据中添加一些字节,并重复此过程,直到哈希值唯一为止,来防止这种情况的发生。

谢谢!关于两个用户使用相同图像的问题。您认为是否可能将userID添加到_emptybuffer byte[]中,该byte[]在我的情况下为空(我认为),以添加盐? - Easyrider
1
是的,那应该可以。MD5使用校验和来计算最终哈希值,TransformFinalBlock是一种表示“这是最后的数据,请完成哈希操作”的方式。或者,您可以将任何其他数据写入传递给CalculateMD5的流的末尾(也许先将图像数据读入中间的MemoryStream,然后附加额外的数据,并将MemoryStream传递给CalculateMD5)。 - mdm

3

还有 BitConverter 类,它有一个 ToString() 方法,可以将字节数组转换为它们的十六进制字符串表示。

所以,可以像这样:

BitConverter.ToString(CalculateMD5(theStream)).Replace("-","");

将为您获取该MD5哈希的典型十六进制字符串表示形式。

2
您无法阅读它,因为它是一组字节,需要使用适当的编码将其转换为可读字符串。

例如,在SHA256类中生成哈希值:
using (System.Security.Cryptography.SHA256 sha = System.Security.Cryptography.SHA256.Create())
      return sha.ComputeHash(data);

然后,如果你想把它转换成字符串以便以可读的形式查看:
string hashValue = Convert.ToBase64String(hash);

当然,除了SHA256和MD5之外,还有其他算法可以生成哈希(有或没有盐)。其中other

0
你尝试过使用CalculateMD5(theStream).ToString()吗?不确定它是否有帮助,但值得一试。
另外,我建议你将CalculateMD5(theStream)的结果保存在本地变量中,然后再进行.ToString()操作。
祝好运,希望有所帮助。

不,这样行不通。Console.WriteLine((new byte[] { 1, 2, 3 }).ToString());会打印出System.Byte[],这不是期望的输出。 - mdm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接