Làm cách nào để chuyển đổi Chuỗi thành băm MD5 trong iOS bằng Swift?


111

Tôi muốn chuyển đổi một chuỗi như "abc" thành băm MD5. Tôi muốn làm điều này trong iOS và Swift. Tôi đã thử sử dụng các giải pháp bên dưới nhưng chúng không hiệu quả với tôi:

Nhập CommonCrypto trong khung Swift

Cách sử dụng phương thức CC_MD5 trong ngôn ngữ nhanh.

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

Để rõ ràng hơn, tôi muốn đạt được đầu ra bằng Swift tương tự như đầu ra của mã PHP này:

$str = "Hello";

echo md5($str);

Đầu ra: 8b1a9953c4611296a827abf8c47804d7


5
Có gì sai với các liên kết bạn đã đưa ra?
jtbandes

2
Các liên kết bạn đã cung cấp sẽ hoạt động. Bạn có thể mô tả vấn đề chính xác của bạn là gì không? Bạn cũng có thể bao gồm một thư viện của bên thứ ba để làm những gì bạn muốn, tức là. github.com/krzyzanowskim/CryptoSwift
Eric Amorde

1
Như tôi đã đề cập rằng tôi mới làm quen với lập trình nhanh, tôi đã bối rối để thực hiện nó theo cách đúng. tôi đã đưa tệp này (#import <CommonCrypto / CommonCrypto.h>) vào tệp bộ điều khiển nhanh. Nhưng cảm ơn vì câu trả lời của bạn, bây giờ nó đã được giải quyết bằng câu trả lời của Mr.zaph dưới đây.
user3606682

Nếu bạn muốn có một thực hiện tại nhà trưởng thành trong Swift, sau đó github.com/onmyway133/SwiftHash
onmyway133

Câu trả lời:


178

Có hai bước:
1. Tạo dữ liệu md5 từ một chuỗi
2. Chuyển dữ liệu md5 thành một chuỗi 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)")

Đầu ra:

thông báo: 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)")

Đầu ra:

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

Đầu ra:

md5Hex: 8b1a9953c4611296a827abf8c47804d7
md5Base64: ixqZU8RhEpaoJ6v4xHgE1w ==

Lưu ý:
#import <CommonCrypto/CommonCrypto.h>phải được thêm vào tệp Bridging-Header

Để biết cách tạo Bridging-Header, hãy xem câu trả lời SO này .

Nói chung MD5 không nên được sử dụng cho công việc mới, SHA256 là phương pháp tốt nhất hiện tại.

Ví dụ từ phần tài liệu không dùng nữa:

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

Các hàm này sẽ băm đầu vào Chuỗi hoặc Dữ liệu bằng một trong tám thuật toán băm mật mã.

Tham số name chỉ định tên hàm băm dưới dạng một chuỗi
được hỗ trợ các hàm là MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 và SHA512 a Ví dụ này yêu cầu Common Crypto
Cần phải có một tiêu đề bắc cầu cho dự án:
#import <CommonCrypto/CommonCrypto.h>
Thêm bảo mật .framework cho dự án.



Hàm này nhận một tên băm và Chuỗi được băm và trả về một Dữ liệu:

name: Tên của hàm băm dưới dạng chuỗi  
string: Chuỗi được băm  
trả về: kết quả được băm dưới dạng Dữ liệu  
func hash(name:String, string:String) -> Data? {
    let data = string.data(using:.utf8)!
    return hash(name:name, data:data)
}

Ví dụ:

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

Đầu ra:

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

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

3
Cảm ơn alottt @zaph, tôi đã đấu tranh cho điều này kể từ hơn 2 ngày. Đã giải quyết được vấn đề với câu trả lời trên của bạn :) Và có, tôi đang truy xuất dữ liệu cũ từ trang web nơi MD5 được sử dụng, vì vậy tôi buộc phải sử dụng MD5. Nhưng nhờ một lần nữa cho câu trả lời và gợi ý để sử dụng SHA256 :)
user3606682

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

