如何使用 Swift 将 iOS 中的 String 转换为 MD5散列?

我希望将类似“ abc”的字符串转换为 MD5散列。我想在 iOS 和 Swift 上做这个。我尝试使用下面的解决方案,但它们对我不起作用:

在 Swift 框架中导入 Common Crypto

如何在快速语言中使用 CC _ MD5方法。

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

更明确地说,我想在 Swift 中实现一个类似于这个 PHP 代码的输出:

$str = "Hello";


echo md5($str);

产出: 8b1a9953c4611296a827abf8c47804d7

114399 次浏览

有两个步骤:
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)")

产出:

摘要: 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)")

产出:

Md5Hex: 8b1a9953c4611296a827abf8c47804d7
Md5Base64: ixqZU8RhEpaoJ6v4xHgE1w = =

Swift 5.0:

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)")

产出:

Md5Hex: 8b1a9953c4611296a827abf8c47804d7
Md5Base64: ixqZU8RhEpaoJ6v4xHgE1w = =

备注:
必须将 #import <CommonCrypto/CommonCrypto.h>添加到桥接头文件中

有关如何创建桥接头,请参见 这么回答

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

弃用文档部分的例子:

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

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

Name 参数将散列函数名指定为 String
支持的函数有 MD2、 MD4、 MD5、 SHA1、 SHA224、 SHA256、 SHA384和 SHA512 一 这个例子需要公共密码
有必要为项目设置一个桥接头:
#import <CommonCrypto/CommonCrypto.h>
向项目中添加 Security.Framework。



这个函数接受一个散列名称和要散列的字符串,并返回一个 Data:

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)
}

例子:

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)")

产出:

clearString: clearData0123456
clearData: <636c6561 72446174 61303132 33343536>


hashSHA256: <aabc766b 6b357564 e41f4f91 2d494bcc bfa16924 b574abbd ba9e3e9d a0c8920a>
hashMD5: <4df665f7 b94aea69 695b0e7b baf9e9d6>

我利用迦太基和塞浦路斯做到了这一点。

  1. 安装迦太基,如果你还没有这样做

  2. 将 Crypto 安装到项目中

  3. 执行「车辆更新」

  4. 如果您从命令行运行,请将框架添加到 Swift 文件中

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
    
  5. Add import Crypto to your swift file.

  6. then it just works!

    print( "convert this".MD5 )
    

这里只有两个注意事项:

使用 加密实现这一点开销太大。

接受的答案是完美的! 然而,我只是想分享一个使用 Swift 2.2斯威夫特 更好代码方法。

请记住,您仍然必须在您的 桥头文件 #import <CommonCrypto/CommonCrypto.h>

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]) }
}
}

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
}

原始链接从 http://iosdeveloperzone.com

这是基于 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()
}
}
}

完全兼容迅捷3.0。您仍然必须在您的桥接头文件的 #import <CommonCrypto/CommonCrypto.h>

我发布了一个 纯 Swift 实现,它不依赖于 CommonCrypto 或者其他任何东西。

代码由一个 快速单列纵队组成,您可以直接将它放到项目中。如果您愿意,还可以将包含的 Xcode 项目与框架和单元测试目标一起使用。

使用起来很简单:

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

指纹: md5: 9e107d9d372bb6826bd81d3542a419d6

快速文件包含文档和更多示例。

MD5是一个哈希算法,不需要使用庞大的 CommonCrypto 库(并且会被 Apple 的评论拒绝) ,只需使用任何 md5哈希库。

我使用的一个这样的库是 SwiftHash,它是 MD5(基于 http://pajhome.org.uk/crypt/md5/md5.html)的一个纯粹的快速实现

在阅读了这里的其他答案之后(也需要支持其他散列类型) ,我编写了一个 String 扩展来处理多个散列类型和输出类型。

NOTE: CommonCrypto is included in Xcode 10, so you can simply import CommonCrypto without having to mess with a bridging header if you have the latest Xcode version installed... Otherwise a bridging header is necessary.


更新: Swift 4和5都使用下面相同的 String + Crypto.ift 文件。

Swift 5有一个独立的 Data + Crypto.ift 文件(见下文) ,用于‘ withUnsafeMutableBytes’和‘ withUnsafeBytes’的 api 在 Swift 4和5之间更改。


String + Crypto.Swift ——(同时适用于 Swift 4和5)

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)
}
}

