Come posso convertire una stringa in un hash MD5 in iOS utilizzando Swift?


111

Voglio convertire una stringa come "abc" in un hash MD5. Voglio farlo in iOS e Swift. Ho provato a utilizzare le soluzioni seguenti ma non funzionavano per me:

Importazione di CommonCrypto in un framework Swift

Come utilizzare il metodo CC_MD5 in un linguaggio rapido.

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

Per essere più chiari, voglio ottenere un output in Swift simile all'output di questo codice PHP:

$str = "Hello";

echo md5($str);

Uscita: 8b1a9953c4611296a827abf8c47804d7


5
Cosa c'è di sbagliato nei link che hai fornito?
jtbandes

2
I link che hai fornito dovrebbero funzionare. Puoi descrivere qual è il tuo problema esatto? Puoi anche includere una libreria di terze parti per fare quello che vuoi, ad es. github.com/krzyzanowskim/CryptoSwift
Eric Amorde

1
Come ho già detto, sono nuovo alla programmazione rapida, ero confuso nell'implementarlo nel modo giusto. stavo includendo questo file (#import <CommonCrypto / CommonCrypto.h>) nel file del controller swift. Ma grazie per le vostre risposte, ora è stato risolto dalla risposta del signor Zaph fornita di seguito.
user3606682

Se desideri un'implementazione interna in Swift, allora github.com/onmyway133/SwiftHash
onmyway133

Risposte:


178

Ci sono due passaggi:
1. Creare dati md5 da una stringa
2. Coprire i dati md5 in una stringa esadecimale

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

Produzione:

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

Produzione:

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

Produzione:

md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w ==

Appunti:
#import <CommonCrypto/CommonCrypto.h> deve essere aggiunto a un file Bridging-Header

Per come creare un Bridging-Header vedere questa risposta SO .

In generale MD5 non dovrebbe essere utilizzato per nuovi lavori, SHA256 è una best practice corrente.

Esempio dalla sezione della documentazione obsoleta:

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

Queste funzioni eseguiranno l'hashing di String o Data input con uno degli otto algoritmi di hash crittografici.

Il parametro name specifica il nome della funzione hash come stringa
Le funzioni supportate sono MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 e SHA512 a Questo esempio richiede Common Crypto
È necessario avere un'intestazione di bridging al progetto:
#import <CommonCrypto/CommonCrypto.h>
Aggiungi la sicurezza .framework al progetto.



Questa funzione accetta un nome hash e una stringa da sottoporre a hashing e restituisce un Data:

nome: un nome di una funzione hash come stringa  
stringa: la stringa da sottoporre ad hashing  
restituisce: il risultato con hash come Data  
func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}

Esempi:

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

Produzione:

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

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

3
Grazie mille @zaph, stavo lottando per questo da più di 2 giorni. Ho risolto con la tua risposta sopra :) E sì, sto recuperando i vecchi dati dal web in cui viene utilizzato MD5, quindi sono costretto a utilizzare MD5. Ma grazie ancora per la risposta e il suggerimento di utilizzare SHA256 :)
user3606682

String(data: digestData, encoding: String.Encoding.utf8)lancifatal error: unexpectedly found nil while unwrapping an Optional value
Siddharth

@ Siddharth Non ci sono abbastanza informazioni nel commento, non è chiaro cosa digestDatasia. Se si tratta di dati hash, è probabile che sia UTF-8 (o qualsiasi codifica di stringa è da scarsa a inesistente.
zaph

1
Ecco come puoi migliorarlo: importa solo i simboli richiesti e non l'intero CommonCrypto, perché altrimenti è un po 'un overhead: import var CommonCrypto.CC_MD5_DIGEST_LENGTH import func CommonCrypto.CC_MD5 import typealias CommonCrypto.CC_LONG
Igor Vasilev

2
@zaph si consiglia di aggiungere la soluzione CryptoKit iOS 13 per la risposta che ho dettagliato nella mia risposta qui sotto: stackoverflow.com/a/56578995/368085
mluisbrown

40

Dopo aver letto le altre risposte qui (e aver bisogno di supportare anche altri tipi di hash) ho scritto un'estensione String che gestisce più tipi di hash e tipi di output.

NOTA: CommonCrypto è incluso in Xcode 10, quindi puoi semplicemente import CommonCryptosenza dover scherzare con un'intestazione di bridging se hai installato l'ultima versione di Xcode ... Altrimenti è necessaria un'intestazione di bridging.


AGGIORNAMENTO: Sia Swift 4 che 5 utilizzano lo stesso file String + Crypto.swift di seguito.

Esiste un file Data + Crypto.swift separato per Swift 5 (vedi sotto) poiché l'API per "withUnsafeMutableBytes" e "withUnsafeBytes" è stato modificato tra Swift 4 e 5.


String + Crypto.swift - (sia per Swift 4 che per 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 - Dati + 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 - Dati + 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()
        }
    }
}

