如何使用ios swift将字符串转换为MD5哈希

use*_*682 96 md5 ios swift

我想转换用户输入或假设任何字符串如"abc"到MD5哈希.我想在ios swift中这样做.我已经提到了以下链接,但解决方案对我不起作用,或者我很困惑,因为我是快速编程的新手,所以我很难实现它.有人可以通过明确的步骤来帮助我实现这一目标.提前致谢!

在Swift框架中导入CommonCrypto

如何在swift语言中使用CC_MD5方法.

http://iosdeveloperzone.com/2014/10/03/using-commoncrypto-in-swift/

为了更清楚,我希望像在php中一样快速实现这一点.

$str = "Hello";

echo md5($str);
Run Code Online (Sandbox Code Playgroud)

输出:8b1a9953c4611296a827abf8c47804d7

zap*_*aph 155

有两个步骤:
1.从字符串创建md5数据
2.将md5数据转换为十六进制字符串

Swift 2.0

func md5(string string: String) -> String {
    var digest = [UInt8](count: Int(CC_MD5_DIGEST_LENGTH), repeatedValue: 0)
    if let data = string.dataUsingEncoding(NSUTF8StringEncoding) {
        CC_MD5(data.bytes, CC_LONG(data.length), &digest)
    }

    var digestHex = ""
    for index in 0..<Int(CC_MD5_DIGEST_LENGTH) {
        digestHex += String(format: "%02x", digest[index])
    }

    return digestHex
}

//Test:
let digest = md5(string:"Hello")
print("digest: \(digest)")
Run Code Online (Sandbox Code Playgroud)

输出:

摘要:8b1a9953c4611296a827abf8c47804d7

Swift 3.0:

func MD5(string: String) -> Data {
    let messageData = string.data(using:.utf8)!
    var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))

    _ = digestData.withUnsafeMutableBytes {digestBytes in
        messageData.withUnsafeBytes {messageBytes in
            CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
        }
    }

    return digestData
}

//Test:
let md5Data = MD5(string:"Hello")

let md5Hex =  md5Data.map { String(format: "%02hhx", $0) }.joined()
print("md5Hex: \(md5Hex)")

let md5Base64 = md5Data.base64EncodedString()
print("md5Base64: \(md5Base64)")
Run Code Online (Sandbox Code Playgroud)

输出:

md5Hex:8b1a9953c4611296a827abf8c47804d7
md5Base64:ixqZU8RhEpaoJ6v4xHgE1w ==

注意:
#import <CommonCrypto/CommonCrypto.h>必须添加到Bridging-Header文件中

有关如何创建桥接标题,请参阅此SO答案.

一般来说,MD5不应该用于新工作,SHA256是当前的最佳实践.

不推荐使用的文档部分示例:

MD2,MD4,MD5,SHA1,SHA224,SHA256,SHA384,SHA512(Swift 3+)

这些函数将使用八种加密哈希算法之一对String或Data输入进行散列.

name参数指定散列函数名称为字符串
支持的函数是MD2,MD4,MD5,SHA1,SHA224,SHA256,SHA384和SHA512 a此示例需要Common Crypto
必须为项目设置桥接头:
#import <CommonCrypto/CommonCrypto.h>
添加安全性.框架到项目.



此函数将哈希名称和字符串进行哈希处理并返回一个数据:

import Foundation
import var CommonCrypto.CC_MD5_DIGEST_LENGTH
import func CommonCrypto.CC_MD5
import typealias CommonCrypto.CC_LONG

func MD5(string: String) -> Data {
        let length = Int(CC_MD5_DIGEST_LENGTH)
        let messageData = string.data(using:.utf8)!
        var digestData = Data(count: length)

        _ = digestData.withUnsafeMutableBytes { digestBytes -> UInt8 in
            messageData.withUnsafeBytes { messageBytes -> UInt8 in
                if let messageBytesBaseAddress = messageBytes.baseAddress, let digestBytesBlindMemory = digestBytes.bindMemory(to: UInt8.self).baseAddress {
                    let messageLength = CC_LONG(messageData.count)
                    CC_MD5(messageBytesBaseAddress, messageLength, digestBytesBlindMemory)
                }
                return 0
            }
        }
        return digestData
    }

//Test:
let md5Data = MD5(string:"Hello")

let md5Hex =  md5Data.map { String(format: "%02hhx", $0) }.joined()
print("md5Hex: \(md5Hex)")

let md5Base64 = md5Data.base64EncodedString()
print("md5Base64: \(md5Base64)")
Run Code Online (Sandbox Code Playgroud)
name: A name of a hash function as a String  
string: The String to be hashed  
returns: the hashed result as Data  