5 —— Data + 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()
}
}
}

4 —— Data + 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(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()
}
}
}

编辑: 因为哈希实际上发生在数据上,所以我将哈希算法拆分成一个数据扩展。这也允许对 SSL 证书固定散列操作使用相同的算法。

下面是一个简短的例子,说明如何将其用于 SSL Pining 操作:

// 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
}

回到原来的答案

我用这个测试了散列算法:

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)")
}

这是打印出来的结果:

md5: c2a9ce57e8df081b4baad80d81868bbb
sha1: 37fb219bf98bee51d2fdc3ba6d866c97f06c8223
sha224: f88e2f20aa89fb4dffb6bdc62d7bd75e1ba02574fae4a437c3bf49c7
sha256: 9da6c02379110815278b615f015f0b254fd3d5a691c9d8abf8141655982c046b
sha384: d9d7fc8aefe7f8f0a969b132a59070836397147338e454acc6e65ca616099d03a61fcf9cc8c4d45a2623145ebd398450
sha512: 349cc35836ba85915ace9d7f895b712fe018452bb4b20ff257257e12adeb1e83ad780c6568a12d03f5b2cb1e3da23b8b7ced9012a188ef3855e0a8f3db211883

我发现这个图书馆似乎工作得很好。

Https://github.com/onmyway133/swifthash

MD5("string")

Swift 4. * ,Xcode 10更新:

在 Xcode 10中,您不必再使用 桥头,您可以直接使用

import CommonCrypto

然后写一个类似这样的方法:

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])
}
}

用法:

MD5("This is my string")

产出:

c2a9ce57e8df081b4baad80d81868bbb

Swift 5 作为字符串扩展名的答案(基于 《不可战胜的科迪》的伟大回答) :

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])
}
}
}

用法:

print("test".md5Value) /*098f6bcd4621d373cade4e832627b4f6*/

在快速编程中,最好使用字符串函数,因此使用起来很容易。 在这里,我使用上面给出的解决方案之一来创建一个 String 扩展

import Foundation
import CommonCrypto


extension String {


func md5() -> 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, self, CC_LONG(self.lengthOfBytes(using: String.Encoding.utf8)))
CC_MD5_Final(&digest, context)
context.deallocate()
var hexString = ""
for byte in digest {
hexString += String(format:"%02x", byte)
}


return hexString
}
}

用法

let md5String = "abc".md5()

我的两分钱(如果你需要快速 md5的 百科/NSData,例如你下载或读二进制磁盘或网络)

(无耻的来自“ Swift 5 answer as a String 座标扩展(基于 Invictus Cody 的伟大答案)”) :

