19

在 Swift 4 中,我们可以使用

var md5: String? {
    guard let data = self.data(using: .utf8) else { return nil }
    let hash = data.withUnsafeBytes { (bytes: UnsafePointer<Data>) -> [UInt8] in
        var hash: [UInt8] = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        CC_MD5(bytes, CC_LONG(data.count), &hash)
        return hash
    }
    return hash.map { String(format: "%02x", $0) }.joined()
}

但在 Swift 5 中withUnsafeBytes使用UnsafeRawBufferPointer而不是UnsafePointer. 如何更改 md5 功能?

4

5 回答 5

31

Swift 5 版本:UnsafeRawBufferPointer用作闭包参数的类型,bytes.baseAddress并将地址传递给 Common Crypto 函数:

import Foundation
import CommonCrypto

extension String {
    var md5: String {
        let data = Data(self.utf8)
        let hash = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) -> [UInt8] in
            var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
            CC_MD5(bytes.baseAddress, CC_LONG(data.count), &hash)
            return hash
        }
        return hash.map { String(format: "%02x", $0) }.joined()
    }
}

(注意,字符串到 UTF-8 数据的转换不能失败,不需要返回可选项。)

CC_MD5 已在 iOS 13 中弃用。相反,您可以使用 CC_SHA256。

于 2019-03-26T12:04:05.827 回答
11

在 iOS 13 及更高版本中,有一个框架是框架和 MD5 哈希函数CryptoKit的包装器。CommonCrypto

import CryptoKit

let d = "Hello"
let r = Insecure.MD5.hash(data: d.data(using: .utf8)!)
print(r)

/*Output: MD5 digest: 8b1a9953c4611296a827abf8c47804d7*/
于 2020-02-28T12:42:01.980 回答
8

在 iOS 13 及更高版本中,有一个框架CryptoKit。尝试使用这个:

extension Data {       
    var md5: String {
        Insecure.MD5
            .hash(data: self)
            .map {String(format: "%02x", $0)}
            .joined()
    }
}
于 2021-08-03T19:46:57.923 回答
6

爱斯基摩人的解决方案

以下是基于爱斯基摩人在 Swift 论坛帖子中提出的解决方案的变体,其中包含UnsafeBytes 数据 API 混淆

extension String {
    func md5() -> String {
        let data = Data(utf8)
        var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))

        data.withUnsafeBytes { buffer in
            _ = CC_MD5(buffer.baseAddress, CC_LONG(buffer.count), &hash)
        }

        return hash.map { String(format: "%02hhx", $0) }.joined()
    }
}

请注意,它实际上与 Martin R 的解决方案相同,但行更短(否return hash)。

使用 NSData 的解决方案

这是一个使用桥接到 NSData 的更短的解决方案。

extension String {
    func md5() -> String {
        let data = Data(utf8) as NSData
        var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        CC_MD5(data.bytes, CC_LONG(data.length), &hash)
        return hash.map { String(format: "%02hhx", $0) }.joined()
    }
}
于 2019-04-02T08:31:25.160 回答
1

CC_MD5 回馈“CC_MD5”在 iOS 13.0 中已被弃用:此功能在密码学上被破坏,不应在安全上下文中使用。客户端应迁移到 SHA256(或更高版本)。

所以要有一个灵活的解决方案:

//OLD
import CommonCrypto

//new:
import CryptoKit

extension String {
var md5: String {

    if #available(iOS 13.0, *) {

        guard let d = self.data(using: .utf8) else { return ""}
        let digest = Insecure.MD5.hash(data: d)
        let h = digest.reduce("") { (res: String, element) in
            let hex = String(format: "%02x", element)
            //print(ch, hex)
            let  t = res + hex
            return t
        }
        return h

    } else {
        // Fall back to pre iOS13
        let length = Int(CC_MD5_DIGEST_LENGTH)
        var digest = [UInt8](repeating: 0, count: length)
        
        if let d = self.data(using: .utf8) {
            _ = d.withUnsafeBytes { body -> String in
                CC_MD5(body.baseAddress, CC_LONG(d.count), &digest)
                return ""
            }
        }
        let result = (0 ..< length).reduce("") {
            $0 + String(format: "%02x", digest[$1])
        }
        return result

    }// end of fall back

}

}

去测试:

func MD5Test() -> Bool{
    let HASHED = "5D41402ABC4B2A76B9719D911017C592"
    let s = "hello"
    let md5_1 = s.md5
    if  md5_1.uppercased() != HASHED{
        return false
    }
    return true
}
于 2021-04-25T10:00:15.103 回答