@Siddharth Không có đủ thông tin trong nhận xét, không rõ digestDatalà gì . Nếu đó là dữ liệu băm thì rất có thể đó là UTF-8 (hoặc bất kỳ mã hóa chuỗi nào mỏng đến mức không tồn tại.
zaph

1
Đây là cách bạn có thể cải thiện nó: chỉ nhập các ký hiệu được yêu cầu chứ không phải toàn bộ CommonCrypto, vì nó hơi tốn chi phí nếu không: nhập var CommonCrypto.CC_MD5_DIGEST_LENGTH nhập func CommonCrypto.CC_MD5 nhập typealias CommonCrypto.CC_LONG
Igor Vasilev

2
@zaph bạn có thể muốn thêm các giải pháp CryptoKit iOS 13 đến câu trả lời của bạn mà tôi trình bày chi tiết trong câu trả lời của tôi dưới đây: stackoverflow.com/a/56578995/368085
mluisbrown

40

Sau khi đọc qua các câu trả lời khác ở đây (và cần hỗ trợ cả các kiểu băm khác), tôi đã viết một phần mở rộng Chuỗi xử lý nhiều kiểu băm và kiểu đầu ra.

LƯU Ý: CommonCrypto được bao gồm trong Xcode 10, vì vậy bạn có thể đơn giản import CommonCryptomà không cần phải làm phiền với tiêu đề bắc cầu nếu bạn đã cài đặt phiên bản Xcode mới nhất ... Nếu không, tiêu đề bắc cầu là cần thiết.


CẬP NHẬT: Cả Swift 4 & 5 đều sử dụng cùng một tệp String + Crypto.swift bên dưới.

Có một tệp Data + Crypto.swift riêng cho Swift 5 (xem bên dưới) làm api cho 'withUnsafeMutableBytes' và 'withUnsafeBytes' được thay đổi giữa Swift 4 và 5.


String + Crypto.swift - (cho cả 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 - Dữ liệu + 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 - Dữ liệu + 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()
        }
    }
}

Chỉnh sửa: vì quá trình băm thực sự xảy ra trên Dữ liệu, tôi đã tách thuật toán băm thành phần mở rộng Dữ liệu. Điều này cũng cho phép sử dụng cùng một thuật toán cho các hoạt động băm ghim Chứng chỉ SSL.

Dưới đây là một ví dụ ngắn về cách bạn có thể sử dụng nó cho hoạt động Ghim 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
}

trở lại câu trả lời ban đầu

Tôi đã thử nghiệm các thuật toán băm bằng cách sử dụng điều này:

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

và đây là kết quả được in:

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

39

Kể từ iOS 13, Apple đã thêm CryptoKitkhuôn khổ để bạn không cần nhập CommonCrypto hoặc xử lý API C của nó nữa:

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
Cũng cần lưu ý rằng điều này cung cấp một phương tiện để tránh cảnh báo về việc MD5 hiện không an toàn. Bạn không cần phải triển khai CommonCrypto trong Objective-C để có thể hỗ trợ pragmas để vô hiệu hóa cảnh báo. Tiện dụng nếu bạn đang làm việc trong môi trường chú trọng đến việc xử lý các cảnh báo.
marcus.ramsden

28

SWIFT 3phiên bản của 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
}

Liên kết gốc từ http://iosdeveloperzone.com


23

Swift 4. *, Xcode 10 Cập nhật:

Trong Xcode 10, bạn không cần phải sử dụng Bridging-Header Anymore, bạn có thể nhập trực tiếp bằng cách sử dụng

import CommonCrypto

Và sau đó viết một phương thức như sau:

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

Sử dụng :

MD5("This is my string")

Đầu ra:

c2a9ce57e8df081b4baad80d81868bbb

giải pháp của bạn đã hoạt động hoàn hảo. Chúng ta có thể thêm giá trị SALT với mã hóa MD5 này không? Tôi muốn mã hóa thêm trong khi của chuỗi. bạn có thể cung cấp một số liên kết sử dụng đầy đủ không?
Punita

Tôi không chắc bạn đang cố gắng đạt được điều gì. Sử dụng "AES128", nếu bạn muốn mã hóa tùy chỉnh với muối. nếu bạn lo lắng về vấn đề bảo mật, hãy xem phần này: stackoverflow.com/a/15775071/3118377 .
Invictus Cody

Cảm ơn Invictus Cody, tôi đã nối SALT với String và có thể lấy MD5.
Punita

Hoạt động tuyệt vời. Nhưng làm thế nào để bạn chuyển đổi nó trở lại String?
DocAsh59 13/02/19

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

Tôi đã phát hành một triển khai Swift thuần túy không phụ thuộc vào CommonCrypto hay bất kỳ thứ gì khác. Nó có sẵn theo giấy phép MIT.