Modifica: poiché l'hash si verifica effettivamente sui dati, ho suddiviso l'algoritmo di hashing in un'estensione dati. Ciò consente di utilizzare lo stesso algoritmo anche per le operazioni hash di blocco del certificato SSL.

Ecco un breve esempio di come potresti usarlo per un'operazione di blocco 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
}

torna alla risposta originale

Ho testato gli algoritmi hash usando questo:

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

e questo è il risultato stampato:

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

39

A partire da iOS 13 Apple ha aggiunto il CryptoKitframework quindi non è più necessario importare CommonCrypto o gestire la sua API C:

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
Vale anche la pena notare che questo fornisce un mezzo per evitare l'avvertimento che MD5 ora è insicuro. Non è necessario implementare CommonCrypto in Objective-C in modo da avere il supporto per i pragma per disabilitare l'avviso. Utile se si lavora in un ambiente che pone l'accento sulla gestione degli avvisi.
marcus.ramsden

28

SWIFT 3versione di 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
}

Link originale da http://iosdeveloperzone.com


23

Swift 4. *, Aggiornamento Xcode 10:

In Xcode 10 non è più necessario utilizzare Bridging-Header , è possibile importare direttamente utilizzando

import CommonCrypto

E poi scrivi un metodo simile a:

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

Utilizzo:

MD5("This is my string")

Produzione:

c2a9ce57e8df081b4baad80d81868bbb

la tua soluzione è perfettamente funzionante. Possiamo aggiungere valore SALT con questa crittografia MD5? Voglio aggiungere durante la crittografia della stringa. potete fornire qualche link completo di utilizzo?
Punita

Non sono sicuro di cosa stai cercando di ottenere. Usa "AES128", se desideri una crittografia personalizzata con salting. se la sicurezza è la tua preoccupazione, dai un'occhiata a: stackoverflow.com/a/15775071/3118377 .
Invictus Cody

Grazie Invictus Cody, ho concatenato SALT con String e in grado di ottenere MD5.
Punita

Funziona alla grande. Ma come riconvertirlo 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

Ho rilasciato un'implementazione Swift pura che non dipende da CommonCrypto o da qualsiasi altra cosa. È disponibile con licenza MIT.

Il codice è costituito da un singolo file swift che puoi semplicemente inserire nel tuo progetto. Se preferisci puoi anche utilizzare il progetto Xcode contenuto con framework e obiettivi di unit test.

È semplice da usare:

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

stampe: md5: 9e107d9d372bb6826bd81d3542a419d6

Il file swift contiene documentazione e altri esempi.


4
Richiede Swift 4, che non è menzionato qui o nel file Leggimi di Github. L'utilizzo non dovrebbe essere considerato senza i dati sulle prestazioni forniti rispetto a Common Crypto. Nota: Common Crypto è certificato FIPS 140, SwiftDigest no. Ecco la domanda chiave: come è meglio di Common Crypto per l'implementazione? Più sicuro: No, più veloce: No.
Zaph

1
@zaph Lo scopo principale è avere un'implementazione md5 che non dipenda da CommonCrypto. Ciò è utile in situazioni in cui CommonCrypto non è disponibile, come i target del framework Swift o su piattaforme non Apple.
Nikolai Ruhe,

4
@zaph Sono d'accordo che le implementazioni rilevanti per la sicurezza non devono essere prese alla leggera. Ma MD5 ha altri usi oltre alla sicurezza, o meglio, la sicurezza è dove MD5 ha prestazioni peggiori. Gli algoritmi di hash vengono utilizzati per l'identificazione, l'ordinamento, l'archiviazione, i dizionari, il rilevamento degli errori e altri motivi. MD5 è particolarmente utile a causa della sua ubiquità. Quindi, mentre sono d'accordo con un paio di tuoi commenti, non condivido il succo. Penso che il tuo punto di vista e le tue argomentazioni siano troppo limitate; non abbraccia l'intero argomento.
Nikolai Ruhe,

2
Inoltre, ho appena testato e la mia implementazione è più veloce di CommonCrypto per messaggi di grandi dimensioni :)
Nikolai Ruhe

2
Mi piace questa implementazione. Grazie mille @NikolaiRuhe! Sono stato in grado di convertirlo facilmente in compatibilità con Swift 3. Ho anche aggiunto alcuni metodi di convenienza tra cui il calcolo del digest del contenuto del file dato un URL e il recupero della codifica base64 (utile per Content-MD5 tra le altre cose). @ Siddharth l'unico file di cui hai bisogno è MD5Digest.swift.
biomiker