例子:

func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}
Run Code Online (Sandbox Code Playgroud)

输出:

let clearString = "clearData0123456"
let clearData   = clearString.data(using:.utf8)!
print("clearString: \(clearString)")
print("clearData: \(clearData as NSData)")

let hashSHA256 = hash(name:"SHA256", string:clearString)
print("hashSHA256: \(hashSHA256! as NSData)")

let hashMD5 = hash(name:"MD5", data:clearData)
print("hashMD5: \(hashMD5! as NSData)")
Run Code Online (Sandbox Code Playgroud)

  • 谢谢alottt @zaph,我在2天多的时间里为此苦苦挣扎.用你的上面的答案得到解决:)是的我从使用MD5的网络中检索旧数据,所以我被迫使用MD5.但再次感谢使用SHA256的答案和建议:) (3认同)
  • @zaph,您可能希望将 iOS 13 CryptoKit 解决方案添加到您的答案中,我在下面的答案中对此进行了详细说明:/sf/answers/3960529681/ (2认同)

dig*_*und 31

在阅读了这里的其他答案(并且还需要支持其他哈希类型)之后,我编写了一个处理多种哈希类型和输出类型的String扩展.

注:CommonCrypto包含在Xcode 10,所以你可以简单import CommonCrypto而无需使用桥接报一塌糊涂,如果你安装了最新版本的Xcode ...否则一个桥接报头是必要的.

SWIFT 4+

字符串+ Crypto.swift

import Foundation
import CommonCrypto

// Defines types of hash string outputs available
public enum HashOutputType {
    // standard hex string output
    case hex
    // base 64 encoded string output
    case base64
}

// Defines types of hash algorithms available
public enum HashType {
    case md5
    case sha1
    case sha224
    case sha256
    case sha384
    case sha512

    var length: Int32 {
        switch self {
        case .md5: return CC_MD5_DIGEST_LENGTH
        case .sha1: return CC_SHA1_DIGEST_LENGTH
        case .sha224: return CC_SHA224_DIGEST_LENGTH
        case .sha256: return CC_SHA256_DIGEST_LENGTH
        case .sha384: return CC_SHA384_DIGEST_LENGTH
        case .sha512: return CC_SHA512_DIGEST_LENGTH
        }
    }
}

public extension String {

    /// Hashing algorithm for hashing a string instance.
    ///
    /// - Parameters:
    ///   - type: The type of hash to use.
    ///   - output: The type of output desired, defaults to .hex.
    /// - Returns: The requested hash output or nil if failure.
    public func hashed(_ type: HashType, output: HashOutputType = .hex) -> String? {

        // convert string to utf8 encoded data
        guard let message = data(using: .utf8) else { return nil }
        return message.hashed(type, output: output)
    } 
}
Run Code Online (Sandbox Code Playgroud)

数据+ Crypto.swift

import Foundation
import CommonCrypto

extension Data {

    /// Hashing algorithm that prepends an RSA2048ASN1Header to the beginning of the data being hashed.
    ///
    /// - Parameters:
    ///   - type: The type of hash algorithm to use for the hashing operation.
    ///   - output: The type of output string desired.
    /// - Returns: A hash string using the specified hashing algorithm, or nil.
    public func hashWithRSA2048Asn1Header(_ type: HashType, output: HashOutputType = .hex) -> String? {

        let rsa2048Asn1Header:[UInt8] = [
            0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
            0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
        ]

        var headerData = Data(rsa2048Asn1Header)
        headerData.append(self)

        return hashed(type, output: output)
    }

