Como posso converter uma String em um hash MD5 no iOS usando Swift?

111

Quero converter uma string como "abc" em um hash MD5. Eu quero fazer isso no iOS e Swift. Tentei usar as soluções abaixo, mas não funcionaram para mim:

Importando CommonCrypto em uma estrutura Swift

Como usar o método CC_MD5 em linguagem rápida.

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

Para ser mais claro, quero obter uma saída em Swift semelhante à saída deste código PHP:

$str = "Hello";

echo md5($str);

Saída: 8b1a9953c4611296a827abf8c47804d7

user3606682
fonte
5
O que há de errado com os links que você forneceu?
jtbandes
2
Os links que você forneceu devem funcionar. Você pode descrever qual é o seu problema exato? Você também pode incluir uma biblioteca de terceiros para fazer o que quiser, ou seja, github.com/krzyzanowskim/CryptoSwift
Eric Amorde
1
Como mencionei que sou novo em programação rápida, estava confuso em implementá-la da maneira certa. Eu estava incluindo este arquivo (#import <CommonCrypto / CommonCrypto.h>) no arquivo do controlador rápido. Mas obrigado por suas respostas, está resolvido agora pela resposta do Sr.zaph dada abaixo.
user3606682
Se você deseja uma implementação interna em Swift, github.com/onmyway133/SwiftHash
onmyway133

Respostas:

178

Existem duas etapas:
1. Crie dados md5 a partir de uma string
2. Converta os dados md5 em uma string 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)")

Resultado:

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

Resultado:

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

Resultado:

md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w ==

Notas:
#import <CommonCrypto/CommonCrypto.h>deve ser adicionado a um arquivo Bridging-Header

Para saber como criar um Bridging-Header, consulte esta resposta do SO .

Em geral, o MD5 não deve ser usado para novos trabalhos, SHA256 é uma prática recomendada atual.

Exemplo da seção de documentação obsoleta:

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

Essas funções farão o hash da entrada de String ou de Dados com um dos oito algoritmos de hash criptográficos.

O parâmetro name especifica o nome da função hash como uma String
As funções suportadas são MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 e SHA512 a Este exemplo requer Common Crypto.
É necessário ter um cabeçalho de ponte para o projeto:
#import <CommonCrypto/CommonCrypto.h>
Adicione a Segurança .framework para o projeto.



Esta função usa um nome hash e String para fazer o hash e retorna um Data:

name: um nome de uma função hash como uma string  
string: a string a ser hash  
retorna: o resultado hash como dados  
func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}

Exemplos:

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

Resultado:

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