10

Solo due note qui:

Usare Crypto è troppo sovraccarico per ottenere proprio questo.

La risposta accettata è perfetta! Tuttavia, volevo solo condividere un approccio al codice Swift ier usando Swift 2.2 .

Tieni presente che devi ancora farlo #import <CommonCrypto/CommonCrypto.h>nel tuo file Bridging-Header

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

Risposta Swift 5 come estensione String (basata sull'ottima risposta di 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])
        }
    }
}

Uso:

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

6

Ecco un'estensione basata sulla risposta di 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()
        }
    }
}

Pienamente compatibile con swift 3.0. Devi ancora farlo #import <CommonCrypto/CommonCrypto.h>nel tuo file Bridging-Header


3

Nella programmazione rapida è meglio creare una funzione stringa, quindi l'uso sarà facile. Qui sto realizzando un'estensione String usando una delle soluzioni sopra indicate. Grazie @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
}
}

uso

let md5String = "abc".md5()

1

Ho usato Cartagine e Cyrpto per farlo.

  1. Installa Carthage se non l'hai già fatto

  2. Installa Crypto nel tuo progetto

  3. eseguire "aggiornamento carrello"

  4. Se stai eseguendo dalla riga di comando, aggiungi nel framework nel file swift

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. Aggiungi import Crypto al tuo file swift.

  6. allora funziona e basta!

    print( "convert this".MD5 )

È un po 'esagerato utilizzare una libreria di crittografia completa quando è necessaria una sola funzione
Mark Bourke

Scusati per il commento del vecchio thread ... Forse, ma le biblioteche comuni sono (presumibilmente) sempre aggiornate con i cambiamenti di piattaforma, producendo così risultati comuni e riducendo al minimo la frammentazione, e nessuno deve reinventare continuamente le ruote o usare un mucchio di Internet- ha trovato codice che può o non può essere affidabile, veloce o modellato su standard. Sono tutto per ridurre al minimo le dipendenze, ma in qualcosa di simile, guardo prima le opzioni del sistema operativo, poi le opzioni di lingua comune e poi le opzioni standard di terze parti, e il risultato è una tantum o "la libreria di questo ragazzo è abbastanza buona" le opzioni durano. * scrollata di spalle *
ChrisH

1

MD5 è un algoritmo di hashing, non è necessario utilizzare l'ingombrante libreria CommonCrypto per questo (e viene rifiutato dalla revisione Apple), basta usare qualsiasi libreria di hashing md5.

Una di queste librerie che utilizzo è SwiftHash , un'implementazione rapida e pura di MD5 (basata su http://pajhome.org.uk/crypt/md5/md5.html )


1

Sulla base della soluzione di Cody , ho un'idea che dovremmo chiarire qual è il risultato di MD5, perché possiamo usare il risultato come una stringa esadecimale o una stringa 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
}

La funzione sopra restituisce effettivamente a [UInt8]e, in base a questo risultato, possiamo ottenere qualsiasi forma di stringa, come hex, base64.

Se si desidera una stringa esadecimale come risultato finale (come chiede la domanda), possiamo continuare a utilizzare la parte restante della soluzione di Cody

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

Se si desidera una stringa Base64 come risultato finale

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

1

Una risposta per Swift 5 con una corretta gestione della memoria e senza Stringclasse all'interno del metodo:

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

esempio

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)

risultati:

md5 Opzionale ("671C121427F12FBBA66CEE71C44CB62C")

sha1 Opzionale ("A6A40B223AE634CFC8C191DDE024BF0ACA56D7FA")

sha224 Opzionale ("334370E82F2F5ECF5B2CA0910C6176D94CBA12FD6F518A7AB8D12ADE")

sha256 Opzionale ("8CF5ED971D6EE2579B1BDEFD4921415AC03DA45B49B89665B3DF197287EFC89D")

sha384 Opzionale ("04BB3551CBD60035BA7E0BAA141AEACE1EF5E17317A8FD108DA12A7A8E98C245E14F92CC1A241C732209EAC9D600602E")

sha512 Opzionale ("1D595EAFEB2162672830885D336F75FD481548AC463BE16A8D98DB33637213F1AEB36FA4977B9C23A82A4FAB8A70C06AFC64C610D3CB1FE77A609DC8EE86AA68")



0

i miei due centesimi (se hai bisogno rapidamente di md5 per Data / NSData, ad esempio hai scaricato o letto binario per disco o netwkork)

(spudorato da "Swift 5 answer as a String extension (based on the great answer of 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])
        }
    }
} 

test:

print("test".data.md5Value) /*098f6bcd4621d373cade4e832627b4f6*/
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.