Comment puis-je convertir une chaîne en hachage MD5 dans iOS à l'aide de Swift?

111

Je veux convertir une chaîne comme "abc" en un hachage MD5. Je veux faire cela dans iOS et Swift. J'ai essayé d'utiliser les solutions ci-dessous mais elles ne fonctionnaient pas pour moi:

Importer CommonCrypto dans un framework Swift

Comment utiliser la méthode CC_MD5 dans un langage rapide.

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

Pour être plus clair, je souhaite obtenir une sortie dans Swift similaire à la sortie de ce code PHP:

$str = "Hello";

echo md5($str);

Sortie: 8b1a9953c4611296a827abf8c47804d7

user3606682
la source
5
Quel est le problème avec les liens que vous avez fournis?
jtbandes
2
Les liens que vous avez fournis devraient fonctionner. Pouvez-vous décrire votre problème exact? Vous pouvez également inclure une bibliothèque tierce pour faire ce que vous voulez, c'est-à-dire. github.com/krzyzanowskim/CryptoSwift
Eric Amorde
1
Comme je l'ai mentionné, je suis nouveau dans la programmation rapide, j'étais confus pour l'implémenter de la bonne manière. J'incluais ce fichier (#import <CommonCrypto / CommonCrypto.h>) dans le fichier du contrôleur rapide. Mais merci pour vos réponses, il est résolu maintenant par la réponse de M.
user3606682
Si vous voulez une implémentation locale dans Swift, alors github.com/onmyway133/SwiftHash
onmyway133

Réponses:

178

Il y a deux étapes:
1. Créez des données md5 à partir d'une chaîne
2. Convertissez les données md5 en une chaîne hexadécimale

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

Production:

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

Production:

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

Production:

md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w ==

Remarques:
#import <CommonCrypto/CommonCrypto.h>doit être ajouté à un fichier d'en-tête de pont

Pour savoir comment créer un en-tête de pont, consultez cette réponse SO .

En général, MD5 ne doit pas être utilisé pour de nouveaux travaux, SHA256 est une bonne pratique actuelle.

Exemple de la section de documentation obsolète:

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

Ces fonctions hacheront l'entrée de chaîne ou de données avec l'un des huit algorithmes de hachage cryptographique.

Le paramètre name spécifie le nom de la fonction de hachage en tant que chaîne
Les fonctions prises en charge sont MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 et SHA512 a Cet exemple nécessite Common Crypto
Il est nécessaire d'avoir un en-tête de pontage pour le projet:
#import <CommonCrypto/CommonCrypto.h>
Ajouter la sécurité .framework au projet.



Cette fonction prend un nom de hachage et une chaîne à hacher et renvoie une donnée:

name: nom d'une fonction de hachage sous forme de chaîne  
string: la chaîne à hacher  
renvoie: le résultat haché sous forme de données  
func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}

Exemples:

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

Production:

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

hashSHA256: <aabc766b 6b357564 e41f4f91 2d494bcc bfa16924 b574abbd ba9e3e9d a0c8920a>
hashMD5: <4df665f7 b94aea69 695b0e7b baf9e9d6>
zaph
la source
3
Merci alottt @zaph, je me débattais pour ça depuis plus de 2 jours. Je l'ai résolu avec votre réponse ci-dessus :) Et oui, je récupère d'anciennes données sur le Web où MD5 est utilisé, alors je suis obligé d'utiliser MD5. Mais merci encore pour la réponse et la suggestion d'utiliser SHA256 :)
user3606682
String(data: digestData, encoding: String.Encoding.utf8)lancersfatal error: unexpectedly found nil while unwrapping an Optional value
Siddharth
@Siddharth Il n'y a pas assez d'informations dans le commentaire, on ne sait pas ce que digestDatac'est. S'il s'agit de données de hachage, il y a des chances que ce soit UTF-8 (ou tout encodage de chaîne est mince à inexistant.
zaph
1
Voici comment vous pouvez l'améliorer: importez uniquement les symboles requis et non l'intégralité de CommonCrypto, car c'est un peu une surcharge sinon: import var CommonCrypto.CC_MD5_DIGEST_LENGTH import func CommonCrypto.CC_MD5 import typealias CommonCrypto.CC_LONG
Igor Vasilev
2
@zaph, vous voudrez peut-être ajouter la solution iOS 13 CryptoKit à votre réponse que j'ai détaillée dans ma réponse ci-dessous: stackoverflow.com/a/56578995/368085
mluisbrown
40

Après avoir lu les autres réponses ici (et avoir également besoin de prendre en charge d'autres types de hachage), j'ai écrit une extension String qui gère plusieurs types de hachage et types de sortie.

REMARQUE: CommonCrypto est inclus dans Xcode 10, vous pouvez donc simplement import CommonCryptosans avoir à jouer avec un en-tête de pontage si vous avez la dernière version de Xcode installée ... Sinon, un en-tête de pontage est nécessaire.


MISE À JOUR: Les Swift 4 et 5 utilisent le même fichier String + Crypto.swift ci-dessous.

Il existe un fichier Data + Crypto.swift séparé pour Swift 5 (voir ci-dessous) comme l'API pour 'withUnsafeMutableBytes' et 'withUnsafeBytes' changé entre Swift 4 et 5.


String + Crypto.swift - (pour Swift 4 et 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 - Données + 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 - Données + 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()
        }
    }
}