hashSHA256: <aabc766b 6b357564 e41f4f91 2d494bcc bfa16924 b574abbd ba9e3e9d a0c8920a>
hashMD5: <4df665f7 b94aea69 695b0e7b baf9e9d6>
zaph
fonte
3
Obrigado alottt @zaph, eu estava lutando por isso há mais de 2 dias. Resolvi com sua resposta acima :) E sim, estou recuperando dados antigos da web onde MD5 é usado, então sou forçado a usar MD5. Mas obrigado novamente pela resposta e sugestão de usar SHA256 :)
user3606682
String(data: digestData, encoding: String.Encoding.utf8)arremessafatal error: unexpectedly found nil while unwrapping an Optional value
Siddharth
@Siddharth Não há informações suficientes no comentário, não está claro o que digestDataé. Se forem dados hash, as chances de serem UTF-8 (ou qualquer codificação de string é
mínima ou
1
Veja como você pode melhorá-lo: importe apenas os símbolos necessários e não todo o CommonCrypto, porque, caso contrário, é um pouco uma sobrecarga: import var CommonCrypto.CC_MD5_DIGEST_LENGTH import func CommonCrypto.CC_MD5 import typealias CommonCrypto.CC_LONG
Igor Vasilev
2
@zaph, você pode adicionar a solução iOS 13 CryptoKit à sua resposta, que detalhei na minha resposta abaixo: stackoverflow.com/a/56578995/368085
mluisbrown
40

Depois de ler as outras respostas aqui (e precisar oferecer suporte a outros tipos de hash também), escrevi uma extensão String que lida com vários tipos de hash e tipos de saída.

NOTA: CommonCrypto está incluído no Xcode 10, portanto, você pode simplesmente import CommonCryptosem ter que mexer com um cabeçalho de ponte se tiver a versão mais recente do Xcode instalada ... Caso contrário, um cabeçalho de ponte é necessário.


ATUALIZAÇÃO: Swift 4 e 5 usam o mesmo arquivo String + Crypto.swift abaixo.

Há um arquivo Data + Crypto.swift separado para o Swift 5 (veja abaixo) como a API para 'withUnsafeMutableBytes' e 'withUnsafeBytes' alterado entre o Swift 4 e 5.


String + Crypto.swift - (para Swift 4 e 5)

import Foundation
import CommonCrypto

// Defines types of hash string outputs available
public enum HashOutputType {
    // standard hex string output
    case hex
    // base 64 encoded string output
    case base64
}

// Defines types of hash algorithms available
public enum HashType {
    case md5
    case sha1
    case sha224
    case sha256
    case sha384
    case sha512

    var length: Int32 {
        switch self {
        case .md5: return CC_MD5_DIGEST_LENGTH
        case .sha1: return CC_SHA1_DIGEST_LENGTH
        case .sha224: return CC_SHA224_DIGEST_LENGTH
        case .sha256: return CC_SHA256_DIGEST_LENGTH
        case .sha384: return CC_SHA384_DIGEST_LENGTH
        case .sha512: return CC_SHA512_DIGEST_LENGTH
        }
    }
}

public extension String {

    /// Hashing algorithm for hashing a string instance.
    ///
    /// - Parameters:
    ///   - type: The type of hash to use.
    ///   - output: The type of output desired, defaults to .hex.
    /// - Returns: The requested hash output or nil if failure.
    public func hashed(_ type: HashType, output: HashOutputType = .hex) -> String? {

        // convert string to utf8 encoded data
        guard let message = data(using: .utf8) else { return nil }
        return message.hashed(type, output: output)
    } 
}

SWIFT 5 - Data + Crypto.swift

import Foundation
import CommonCrypto

extension Data {

    /// Hashing algorithm that prepends an RSA2048ASN1Header to the beginning of the data being hashed.
    ///
    /// - Parameters:
    ///   - type: The type of hash algorithm to use for the hashing operation.
    ///   - output: The type of output string desired.
    /// - Returns: A hash string using the specified hashing algorithm, or nil.
    public func hashWithRSA2048Asn1Header(_ type: HashType, output: HashOutputType = .hex) -> String? {

        let rsa2048Asn1Header:[UInt8] = [
            0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
            0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
        ]

        var headerData = Data(rsa2048Asn1Header)
        headerData.append(self)

        return hashed(type, output: output)
    }

    /// Hashing algorithm for hashing a Data instance.
    ///
    /// - Parameters:
    ///   - type: The type of hash to use.
    ///   - output: The type of hash output desired, defaults to .hex.
    ///   - Returns: The requested hash output or nil if failure.
    public func hashed(_ type: HashType, output: HashOutputType = .hex) -> String? {

        // setup data variable to hold hashed value
        var digest = Data(count: Int(type.length))

        _ = digest.withUnsafeMutableBytes{ digestBytes -> UInt8 in
            self.withUnsafeBytes { messageBytes -> UInt8 in
                if let mb = messageBytes.baseAddress, let db = digestBytes.bindMemory(to: UInt8.self).baseAddress {
                    let length = CC_LONG(self.count)
                    switch type {
                    case .md5: CC_MD5(mb, length, db)
                    case .sha1: CC_SHA1(mb, length, db)
                    case .sha224: CC_SHA224(mb, length, db)
                    case .sha256: CC_SHA256(mb, length, db)
                    case .sha384: CC_SHA384(mb, length, db)
                    case .sha512: CC_SHA512(mb, length, db)
                    }
                }
                return 0
            }
        }

        // return the value based on the specified output type.
        switch output {
        case .hex: return digest.map { String(format: "%02hhx", $0) }.joined()
        case .base64: return digest.base64EncodedString()
        }
    }
}

SWIFT 4 - Data + Crypto.swift

import Foundation
import CommonCrypto 

extension Data {

    /// Hashing algorithm that prepends an RSA2048ASN1Header to the beginning of the data being hashed.
    ///
    /// - Parameters:
    ///   - type: The type of hash algorithm to use for the hashing operation.
    ///   - output: The type of output string desired.
    /// - Returns: A hash string using the specified hashing algorithm, or nil.
    public func hashWithRSA2048Asn1Header(_ type: HashType, output: HashOutputType = .hex) -> String? {

        let rsa2048Asn1Header:[UInt8] = [
            0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
            0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
        ]

        var headerData = Data(bytes: rsa2048Asn1Header)
        headerData.append(self)

        return hashed(type, output: output)
    }

    /// Hashing algorithm for hashing a Data instance.
    ///
    /// - Parameters:
    ///   - type: The type of hash to use.
    ///   - output: The type of hash output desired, defaults to .hex.
    ///   - Returns: The requested hash output or nil if failure.
    public func hashed(_ type: HashType, output: HashOutputType = .hex) -> String? {

        // setup data variable to hold hashed value
        var digest = Data(count: Int(type.length))

        // generate hash using specified hash type
        _ = digest.withUnsafeMutableBytes { (digestBytes: UnsafeMutablePointer<UInt8>) in
            self.withUnsafeBytes { (messageBytes: UnsafePointer<UInt8>) in
                let length = CC_LONG(self.count)
                switch type {
                case .md5: CC_MD5(messageBytes, length, digestBytes)
                case .sha1: CC_SHA1(messageBytes, length, digestBytes)
                case .sha224: CC_SHA224(messageBytes, length, digestBytes)
                case .sha256: CC_SHA256(messageBytes, length, digestBytes)
                case .sha384: CC_SHA384(messageBytes, length, digestBytes)
                case .sha512: CC_SHA512(messageBytes, length, digestBytes)
                }
            }
        }

        // return the value based on the specified output type.
        switch output {
        case .hex: return digest.map { String(format: "%02hhx", $0) }.joined()
        case .base64: return digest.base64EncodedString()
        }
    }
}

Editar: uma vez que o hash realmente acontece nos dados, divido o algoritmo de hash em uma extensão de dados. Isso permite que o mesmo algoritmo seja usado para operações de hash de fixação de certificado SSL também.

Aqui está um pequeno exemplo de como você pode usá-lo para uma operação de fixação 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 volta à resposta original

Testei os algoritmos de hash usando isto:

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 estes são os resultados impressos:

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

A partir do iOS 13, a Apple adicionou a CryptoKitestrutura para que você não precise mais importar CommonCrypto ou lidar com 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()
}
Mluisbrown
fonte
3
Também é importante notar que isso fornece um meio de evitar o aviso de que o MD5 agora é inseguro. Você não precisa implementar CommonCrypto em Objective-C para ter suporte para pragmas para desativar o aviso. Útil se você estiver trabalhando em um ambiente que enfatiza o tratamento de avisos.
marcus.ramsden
28

