Bagaimana cara mengonversi String menjadi hash MD5 di iOS menggunakan Swift?

111

Saya ingin mengubah string seperti "abc" menjadi hash MD5. Saya ingin melakukan ini di iOS dan Swift. Saya telah mencoba menggunakan solusi di bawah ini tetapi tidak berhasil untuk saya:

Mengimpor CommonCrypto dalam kerangka Swift

Cara menggunakan metode CC_MD5 dalam bahasa cepat.

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

Untuk lebih jelasnya, saya ingin mencapai keluaran di Swift yang mirip dengan keluaran kode PHP ini:

$str = "Hello";

echo md5($str);

Keluaran: 8b1a9953c4611296a827abf8c47804d7

pengguna3606682
sumber
5
Apa yang salah dengan tautan yang Anda berikan?
jtbandes
2
Tautan yang Anda berikan harus berfungsi. Bisakah Anda menjelaskan apa sebenarnya masalah Anda? Anda juga bisa menyertakan perpustakaan pihak ketiga untuk melakukan apa yang Anda inginkan, yaitu. github.com/krzyzanowskim/CryptoSwift
Eric Amorde
1
Seperti yang telah saya sebutkan bahwa saya baru mengenal program cepat, saya bingung untuk menerapkannya dengan cara yang benar. saya memasukkan file ini (#import <CommonCrypto / CommonCrypto.h>) dalam file pengontrol cepat. Tapi terima kasih atas balasan Anda, itu diselesaikan sekarang dengan jawaban Mr.zaph yang diberikan di bawah ini.
user3606682
Jika Anda menginginkan implementasi yang dikembangkan sendiri di Swift, maka github.com/onmyway133/SwiftHash
onmyway133

Jawaban:

178

Ada dua langkah:
1. Membuat data md5 dari string
2. Menyamarkan data md5 menjadi string hex

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

Keluaran:

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

Keluaran:

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

Keluaran:

md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w ==

Catatan:
#import <CommonCrypto/CommonCrypto.h>harus ditambahkan ke file Bridging-Header

Untuk cara membuat Bridging-Header lihat jawaban SO ini .

Secara umum MD5 tidak boleh digunakan untuk pekerjaan baru, SHA256 adalah praktik terbaik saat ini.

Contoh dari bagian dokumentasi yang tidak digunakan lagi:

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

Fungsi-fungsi ini akan melakukan hash baik String atau input Data dengan salah satu dari delapan algoritme hash kriptografi.

Parameter nama menentukan nama fungsi hash sebagai String
Fungsi yang didukung adalah MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 dan SHA512 a Contoh ini memerlukan Common Crypto
Perlu memiliki header penghubung ke proyek:
#import <CommonCrypto/CommonCrypto.h>
Tambahkan Keamanan .framework untuk proyek.



Fungsi ini mengambil nama hash dan String untuk di-hash dan mengembalikan Data:

name: Nama dari fungsi hash sebagai String  
string: String yang akan di-hash  
return: hasil hash sebagai Data  
func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}

Contoh:

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

Keluaran:

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

