Jak przekonwertować ciąg znaków na skrót MD5 w systemie iOS przy użyciu języka Swift?


111

Chcę przekonwertować ciąg, taki jak „abc”, na skrót MD5. Chcę to zrobić w iOS i Swift. Próbowałem użyć poniższych rozwiązań, ale nie działały one dla mnie:

Importowanie CommonCrypto w środowisku Swift

Jak korzystać z metody CC_MD5 w języku Swift.

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

Aby być bardziej zrozumiałym, chcę uzyskać wynik w Swift podobny do wyniku tego kodu PHP:

$str = "Hello";

echo md5($str);

Wyjście: 8b1a9953c4611296a827abf8c47804d7


5
Co jest nie tak z linkami, które podałeś?
jtbandes

2
Podane linki powinny działać. Czy możesz opisać dokładny problem? Możesz również dołączyć bibliotekę innej firmy, aby robić to, co chcesz, tj. github.com/krzyzanowskim/CryptoSwift
Eric Amorde

1
Jak wspomniałem, jestem nowy w szybkim programowaniu, byłem zdezorientowany, aby zaimplementować go we właściwy sposób. Załączałem ten plik (#import <CommonCrypto / CommonCrypto.h>) do szybkiego pliku kontrolera. Ale dzięki za odpowiedzi, rozwiązuje go teraz odpowiedź Pana Zapha podana poniżej.
user3606682

Jeśli chcesz własną implementację w Swift, to github.com/onmyway133/SwiftHash
onmyway133

Odpowiedzi:


178

Istnieją dwa kroki:
1. Utwórz dane md5 z łańcucha
2. Zamień dane md5 na ciąg szesnastkowy

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

Wynik:

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

Wynik:

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

Wynik:

md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w ==

Uwagi:
#import <CommonCrypto/CommonCrypto.h>należy dodać do pliku Bridging-Header

Aby dowiedzieć się, jak utworzyć nagłówek mostkujący, zobacz tę odpowiedź SO .

Generalnie MD5 nie powinien być używany do nowych prac, SHA256 jest obecnie najlepszą praktyką.

Przykład z przestarzałej sekcji dokumentacji:

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

Te funkcje będą mieszać ciąg znaków lub dane wejściowe za pomocą jednego z ośmiu kryptograficznych algorytmów wyznaczania wartości skrótu.

Parametr name określa nazwę funkcji skrótu jako ciąg
znaków Obsługiwane funkcje to MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 i SHA512 a Ten przykład wymaga Common Crypto
Konieczne jest posiadanie nagłówka mostkowania do projektu:
#import <CommonCrypto/CommonCrypto.h>
Dodaj zabezpieczenia .framework do projektu.



Ta funkcja przyjmuje nazwę skrótu i ​​ciąg znaków do zaszyfrowania i zwraca Data:

name: nazwa funkcji skrótu jako ciąg  
string: ciąg do haszowania  
zwraca: zaszyfrowany wynik jako Data  
func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}

Przykłady:

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

Wynik:

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

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

3
Dzięki alottt @zaph, walczyłem o to od ponad 2 dni. Twoja odpowiedź została rozwiązana :) I tak, pobieram stare dane z sieci, w której jest używany MD5, więc jestem zmuszony do korzystania z MD5. Ale jeszcze raz dziękuję za odpowiedź i sugestię użycia SHA256 :)
user3606682

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