SWIFT 3versão 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
}

Link original de http://iosdeveloperzone.com

wajih
fonte
23

Swift 4. *, atualização do Xcode 10:

No Xcode 10 você não precisa mais usar o Bridging-Header , você pode importar diretamente usando

import CommonCrypto

E então escreva um 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")

Resultado:

c2a9ce57e8df081b4baad80d81868bbb
Invictus Cody
fonte
sua solução funcionou perfeitamente. Podemos adicionar valor SALT com essa criptografia MD5? Eu quero adicionar enquanto a criptografia da string. você pode fornecer algum link de uso completo?
Punita de
Não tenho certeza do que você está tentando alcançar. Use "AES128" se quiser criptografia personalizada com sal. se a segurança for sua preocupação, consulte: stackoverflow.com/a/15775071/3118377 .
Invictus Cody
Obrigado Invictus Cody, concatenei SALT com String e consegui obter MD5.
Punita
Funciona bem. Mas como você o converte de volta para 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

Eu lancei uma implementação Swift pura que não depende de CommonCrypto ou qualquer outra coisa. Está disponível sob licença do MIT.

O código consiste em um único arquivo swift que você pode simplesmente soltar em seu projeto. Se preferir, você também pode usar o projeto Xcode contido com alvos de estrutura e teste de unidade.

É simples de usar:

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

estampas: md5: 9e107d9d372bb6826bd81d3542a419d6

O arquivo swift contém documentação e mais exemplos.