hashSHA256: <aabc766b 6b357564 e41f4f91 2d494bcc bfa16924 b574abbd ba9e3e9d a0c8920a>
hashMD5: <4df665f7 b94aea69 695b0e7b baf9e9d6>
zaph
sumber
3
Terima kasih alottt @zaph, saya berjuang untuk ini sejak lebih dari 2 hari. Mengatasi dengan jawaban Anda di atas :) Dan ya saya mengambil data lama dari web tempat MD5 digunakan, jadi saya terpaksa menggunakan MD5. Tapi sekali lagi terima kasih atas jawaban dan saran untuk menggunakan SHA256 :)
user3606682
String(data: digestData, encoding: String.Encoding.utf8)melemparfatal error: unexpectedly found nil while unwrapping an Optional value
Siddharth
@Siddharth Tidak cukup informasi di komentar, tidak jelas apa digestData. Jika itu adalah data hash, kemungkinannya atau itu UTF-8 (atau pengkodean string apa pun sangat tipis hingga tidak ada.
zaph
1
Berikut cara memperbaikinya: impor hanya simbol yang diperlukan dan bukan seluruh CommonCrypto, karena ini sedikit berlebihan jika tidak: import var CommonCrypto.CC_MD5_DIGEST_LENGTH import func CommonCrypto.CC_MD5 import typealias CommonCrypto.CC_LONG
Igor Vasilev
2
@zaph Anda mungkin ingin menambahkan solusi CryptoKit iOS 13 ke jawaban Anda yang saya jelaskan dalam jawaban saya di bawah ini: stackoverflow.com/a/56578995/368085
mluisbrown
40

Setelah membaca jawaban lain di sini (dan perlu mendukung jenis hash lainnya juga) saya menulis ekstensi String yang menangani beberapa jenis hash dan jenis keluaran.

CATATAN: CommonCrypto disertakan dalam Xcode 10, jadi Anda dapat dengan mudah import CommonCryptotanpa harus mengacaukan header bridging jika Anda menginstal versi Xcode terbaru ... Jika tidak, diperlukan header bridging.


UPDATE: Baik Swift 4 & 5 menggunakan file String + Crypto.swift yang sama di bawah ini.

Ada file Data + Crypto.swift terpisah untuk Swift 5 (lihat di bawah) sebagai api untuk 'withUnsafeMutableBytes' dan 'withUnsafeBytes' diubah antara Swift 4 & 5.


String + Crypto.swift - (untuk Swift 4 & 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()
        }
    }
}

Sunting: karena hash benar-benar terjadi pada Data, saya membagi algoritma hashing menjadi ekstensi Data. Hal ini memungkinkan algoritme yang sama digunakan untuk operasi hash penyematan Sertifikat SSL juga.

Berikut adalah contoh singkat bagaimana Anda dapat menggunakannya untuk operasi Penyematan 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
}

kembali ke jawaban awal

Saya menguji algoritma hash menggunakan ini:

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

dan ini hasil cetakannya:

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

Mulai iOS 13 Apple telah menambahkan CryptoKitkerangka kerja sehingga Anda tidak perlu lagi mengimpor CommonCrypto atau berurusan dengan C API-nya:

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
sumber
3
Perlu juga dicatat bahwa ini memberikan cara untuk menghindari peringatan tentang MD5 yang sekarang tidak aman. Anda tidak perlu mengimplementasikan CommonCrypto di Objective-C sehingga Anda memiliki dukungan untuk pragma untuk menonaktifkan peringatan. Berguna jika Anda bekerja di lingkungan yang menekankan pada penanganan peringatan.
marcus.ramsden
28

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

Tautan asli dari http://iosdeveloperzone.com

wajih
sumber
23

Swift 4. *, Pembaruan Xcode 10:

Di Xcode 10 Anda tidak harus menggunakan Bridging-Header Anymore, Anda dapat langsung mengimpor menggunakan

import CommonCrypto

Dan kemudian tulis metode seperti:

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

Penggunaan:

MD5("This is my string")

Keluaran:

c2a9ce57e8df081b4baad80d81868bbb
Invictus Cody
sumber
solusi Anda bekerja dengan sempurna. Bisakah kita menambahkan nilai SALT dengan enkripsi MD5 ini? Saya ingin menambahkan saat enkripsi string. dapatkah Anda memberikan beberapa tautan berguna?
Punita
Saya tidak yakin apa yang ingin Anda capai. Gunakan "AES128", jika Anda ingin enkripsi khusus dengan penggaraman. jika keamanan adalah perhatian Anda, Lihat ini: stackoverflow.com/a/15775071/3118377 .
Invictus Cody
Terima kasih Invictus Cody, saya telah menggabungkan SALT dengan String dan bisa mendapatkan MD5.
Punita
Bekerja dengan baik. Tetapi bagaimana Anda mengubahnya kembali menjadi 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