@Siddharth W komentarzu nie ma wystarczających informacji, nie jest jasne, co digestDatajest. Jeśli są to dane haszujące, istnieje prawdopodobieństwo, że będzie to UTF-8 (lub jakiekolwiek kodowanie ciągów jest niewielkie lub nie istnieje.
zaph

1
Oto jak możesz to ulepszyć: importuj tylko wymagane symbole, a nie cały CommonCrypto, ponieważ w przeciwnym razie jest to trochę narzut: import var CommonCrypto.CC_MD5_DIGEST_LENGTH import func CommonCrypto.CC_MD5 import typealias CommonCrypto.CC_LONG
Igor Vasilev

2
@zaph możesz dodać rozwiązanie CryptoKit iOS 13 do swojej odpowiedzi, którą szczegółowo
opisałem

40

Po przeczytaniu innych odpowiedzi tutaj (i konieczności obsługi również innych typów skrótów) napisałem rozszerzenie String, które obsługuje wiele typów skrótów i typów danych wyjściowych.

UWAGA: CommonCrypto jest zawarte w Xcode 10, więc możesz po prostu import CommonCryptobez bałaganu z nagłówkiem mostkującym, jeśli masz zainstalowaną najnowszą wersję Xcode ... W przeciwnym razie nagłówek mostkujący jest konieczny.


AKTUALIZACJA: Zarówno Swift 4, jak i 5 używają tego samego pliku String + Crypto.swift poniżej.

Istnieje oddzielny plik Data + Crypto.swift dla Swift 5 (patrz poniżej) jako interfejs API dla „withUnsafeMutableBytes” i „withUnsafeBytes” zmieniony między Swift 4 i 5.


String + Crypto.swift - (dla Swift 4 i 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 - Dane + 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 - Dane + 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()
        }
    }
}

Edycja: ponieważ hash faktycznie dzieje się na danych, podzieliłem algorytm haszowania na rozszerzenie danych. Pozwala to na użycie tego samego algorytmu do przypinania operacji skrótu certyfikatu SSL.

Oto krótki przykład tego, jak możesz go użyć do operacji przypinania 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
}

z powrotem do pierwotnej odpowiedzi

Przetestowałem algorytmy skrótu, używając tego:

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

a oto wydrukowane wyniki:

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

40

Od iOS 13 Apple dodał CryptoKitframework, więc nie musisz już importować CommonCrypto ani zajmować się jego C API:

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
Warto również zauważyć, że jest to sposób na uniknięcie ostrzeżenia o niebezpiecznym zabezpieczeniu MD5. Nie musisz implementować CommonCrypto w Objective-C, aby mieć obsługę pragm, aby wyłączyć ostrzeżenie. Przydatny, jeśli pracujesz w środowisku, w którym kładzie się nacisk na radzenie sobie z ostrzeżeniami.
marcus.ramsden

28

SWIFT 3wersja 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
}

Oryginalny link z http://iosdeveloperzone.com


23

Swift 4. *, aktualizacja Xcode 10:

W Xcode 10 nie musisz już używać Bridging-Header , możesz bezpośrednio importować za pomocą

import CommonCrypto

Następnie napisz metodę taką jak:

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

Stosowanie :

MD5("This is my string")

Wynik:

c2a9ce57e8df081b4baad80d81868bbb

Twoje rozwiązanie działa doskonale. Czy możemy dodać wartość SALT z tym szyfrowaniem MD5? Chcę dodać podczas szyfrowania ciągu. czy możesz podać pełny link do użycia?
Punita

Nie jestem pewien, co próbujesz osiągnąć. Użyj „AES128”, jeśli chcesz niestandardowego szyfrowania z solą. jeśli zależy Ci na bezpieczeństwie, sprawdź to: stackoverflow.com/a/15775071/3118377 .
Invictus Cody

Dzięki Invictus Cody, połączyłem SALT ze Stringiem i mogę uzyskać MD5.
Punita,

Działa świetnie. Ale jak przekonwertować go z powrotem na 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

Wydałem czystą implementację Swift , która nie zależy od CommonCrypto ani niczego innego. Jest dostępny na licencji MIT.

Kod składa się z pojedynczego pliku Swift , który możesz po prostu wrzucić do projektu. Jeśli wolisz, możesz również użyć zawartego projektu Xcode z obiektami docelowymi testów strukturalnych i jednostkowych.

Jest prosty w użyciu:

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

wydruki: md5: 9e107d9d372bb6826bd81d3542a419d6