Edit: puisque le hachage se produit réellement sur les données, j'ai divisé l'algorithme de hachage en une extension de données. Cela permet également d'utiliser le même algorithme pour les opérations de hachage d'épinglage de certificats SSL.

Voici un court exemple de la façon dont vous pourriez l'utiliser pour une opération d'épinglage 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
}

retour à la réponse originale

J'ai testé les algorithmes de hachage en utilisant ceci:

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

et voici les résultats imprimés:

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

Depuis iOS 13, Apple a ajouté le CryptoKitframework afin que vous n'ayez plus besoin d'importer CommonCrypto ou de gérer son 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()
}
mluisbrown
la source
3
Il est également intéressant de noter que cela permet d'éviter l'avertissement selon lequel MD5 n'est pas sécurisé. Vous n'avez pas besoin d'implémenter CommonCrypto dans Objective-C afin de prendre en charge les pragmas pour désactiver l'avertissement. Pratique si vous travaillez dans un environnement qui met l'accent sur la gestion des avertissements.
marcus.ramsden
28

SWIFT 3version de 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
}

Lien original de http://iosdeveloperzone.com

wajih
la source
23

Swift 4. *, mise à jour Xcode 10:

Dans Xcode 10, vous n'avez plus besoin d'utiliser Bridging-Header , vous pouvez importer directement en utilisant

import CommonCrypto

Et puis écrivez une méthode quelque chose comme:

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

Utilisation:

MD5("This is my string")

Production:

c2a9ce57e8df081b4baad80d81868bbb
Invictus Cody
la source
votre solution est parfaitement travaillée. Pouvons-nous ajouter de la valeur SALT avec ce cryptage MD5? Je veux ajouter pendant le cryptage de la chaîne. pouvez-vous fournir un lien d'utilisation complète?
Punita
Je ne sais pas ce que vous essayez de réaliser. Utilisez "AES128", si vous souhaitez un cryptage personnalisé avec salage. si la sécurité est votre préoccupation, vérifiez ceci: stackoverflow.com/a/15775071/3118377 .
Invictus Cody
Merci Invictus Cody, j'ai concaténé SALT avec String et j'ai pu obtenir MD5.
Punita
Fonctionne très bien. Mais comment le reconvertir en 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

J'ai publié une implémentation Swift pure qui ne dépend pas de CommonCrypto ou de quoi que ce soit d'autre. Il est disponible sous licence MIT.

Le code se compose d'un seul fichier Swift que vous pouvez simplement déposer dans votre projet. Si vous préférez, vous pouvez également utiliser le projet Xcode contenu avec des cibles de framework et de test unitaire.

C'est simple à utiliser:

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

imprime: md5: 9e107d9d372bb6826bd81d3542a419d6

Le fichier swift contient de la documentation et d'autres exemples.

Nikolai Ruhe
la source
4
Nécessite Swift 4 qui n'est pas mentionné ici ou sur le Lisez-moi de Github. L'utilisation ne doit pas être envisagée sans les chiffres de performance fournis par rapport à Common Crypto. Remarque: Common Crypto est certifié FIPS 140, SwiftDigest ne l'est pas. Voici la question clé: en quoi est-ce meilleur que Common Crypto pour la mise en œuvre? Plus sûr: Non, plus vite: Non
zaph
1
@zaph Le but principal est d'avoir une implémentation md5 qui ne dépend pas de CommonCrypto. Cela est utile dans les situations où CommonCrypto n'est pas disponible, comme les cibles du framework Swift ou sur les plates-formes non Apple.
Nikolai Ruhe
4
@zaph Je suis d'accord que les implémentations liées à la sécurité ne doivent pas être prises à la légère. Mais MD5 a d'autres utilisations que la sécurité - ou, plutôt, la sécurité est celle où MD5 fonctionne le moins bien. Les algorithmes de hachage sont utilisés pour l'identification, le tri, le stockage, les dictionnaires, la détection d'erreurs et d'autres raisons. MD5 est particulièrement utile en raison de son ubiquité. Donc, bien que je sois d'accord avec quelques-uns de vos commentaires, je ne suis pas d'accord avec l'essentiel. Je pense que votre point de vue et votre argumentation sont trop étroits; il n’englobe pas l’ensemble du sujet.
Nikolai Ruhe
2
De plus, je viens de tester, et mon implémentation est plus rapide que CommonCrypto pour les gros messages :)
Nikolai Ruhe
2
J'aime cette implémentation. Merci beaucoup @NikolaiRuhe! J'ai pu le convertir facilement en compatibilité Swift 3. J'ai également ajouté quelques méthodes pratiques, notamment le calcul du résumé du contenu du fichier à partir d'une URL et la récupération de l'encodage base64 (utile pour Content-MD5 entre autres). @Siddharth, le seul fichier dont vous avez besoin est MD5Digest.swift.
biomiker
10

