Wie kann ich mit Swift einen String in iOS in einen MD5-Hash konvertieren?

110

Ich möchte einen String wie "abc" in einen MD5-Hash konvertieren. Ich möchte dies in iOS und Swift tun. Ich habe versucht, die folgenden Lösungen zu verwenden, aber sie haben bei mir nicht funktioniert:

CommonCrypto in ein Swift-Framework importieren

Verwendung der CC_MD5-Methode in schneller Sprache.

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

Um es klarer zu machen, möchte ich eine Ausgabe in Swift erzielen, die der Ausgabe dieses PHP-Codes ähnelt:

$str = "Hello";

echo md5($str);

Ausgabe: 8b1a9953c4611296a827abf8c47804d7

user3606682
quelle
5
Was ist los mit den Links, die du gegeben hast?
Jtbandes
2
Die von Ihnen angegebenen Links sollten funktionieren. Können Sie beschreiben, was Ihr genaues Problem ist? Sie können auch eine Drittanbieter-Bibliothek hinzufügen, um das zu tun, was Sie möchten, z. github.com/krzyzanowskim/CryptoSwift
Eric Amorde
1
Da ich erwähnt habe, dass ich neu in der schnellen Programmierung bin, war ich verwirrt, sie richtig umzusetzen. Ich habe diese Datei (#import <CommonCrypto / CommonCrypto.h>) in die Swift-Controller-Datei aufgenommen. Aber danke für Ihre Antworten, es wird jetzt durch die unten angegebene Antwort von Mr. Zaph gelöst.
user3606682
Wenn Sie eine selbst entwickelte Implementierung in Swift wünschen, dann github.com/onmyway133/SwiftHash
onmyway133

Antworten:

178

Es gibt zwei Schritte:
1. Erstellen Sie MD5-Daten aus einer Zeichenfolge.
2. Verdecken Sie die MD5-Daten in eine Hex-Zeichenfolge

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

Ausgabe:

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

Ausgabe:

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

Ausgabe:

md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w ==

Hinweise:
#import <CommonCrypto/CommonCrypto.h>muss zu einer Bridging-Header-Datei hinzugefügt werden

Informationen zum Erstellen eines Bridging-Headers finden Sie in dieser SO-Antwort .

Im Allgemeinen sollte MD5 nicht für neue Arbeiten verwendet werden. SHA256 ist eine aktuelle Best Practice.

Beispiel aus dem veralteten Dokumentationsabschnitt:

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

Diese Funktionen hashen entweder Zeichenfolgen oder Daten mit einem von acht kryptografischen Hash-Algorithmen.

Der Parameter Name gibt den Hash - Funktion Namen als String
Unterstützte Funktionen sind MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 und SHA512 ein Dieses Beispiel erfordert ein gemeinsames Crypto
Es ist notwendig , eine Brückenkopf zum Projekt haben:
#import <CommonCrypto/CommonCrypto.h>
Fügen Sie die Sicherheit .framework zum Projekt.



Diese Funktion verwendet einen Hash-Namen und einen zu hashenden String und gibt Daten zurück:

name: Der Name einer Hash-Funktion als String  
string: Der zu hashende String  
Rückgabe: Das Hash-Ergebnis als Daten  
func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}

Beispiele:

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

Ausgabe:

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

hashSHA256: <aabc766b 6b357564 e41f4f91 2d494bcc bfa16924 b574abbd ba9e3e9d a0c8920a>
hashMD5: <4df665f7 b94aea69 695b0e7b baf9e9d6>
zaph
quelle
3
Danke alottt @zaph, ich habe seit mehr als 2 Tagen darum gekämpft. Habe es mit deiner obigen Antwort gelöst :) Und ja, ich rufe alte Daten aus dem Web ab, in dem MD5 verwendet wird, also bin ich gezwungen, MD5 zu verwenden. Aber nochmals
vielen
String(data: digestData, encoding: String.Encoding.utf8)Würfefatal error: unexpectedly found nil while unwrapping an Optional value
Siddharth
@Siddharth Es gibt nicht genug Informationen im Kommentar, es ist nicht klar, was digestDataist. Wenn es sich um Hash-Daten handelt, ist die Wahrscheinlichkeit
groß, dass
1
Hier erfahren Sie, wie Sie es verbessern können: Importieren Sie nur die erforderlichen Symbole und nicht das gesamte CommonCrypto, da dies sonst ein wenig aufwändig ist: Importieren Sie var CommonCrypto.CC_MD5_DIGEST_LENGTH importieren Sie func CommonCrypto.CC_MD5 importieren Sie Typealias CommonCrypto.CC_LONG
Igor Vasilev
2
@zaph möchten Sie vielleicht die iOS 13 CryptoKit-Lösung zu Ihrer Antwort hinzufügen, die ich in meiner Antwort unten detailliert beschrieben habe: stackoverflow.com/a/56578995/368085
mluisbrown
39