    /// Hashing algorithm for hashing a Data instance.
    ///
    /// - Parameters:
    ///   - type: The type of hash to use.
    ///   - output: The type of hash output desired, defaults to .hex.
    ///   - Returns: The requested hash output or nil if failure.
    public func hashed(_ type: HashType, output: HashOutputType = .hex) -> String? {

        // setup data variable to hold hashed value
        var digest = Data(count: Int(type.length))

        _ = digest.withUnsafeMutableBytes{ digestBytes -> UInt8 in
            self.withUnsafeBytes { messageBytes -> UInt8 in
                if let mb = messageBytes.baseAddress, let db = digestBytes.bindMemory(to: UInt8.self).baseAddress {
                    let length = CC_LONG(self.count)
                    switch type {
                    case .md5: CC_MD5(mb, length, db)
                    case .sha1: CC_SHA1(mb, length, db)
                    case .sha224: CC_SHA224(mb, length, db)
                    case .sha256: CC_SHA256(mb, length, db)
                    case .sha384: CC_SHA384(mb, length, db)
                    case .sha512: CC_SHA512(mb, length, db)
                    }
                }
                return 0
            }
        }

        // return the value based on the specified output type.
        switch output {
        case .hex: return digest.map { String(format: "%02hhx", $0) }.joined()
        case .base64: return digest.base64EncodedString()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:由于散列实际上发生在数据上,我将散列算法拆分为数据扩展.这允许相同的算法也用于SSL证书固定哈希操作.

以下是如何将其用于SSL固定操作的简短示例:

import Foundation
import CommonCrypto 

extension Data {

    /// Hashing algorithm that prepends an RSA2048ASN1Header to the beginning of the data being hashed.
    ///
    /// - Parameters:
    ///   - type: The type of hash algorithm to use for the hashing operation.
    ///   - output: The type of output string desired.
    /// - Returns: A hash string using the specified hashing algorithm, or nil.
    public func hashWithRSA2048Asn1Header(_ type: HashType, output: HashOutputType = .hex) -> String? {

        let rsa2048Asn1Header:[UInt8] = [
            0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
            0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
        ]

        var headerData = Data(bytes: rsa2048Asn1Header)
        headerData.append(self)

        return hashed(type, output: output)
    }

    /// Hashing algorithm for hashing a Data instance.
    ///
    /// - Parameters:
    ///   - type: The type of hash to use.
    ///   - output: The type of hash output desired, defaults to .hex.
    ///   - Returns: The requested hash output or nil if failure.
    public func hashed(_ type: HashType, output: HashOutputType = .hex) -> String? {

        // setup data variable to hold hashed value
        var digest = Data(count: Int(type.length))

        // generate hash using specified hash type
        _ = digest.withUnsafeMutableBytes { (digestBytes: UnsafeMutablePointer<UInt8>) in
            self.withUnsafeBytes { (messageBytes: UnsafePointer<UInt8>) in
                let length = CC_LONG(self.count)
                switch type {
                case .md5: CC_MD5(messageBytes, length, digestBytes)
                case .sha1: CC_SHA1(messageBytes, length, digestBytes)
                case .sha224: CC_SHA224(messageBytes, length, digestBytes)
                case .sha256: CC_SHA256(messageBytes, length, digestBytes)
                case .sha384: CC_SHA384(messageBytes, length, digestBytes)
                case .sha512: CC_SHA512(messageBytes, length, digestBytes)
                }
            }
        }

        // return the value based on the specified output type.
        switch output {
        case .hex: return digest.map { String(format: "%02hhx", $0) }.joined()
        case .base64: return digest.base64EncodedString()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

回到原来的答案

我用这个测试了哈希算法:

// Certificate pinning - get certificate as data
let data: Data = SecCertificateCopyData(serverCertificate) as Data

// compare hash of server certificate with local (expected) hash value
guard let serverHash = data.hashWithRSA2048Asn1Header(.sha256, output: .base64), serverHash == storedHash else {
    print("SSL PINNING: Server certificate hash does not match specified hash value.")
    return false
}
Run Code Online (Sandbox Code Playgroud)

这是打印结果:

let value = "This is my string"

if let md5 = value.hashed(.md5) {
    print("md5: \(md5)")
}
if let sha1 = value.hashed(.sha1) {
    print("sha1: \(sha1)")
}
if let sha224 = value.hashed(.sha224) {
    print("sha224: \(sha224)")
}
if let sha256 = value.hashed(.sha256) {
    print("sha256: \(sha256)")
}
if let sha384 = value.hashed(.sha384) {
    print("sha384: \(sha384)")
}
if let sha512 = value.hashed(.sha512) {
    print("sha512: \(sha512)")
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢Swift 5更新 (2认同)

waj*_*jih 28

SWIFT 3版本md5 function:

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
}
Run Code Online (Sandbox Code Playgroud)

来自http://iosdeveloperzone.com的原始链接


小智 22

Swift 4.*,Xcode 10更新:

在Xcode 10中,您不必再使用Bridging-Header,您可以直接使用

import CommonCrypto
Run Code Online (Sandbox Code Playgroud)

然后写一个类似于的方法:

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])
        }
    }
Run Code Online (Sandbox Code Playgroud)

用法:

MD5("This is my string")
Run Code Online (Sandbox Code Playgroud)

输出:

c2a9ce57e8df081b4baad80d81868bbb
Run Code Online (Sandbox Code Playgroud)


Nik*_*uhe 17

我发布了一个纯粹的Swift实现,它不依赖于CommonCrypto或其他任何东西.它在MIT许可下可用.

代码由一个swift文件组成,您可以将其放入项目中.如果您愿意,还可以将包含的Xcode项目与框架和单元测试目标一起使用.

它使用简单:

let input = "The quick brown fox jumps over the lazy dog"
let digest = input.utf8.md5
print("md5: \(digest)")
Run Code Online (Sandbox Code Playgroud)

打印: md5: 9e107d9d372bb6826bd81d3542a419d6

swift文件包含文档和更多示例.

  • 需要此处未提及的Swift 4或Github自述文件.如果没有与Common Crypto相比提供的性能数据,则不应考虑使用.注意:Common Crypto是FIPS 140认证的,而SwiftDigest则不是.这是一个关键问题:这比Common Crypto更好地实现了吗?更安全:不,更快:不. (4认同)
  • @zaph我同意安全相关的实现不能掉以轻心.但MD5除了安全性之外还有其他用途 - 或者说,安全性是MD5表现最差的地方.散列算法用于识别,排序,存储,字典,错误检测和其他原因.MD5因其无处不在而特别有用.所以,虽然我同意你的一些意见,但我不同意这个要点.我认为你的观点和争论太狭隘了; 它不包含整个主题. (3认同)
  • 另外,我刚测试过,我的实现比CommonCrypto更快的大消息:) (2认同)
  • 我喜欢这个实现.非常感谢@NikolaiRuhe!我能够轻松地将其转换为Swift 3兼容性.我还添加了一些方便的方法,包括计算给定URL的文件内容的摘要,以及检索base64编码(对于Content-MD5等有用).@Siddharth你需要的唯一文件是MD5Digest.swift. (2认同)

Rad*_*che 16

Swift 5.3你可以做

import CryptoKit

func md5Hash(_ source: String) -> String {
    return Insecure.MD5.hash(data: source.data(using: .utf8)!).map { String(format: "%02hhx", $0) }.joined()
}
Run Code Online (Sandbox Code Playgroud)


Hug*_*nso 10

这里只有两个注释:

使用Crypto实现这一目标的开销太大了.

接受的答案是完美的!不过我只是想用Swift 2.2分享一个Swift ier代码方法.

请记住,您仍然必须#import <CommonCrypto/CommonCrypto.h>在您的Bridging-Header文件中

struct MD5Digester {
    // return MD5 digest of string provided
    static func digest(string: String) -> String? {

        guard let data = string.dataUsingEncoding(NSUTF8StringEncoding) else { return nil }

        var digest = [UInt8](count: Int(CC_MD5_DIGEST_LENGTH), repeatedValue: 0)

        CC_MD5(data.bytes, CC_LONG(data.length), &digest)

        return (0..<Int(CC_MD5_DIGEST_LENGTH)).reduce("") { $0 + String(format: "%02x", digest[$1]) }
    }
}
Run Code Online (Sandbox Code Playgroud)


Tam*_*gel 9

Swift 5作为字符串扩展回答(基于Invictus Cody 的精彩回答):

import CommonCrypto

extension String {
    var md5Value: String {
        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 ""
            }
        }

