为什么 MD5 散列如此困难并且在 Swift 3 中?

Why is MD5 hashing so hard and in Swift 3?

好的,所以你时不时会遇到一些你在使用各种框架和库之前已经解决的问题,以及在互联网上找不到的东西,你的问题解决得相对快速和容易,你也会了解为什么你的问题是首先是一个问题。

但是,有时您会遇到绝对意义为 0 的问题,当解决方案具有负面意义时更糟。

我的问题是我想使用 Data 并从中生成 MD5 散列。

我找到了各种解决方案,但其中 none 有效。

真正让我烦恼的是,对于从任何东西中获取 MD5 哈希值这样的琐碎任务,解决方案似乎是多么不必要的复杂。

我正在尝试使用 SoffesCryptoCommonCrypto 框架,它们看起来相当简单,对吧?对吧?

是的!

但为什么我仍然收到错误 fatal error: unexpectedly found nil while unwrapping an Optional value

据我了解,myData.md5SoffesCrypto 的扩展中提供的数据似乎是 "optional"。但是为什么?

我要执行的代码是:

print(" md5 result: " + String(data: myData.md5, encoding: .utf8)!)

其中 myData 100% 有数据,因为在上面的代码行之后,我将该数据发送到服务器,并且数据存在。

最重要的是,通过 print(String(myData.md5.count)) 打印 myData.md5.count 的计数非常有效。

所以我的问题基本上是:如何对数据进行 MD5 哈希处理并将其打印为字符串?

编辑:

我试过的

有效

MD5: 在 PHP 脚本中输入字符串 test 得到 098f6bcd4621d373cade4e832627b4f6 Swift 代码 "test".md5() 也给了我 098f6bcd4621d373cade4e832627b4f6

不行

UInt8 字节数组从 Data.md5() 转换为表示正确 MD5 值的字符串。

我做过的不同测试如下:

var hash = ""
for byte in myData.data.md5() {
    hash +=  String(format: "%02x", byte)
}
print("loop = " + hash) //test 1

print("myData.md5().toHexString() = " +  myData.md5().toHexString()) //test 2

print("CryptoSwift.Digest.md5([UInt8](myData)) = " + CryptoSwift.Digest.md5([UInt8](myData)).toHexString()) //test 3

使用 500 字节测试数据的所有三个测试都给我 MD5 值 56f6955d148ad6b6abbc9088b4ae334d 而我的 PHP 脚本给了我 6081d190b3ec6de47a74d34f6316ac6b

测试样本(64字节): 原始数据:

FFD8FFE0 00104A46 49460001 01010048 00480000 FFE13572 45786966 00004D4D
002A0000 0008000B 01060003 00000001 00020000 010F0002 00000012 00000092

测试 1、2 和 3 MD5:7f0a012239d9fde5a46071640d2d8c83

PHP MD5: 06eb0c71d8839a4ac91ee42c129b8ba3

PHP代码:echo md5($_FILES["file"]["tmp_name"])

我使用一个名为 'CryptoSwift' 的库来创建散列,并在发送 it/store 之前加密数据。非常好用。

它可以在这里 https://github.com/krzyzanowskim/CryptoSwift 找到,您甚至可以通过将 pod 'CryptoSwift' 添加到您的 podfile 来使用 CocoaPods 安装它。

安装后,散列 Data 对象就像调用 Data.md5() 一样简单!它真的很容易。它还支持其他哈希算法,例如 SHA.

然后您可以只打印 MD5 对象,CryptoSwift 会为您将其转换为字符串。

有关创建摘要的完整文档可在此处找到:https://github.com/krzyzanowskim/CryptoSwift#calculate-digest

感谢 Jacob King,我尝试了一个更简单的 MD5 框架,称为 CryptoSwift。

用户 Codo 启发我深入研究我的 PHP 脚本,因为他建议我实际上不是在散列数据内容,而是文件名,这是正确的。

然而,最初的问题不是关于使用哪个框架或关于为什么我的应用程序和我的 PHP 脚本 return 不同 MD5 值的建议。

问题最初是关于为什么我会收到错误

fatal error: unexpectedly found nil while unwrapping an Optional value

在代码行说

print(" md5 result: " + String(data: myData.md5, encoding: .utf8)!)

所以答案是我不应该尝试转换 MD5() 函数的 16 字节数据输出,而是调用 MD5() 的子函数 toHexString()

所以正确的代码行应该如下所示:

print("md5 result: " + myData.md5().toHexString())

奖金

我的 PHP 脚本现在包含以下代码:

move_uploaded_file($_FILES["file"]["tmp_name"], $target_dir); //save data to disk
$md5_of_data = md5_file ($target_dir); //get MD5 of saved data

奖金-奖金 问题和解决方案是我正在研究的一个名为 AssetManager 的小框架的一部分,可以在这里找到:https://github.com/aidv/AssetManager

您问题的简单答案是:

String(data: someData, encoding: .utf8)

returns nil 如果 someData 不是正确的 UTF8 编码数据。如果您尝试像这样打开 nil

String(data: someDate, encoding: .utf8)!

你得到:

fatal error: unexpectedly found nil while unwrapping an Optional value

所以它的核心与散列或加密无关。

MD5(或与此相关的任何哈希算法)的输入和输出都是二进制数据(而不是文本或字符串)。所以MD5的输出不是UTF8编码的数据。这就是为什么上面的字符串初始化器总是失败。

如果您想在控制台中显示二进制数据,您需要将其转换为可读的表示形式。最常见的是十六进制数字或Base 64编码。

注意:一些加密库允许您将字符串输入到它们的哈希函数中。他们会使用某种字符编码将字符串默默地转换为二进制表示形式。如果编码不匹配,则散列值在系统和编程语言之间不匹配。所以你最好试着理解为什么他们真的在后台做。