Nikolai Ruhe
fonte
4
Requer Swift 4, que não é mencionado aqui ou no Leia-me do Github. O uso não deve ser considerado sem os números de desempenho fornecidos em comparação ao Common Crypto. Nota: Common Crypto é certificado pelo FIPS 140, o SwiftDigest não. Aqui está a questão-chave: como isso é melhor do que a criptografia comum para a implementação? Mais seguro: Não, mais rápido: Não.
zaph
1
@zaph O objetivo principal é ter uma implementação md5 que não dependa do CommonCrypto. Isso é útil em situações em que CommonCrypto não está disponível - como destinos de framework Swift ou em plataformas não Apple.
Nikolai Ruhe
4
@zaph Concordo que as implementações relevantes para a segurança não devem ser consideradas levianamente. Mas o MD5 tem outros usos além da segurança - ou melhor, é na segurança que o MD5 tem pior desempenho. Algoritmos de hash são usados ​​para identificação, classificação, armazenamento, dicionários, detecção de erros e outros motivos. MD5 é especialmente útil por causa de sua onipresença. Portanto, embora eu concorde com alguns de seus comentários, não concordo com a essência. Acho que seu ponto de vista e argumentação são muito estreitos; não abrange todo o tópico.
Nikolai Ruhe
2
Além disso, acabei de testar e minha implementação é mais rápida do que CommonCrypto para mensagens grandes :)
Nikolai Ruhe
2
Eu gosto dessa implementação. Muito obrigado @NikolaiRuhe! Consegui convertê-lo facilmente para compatibilidade com o Swift 3. Também adicionei alguns métodos convenientes, incluindo compilação de computação do conteúdo do arquivo dado um URL e recuperação da codificação base64 (útil para Content-MD5, entre outras coisas). @Siddharth, o único arquivo de que você precisa é MD5Digest.swift.
biomiker de
10

Apenas duas notas aqui:

Usar a criptografia é uma sobrecarga muito grande para conseguir exatamente isso.

A resposta aceita é perfeita! No entanto, eu só queria compartilhar uma abordagem de código Swift ier usando Swift 2.2 .

Por favor, tenha em mente que você ainda precisa #import <CommonCrypto/CommonCrypto.h>em seu arquivo 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]) }
    }
}
Hugo Alonso
fonte
7

Resposta do Swift 5 como uma extensão String (baseada na ótima resposta 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
fonte
6

Aqui está uma extensão baseada na resposta 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 compatível com o swift 3.0. Você ainda precisa #import <CommonCrypto/CommonCrypto.h>no seu arquivo Bridging-Header

Glaubenio Patricio
fonte
3

Na programação rápida, é melhor fazer uma string funcionar, então o uso será fácil. Aqui estou fazendo uma extensão de String usando uma das soluções fornecidas acima. Obrigado @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
fonte
1

Usei Cartago e Cyrpto para fazer isso.

  1. Instale Cartago se ainda não o tiver feito

  2. Instale o Crypto em seu projeto

  3. execute 'atualização de cartage'

  4. Se você estiver executando a partir da linha de comando, adicione na estrutura no arquivo swift

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. Adicione importação Crypto ao seu arquivo rápido.

  6. então ele simplesmente funciona!

    print( "convert this".MD5 )
Keith John Hutchison
fonte
É um pouco exagerado usar uma biblioteca de criptografia completa quando apenas uma função é necessária
Mark Bourke
Peça desculpas pelo comentário do tópico antigo ... Talvez, mas as bibliotecas comuns estão (presumivelmente) sempre atualizadas com as mudanças de plataforma, produzindo resultados comuns e minimizando a fragmentação, e ninguém tem que reinventar rodas continuamente ou usar um monte de internet- código encontrado que pode ou não ser confiável, rápido ou padronizado. Sou totalmente a favor de minimizar dependências, mas em algo assim, eu examino as opções do sistema operacional primeiro, as opções de linguagem comum em segundo e, a seguir, as opções padrão de terceiros, e o resultado é pontual ou "a biblioteca desse cara é muito boa" as opções duram. * encolher os ombros *
ChrisH,
1

MD5 é um algoritmo de hash, não há necessidade de usar a biblioteca CommonCrypto volumosa para isso (e foi rejeitado pela revisão da Apple), basta usar qualquer biblioteca de hash md5.

Uma dessas bibliotecas que uso é o SwiftHash , uma implementação pura e rápida do MD5 (com base em http://pajhome.org.uk/crypt/md5/md5.html )

Nagendra Rao
fonte
1

Com base na solução de Cody , tenho a ideia de que devemos esclarecer qual é o resultado do MD5, porque podemos usar o resultado como uma string hexadecimal ou uma string 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
}

A função acima realmente retorna a [UInt8], e com base nesse resultado, podemos obter qualquer forma de string, como hex, base64.

Se uma string hexadecimal é desejada como o resultado final (como a pergunta pede), podemos continuar usando o resto da solução de Cody

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

Se uma string Base64 for desejada como o resultado final

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

Uma resposta para o Swift 5 com gerenciamento de memória adequado e sem Stringclasse dentro do 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
        }
    }
}

exemplo

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
fonte
0

meus dois centavos (se você precisar rapidamente md5 para Data / NSData, por exemplo, você baixou ou leu binário para disco ou rede)

(desavergonhado de "Swift 5 answer as a String extension (baseado na ótima resposta 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])
        }
    }
} 

teste:

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