Search code examples
iosswiftmd5

How can I convert a String to an MD5 hash in iOS using Swift?


I want to convert a string like "abc" to an MD5 hash. I want to do this in iOS and Swift. I have tried using the solutions below but they were not working for me:

Importing CommonCrypto in a Swift framework

How to use CC_MD5 method in swift language.

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

To be more clear, I want to achieve an output in Swift similar to this PHP code's output:

$str = "Hello";

echo md5($str);

Output: 8b1a9953c4611296a827abf8c47804d7


Solution

  • There are two steps:
    1. Create md5 data from a string
    2. Covert the md5 data to a hex string

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

    Output:

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

    Output:

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

    Output:

    md5Hex: 8b1a9953c4611296a827abf8c47804d7
    md5Base64: ixqZU8RhEpaoJ6v4xHgE1w==

    Notes:
    #import <CommonCrypto/CommonCrypto.h> must be added to a Bridging-Header file

    For how to create a Bridging-Header see this SO answer.

    In general MD5 should not be used for new work, SHA256 is a current best practice.

    Example from deprecated documentation section:

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

    These functions will hash either String or Data input with one of eight cryptographic hash algorithms.

    The name parameter specifies the hash function name as a String
    Supported functions are MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384 and SHA512 a This example requires Common Crypto
    It is necessary to have a bridging header to the project:
    #import <CommonCrypto/CommonCrypto.h>
    Add the Security.framework to the project.



    This function takes a hash name and String to be hashed and returns a Data:

    name: A name of a hash function as a String  
    string: The String to be hashed  
    returns: the hashed result as Data  
    
    func hash(name:String, string:String) -> Data? {
        let data = string.data(using:.utf8)!
        return hash(name:name, data:data)
    }
    

    Examples:

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

    Output:

    clearString: clearData0123456
    clearData: <636c6561 72446174 61303132 33343536>
    
    hashSHA256: <aabc766b 6b357564 e41f4f91 2d494bcc bfa16924 b574abbd ba9e3e9d a0c8920a>
    hashMD5: <4df665f7 b94aea69 695b0e7b baf9e9d6>