Nachdem ich die anderen Antworten hier gelesen hatte (und auch andere Hash-Typen unterstützen musste), schrieb ich eine String-Erweiterung, die mehrere Hash-Typen und Ausgabetypen behandelt.

HINWEIS: CommonCrypto ist in Xcode 10 enthalten, sodass Sie einfach import CommonCryptomit einem Bridging-Header herumspielen müssen, wenn Sie die neueste Xcode-Version installiert haben. Andernfalls ist ein Bridging-Header erforderlich.


UPDATE: Sowohl Swift 4 als auch Swift verwenden dieselbe String + Crypto.swift-Datei.

Es gibt eine separate Data + Crypto.swift-Datei für Swift 5 (siehe unten), da die API für 'withUnsafeMutableBytes' und 'withUnsafeBytes' zwischen Swift 4 und 5 geändert wurde.


String + Crypto.swift - (für 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 - 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()
        }
    }
}

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

Bearbeiten: Da der Hash tatsächlich auf den Daten auftritt, habe ich den Hashing-Algorithmus in eine Datenerweiterung aufgeteilt. Auf diese Weise kann derselbe Algorithmus auch für das Fixieren von Hash-Vorgängen mit SSL-Zertifikaten verwendet werden.

Hier ist ein kurzes Beispiel, wie Sie es für einen SSL-Pinning-Vorgang verwenden können:

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

zurück zur ursprünglichen Antwort

Ich habe die Hash-Algorithmen folgendermaßen getestet:

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

und das sind die gedruckten Ergebnisse:

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

Ab iOS 13 hat Apple das CryptoKitFramework hinzugefügt, sodass Sie CommonCrypto nicht mehr importieren oder sich mit seiner C-API befassen müssen:

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()
}
mluisbrown
quelle
3
Es ist auch erwähnenswert, dass dies ein Mittel ist, um die Warnung zu vermeiden, dass MD5 jetzt unsicher ist. Sie müssen CommonCrypto nicht in Objective-C implementieren, damit Sie Pragmas unterstützen können, um die Warnung zu deaktivieren. Praktisch, wenn Sie in einer Umgebung arbeiten, in der der Umgang mit Warnungen im Vordergrund steht.
marcus.ramsden
28

SWIFT 3Version von 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
}

Ursprünglicher Link von http://iosdeveloperzone.com

wajih
quelle
23

Swift 4. *, Xcode 10 Update:

In Xcode 10 müssen Sie Bridging-Header nicht mehr verwenden, sondern können direkt mit importieren

import CommonCrypto

Und dann schreibe eine Methode wie:

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

Verwendung :

MD5("This is my string")

Ausgabe:

c2a9ce57e8df081b4baad80d81868bbb
Invictus Cody
quelle
Ihre Lösung ist perfekt funktioniert. Können wir mit dieser MD5-Verschlüsselung einen SALT-Wert hinzufügen? Ich möchte während der Verschlüsselung der Zeichenfolge hinzufügen. Können Sie einen Link zur vollständigen Verwendung bereitstellen?
Punita
Ich bin mir nicht sicher, was Sie erreichen wollen. Verwenden Sie "AES128", wenn Sie eine benutzerdefinierte Verschlüsselung mit Salting wünschen. Wenn die Sicherheit von Ihnen ein Anliegen ist, überprüfen Sie dies: stackoverflow.com/a/15775071/3118377 .
Invictus Cody
Dank Invictus Cody habe ich SALT mit String verkettet und kann MD5 bekommen.
Punita
Funktioniert super. Aber wie konvertiert man es zurück in 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

