保存到相册后,相机图像的SHA256有所不同

时间:2019-04-26 13:32:02

标签: ios swift

Xcode 10.2Swift 5

我从相机中拾取图像,并将图像的SHA256哈希计算为字符串,然后将图像保存到iPhone相册中。

//Save photo to album. Photo comes from UIImagePickerController
UIImageWriteToSavedPhotosAlbum(self.photo, self, #selector(saveimage(_:didFinishSavingWithError:contextInfo:)), nil)

//Calculate hash
let imageData : Data = self.photo!.pngData()! 
let imageHash : String = getImageHash(data: imageData)    

func getImageHash(data : Data) -> String {

    var hashBytes = [UInt8](repeating: 0,  count: Int(CC_SHA256_DIGEST_LENGTH))
    data.withUnsafeBytes {
        _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hashBytes)
    }

    var hex = ""
    for index in 0..<Int(CC_SHA256_DIGEST_LENGTH) {
        hex += String(format: "%02x", hashBytes[index])
    }
    print(hex)
    return hex
}

但是,代码为我提供的图像的SHA256与保存后的图像不同。我将照片转移到Mac上,并通过shasum -a 256检查了哈希,然后将其直接从iPhone上传到了在线哈希生成器,该哈希生成器提供了与Mac相同的哈希。

因此,我计算哈希值的代码错误或使用UIImageWriteToSavedPhotosAlbum(...)存储照片时更改了名称或属性之类的内容。有任何解决方法的想法吗?

1 个答案:

答案 0 :(得分:2)

我对此事进行了进一步的研究,看来您在UIImage中拥有的数据确实与您作为文件打开的数据不同,我相信这正是导致问题的原因。请注意,出于可读性考虑,我缩短了base64数据。

迅速

func getImageHash(data: Data) -> String {
    var hashBytes = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)
    data.withUnsafeBytes {
        _ = CC_SHA256($0.baseaddress, CC_LONG(data.count), &hashBytes)
    }
    var hex = ""
    for index in 0 ..< Int(CC_SHA256_DIGEST_LENGTH) {
        hex += String(format: "%02x", hashbytes[index])
    }
    return hex
}

该功能很好,我将使用iOS的Assets文件夹作为示例。

let imageData = UIImage(named: "Example")!.pngData()!
print(imageData.base64EncodedString())
// 'iVBORw0KGgoAAAANSUhEUgAAAG8AAACACAQAAACv3v+8AAAM82lD [...] gAAAABJRU5ErkJggg=='
let imageHash = getImageHash(data: imageData)
print(imageHash)
// '145036245c9f675963cc8de2147887f9feded5813b0539d2320d201d9ce63397'

就我们目前而言,哈希计算正确。我对base64数据很感兴趣,因此我也可以在其他平台上使用它。

Python

import hashlib
import base64

img_d = base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAG8AAACACAQAAACv3v+8AAAM82lD [...] gAAAABJRU5ErkJggg==')
m = hashlib.sha256()
m.update(img_d)
m.digest().hex()
# '145036245c9f675963cc8de2147887f9feded5813b0539d2320d201d9ce63397'

因此,似乎哈希计算正确,但仅针对base64数据。那么区别是什么呢?让我们再次使用Python进行调查。我使用PIL直接加载图像。

import hashlib
from PIL import Image

i = Image.open('/path/to/file')
img_d = i.tobytes()
m = hashlib.sha256()
m.update(img_d)
m.digest().hex()
# 'f650b1b95a50c3a2b77da7a0825c3c01066385a12c8fe50b449ffc8c7249e370'

所以现在我们确实有了一个不同的哈希。让我们在终端中尝试最后一件事openssl dgst

终端

echo 'iVBORw0KGgoAAAANSUhEUgAAAG8AAACACAQAAACv3v+8AAAM82lD [...] gAAAABJRU5ErkJggg==' | base64 --decode | openssl dgst -sha256
145036245c9f675963cc8de2147887f9feded5813b0539d2320d201d9ce63397

好吧,的确,openssl摘要可以计算base64数据上的哈希,并且确实匹配。

openssl dgst -sha256 /path/to/file
SHA256(/path/to/file)= d15c2d0c186a46b41c34a312eaf1c7e4b0f7a51bdb9c53a91dc361385ba23e64

所以这很有趣。散列的base64数据具有100%的成功率,但是在Python和终端中加载它们会导致两个不同的哈希。我不知道它们为何不同的原因。我确实相信我在前面的评论中提到的内容是正确的,对文件进行哈希处理将导致不同的哈希,因为文件的元数据也将进行哈希处理。

为了提供解决方案:请尝试对原始图像数据而不是文件进行哈希处理。这是最大的成功机会。希望这会有所帮助。