Plik swift zawiera dokumentację i więcej przykładów.


4
Wymaga Swift 4, o którym nie wspomniano tutaj ani w pliku ReadMe Github. Użycie nie powinno być brane pod uwagę bez danych dotyczących wydajności w porównaniu do Common Crypto. Uwaga: Common Crypto ma certyfikat FIPS 140, SwiftDigest nie. Oto kluczowe pytanie: w jaki sposób jest to lepsze niż Common Crypto w implementacji? Bardziej bezpieczne: Nie, szybciej: Nie
zaph

1
@zaph Głównym celem jest posiadanie implementacji md5, która nie jest zależna od CommonCrypto. Jest to pomocne w sytuacjach, gdy CommonCrypto nie jest dostępne - na przykład cele Swift Framework lub na platformach innych niż Apple.
Nikolai Ruhe

4
@zaph Zgadzam się, że implementacji związanych z bezpieczeństwem nie należy lekceważyć. Ale MD5 ma inne zastosowania niż bezpieczeństwo - a raczej bezpieczeństwo jest tam, gdzie MD5 działa najgorzej. Algorytmy haszujące są używane do identyfikacji, sortowania, przechowywania, słowników, wykrywania błędów i innych powodów. MD5 jest szczególnie przydatny ze względu na jego wszechobecność. Tak więc, chociaż zgadzam się z kilkoma twoimi uwagami, nie zgadzam się z sednem. Myślę, że twój punkt widzenia i argumentacja są zbyt wąskie; nie obejmuje całości tematu.
Nikolai Ruhe

2
Właśnie przetestowałem i moja implementacja jest szybsza niż CommonCrypto dla dużych wiadomości :)
Nikolai Ruhe

2
Podoba mi się ta realizacja. Bardzo dziękuję @NikolaiRuhe! Udało mi się łatwo przekonwertować go na zgodność ze Swift 3. Dodałem również kilka wygodnych metod, w tym obliczanie skrótu zawartości pliku z podanym adresem URL i pobieranie kodowania base64 (przydatne między innymi dla Content-MD5). @Siddharth jedyny potrzebny plik to MD5Digest.swift.
biomiker

10

Tylko dwie uwagi:

Korzystanie z Crypto jest zbyt dużym obciążeniem, aby to osiągnąć.

Odpowiedź akceptowana jest idealny! Niemniej jednak chciałem tylko podzielić się podejściem do kodu Swift ier przy użyciu Swift 2.2 .

Pamiętaj, że nadal musisz mieć to #import <CommonCrypto/CommonCrypto.h>w pliku 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

Odpowiedź Swift 5 jako rozszerzenie String (w oparciu o świetną odpowiedź 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])
        }
    }
}

Stosowanie:

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

6

Oto rozszerzenie oparte na odpowiedzi 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()
        }
    }
}

W pełni kompatybilny ze swift 3.0. Nadal musisz mieć #import <CommonCrypto/CommonCrypto.h>w swoim pliku Bridging-Header


3

W szybkim programowaniu lepiej jest utworzyć funkcję łańcuchową, więc użycie będzie łatwe. Tutaj robię rozszerzenie String przy użyciu jednego z podanych powyżej rozwiązań. Dzięki @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
}
}

Stosowanie

let md5String = "abc".md5()

1

Wykorzystałem do tego Kartaginę i Cyrpto.

  1. Zainstaluj Kartaginę, jeśli jeszcze tego nie zrobiłeś

  2. Zainstaluj Crypto w swoim projekcie

  3. wykonaj „aktualizację wózka”

  4. Jeśli korzystasz z wiersza poleceń, dodaj strukturę w pliku Swift

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. Dodaj import Crypto do swojego pliku Swift.

  6. to po prostu działa!

    print( "convert this".MD5 )

Używanie pełnej biblioteki kryptograficznej, gdy potrzebna jest tylko jedna funkcja, jest trochę
Mark Bourke,