Juste deux notes ici:

L'utilisation de Crypto est trop lourde pour y parvenir.

La réponse acceptée est parfaite! Néanmoins, je voulais juste partager une approche de code Swift ier utilisant Swift 2.2 .

Veuillez garder à l'esprit que vous devez toujours le faire #import <CommonCrypto/CommonCrypto.h>dans votre fichier d'en -tête de pont

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
la source
7

Réponse Swift 5 en tant qu'extension String (basée sur la grande réponse d'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])
        }
    }
}

Usage:

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

Voici une extension basée sur la réponse 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()
        }
    }
}

Entièrement compatible avec swift 3.0, vous devez toujours le faire #import <CommonCrypto/CommonCrypto.h>dans votre fichier Bridging-Header

Glaubenio Patricio
la source
3

Dans la programmation rapide, il est préférable de créer une fonction de chaîne, donc l'utilisation sera facile. Ici, je crée une extension String en utilisant l'une des solutions ci-dessus. Merci @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
}
}

Usage

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

J'ai utilisé Carthage et Cyrpto pour faire cela.

  1. Installez Carthage si vous ne l'avez pas déjà fait

  2. Installez Crypto dans votre projet

  3. exécuter la 'mise à jour du cartage'

  4. Si vous exécutez à partir de la ligne de commande, ajoutez le framework dans le fichier swift

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. Ajoutez import Crypto à votre fichier swift.

  6. alors ça marche!

    print( "convert this".MD5 )
Keith John Hutchison
la source
C'est un peu exagéré d'utiliser une bibliothèque de cryptographie à part entière lorsqu'une seule fonction est nécessaire
Mark Bourke
Excusez-vous pour le commentaire de l'ancien thread ... Peut-être, mais les bibliothèques communes sont (vraisemblablement) toujours à jour avec les changements de plate-forme, donnant ainsi des résultats communs et minimisant la fragmentation, et personne n'a à réinventer continuellement les roues ou à utiliser un tas d'Internet- trouvé du code qui peut ou non être fiable, rapide ou calqué sur des normes. Je suis tout à fait pour la minimisation des dépendances, mais dans quelque chose comme ça, je regarde d'abord les options du système d'exploitation, les options de langage commun ensuite, et les options standard tierces ensuite, et le résultat est ponctuel ou "la bibliothèque de ce type est plutôt bonne" les options durent. * haussement d'épaules *
ChrisH
1

MD5 est un algorithme de hachage, pas besoin d'utiliser la volumineuse bibliothèque CommonCrypto pour cela (et être rejeté par la revue Apple), utilisez simplement n'importe quelle bibliothèque de hachage md5.

Une de ces bibliothèques que j'utilise est SwiftHash , une implémentation pure et rapide de MD5 (basée sur http://pajhome.org.uk/crypt/md5/md5.html )

Nagendra Rao
la source
1

Sur la base de la solution de Cody , j'ai une idée selon laquelle nous devrions clarifier le résultat de MD5, car nous pouvons utiliser le résultat sous forme de chaîne hexadécimale ou de chaîne 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 fonction ci-dessus renvoie en fait a [UInt8], et sur la base de ce résultat, nous pouvons obtenir n'importe quelle forme de chaîne, telle que hex, base64.

Si une chaîne hexadécimale est souhaitée comme résultat final (comme le demande la question), nous pouvons continuer à utiliser le reste de la solution de Cody

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

Si une chaîne Base64 est souhaitée comme résultat final

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

Une réponse pour Swift 5 avec une bonne gestion de la mémoire et sans Stringclasse à l'intérieur de la méthode:

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

exemple

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)

Résultats:

md5 en option ("671C121427F12FBBA66CEE71C44CB62C")

sha1 Facultatif ("A6A40B223AE634CFC8C191DDE024BF0ACA56D7FA")

sha224 Facultatif ("334370E82F2F5ECF5B2CA0910C6176D94CBA12FD6F518A7AB8D12ADE")

sha256 Facultatif ("8CF5ED971D6EE2579B1BDEFD4921415AC03DA45B49B89665B3DF197287EFC89D")

sha384 Facultatif ("04BB3551CBD60035BA7E0BAA141AEACE1EF5E17317A8FD108DA12A7A8E98C245E14F92CC1A241C732209EAC9D600602E")

sha512 Facultatif ("1D595EAFEB2162672830885D336F75FD481548AC463BE16A8D98DB33637213F1AEB36FA4977B9C23A82A4FAB8A70C06AFC64C610D3CB1FE77A609DC8EE86AA68")

Vyacheslav
la source
0

mes deux cents (si vous avez besoin rapidement de md5 pour les données / NSData, par exemple vous avez téléchargé ou lu le binaire pour le disque ou le réseau)

(sans vergogne d'après "Swift 5 answer as a String extension (basé sur la grande réponse d'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])
        }
    }
} 

tester:

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