¿Cómo puedo convertir una cadena en un hash MD5 en iOS usando Swift?

111

Quiero convertir una cadena como "abc" en un hash MD5. Quiero hacer esto en iOS y Swift. Intenté usar las soluciones a continuación, pero no me funcionaron:

Importación de CommonCrypto en un marco Swift

Cómo utilizar el método CC_MD5 en lenguaje rápido.

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

Para ser más claro, quiero lograr una salida en Swift similar a la salida de este código PHP:

$str = "Hello";

echo md5($str);

Salida: 8b1a9953c4611296a827abf8c47804d7

usuario3606682
fuente
5
¿Qué pasa con los enlaces que proporcionaste?
jtbandes
2
Los enlaces que proporcionó deberían funcionar. ¿Puede describir cuál es su problema exacto? También puede incluir una biblioteca de terceros para hacer lo que quiera, es decir. github.com/krzyzanowskim/CryptoSwift
Eric Amorde
1
Como mencioné que soy nuevo en la programación rápida, estaba confundido para implementarlo de la manera correcta. Estaba incluyendo este archivo (#import <CommonCrypto / CommonCrypto.h>) en el archivo del controlador rápido. Pero gracias por sus respuestas, ahora se resuelve con la respuesta del Sr.zaph que se da a continuación.
user3606682
Si desea una implementación local en Swift, github.com/onmyway133/SwiftHash
onmyway133

Respuestas:

178

Hay dos pasos:
1. Crear datos md5 a partir de una cadena.
2. Convertir los datos md5 en una cadena hexadecimal.

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

Salida:

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

Salida:

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

Salida:

md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w ==

Notas:
#import <CommonCrypto/CommonCrypto.h>debe agregarse a un archivo de encabezado puente

Para saber cómo crear un encabezado de puente, consulte esta respuesta SO .

En general, MD5 no debe usarse para trabajos nuevos, SHA256 es una de las mejores prácticas actuales.

Ejemplo de la sección de documentación obsoleta:

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

Estas funciones procesarán la entrada de datos o cadenas con uno de los ocho algoritmos hash criptográficos.

El parámetro de nombre especifica el nombre de la función hash como una cadena
Las funciones admitidas son MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 y SHA512 a Este ejemplo requiere Common Crypto
Es necesario tener un encabezado puente para el proyecto:
#import <CommonCrypto/CommonCrypto.h>
Agregar la seguridad .framework al proyecto.



Esta función toma un nombre hash y una cadena para ser hash y devuelve un dato:

nombre: un nombre de una función hash como una cadena  
cadena: la cadena que se va a aplicar hash  
devuelve: el resultado hash como datos  
func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}

Ejemplos:

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

Salida:

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

hashSHA256: <aabc766b 6b357564 e41f4f91 2d494bcc bfa16924 b574abbd ba9e3e9d a0c8920a>
hashMD5: <4df665f7 b94aea69 695b0e7b baf9e9d6>
zaph
fuente
3
Muchas gracias @zaph, estuve luchando por esto desde hace más de 2 días. Lo resolví con tu respuesta anterior :) Y sí, estoy recuperando datos antiguos de la web donde se usa MD5, así que me veo obligado a usar MD5. Pero gracias de nuevo por la respuesta y la sugerencia de usar SHA256 :)
user3606682
String(data: digestData, encoding: String.Encoding.utf8)lanzafatal error: unexpectedly found nil while unwrapping an Optional value
Siddharth
@Siddharth No hay suficiente información en el comentario, no está claro qué digestDataes. Si se trata de datos hash, las posibilidades de que sea UTF-8 (o cualquier codificación de cadena es escasa o inexistente.)
zaph
1
Así es como puede mejorarlo: importe solo los símbolos requeridos y no el CommonCrypto completo, porque de lo contrario es un poco sobrecargado: import var CommonCrypto.CC_MD5_DIGEST_LENGTH import func CommonCrypto.CC_MD5 import typealias CommonCrypto.CC_LONG
Igor Vasilev
2
@zaph, es posible que desee agregar la solución iOS 13 CryptoKit a su respuesta que detallé en mi respuesta a continuación: stackoverflow.com/a/56578995/368085
mluisbrown
40

Después de leer las otras respuestas aquí (y necesitar también admitir otros tipos de hash), escribí una extensión de cadena que maneja múltiples tipos de hash y tipos de salida.

NOTA: CommonCrypto está incluido en Xcode 10, por lo que puede simplemente import CommonCryptosin tener que meterse con un encabezado puente si tiene instalada la última versión de Xcode ... De lo contrario, es necesario un encabezado puente.


