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


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>

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

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

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


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

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.


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

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

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


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

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 )

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


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

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



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*/
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.