Ich habe eine reine Swift-Implementierung veröffentlicht , die nicht von CommonCrypto oder irgendetwas anderem abhängt. Es ist unter MIT-Lizenz erhältlich.

Der Code besteht aus einer einzelnen schnellen Datei , die Sie einfach in Ihr Projekt können. Wenn Sie möchten, können Sie auch das enthaltene Xcode-Projekt mit Framework- und Unit-Test-Zielen verwenden.

Es ist einfach zu bedienen:

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

Drucke: md5: 9e107d9d372bb6826bd81d3542a419d6

Die schnelle Datei enthält Dokumentation und weitere Beispiele.

Nikolai Ruhe
quelle
4
Benötigt Swift 4, das hier oder auf dem Github ReadMe nicht erwähnt wird. Die Verwendung sollte nicht ohne die im Vergleich zu Common Crypto angegebenen Leistungsdaten berücksichtigt werden. Hinweis: Common Crypto ist FIPS 140-zertifiziert, SwiftDigest nicht. Hier ist die Schlüsselfrage: Wie ist dies für die Implementierung besser als Common Crypto?
Sicherer
1
@zaph Der Hauptzweck ist eine MD5-Implementierung, die nicht von CommonCrypto abhängt. Dies ist hilfreich in Situationen, in denen CommonCrypto nicht verfügbar ist, z. B. bei Swift-Framework-Zielen oder auf Plattformen, die nicht von Apple stammen.
Nikolai Ruhe
4
@zaph Ich stimme zu, dass sicherheitsrelevante Implementierungen nicht leicht genommen werden dürfen. MD5 hat jedoch andere Verwendungszwecke als Sicherheit - oder besser gesagt, Sicherheit ist dort, wo MD5 am schlechtesten abschneidet. Hashing-Algorithmen werden zur Identifizierung, Sortierung, Speicherung, Wörterbüchern, Fehlererkennung und aus anderen Gründen verwendet. MD5 ist wegen seiner Allgegenwart besonders nützlich. Obwohl ich einigen Ihrer Kommentare zustimme, stimme ich dem Kern nicht zu. Ich denke, Ihr Standpunkt und Ihre Argumentation sind zu eng; es umfasst nicht das gesamte Thema.
Nikolai Ruhe
2
Außerdem habe ich gerade getestet, und meine Implementierung ist schneller als CommonCrypto für große Nachrichten :)
Nikolai Ruhe
2
Ich mag diese Implementierung. Vielen Dank @NikolaiRuhe! Ich konnte es problemlos auf Swift 3-Kompatibilität umstellen. Ich habe auch einige praktische Methoden hinzugefügt, darunter das Berechnen des Digests von Dateiinhalten unter Angabe einer URL und das Abrufen der Base64-Codierung (nützlich unter anderem für Content-MD5). @Siddharth Die einzige Datei, die Sie benötigen, ist MD5Digest.swift.
Biomiker
10

Nur zwei Anmerkungen hier:

Verwenden von Crypto ist zu aufwendig, um genau dies zu erreichen.

Die akzeptierte Antwort ist perfekt! Trotzdem wollte ich nur einen Swift ier Code-Ansatz mit Swift 2.2 teilen .

Bitte beachten Sie, dass Sie dies noch #import <CommonCrypto/CommonCrypto.h>in Ihrer Bridging-Header- Datei tun müssen

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]) }
    }
}
Hugo Alonso
quelle
7

Swift 5- Antwort als String-Erweiterung (basierend auf der großartigen Antwort von 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])
        }
    }
}

Verwendung:

print("test".md5Value) /*098f6bcd4621d373cade4e832627b4f6*/
Tamás Sengel
quelle
6

Hier ist eine Erweiterung basierend auf Zaph Antwort

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

Voll kompatibel mit Swift 3.0. Sie müssen sich noch #import <CommonCrypto/CommonCrypto.h>in Ihrer Bridging-Header-Datei befinden

Glaubenio Patricio
quelle
3

Bei der schnellen Programmierung ist es besser, eine Zeichenfolgefunktion zu erstellen, damit die Verwendung einfach ist. Hier mache ich eine String-Erweiterung mit einer der oben angegebenen Lösungen. Danke @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
}
}

Verwendung

let md5String = "abc".md5()
Rahul K Rajan
quelle
1