ACTUALIZACIÓN: Ambos Swift 4 y 5 usan el mismo archivo String + Crypto.swift a continuación.

Hay un archivo Data + Crypto.swift separado para Swift 5 (ver más abajo) como la API para 'withUnsafeMutableBytes' y 'withUnsafeBytes' cambiada entre Swift 4 y 5.


String + Crypto.swift - (para Swift 4 y 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 - Datos + 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 - Datos + 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()
        }
    }
}

Editar: dado que el hash realmente ocurre en los datos, divido el algoritmo de hash en una extensión de datos. Esto permite que el mismo algoritmo se utilice también para operaciones hash de fijación de certificados SSL.

Aquí hay un breve ejemplo de cómo puede usarlo para una operación de fijación de 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
}

de vuelta a la respuesta original

Probé los algoritmos hash usando esto:

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

y estos son los resultados impresos:

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

A partir de iOS 13, Apple ha agregado el CryptoKitmarco, por lo que ya no necesita importar CommonCrypto o manejar su 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
fuente
3
También vale la pena señalar que esto proporciona un medio para evitar la advertencia de que MD5 ahora es inseguro. No es necesario implementar CommonCrypto en Objective-C para que tenga soporte para pragmas para deshabilitar la advertencia. Útil si está trabajando en un entorno que pone énfasis en lidiar con las advertencias.
marcus.ramsden
28

SWIFT 3versión 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
}

Enlace original de http://iosdeveloperzone.com

wajih
fuente
23

Swift 4. *, actualización de Xcode 10:

En Xcode 10 ya no tiene que usar Bridging-Header , puede importar directamente usando

import CommonCrypto

Y luego escribe un método como:

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

Uso:

MD5("This is my string")

Salida:

c2a9ce57e8df081b4baad80d81868bbb
Invictus Cody
fuente
tu solución está perfectamente trabajada. ¿Podemos agregar valor SALT con este cifrado MD5? Quiero agregar mientras se encripta la cadena. ¿Puede proporcionar algún enlace de uso completo?
Punita
No estoy seguro de qué estás tratando de lograr. Utilice "AES128", si desea cifrado personalizado con salazón. Si le preocupa la seguridad, consulte esto: stackoverflow.com/a/15775071/3118377 .
Invictus Cody
Gracias Invictus Cody, he concatenado SALT con String y he podido obtener MD5.
Punita
Funciona genial. Pero, ¿cómo se vuelve a convertir 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

Lancé una implementación Swift pura que no depende de CommonCrypto ni de nada más. Está disponible bajo licencia MIT.

El código consta de un único archivo rápido que puede colocar en su proyecto. Si lo prefiere, también puede usar el proyecto Xcode contenido con objetivos de prueba unitaria y marco.

Es simple de usar:

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

huellas dactilares: md5: 9e107d9d372bb6826bd81d3542a419d6

El archivo rápido contiene documentación y más ejemplos.

Nikolai Ruhe
fuente
4
Requiere Swift 4, que no se menciona aquí ni en el archivo Léame de Github. El uso no debe considerarse sin las cifras de rendimiento proporcionadas en comparación con Common Crypto. Nota: Common Crypto tiene certificación FIPS 140, SwiftDigest no. Aquí está la pregunta clave: ¿Cómo es esto mejor que Common Crypto para la implementación? Más seguro: no, más rápido: no
zaph
1
@zaph El propósito principal es tener una implementación md5 que no dependa de CommonCrypto. Eso es útil en situaciones en las que CommonCrypto no está disponible, como los objetivos del marco Swift o en plataformas que no son de Apple.
Nikolai Ruhe
4
@zaph Estoy de acuerdo en que las implementaciones relevantes para la seguridad no deben tomarse a la ligera. Pero MD5 tiene otros usos además de la seguridad, o más bien, la seguridad es donde MD5 se desempeña peor. Los algoritmos de hash se utilizan para la identificación, clasificación, almacenamiento, diccionarios, detección de errores y otras razones. MD5 es especialmente útil debido a su ubicuidad. Entonces, aunque estoy de acuerdo con un par de sus comentarios, no estoy de acuerdo con la esencia. Creo que su punto de vista y su argumentación son demasiado estrechos; no abarca todo el tema.
Nikolai Ruhe
2
Además, acabo de probar y mi implementación es más rápida que CommonCrypto para mensajes grandes :)
Nikolai Ruhe
2
Me gusta esta implementación. ¡Muchas gracias @NikolaiRuhe! Pude convertirlo fácilmente a compatibilidad con Swift 3. También agregué algunos métodos de conveniencia, incluido el resumen informático del contenido del archivo dado una URL y la recuperación de la codificación base64 (útil para Content-MD5, entre otras cosas). @Siddharth, el único archivo que necesita es MD5Digest.swift.
biomiker
10