Mã bao gồm một tệp nhanh duy nhất mà bạn có thể đưa vào dự án của mình. Nếu muốn, bạn cũng có thể sử dụng dự án Xcode có chứa các mục tiêu thử nghiệm khung và đơn vị.

Nó đơn giản để sử dụng:

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

bản in: md5: 9e107d9d372bb6826bd81d3542a419d6

Tệp nhanh chứa tài liệu và nhiều ví dụ khác.


4
Yêu cầu Swift 4 không được đề cập ở đây hoặc trên Github ReadMe. Không nên xem xét việc sử dụng nếu không có các số liệu hiệu suất được cung cấp so với Crypto thông thường. Lưu ý: Common Crypto được chứng nhận FIPS 140, SwiftDigest thì không. Đây là câu hỏi quan trọng: Điều này tốt hơn Crypto thông thường như thế nào để triển khai? An toàn hơn: Không, nhanh hơn: Không
zaph 21/09/17

1
@zaph Mục đích chính là triển khai md5 không phụ thuộc vào CommonCrypto. Điều đó rất hữu ích trong những trường hợp không có CommonCrypto - như các mục tiêu khung Swift hoặc trên các nền tảng không phải của Apple.
Nikolai Ruhe

4
@zaph Tôi đồng ý rằng không thể xem nhẹ các triển khai liên quan đến bảo mật. Nhưng MD5 có những công dụng khác ngoài bảo mật — hay đúng hơn, bảo mật là nơi MD5 hoạt động kém nhất. Các thuật toán băm được sử dụng để xác định, sắp xếp, lưu trữ, từ điển, phát hiện lỗi và các lý do khác. MD5 đặc biệt hữu ích vì tính phổ biến của nó. Vì vậy, trong khi tôi đồng ý với một số ý kiến ​​của bạn, tôi không đồng ý với ý chính. Tôi nghĩ rằng quan điểm và lập luận của bạn quá hạn hẹp; nó không bao gồm toàn bộ chủ đề.
Nikolai Ruhe

2
Ngoài ra, tôi chỉ thử nghiệm, và thực hiện của tôi là nhanh hơn so với CommonCrypto cho thông điệp lớn :)
Nikolai Ruhe

2
Tôi thích cách triển khai này. Cảm ơn @NikolaiRuhe rất nhiều! Tôi đã có thể dễ dàng chuyển đổi nó sang khả năng tương thích với Swift 3. Tôi cũng đã thêm một số phương pháp tiện lợi bao gồm tính toán thông báo nội dung tệp có URL và truy xuất mã hóa base64 (hữu ích cho Content-MD5 trong số những thứ khác). @Siddharth tệp duy nhất bạn cần là MD5Digest.swift.
biomiker 10/02/18

10

Chỉ có hai lưu ý ở đây:

Sử dụng Crypto là quá nhiều chi phí để đạt được chỉ này.

Các câu trả lời được chấp nhận là hoàn hảo! Tuy nhiên, tôi chỉ muốn chia sẻ cách tiếp cận mã Swift ier bằng Swift 2.2 .

Xin lưu ý rằng bạn vẫn phải có #import <CommonCrypto/CommonCrypto.h>trong tệp Bridging-Header của mình

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

Câu trả lời Swift 5 dưới dạng phần mở rộng Chuỗi (dựa trên câu trả lời tuyệt vời của 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])
        }
    }
}

Sử dụng:

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

6

Đây là phần mở rộng dựa trên câu trả lời 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()
        }
    }
}

Hoàn toàn tương thích với swift 3.0. Bạn vẫn phải có #import <CommonCrypto/CommonCrypto.h>trong tệp Bridging-Header của mình


3

Trong lập trình nhanh, tốt hơn hết là tạo một hàm chuỗi, vì vậy việc sử dụng sẽ dễ dàng. Ở đây tôi đang tạo tiện ích mở rộng Chuỗi bằng một trong các giải pháp đã cho ở trên. Cảm ơn @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
}
}

Sử dụng

let md5String = "abc".md5()

1