Przepraszamy za komentarz ze starego wątku ... Być może, ale popularne biblioteki są (prawdopodobnie) zawsze na bieżąco ze zmianami platformy, uzyskując w ten sposób wspólne wyniki i minimalizując fragmentację, i nikt nie musi ciągle wymyślać kół ani korzystać z mnóstwa Internetu. znalazł kod, który może, ale nie musi być niezawodny, szybki lub wzorowany na standardach. Jestem za minimalizowaniem zależności, ale w czymś takim, najpierw patrzę na opcje systemu operacyjnego, potem na opcje wspólnego języka, a następnie na standardowe opcje innych firm, co skutkuje jednorazowymi lub „biblioteka tego gościa jest całkiem dobra” opcje trwają. * wzruszenie ramionami *
ChrisH

1

MD5 to algorytm haszujący, nie ma potrzeby używania do tego obszernej biblioteki CommonCrypto (i zostaje odrzucony przez przegląd Apple), po prostu użyj dowolnej biblioteki haszującej md5.

Jedną z takich bibliotek, których używam, jest SwiftHash , czysta szybka implementacja MD5 (oparta na http://pajhome.org.uk/crypt/md5/md5.html )


1

Opierając się na rozwiązaniu Cody'ego , mam pomysł, że powinniśmy wyjaśnić, jaki jest wynik MD5, ponieważ możemy użyć wyniku jako ciągu szesnastkowego lub ciągu 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
}

Powyższa funkcja w rzeczywistości zwraca a [UInt8]i na podstawie tego wyniku możemy uzyskać dowolną formę ciągu, na przykład hex, base64.

Jeśli jako wynik końcowy (jak zadaje się pytanie) potrzebny jest ciąg szesnastkowy, możemy nadal używać pozostałej części rozwiązania Cody'ego

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

Jeśli jako wynik końcowy wymagany jest ciąg Base64

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

1

Odpowiedź na Swift 5 z odpowiednim zarządzaniem pamięcią i bez Stringklasy wewnątrz metody:

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

przykład

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)

Wyniki:

md5 Opcjonalnie („671C121427F12FBBA66CEE71C44CB62C”)

sha1 Opcjonalnie („A6A40B223AE634CFC8C191DDE024BF0ACA56D7FA”)

sha224 Opcjonalnie („334370E82F2F5ECF5B2CA0910C6176D94CBA12FD6F518A7AB8D12ADE”)

sha256 Opcjonalnie („8CF5ED971D6EE2579B1BDEFD4921415AC03DA45B49B89665B3DF197287EFC89D”)

sha384 Opcjonalnie („04BB3551CBD60035BA7E0BAA141AEACE1EF5E17317A8FD108DA12A7A8E98C245E14F92CC1A241C732209EAC9D600602E”)

sha512 Opcjonalnie ("1D595EAFEB2162672830885D336F75FD481548AC463BE16A8D98DB33637213F1AEB36FA4977B9C23A82A4FAB8A70C06AFC64C610D3CB1FE77A609DC8EE86AA68")



0

moje dwa centy (jeśli potrzebujesz szybko md5 dla danych / NSData, na przykład pobrałeś lub przeczytałeś plik binarny na dysk lub sieć)

(bezwstydne z „Swift 5 answer as a String extension (w oparciu o wspaniałą odpowiedź Invictus Cody”)):

extension Data {
    var md5Value: String {
        let length = Int(CC_MD5_DIGEST_LENGTH)
        var digest = [UInt8](repeating: 0, count: length)

        _ = self.withUnsafeBytes { body -> String in
            CC_MD5(body.baseAddress, CC_LONG(self.count), &digest)
            return ""
        }


        return (0 ..< length).reduce("") {
            $0 + String(format: "%02x", digest[$1])
        }
    }
} 

test:

print("test".data.md5Value) /*098f6bcd4621d373cade4e832627b4f6*/
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.