在Swift 3中使用ansi字符串上的MD5哈希值

时间:2017-03-07 18:51:12

标签: swift hash md5

我有一个小函数,它接受一个字符串并返回其MD5哈希值。问题是,它需要一个UTF8字符串,我需要它来计算用iso-8859-1(~ansi)编码的字节数组的哈希值。

如何更改以下代码以接受字节数组,然后返回其散列值?

static func md5(_ string: String) -> String {
    let context = UnsafeMutablePointer<CC_MD5_CTX>.allocate(capacity: 1)
    var digest = Array<UInt8>(repeating:0, count:Int(CC_MD5_DIGEST_LENGTH))
    CC_MD5_Init(context)
    CC_MD5_Update(context, string, CC_LONG(string.lengthOfBytes(using: String.Encoding.utf8)))
    CC_MD5_Final(&digest, context)
    context.deallocate(capacity: 1)
    var hexString = ""
    for byte in digest {
        hexString += String(format:"%02x", byte)
    }

    return hexString
}

棘手的部分是CC_MD5_Update调用。感谢。

3 个答案:

答案 0 :(得分:1)

您可以轻松修改函数以获取任意字节 数组作为参数。 CC_MD5_Update映射到Swift为

func CC_MD5_Update(_ c: UnsafeMutablePointer<CC_MD5_CTX>!, _ data: UnsafeRawPointer!, _ len: CC_LONG) -> Int32

您可以将数组作为UnsafeRawPointer参数传递:

func md5(bytes: [UInt8]) -> String {
    var context = CC_MD5_CTX()
    var digest = Array<UInt8>(repeating:0, count:Int(CC_MD5_DIGEST_LENGTH))
    CC_MD5_Init(&context)
    CC_MD5_Update(&context, bytes, CC_LONG(bytes.count))
    CC_MD5_Final(&digest, &context)
    return digest.map { String(format: "%02hhx", $0) }.joined()
}

(我也简化了一点。)

或者,传递一个Data参数:

func md5(data: Data) -> String {
    var context = CC_MD5_CTX()
    var digest = Array<UInt8>(repeating:0, count:Int(CC_MD5_DIGEST_LENGTH))
    CC_MD5_Init(&context)
    data.withUnsafeBytes {
        _ = CC_MD5_Update(&context, $0, CC_LONG(data.count))
    }
    CC_MD5_Final(&digest, &context)
    return digest.map { String(format: "%02hhx", $0) }.joined()
}

然后可以用作

let s = "foo"
if let data = s.data(using: .isoLatin1) {
    let hash = md5(data: data)
    print(hash)
}
Swift 5:

更新

import CommonCrypto

func md5(data: Data) -> String {
    var context = CC_MD5_CTX()
    var digest = Array<UInt8>(repeating:0, count:Int(CC_MD5_DIGEST_LENGTH))
    CC_MD5_Init(&context)
    data.withUnsafeBytes {
        _ = CC_MD5_Update(&context, $0.baseAddress, CC_LONG(data.count))
    }
    CC_MD5_Final(&digest, &context)
    return digest.map { String(format: "%02hhx", $0) }.joined()
}

答案 1 :(得分:0)

如果您确定自己的字符串&#39;仅包含utf8字符,使用string.utf8调用CC_MD5_Update:

CC_MD5_Update(context, string.utf8, CC_LONG(string.lengthOfBytes(using: String.Encoding.utf8)))

swift中的字符串很有趣&#39;,这是关于这个主题的好读物:https://oleb.net/blog/2016/08/swift-3-strings/

答案 2 :(得分:0)

// requires a bridging header with this:
// #import <CommonCrypto/CommonCrypto.h>
func MD5(_ string: String) -> String? {
    let length = Int(CC_MD5_DIGEST_LENGTH)
    var digest = [UInt8](repeating: 0, count: length)
    if let d = string.data(using: String.Encoding.utf8) {
        d.withUnsafeBytes { (body: UnsafePointer<UInt8>) in
            CC_MD5(body, CC_LONG(d.count), &digest)
        }
    }
    return (0..<length).reduce("") {
        $0 + String(format: "%02x", digest[$1])
    }
}

Justin回答:https://gist.github.com/jstn/787da74ab4be9d4cf3cb