如何使用 Swift 在 iOS 中将字符串转换为 MD5 哈希?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32163848/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I convert a String to an MD5 hash in iOS using Swift?
提问by user3606682
I want to convert a string like "abc" to an MD5 hash. I want to do this in iOS and Swift. I have tried using the solutions below but they were not working for me:
我想将像“abc”这样的字符串转换为 MD5 哈希。我想在 iOS 和 Swift 中做到这一点。我曾尝试使用以下解决方案,但它们对我不起作用:
Importing CommonCrypto in a Swift framework
How to use CC_MD5 method in swift language.
http://iosdeveloperzone.com/2014/10/03/using-commoncrypto-in-swift/
http://iosdeveloperzone.com/2014/10/03/using-commoncrypto-in-swift/
To be more clear, I want to achieve an output in Swift similar to this PHP code's output:
更清楚地说,我想在 Swift 中实现类似于此 PHP 代码输出的输出:
$str = "Hello";
echo md5($str);
Output: 8b1a9953c4611296a827abf8c47804d7
输出:8b1a9953c4611296a827abf8c47804d7
回答by zaph
There are two steps:
1. Create md5 data from a string
2. Covert the md5 data to a hex string
有两个步骤:
1. 从字符串创建 md5 数据
2. 将 md5 数据转换为十六进制字符串
Swift 2.0:
斯威夫特 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)")
Output:
输出:
digest: 8b1a9953c4611296a827abf8c47804d7
摘要:8b1a9953c4611296a827abf8c47804d7
Swift 3.0:
斯威夫特 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", 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", name: A name of a hash function as a String
string: The String to be hashed
returns: the hashed result as Data
) }.joined()
print("md5Hex: \(md5Hex)")
let md5Base64 = md5Data.base64EncodedString()
print("md5Base64: \(md5Base64)")
) }.joined()
print("md5Hex: \(md5Hex)")
let md5Base64 = md5Data.base64EncodedString()
print("md5Base64: \(md5Base64)")
Output:
输出:
md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w==
md5Hex:8b1a9953c4611296a827abf8c47804d7
md5Base64:ixqZU8RhEpaoJ6v4xHgE1w==
Swift 5.0:
斯威夫特 5.0:
func hash(name:String, string:String) -> Data? {
let data = string.data(using:.utf8)!
return hash(name:name, data:data)
}
Output:
输出:
md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w==
md5Hex:8b1a9953c4611296a827abf8c47804d7
md5Base64:ixqZU8RhEpaoJ6v4xHgE1w==
Notes:#import <CommonCrypto/CommonCrypto.h>
must be added to a Bridging-Header file
注意:#import <CommonCrypto/CommonCrypto.h>
必须添加到 Bridging-Header 文件中
For how to create a Bridging-Header see this SO answer.
有关如何创建桥接头,请参阅此 SO 答案。
In general MD5 should not be used for new work, SHA256 is a current best practice.
一般来说 MD5 不应用于新工作,SHA256 是当前的最佳实践。
Example from deprecated documentation section:
弃用文档部分的示例:
MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384, SHA512 (Swift 3+)
MD2、MD4、MD5、SHA1、SHA224、SHA256、SHA384、SHA512(Swift 3+)
These functions will hash either String or Data input with one of eight cryptographic hash algorithms.
这些函数将使用八种加密散列算法之一散列字符串或数据输入。
The name parameter specifies the hash function name as a String
Supported functions are MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 and SHA512
a
This example requires Common Crypto
It is necessary to have a bridging header to the project:#import <CommonCrypto/CommonCrypto.h>
Add the Security.framework to the project.
name 参数将哈希函数名称指定为 String
支持的函数有 MD2、MD4、MD5、SHA1、SHA224、SHA256、SHA384 和 SHA512 a 此示例需要 Common Crypto
项目必须有桥接头:#import <CommonCrypto/CommonCrypto.h>
添加安全性.framework 到项目。
This function takes a hash name and String to be hashed and returns a 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>
Examples:
例子:
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)
}
}
Output:
输出:
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", 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", // 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
}
) }.joined()
case .base64: return digest.base64EncodedString()
}
}
}
) }.joined()
case .base64: return digest.base64EncodedString()
}
}
}
回答by digitalHound
After reading through the other answers on here (and needing to support other hash types as well) I wrote a String extension that handles multiple hash types and output types.
在阅读了此处的其他答案(并且还需要支持其他散列类型)后,我编写了一个 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.
注意:CommonCrypto 包含在 Xcode 10 中,因此import CommonCrypto
如果您安装了最新的 Xcode 版本,您可以简单地不必弄乱桥接头......否则需要桥接头。
UPDATE: Both Swift 4 & 5 use the same String+Crypto.swift file below.
更新:Swift 4 和 5 使用下面相同的 String+Crypto.swift 文件。
There is a separate Data+Crypto.swift file for Swift 5 (see below) as the api for 'withUnsafeMutableBytes' and 'withUnsafeBytes' changed between Swift 4 & 5.
Swift 5 有一个单独的 Data+Crypto.swift 文件(见下文),因为“withUnsafeMutableBytes”和“withUnsafeBytes”的 api 在 Swift 4 和 5 之间发生了变化。
String+Crypto.swift -- (for both Swift 4 & 5)
String+Crypto.swift --(适用于 Swift 4 和 5)
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)")
}
SWIFT 5-- Data+Crypto.swift
SWIFT 5-- 数据+Crypto.swift
md5: c2a9ce57e8df081b4baad80d81868bbb
sha1: 37fb219bf98bee51d2fdc3ba6d866c97f06c8223
sha224: f88e2f20aa89fb4dffb6bdc62d7bd75e1ba02574fae4a437c3bf49c7
sha256: 9da6c02379110815278b615f015f0b254fd3d5a691c9d8abf8141655982c046b
sha384: d9d7fc8aefe7f8f0a969b132a59070836397147338e454acc6e65ca616099d03a61fcf9cc8c4d45a2623145ebd398450
sha512: 349cc35836ba85915ace9d7f895b712fe018452bb4b20ff257257e12adeb1e83ad780c6568a12d03f5b2cb1e3da23b8b7ced9012a188ef3855e0a8f3db211883
SWIFT 4-- Data+Crypto.swift
SWIFT 4-- 数据+Crypto.swift
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", 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
}
)
}.joined()
}
Edit: since the hash actually happens on the Data, I split the hashing algorithm out into a Data extension. This allows the same algorithm to be used for SSL Certificate pinning hash operations as well.
编辑:由于哈希实际上发生在数据上,我将哈希算法拆分为数据扩展。这也允许将相同的算法用于 SSL 证书固定哈希操作。
Here's a short example of how you might use it for an SSL Pinning operation:
下面是一个简短的示例,说明如何将其用于 SSL 固定操作:
import CommonCrypto
back to the original answer
回到原来的答案
I tested the hash algorithms using this:
我使用这个测试了哈希算法:
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("") {
MD5("This is my string")
+ String(format: "%02x", digest[])
}
}
and this is the printed results:
这是打印的结果:
c2a9ce57e8df081b4baad80d81868bbb
回答by mluisbrown
回答by wajih
SWIFT 3
version of md5 function
:
SWIFT 3
版本md5 function
:
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("") { 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", 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("") {
print("test".md5Value) /*098f6bcd4621d373cade4e832627b4f6*/
+ String(format: "%02x", digest[])
}
}
}
) }.joined()
}
}
}
+ String(format: "%02x", digest[]) }
}
}
Original link from http://iosdeveloperzone.com
回答by Invictus Cody
Swift 4.* , Xcode 10 Update :
Swift 4.* ,Xcode 10 更新:
In Xcode 10 you don't have to use Bridging-HeaderAnymore , you can directly import using
在 Xcode 10 中,您不必再使用Bridging-Header,您可以使用直接导入
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
}
}
And Then write a method something like :
然后写一个类似的方法:
let md5String = "abc".md5()
Usage :
用法 :
##代码##Output:
输出:
##代码##回答by Nikolai Ruhe
I released a pure Swift implementationthat does not depend on CommonCrypto or anything else. It's available under MIT license.
我发布了一个不依赖于 CommonCrypto 或其他任何东西的纯 Swift 实现。它在 MIT 许可下可用。
The code consists of a single swift filethat you can just drop into your project. If you prefer you can also use the contained Xcode project with framework and unit test targets.
该代码由一个swift 文件组成,您可以将其放入您的项目中。如果您愿意,您还可以将包含的 Xcode 项目与框架和单元测试目标一起使用。
It's simple to use:
使用起来很简单:
##代码##prints: md5: 9e107d9d372bb6826bd81d3542a419d6
印刷: md5: 9e107d9d372bb6826bd81d3542a419d6
The swift file contains documentation and more examples.
swift 文件包含文档和更多示例。
回答by Hugo Alonso
Just two notes here:
这里只有两个注意事项:
Using Cryptois too much overhead for achieving just this.
使用Crypto实现这一目标的开销太大。
The accepted answeris perfect! Nevertheless I just wanted to share a Swiftiercode approach using Swift 2.2.
该接受的答案是完美的!尽管如此,我只是想分享一个使用Swift 2.2的Swift ier代码方法。
Please bear in mind that you still have to #import <CommonCrypto/CommonCrypto.h>
in your Bridging-Headerfile
请记住,您仍然必须#import <CommonCrypto/CommonCrypto.h>
在桥接头文件中
回答by Glaubenio Patricio
Here's an extension based on zaph answer
这是基于 zaph answer 的扩展
##代码##Fully compatible with swift 3.0.you still have to #import <CommonCrypto/CommonCrypto.h>
in your Bridging-Header file
与 swift 3.0 完全兼容#import <CommonCrypto/CommonCrypto.h>
。你仍然需要在你的 Bridging-Header 文件中
回答by Tamás Sengel
Swift 5answer as a String extension (based on the great answer of Invictus Cody):
Swift 5作为字符串扩展回答(基于Invictus Cody 的精彩回答):
##代码##Usage:
用法:
##代码##回答by Rahul K Rajan
In swift programming its better to make a string function, so the use will be easy. Here I am making a String extension using one of the above given solution. Thanks @wajih
在 swift 编程中最好制作一个字符串函数,这样使用起来会很容易。在这里,我使用上面给出的解决方案之一进行字符串扩展。谢谢@wajih
##代码##Usage
用法
##代码##