Tôi đã sử dụng Carthage và Cyrpto để làm điều này.

  1. Cài đặt Carthage nếu bạn chưa làm như vậy

  2. Cài đặt tiền điện tử vào dự án của bạn

  3. thực hiện 'cập nhật giỏ hàng'

  4. Nếu bạn đang chạy từ dòng lệnh, hãy thêm vào khung trong tệp nhanh

    #!/usr/bin/env xcrun swift -F Carthage/Build/Mac
  5. Thêm nhập Crypto vào tệp nhanh của bạn.

  6. sau đó nó chỉ hoạt động!

    print( "convert this".MD5 )

Đó là một chút trên đầu sử dụng một thư viện mật mã chính thức đầy đủ khi chỉ có một chức năng là cần thiết
Đánh dấu Bourke

Xin lỗi vì nhận xét cũ ... Có lẽ, nhưng các thư viện thông thường (có lẽ) luôn cập nhật các thay đổi nền tảng, do đó mang lại kết quả chung và giảm thiểu phân mảnh, và không ai phải liên tục phát minh lại bánh xe hoặc sử dụng nhiều mạng internet- mã được tìm thấy có thể đáng tin cậy hoặc không đáng tin cậy, nhanh chóng hoặc theo mẫu trên các tiêu chuẩn. Tôi là tất cả để giảm thiểu sự phụ thuộc, nhưng trong một cái gì đó như thế này, tôi xem xét các tùy chọn hệ điều hành trước tiên, tùy chọn ngôn ngữ chung thứ hai và tiếp theo là các tùy chọn tiêu chuẩn của bên thứ ba, và kết quả là "thư viện của anh chàng này khá tốt" tùy chọn cuối cùng. * nhún vai *
ChrisH

1

MD5 là một thuật toán băm, không cần sử dụng thư viện CommonCrypto cồng kềnh cho việc này (và bị Apple từ chối đánh giá), chỉ cần sử dụng bất kỳ thư viện băm md5 nào.

Một trong những thư viện mà tôi sử dụng là SwiftHash , một triển khai nhanh chóng thuần túy của MD5 (dựa trên http://pajhome.org.uk/crypt/md5/md5.html )


1

Dựa trên giải pháp của Cody , tôi có ý kiến ​​rằng chúng ta nên làm rõ kết quả của MD5 là gì, bởi vì chúng ta có thể sử dụng kết quả dưới dạng chuỗi hex hoặc chuỗi 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
}

Hàm trên thực sự trả về a [UInt8]và dựa trên kết quả này, chúng ta có thể nhận được bất kỳ dạng chuỗi nào, chẳng hạn như hex, base64.

Nếu muốn một chuỗi hex là kết quả cuối cùng (như câu hỏi đặt ra), chúng ta có thể tiếp tục sử dụng phần còn lại của giải pháp Cody

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

Nếu một chuỗi Base64 được muốn là kết quả cuối cùng

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

1

Một câu trả lời cho Swift 5 với quản lý bộ nhớ thích hợp và không có Stringlớp bên trong phương thức:

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

thí dụ

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)

Các kết quả:

md5 Tùy chọn ("671C121427F12FBBA66CEE71C44CB62C")

sha1 Tùy chọn ("A6A40B223AE634CFC8C191DDE024BF0ACA56D7FA")

sha224 Tùy chọn ("334370E82F2F5ECF5B2CA0910C6176D94CBA12FD6F518A7AB8D12ADE")

sha256 Tùy chọn ("8CF5ED971D6EE2579B1BDEFD4921415AC03DA45B49B89665B3DF197287EFC89D")

sha384 Tùy chọn ("04BB3551CBD60035BA7E0BAA141AEACE1EF5E17317A8FD108DA12A7A8E98C245E14F92CC1A241C732209EAC9D600602E")

sha512 Tùy chọn ("1D595EAFEB2162672830885D336F75FD481548AC463BE16A8D98DB33637213F1AEB36FA4977B9C23A82A4FAB8A70C06AFC64C610D3CB1FE77A609DC8EE86AA68")



0

hai xu của tôi (nếu bạn cần nhanh chóng md5 cho Dữ liệu / NSData, ví dụ: bạn đã tải xuống hoặc đọc tệp nhị phân cho đĩa hoặc netwkork)

(không biết xấu hổ từ "Câu trả lời Swift 5 dưới dạng phần mở rộng Chuỗi (dựa trên câu trả lời tuyệt vời của 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])
        }
    }
} 

kiểm tra:

print("test".data.md5Value) /*098f6bcd4621d373cade4e832627b4f6*/
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.