Ich habe dazu Karthago und Cyrpto benutzt.

  1. Installieren Sie Karthago, falls Sie dies noch nicht getan haben

  2. Installieren Sie Crypto in Ihrem Projekt

  3. 'Cartage Update' ausführen

  4. Wenn Sie über die Befehlszeile ausgeführt werden, fügen Sie das Framework in die Swift-Datei ein

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. Fügen Sie Ihrer schnellen Datei Import Crypto hinzu.

  6. dann funktioniert es einfach!

    print( "convert this".MD5 )
Keith John Hutchison
quelle
Es ist etwas übertrieben, eine vollwertige Kryptografie-Bibliothek zu verwenden, wenn nur eine Funktion benötigt wird
Mark Bourke
Entschuldigen Sie den Kommentar des alten Threads ... Vielleicht, aber gemeinsame Bibliotheken sind (vermutlich) immer auf dem neuesten Stand der Plattformänderungen, was zu gemeinsamen Ergebnissen führt und die Fragmentierung minimiert, und niemand muss die Räder ständig neu erfinden oder eine Menge Internet verwenden. gefundener Code, der zuverlässig, schnell oder nach Standards strukturiert sein kann oder nicht. Ich bin alle dafür, Abhängigkeiten zu minimieren, aber in so etwas schaue ich zuerst auf die Betriebssystemoptionen, dann auf die allgemeinen Sprachoptionen und dann auf die Standardoptionen von Drittanbietern und führe zu einmaligen Ergebnissen oder "Die Bibliothek dieses Typen ist ziemlich gut". Optionen zuletzt. * Achselzucken *
ChrisH
1

MD5 ist ein Hashing-Algorithmus. Sie müssen hierfür nicht die umfangreiche CommonCrypto-Bibliothek verwenden (und werden von Apple abgelehnt). Verwenden Sie einfach eine beliebige MD5-Hashing-Bibliothek.

Eine solche Bibliothek, die ich benutze, ist SwiftHash , eine reine schnelle Implementierung von MD5 (basierend auf http://pajhome.org.uk/crypt/md5/md5.html ).

Nagendra Rao
quelle
1

Basierend auf Codys Lösung habe ich die Idee, dass wir klären sollten, was das Ergebnis von MD5 ist, da wir das Ergebnis möglicherweise als Hex-Zeichenfolge oder Base64-Zeichenfolge verwenden.

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
}

Die obige Funktion gibt tatsächlich a zurück [UInt8], und basierend auf diesem Ergebnis können wir jede Form von Zeichenfolge erhalten, z. B. hex, base64.

Wenn eine Hex-Zeichenfolge als Endergebnis gewünscht wird (wie in der Frage gestellt), können wir den Rest der Cody-Lösung weiterhin verwenden

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

Wenn eine Base64-Zeichenfolge als Endergebnis gewünscht wird

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

Eine Antwort für Swift 5 mit ordnungsgemäßer Speicherverwaltung und ohne StringKlasse innerhalb der Methode:

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

Beispiel

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)

Ergebnisse:

md5 Optional ("671C121427F12FBBA66CEE71C44CB62C")

sha1 Optional ("A6A40B223AE634CFC8C191DDE024BF0ACA56D7FA")

sha224 Optional ("334370E82F2F5ECF5B2CA0910C6176D94CBA12FD6F518A7AB8D12ADE")

sha256 Optional ("8CF5ED971D6EE2579B1BDEFD4921415AC03DA45B49B89665B3DF197287EFC89D")

sha384 Optional ("04BB3551CBD60035BA7E0BAA141AEACE1EF5E17317A8FD108DA12A7A8E98C245E14F92CC1A241C732209EAC9D600602E")

sha512 Optional ("1D595EAFEB2162672830885D336F75FD481548AC463BE16A8D98DB33637213F1AEB36FA4977B9C23A82A4FAB8A70C06AFC64C610D3CB1FE77A609DC8EE86AA68")

Vyacheslav
quelle
0

meine zwei Cent (wenn Sie schnell md5 für Data / NSData benötigen, zum Beispiel haben Sie Binärdateien für Disk oder Netwkork heruntergeladen oder gelesen)

(schamlos aus "Swift 5-Antwort als String-Erweiterung (basierend auf der großartigen Antwort von 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])
        }
    }
} 

Prüfung:

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