Swift를 사용하여 iOS에서 문자열을 MD5 해시로 변환하려면 어떻게해야합니까?


111

"abc"와 같은 문자열을 MD5 해시로 변환하고 싶습니다. iOS와 Swift에서 이것을하고 싶습니다. 아래 솔루션을 사용해 보았지만 저에게 효과적이지 않았습니다.

Swift 프레임 워크에서 CommonCrypto 가져 오기

빠른 언어로 CC_MD5 방법을 사용하는 방법.

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

좀 더 명확하게 말하자면,이 PHP 코드의 출력과 유사한 Swift에서 출력을 얻고 싶습니다.

$str = "Hello";

echo md5($str);

출력 : 8b1a9953c4611296a827abf8c47804d7


5
당신이 준 링크에 무슨 문제가 있습니까?
jtbandes

2
제공 한 링크가 작동합니다. 정확한 문제가 무엇인지 설명 할 수 있습니까? 원하는 작업을 수행하기 위해 타사 라이브러리를 포함 할 수도 있습니다. github.com/krzyzanowskim/CryptoSwift
에릭 Amorde

1
내가 빠른 프로그래밍에 익숙하지 않다고 언급했듯이 올바른 방식으로 구현하는 데 혼란 스러웠습니다. 이 파일 (#import <CommonCrypto / CommonCrypto.h>)을 신속한 컨트롤러 파일에 포함 시켰습니다. 그러나 귀하의 답변에 감사 드리며, 이제 아래에 주어진 Mr.zaph 답변으로 해결되었습니다.
user3606682 2015-08-24

Swift에서 자체 개발 한 구현을 원한다면 github.com/onmyway133/SwiftHash
onmyway133

답변:


178

두 단계가 있습니다.
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>

3
감사합니다 alottt @zaph, 나는 이틀 이상 이후로 이것을 위해 고군분투했습니다. 위의 답변으로 해결되었습니다 :) 그리고 예 MD5가 사용되는 웹에서 오래된 데이터를 검색하므로 MD5를 사용해야합니다. 하지만 SHA256 사용에 대한 답변과 제안에 다시 한 번 감사드립니다. :)
user3606682

String(data: digestData, encoding: String.Encoding.utf8)슬로우fatal error: unexpectedly found nil while unwrapping an Optional value
싯다 르트 나라 얀

@Siddharth 의견에 충분한 정보가 없습니다 digestData. 무엇인지 명확하지 않습니다 . 해시 데이터 인 경우 가능성이 있거나 UTF-8 (또는 모든 문자열 인코딩이 존재하지 않는 것까지 슬림합니다.
zaph

1
개선 할 수있는 방법은 다음과 같습니다. CommonCrypto 전체가 아닌 필수 기호 만 가져 오십시오. 그렇지 않으면 약간의 오버 헤드가 발생합니다. import var CommonCrypto.CC_MD5_DIGEST_LENGTH import func CommonCrypto.CC_MD5 import typealias CommonCrypto.CC_LONG
Igor Vasilev

2
@zaph 아래 답변에 자세히 설명 된 답변에 iOS 13 CryptoKit 솔루션을 추가하고 싶을 수 있습니다. stackoverflow.com/a/56578995/368085
mluisbrown

40

여기에서 다른 답변을 읽은 후 (다른 해시 유형도 지원해야 함) 여러 해시 유형과 출력 유형을 처리하는 문자열 확장을 작성했습니다.

참고 : 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

39

현재 아이폰 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()
}

3
이것은 MD5가 현재 안전하지 않다는 경고를 피하는 수단을 제공한다는 점도 주목할 가치가 있습니다. 경고를 비활성화하기 위해 pragma를 지원하도록 Objective-C에서 CommonCrypto를 구현할 필요가 없습니다. 경고 처리에 중점을 둔 환경에서 작업하는 경우 편리합니다.
marcus.ramsden

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
}

http://iosdeveloperzone.com의 원본 링크


23

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

귀하의 솔루션은 완벽하게 작동합니다. 이 MD5 암호화로 SALT 값을 추가 할 수 있습니까? 문자열을 암호화하면서 추가하고 싶습니다. 유용한 링크를 제공 할 수 있습니까?
Punita 19.01.28

나는 당신이 성취하려는 것이 무엇인지 잘 모르겠습니다. 솔팅을 통한 사용자 지정 암호화를 원하는 경우 "AES128"을 사용합니다. 보안이 우려되는 경우 다음을 확인하십시오. stackoverflow.com/a/15775071/3118377 .
Invictus Cody

감사합니다 Invictus Cody, SALT를 String과 연결하고 MD5를 얻을 수 있습니다.
Punita 2019

잘 작동합니다. 그러나 어떻게 다시 String으로 변환합니까?
DocAsh59

1
Swift 5 :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: .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]) } }
Jim B

17

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

신속한 파일에는 문서와 더 많은 예제가 포함되어 있습니다.


4
여기 또는 Github ReadMe에 언급되지 않은 Swift 4가 필요합니다. Common Crypto와 비교하여 제공된 성능 수치없이 사용을 고려해서는 안됩니다. 참고 : Common Crypto는 FIPS 140 인증을 받았지만 SwiftDigest는 인증되지 않았습니다. 핵심 질문은 다음과 같습니다. 구현을 위해 이것이 Common Crypto보다 나은 방법은 무엇입니까? 더 안전함 : 아니요, 더 빠르게 : 아니요
zaph