Solo dos notas aquí:

Usar Crypto es demasiado para lograr esto.

¡La respuesta aceptada es perfecta! Sin embargo, solo quería compartir un enfoque de código Swift ier utilizando Swift 2.2 .

Tenga en cuenta que aún tiene que hacerlo #import <CommonCrypto/CommonCrypto.h>en su archivo de encabezado puente

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

Respuesta de Swift 5 como una extensión de cadena (basada en la gran respuesta de 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*/
Tamás Sengel
fuente
6

Aquí hay una extensión basada en la respuesta de 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()
        }
    }
}

Totalmente compatible con swift 3.0, todavía tiene que hacerlo #import <CommonCrypto/CommonCrypto.h>en su archivo Bridging-Header

Glaubenio Patricio
fuente
3

En la programación rápida, es mejor hacer una función de cadena, por lo que el uso será fácil. Aquí estoy haciendo una extensión String usando una de las soluciones dadas anteriormente. Gracias @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()
Rahul K Rajan
fuente
1

Usé Carthage y Cyrpto para hacer esto.

  1. Instale Carthage si aún no lo ha hecho

  2. Instale Crypto en su proyecto

  3. ejecutar 'actualización de transporte'

  4. Si está ejecutando desde la línea de comandos, agregue el marco en el archivo rápido

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. Agregue Importar Crypto a su archivo rápido.

  6. entonces simplemente funciona!

    print( "convert this".MD5 )
Keith John Hutchison
fuente
Es un poco exagerado usar una biblioteca de criptografía completa cuando solo se necesita una función
Mark Bourke
Discúlpese por el comentario del viejo hilo ... Quizás, pero las bibliotecas comunes están (presumiblemente) siempre al día con los cambios de plataforma, lo que produce resultados comunes y minimiza la fragmentación, y nadie tiene que reinventar continuamente ruedas o usar un montón de Internet. encontró código que puede o no ser confiable, rápido o basado en estándares. Estoy a favor de minimizar las dependencias, pero en algo como esto, primero miro las opciones del sistema operativo, las opciones de lenguaje común en segundo y las opciones estándar de terceros a continuación, y el resultado es algo único o "la biblioteca de este tipo es bastante buena". opciones duran. * encogimiento de hombros *
ChrisH
1

MD5 es un algoritmo de hash, no es necesario usar la enorme biblioteca CommonCrypto para esto (y ser rechazado por la revisión de Apple), solo use cualquier biblioteca de hash md5.

Una de esas bibliotecas que uso es SwiftHash , una implementación pura y rápida de MD5 (basada en http://pajhome.org.uk/crypt/md5/md5.html )

Nagendra Rao
fuente
1

Según la solución de Cody , tengo la idea de que deberíamos aclarar cuál es el resultado de MD5, porque podemos usar el resultado como una cadena hexadecimal o una cadena 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 función anterior en realidad devuelve a [UInt8], y en base a este resultado, podemos obtener cualquier forma de cadena, como hex, base64.

Si se desea una cadena hexadecimal como resultado final (como pide la pregunta), podemos seguir usando el resto de la solución 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 se desea una cadena Base64 como resultado final

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

Una respuesta para Swift 5 con una gestión de memoria adecuada y sin Stringclase dentro del método:

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

ejemplo

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)

Resultados:

md5 Opcional ("671C121427F12FBBA66CEE71C44CB62C")

sha1 Opcional ("A6A40B223AE634CFC8C191DDE024BF0ACA56D7FA")

sha224 Opcional ("334370E82F2F5ECF5B2CA0910C6176D94CBA12FD6F518A7AB8D12ADE")

sha256 Opcional ("8CF5ED971D6EE2579B1BDEFD4921415AC03DA45B49B89665B3DF197287EFC89D")

sha384 Opcional ("04BB3551CBD60035BA7E0BAA141AEACE1EF5E17317A8FD108DA12A7A8E98C245E14F92CC1A241C732209EAC9D600602E")

sha512 Opcional ("1D595EAFEB2162672830885D336F75FD481548AC463BE16A8D98DB33637213F1AEB36FA4977B9C23A82A4FAB8A70C06AFC64C610D3CB1FE77A609DC8EE86AA68")

Vyacheslav
fuente
0

mis dos centavos (si necesita rápidamente md5 para Data / NSData, por ejemplo, descargó o leyó binario para disco o netwkork)

(descarado de "Swift 5 responde como una extensión de String (basado en la gran respuesta de 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])
        }
    }
} 

prueba:

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