【问题标题】:Using MD5 hash value on an ansi string in Swift 3在 Swift 3 中对 ansi 字符串使用 MD5 哈希值
【发布时间】:2017-03-07 18:51:12
【问题描述】:

我有一个小函数,它接受一个字符串并返回它的 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 调用。谢谢。

【问题讨论】:

    标签: swift hash md5


    【解决方案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()
    }
    

    【讨论】:

    • 谢谢!这就像一个魅力。我决定使用“数据”方法。感谢您的帮助,马丁。
    • 除此之外,digest.map { ... }.joined() 是一个不错的单行。
    【解决方案2】:

    如果您确定您的“字符串”仅包含 utf8 字符,请使用 string.utf8 调用 CC_MD5_Update:

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

    swift 中的字符串很“有趣”,这是一个很好的主题阅读:https://oleb.net/blog/2016/08/swift-3-strings/

    【讨论】:

      【解决方案3】:
      // 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])
          }
      }
      

      贾斯汀回答:https://gist.github.com/jstn/787da74ab4be9d4cf3cb

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-01
        • 2012-07-12
        • 2012-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多