1
@zaph 주된 목적은 CommonCrypto에 의존하지 않는 md5 구현을 갖는 것입니다. 이는 Swift 프레임 워크 대상 또는 비 Apple 플랫폼과 같이 CommonCrypto를 사용할 수없는 상황에서 유용합니다.
Nikolai Ruhe

4
@zaph 보안 관련 구현을 가볍게 다루지 않는다는 데 동의합니다. 그러나 MD5는 보안이 아닌 다른 용도로 사용됩니다. 오히려 보안이 MD5 성능이 가장 나쁜 곳입니다. 해싱 알고리즘은 식별, 정렬, 저장, 사전, 오류 감지 및 기타 이유에 사용됩니다. MD5는 편재성 때문에 특히 유용합니다. 따라서 귀하의 몇 가지 의견에 동의하지만 요점에 동의하지 않습니다. 나는 당신의 관점과 논쟁이 너무 좁다 고 생각합니다. 주제 전체를 포함하지 않습니다.
Nikolai Ruhe

2
또한, 방금 테스트했으며 큰 메시지에 대한 구현이 CommonCrypto보다 빠릅니다. :)
Nikolai Ruhe

2
이 구현이 마음에 듭니다. @NikolaiRuhe 대단히 감사합니다! 나는 그것을 Swift 3 호환성으로 쉽게 변환 할 수있었습니다. 또한 URL이 지정된 파일 내용의 다이제스트를 계산하고 base64 인코딩을 검색하는 등 몇 가지 편리한 방법을 추가했습니다 (특히 Content-MD5에 유용함). @Siddharth는 MD5Digest.swift뿐입니다.
biomiker

10

여기에 두 가지 참고 :

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

7

String 확장으로 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])
        }
    }
}

용법:

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

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

swift 3.0과 완벽하게 호환됩니다. #import <CommonCrypto/CommonCrypto.h>Bridging-Header 파일에 있어야 합니다.


3

신속한 프로그래밍에서는 문자열 함수를 만드는 것이 더 좋으므로 사용이 쉽습니다. 여기에서는 위의 솔루션 중 하나를 사용하여 문자열 확장을 만들고 있습니다. 감사합니다 @wajih

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

1

이 작업을 위해 Carthage와 Cyrpto를 사용했습니다.

  1. 아직 설치하지 않은 경우 Carthage를 설치하십시오.

  2. 프로젝트에 Crypto 설치

  3. '카티지 업데이트'실행

  4. 명령 줄에서 실행하는 경우 swift 파일의 프레임 워크에 추가

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. 신속한 파일에 Import Crypto를 추가하십시오.

  6. 그런 다음 작동합니다!

    print( "convert this".MD5 )

하나의 기능 만 필요할 때 완전한 암호화 라이브러리를 사용하는 것은 다소
Mark Bourke

오래된 스레드 주석에 대해 사과하십시오 ... 아마도, 공통 라이브러리는 (아마도) 항상 플랫폼 변경에 따라 최신 상태로 유지되므로 공통 결과를 산출하고 조각화를 최소화하며 아무도 계속해서 바퀴를 재발 명하거나 인터넷을 사용할 필요가 없습니다. 신뢰할 수 있거나 빠르거나 표준에 따라 패턴 화 된 코드를 찾았습니다. 나는 모두 의존성을 최소화하기 위해 노력하고 있지만, 이와 같은 경우에는 OS 옵션을 먼저, 공통 언어 옵션을 두 번째로, 다음으로 타사 표준 옵션을 살펴보고 결과적으로 일회성 또는 "이 사람의 라이브러리가 꽤 좋습니다"를 봅니다. 옵션은 마지막입니다. * 어깨를 으쓱 *
ChrisH

1

MD5는 해싱 알고리즘이므로 부피가 큰 CommonCrypto 라이브러리를 사용할 필요가 없으며 (Apple 검토에서 거부 됨) md5 해싱 라이브러리 만 사용하면됩니다.

내가 사용하는 그러한 라이브러리 중 하나 는 MD5의 순수한 신속한 구현 인 SwiftHash 입니다 ( http://pajhome.org.uk/crypt/md5/md5.html 기반 )


1

Cody의 솔루션을 기반으로 결과를 16 진 문자열 또는 Base64 문자열로 사용할 수 있기 때문에 MD5의 결과가 무엇인지 명확히해야한다는 생각이 있습니다.

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]결과를 기반으로 16 진수, base64와 같은 모든 형식의 문자열을 얻을 수 있습니다.

최종 결과로 16 진수 문자열이 필요하면 (질문에서 묻는 것처럼) 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()
    }
}

1

적절한 메모리 관리가 있고 메서드 내부에 클래스가 없는 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")



0

내 2 센트 ( 예를 들어 디스크 또는 netwkork 용 바이너리를 다운로드하거나 읽은 경우와 같이 데이터 / NSData에 대해 md5가 빠르게 필요한 경우 )

( "문자열 확장으로서의 스위프트 5 답변 (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*/
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.