extension Data {
var md5Value: String {
let length = Int(CC_MD5_DIGEST_LENGTH)
var digest = [UInt8](repeating: 0, count: length)


_ = self.withUnsafeBytes { body -> String in
CC_MD5(body.baseAddress, CC_LONG(self.count), &digest)
return ""
}




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

测试:

print("test".data.md5Value) /*098f6bcd4621d373cade4e832627b4f6*/

基于 Cody 的解决方案,我有一个想法,我们应该澄清 MD5的结果是什么,因为我们可以将结果用作十六进制字符串或 Base64字符串。

func md5(_ string: String) -> [UInt8] {
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 digest
}

上面的函数实际上返回一个 [UInt8],基于这个结果,我们可以得到任何形式的字符串,比如十六进制的 base64。

如果需要一个十六进制字符串作为最终结果(正如问题所问的那样) ,我们可以继续使用 Cody 的解决方案的其余部分

extension String {
var md5Hex: String {
let length = Int(CC_MD5_DIGEST_LENGTH)
return (0..<length).reduce("") {
$0 + String(format: "%02x", digest[$1])
}
}
}

如果需要 Base64字符串作为最终结果

extension String {
var md5Base64: String {
let md5edData = Data(bytes: md5(self))
return md5edData.base64EncodedString()
}
}

IOS13开始,苹果已经添加了 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()
}


Swift 5的一个解决方案,它具有适当的内存管理,并且在方法内没有 String类:

typealias CBridgeCryptoMethodType = (UnsafeRawPointer?,
UInt32,
UnsafeMutablePointer<UInt8>?)
-> UnsafeMutablePointer<UInt8>?


private enum HashType {


// MARK: - Cases


case md5
case sha1
case sha224
case sha256
case sha384
case sha512
}


extension Data {
var hexString: String {
let localHexString = reduce("", { previous, current in
return previous + String(format: "%02X", current)
})
return localHexString
}
var md5: Data {
return hashed(for: .md5)
}
var sha1: Data {
return hashed(for: .sha1)
}
var sha224: Data {
return hashed(for: .sha224)
}
var sha256: Data {
return hashed(for: .sha256)
}
var sha384: Data {
return hashed(for: .sha384)
}
var sha512: Data {
return hashed(for: .sha512)
}


private func hashed(for hashType: HashType) -> Data {
return withUnsafeBytes { (rawBytesPointer: UnsafeRawBufferPointer) -> Data in
guard let bytes = rawBytesPointer.baseAddress?.assumingMemoryBound(to: Float.self) else {
return Data()
}
let hashMethod: CBridgeCryptoMethodType
let digestLength: Int
switch hashType {
case .md5:
hashMethod = CC_MD5
digestLength = Int(CC_MD5_DIGEST_LENGTH)
case .sha1:
hashMethod = CC_SHA1
digestLength = Int(CC_SHA1_DIGEST_LENGTH)
case .sha224:
hashMethod = CC_SHA224
digestLength = Int(CC_SHA224_DIGEST_LENGTH)
case .sha256:
hashMethod = CC_SHA256
digestLength = Int(CC_SHA256_DIGEST_LENGTH)
case .sha384:
hashMethod = CC_SHA384
digestLength = Int(CC_SHA384_DIGEST_LENGTH)
case .sha512:
hashMethod = CC_SHA512
digestLength = Int(CC_SHA512_DIGEST_LENGTH)
}
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: digestLength)
_ = hashMethod(bytes, CC_LONG(count), result)
let md5Data = Data(bytes: result, count: digestLength)
result.deallocate()
return md5Data
}
}
}

例子

let str = "The most secure string ever"
print("md5", str.data(using: .utf8)?.md5.hexString)
print("sha1", str.data(using: .utf8)?.sha1.hexString)
print("sha224", str.data(using: .utf8)?.sha224.hexString)
print("sha256", str.data(using: .utf8)?.sha256.hexString)
print("sha384", str.data(using: .utf8)?.sha384.hexString)
print("sha512", str.data(using: .utf8)?.sha512.hexString)

结果:

Md5可选(“671C121427F12FBBA66CEE71C44CB62C”)

Sha1可选(“ A6A40B223AE634CFC8C191DDE024BF0ACA56D7FA”)

Sha224 可选(“334370E82F2F5ECF5B2CA0910C6176D94CBA12FD6F518A7AB8D12ADE”)

Sha256 可选(“8CF5ED971D6EE2579B1BDEFD4921415AC03DA45B49B89665B3DF197287EFC89D”)

Sha384 可选(“04BB3551CBD60035BA7E0BAA141AEACE1EF5E17317A8FD108DA12A7A8E98C245E14F92CC1A241C732209EAC9D600602E”)

Sha512 可选(“1D595EAFEB2162672830885D336F75FD481548AC463BE16A8D98DB33637213F1AEB36FA4977B9C23A82A4FAB8A70C06AFC64C610D3CB1FE77A609DC8EE86AA68”)

import CryptoKit
private func MD5Base64(_ string: String) -> String {
let digest = Insecure.MD5.hash(data: string.data(using: .utf8) ?? Data())
let digestString = digest.map { String(format: "%02hhx", $0) }.joined()
return digestString.toBase64()
}


extension String {
func toBase64() -> String {
return Data(self.utf8).base64EncodedString()
}
}

斯威夫特5.3你可以做

import CryptoKit


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

Swift 5.3: 基于@Radu Ursache 和@mluisbrown 的答案: String 上的一个简单扩展

import CryptoKit


extension String {
func md5() -> String {
return Insecure.MD5.hash(data: self.data(using: .utf8)!).map { String(format: "%02hhx", $0) }.joined()
}
}

用法:

"My awesome String".md5()