Saya merilis implementasi Swift murni yang tidak bergantung pada CommonCrypto atau apa pun. Ini tersedia di bawah lisensi MIT.

Kode ini terdiri dari satu file swift yang bisa Anda masukkan ke dalam proyek Anda. Jika mau, Anda juga dapat menggunakan proyek Xcode yang dimuat dengan kerangka kerja dan target pengujian unit.

Mudah digunakan:

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

cetakan: md5: 9e107d9d372bb6826bd81d3542a419d6

File swift berisi dokumentasi dan lebih banyak contoh.

Nikolai Ruhe
sumber
4
Membutuhkan Swift 4 yang tidak disebutkan di sini atau di Github ReadMe. Penggunaan tidak boleh dipertimbangkan tanpa angka kinerja yang diberikan dibandingkan dengan Common Crypto. Catatan: Common Crypto bersertifikat FIPS 140, SwiftDigest tidak. Inilah pertanyaan kuncinya: Bagaimana ini lebih baik daripada Common Crypto untuk implementasinya? Lebih aman: Tidak, lebih cepat: Tidak.
zaph
1
@zaph Tujuan utamanya adalah untuk memiliki implementasi md5 yang tidak bergantung pada CommonCrypto. Itu berguna dalam situasi di mana CommonCrypto tidak tersedia — seperti target framework Swift atau di platform non-Apple.
Nikolai Ruhe
4
@zaph Saya setuju bahwa penerapan terkait keamanan tidak bisa dianggap enteng. Tetapi MD5 memiliki kegunaan lain selain keamanan — atau, lebih tepatnya, keamanan adalah tempat MD5 berkinerja terburuk. Algoritme hashing digunakan untuk identifikasi, pengurutan, penyimpanan, kamus, deteksi kesalahan, dan alasan lainnya. MD5 sangat berguna karena keberadaannya di mana-mana. Jadi, meskipun saya setuju dengan beberapa komentar Anda, saya tidak setuju dengan intinya. Saya pikir sudut pandang dan perdebatan Anda terlalu sempit; itu tidak mencakup keseluruhan topik.
Nikolai Ruhe
2
Juga, saya baru saja menguji, dan implementasinya lebih cepat daripada CommonCrypto untuk pesan besar :)
Nikolai Ruhe
2
Saya suka implementasi ini. Terima kasih banyak @NikolaiRuhe! Saya dapat mengubahnya dengan mudah ke kompatibilitas Swift 3. Saya juga menambahkan beberapa metode kemudahan termasuk menghitung intisari konten file yang diberi URL, dan mengambil pengkodean base64 (berguna untuk Content-MD5, antara lain). @Siddharth satu-satunya file yang Anda butuhkan adalah MD5Digest.swift.
biomiker
10

Hanya dua catatan di sini:

Menggunakan Crypto terlalu berlebihan untuk mencapai hal ini.

The jawaban yang diterima adalah sempurna! Namun saya hanya ingin berbagi Swift IER pendekatan kode menggunakan Swift 2.2 .

Harap diingat bahwa Anda masih harus #import <CommonCrypto/CommonCrypto.h>di Anda Bridging-Header File

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

Jawaban Swift 5 sebagai ekstensi String (berdasarkan jawaban hebat 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])
        }
    }
}

Pemakaian:

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

Berikut ekstensi berdasarkan jawaban 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()
        }
    }
}

Sepenuhnya kompatibel dengan swift 3.0. Anda masih harus #import <CommonCrypto/CommonCrypto.h>menggunakan file Bridging-Header Anda

Glaubenio Patricio
sumber
3

Dalam pemrograman cepat sebaiknya membuat fungsi string, agar penggunaannya mudah. Di sini saya membuat ekstensi String menggunakan salah satu solusi yang diberikan di atas. Terima kasih @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
}
}

Pemakaian

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

