“abc”와 같은 문자열을 MD5 해시로 변환하고 싶습니다. iOS와 Swift에서 이것을하고 싶습니다. 아래 솔루션을 사용해 보았지만 저에게 효과적이지 않았습니다.
Swift 프레임 워크에서 CommonCrypto 가져 오기
http://iosdeveloperzone.com/2014/10/03/using-commoncrypto-in-swift/
좀 더 명확하게 말하자면,이 PHP 코드의 출력과 유사한 Swift에서 출력을 얻고 싶습니다.
$str = "Hello";
echo md5($str);
출력 : 8b1a9953c4611296a827abf8c47804d7
답변
두 단계가 있습니다.
1. 문자열에서 md5 데이터 생성
2. md5 데이터를 16 진수 문자열로 변환
스위프트 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
스위프트 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 ==
스위프트 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>
브리징 헤더 파일에 추가해야합니다.
Bridging-Header를 만드는 방법은 this SO answer를 참조하십시오 .
일반적으로 MD5는 새로운 작업에 사용해서는 안되며 SHA256은 현재 모범 사례입니다.
더 이상 사용되지 않는 문서 섹션의 예 :
MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384, SHA512 (Swift 3+)
이러한 함수는 8 개의 암호화 해시 알고리즘 중 하나를 사용하여 문자열 또는 데이터 입력을 해시합니다.
name 매개 변수는 해시 함수 이름을 문자열로 지정합니다.
지원되는 함수는 MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 및 SHA512입니다.이 예제에는 공통 암호화
가 필요합니다. 프로젝트에 브리징 헤더가 있어야합니다.
#import <CommonCrypto/CommonCrypto.h>
보안 추가 .framework를 프로젝트에 추가합니다.
이 함수는 해시 할 해시 이름과 문자열을 가져 와서 데이터를 반환합니다.
name : 문자열로 된 해시 함수의 이름 문자열 : 해시 할 문자열 반환 : 해시 된 결과 데이터
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>
답변
여기에서 다른 답변을 읽은 후 (다른 해시 유형도 지원해야 함) 여러 해시 유형과 출력 유형을 처리하는 문자열 확장을 작성했습니다.
참고 : CommonCrypto는 Xcode 10에 포함되어 있으므로 import CommonCrypto
최신 Xcode 버전이 설치되어 있으면 브리징 헤더를 엉망으로 만들 필요없이 간단하게 할 수 있습니다 . 그렇지 않으면 브리징 헤더가 필요합니다.
업데이트 : Swift 4와 5는 아래의 동일한 String + Crypto.swift 파일을 사용합니다.
Swift 4와 5 사이에서 변경된 ‘withUnsafeMutableBytes’및 ‘withUnsafeBytes’에 대한 API로 Swift 5 (아래 참조)에 대한 별도의 Data + Crypto.swift 파일이 있습니다.
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)
}
}
SWIFT 5 데이터 + 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()
}
}
}
SWIFT 4 데이터 + 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 고정 작업에 사용할 수있는 간단한 예입니다.
// 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
답변
현재 아이폰 OS (13) 애플은 추가했습니다 CryptoKit
더 이상 필요가 C API를 CommonCrypto 또는 거래를 가져올 수 없습니다 할 수 있도록 프레임 워크를 :
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 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
}
답변
Swift 4. *, Xcode 10 업데이트 :
Xcode 10에서는 더 이상 Bridging-Header 를 사용할 필요가 없으며 다음을 사용 하여 직접 가져올 수 있습니다.
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
답변
CommonCrypto 또는 다른 것에 의존하지 않는 순수한 Swift 구현 을 출시했습니다 . MIT 라이선스에 따라 사용할 수 있습니다.
코드는 단일 신속한 파일 로 구성 됩니다. 프로젝트에 드롭 할 수 . 원하는 경우 프레임 워크 및 단위 테스트 대상과 함께 포함 된 Xcode 프로젝트를 사용할 수도 있습니다.
사용이 간단합니다.
let input = "The quick brown fox jumps over the lazy dog"
let digest = input.utf8.md5
print("md5: \(digest)")
인쇄물: md5: 9e107d9d372bb6826bd81d3542a419d6
신속한 파일에는 문서와 더 많은 예제가 포함되어 있습니다.
답변
여기에 두 가지 참고 :
Crypto를 사용하는 것은 이것을 달성하기에는 너무 많은 오버 헤드입니다.
허용 대답은 완벽하다! 그럼에도 불구하고 저는 Swift 2.2를 사용 하는 Swift ier 코드 접근법 을 공유하고 싶었습니다 .
Bridging-Header 파일 #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]) }
}
}