        return (0 ..< length).reduce("") {
            $0 + String(format: "%02x", digest[$1])
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

print("test".md5Value) /*098f6bcd4621d373cade4e832627b4f6*/
Run Code Online (Sandbox Code Playgroud)


mlu*_*own 7

iOS 13开始, Apple已添加CryptoKit框架,因此您不再需要导入CommonCrypto或处理其C API:

import Foundation
import CryptoKit

func MD5(string: String) -> String {
    let digest = Insecure.MD5.hash(data: string.data(using: .utf8) ?? Data())

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

Run Code Online (Sandbox Code Playgroud)

  • 还值得注意的是,这提供了一种避免有关 MD5 现在不安全的警告的方法。您不需要在 Objective-C 中实现 CommonCrypto,以便支持编译指示来禁用警告。如果您在强调处理警告的环境中工作,这会很方便。 (4认同)
  • 请注意,要将摘要转换为 Base64 编码格式而不是十六进制格式,请将 return 语句更改为“return Data(digest).base64EncodedString()” (2认同)

小智 6

这是基于zaph答案的扩展

extension String{
    var MD5:String {
        get{
            let messageData = self.data(using:.utf8)!
            var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))

            _ = digestData.withUnsafeMutableBytes {digestBytes in
                messageData.withUnsafeBytes {messageBytes in
                    CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
                }
            }

            return digestData.map { String(format: "%02hhx", $0) }.joined()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

与swift 3.0完全兼容#import <CommonCrypto/CommonCrypto.h>.你仍然必须在你的Bridging-Header文件中