Saya menggunakan Carthage dan Cyrpto untuk melakukan ini.

  1. Instal Carthage jika Anda belum melakukannya

  2. Instal Crypto ke dalam proyek Anda

  3. jalankan 'update cartage'

  4. Jika Anda menjalankan dari baris perintah, tambahkan kerangka kerja di file swift

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. Tambahkan impor Crypto ke file swift Anda.

  6. maka itu akan berhasil!

    print( "convert this".MD5 )
Keith John Hutchison
sumber
Agak berlebihan untuk menggunakan pustaka kriptografi yang lengkap ketika hanya satu fungsi yang dibutuhkan
Mark Bourke
Minta maaf atas komentar utas lama ... Mungkin, tetapi perpustakaan umum (mungkin) selalu mutakhir dengan perubahan platform, sehingga menghasilkan hasil yang sama dan meminimalkan fragmentasi, dan tidak ada yang harus terus-menerus menemukan kembali roda atau menggunakan banyak internet- menemukan kode yang mungkin atau mungkin tidak dapat diandalkan, cepat, atau berpola pada standar. Saya setuju untuk meminimalkan ketergantungan, tetapi dalam hal seperti ini, saya melihat opsi OS terlebih dahulu, opsi bahasa umum kedua, dan opsi standar pihak ketiga berikutnya, dan menghasilkan satu kali atau "perpustakaan orang ini cukup bagus" pilihan terakhir. * mengangkat bahu *
ChrisH
1

MD5 adalah algoritma hashing, tidak perlu menggunakan pustaka CommonCrypto yang besar untuk ini (dan ditolak oleh tinjauan Apple), cukup gunakan pustaka hashing md5.

Salah satu pustaka yang saya gunakan adalah SwiftHash , implementasi cepat murni MD5 (berdasarkan http://pajhome.org.uk/crypt/md5/md5.html )

Nagendra Rao
sumber
1

Berdasarkan solusi Cody , saya punya ide bahwa kita harus mengklarifikasi apa hasil dari MD5, karena kita dapat menggunakan hasilnya sebagai string hex, atau 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
}

Fungsi di atas sebenarnya mengembalikan a [UInt8] , dan berdasarkan hasil ini, kita bisa mendapatkan bentuk string apa pun, seperti hex, base64.

Jika string hex diinginkan sebagai hasil akhir (seperti pertanyaan yang diajukan), kita dapat tetap menggunakan bagian lain dari solusi Cody

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

Jika string Base64 diinginkan sebagai hasil akhir

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

Jawaban untuk Swift 5 dengan manajemen memori yang tepat dan tanpa Stringkelas di dalam metode:

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

contoh

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)

Hasil:

md5 Opsional ("671C121427F12FBBA66CEE71C44CB62C")

sha1 Opsional ("A6A40B223AE634CFC8C191DDE024BF0ACA56D7FA")

sha224 Opsional ("334370E82F2F5ECF5B2CA0910C6176D94CBA12FD6F518A7AB8D12ADE")

sha256 Opsional ("8CF5ED971D6EE2579B1BDEFD4921415AC03DA45B49B89665B3DF197287EFC89D")

sha384 Opsional ("04BB3551CBD60035BA7E0BAA141AEACE1EF5E17317A8FD108DA12A7A8E98C245E14F92CC1A241C732209EAC9D600602E")

sha512 Opsional ("1D595EAFEB2162672830885D336F75FD481548AC463BE16A8D98DB33637213F1AEB36FA4977B9C23A82A4FAB8A70C06AFC64C610D3CB1FE77A609DC8EE86AA68")

Vyacheslav
sumber
0

dua sen saya (jika Anda membutuhkan md5 cepat untuk Data / NSData, misalnya Anda mengunduh atau membaca biner untuk disk atau netwkork)

(tidak tahu malu dari "jawaban Swift 5 sebagai ekstensi String (berdasarkan jawaban hebat 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])
        }
    }
} 

uji:

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