Swift 3 rendant les fonctions sha1, sha256 et md5

dans Swift 2, j'ai utilisé le code suivant pour étendre les variables de chaîne et pour pouvoir faire sha1, sha256, et md5.

après avoir migré vers swift 3, le code ne fonctionne plus! J'ai essayé de le convertir, mais j'ai fait des erreurs.

une idée de comment résoudre ce problème?

extension NSData {
    func hexString() -> String {
        var string = String()
        for i in UnsafeBufferPointer<UInt8>(start: UnsafeMutablePointer<UInt8>(bytes), count: length) {
            string += Int(i).hexString()
        }
        return string
    }

    func MD5() -> NSData {
        let result = NSMutableData(length: Int(CC_MD5_DIGEST_LENGTH))!
        CC_MD5(bytes, CC_LONG(length), UnsafeMutablePointer<UInt8>(result.mutableBytes))
        return NSData(data: result)
    }

    func SHA1() -> NSData {
        let result = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH))!
        CC_SHA1(bytes, CC_LONG(length), UnsafeMutablePointer<UInt8>(result.mutableBytes))
        return NSData(data: result)
    }

    func SHA256() -> NSData {
        let result = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH))
        CC_SHA256(bytes, CC_LONG(length), UnsafeMutablePointer(result!.mutableBytes))
        return NSData(data: result!)
    }
}

extension String {
    func hexString() -> String {
        return (self as NSString).dataUsingEncoding(NSUTF8StringEncoding)!.hexString()
    }

    func MD5() -> String {
        return (self as NSString).dataUsingEncoding(NSUTF8StringEncoding)!.MD5().hexString()
    }

    func SHA1() -> String {
        return (self as NSString).dataUsingEncoding(NSUTF8StringEncoding)!.SHA1().hexString()
    }

    func SHA256() -> String {
        return (self as NSString).dataUsingEncoding(NSUTF8StringEncoding)!.SHA256().hexString()
    }

}
10
demandé sur Hamid 2016-09-25 09:30:03

4 réponses

vous feriez mieux D'utiliser Swift Data dans Swift 3.

et en travaillant avec Data, vous devez utiliser withUnsafeBytes(_:) ou withUnsafeMutableBytes(_:), où vous utilisiez bytes ou mutableBytes respectivement.

withUnsafeBytes ( _ :)

withunsafemutable bytes ( _ :)

extension Data {
    func hexString() -> String {
        let string = self.map{Int().hexString()}.joined()
        return string
    }

    func MD5() -> Data {
        var result = Data(count: Int(CC_MD5_DIGEST_LENGTH))
        _ = result.withUnsafeMutableBytes {resultPtr in
            self.withUnsafeBytes {(bytes: UnsafePointer<UInt8>) in
                CC_MD5(bytes, CC_LONG(count), resultPtr)
            }
        }
        return result
    }

    /*
    ... nearly the same for `SHA1` and `SHA256`.
     */
}

extension String {
    func hexString() -> String {
        return self.data(using: .utf8)!.hexString()
    }

    func MD5() -> String {
        return self.data(using: .utf8)!.MD5().hexString()
    }

    /*
    ... nearly the same for `SHA1` and `SHA256`.
     */
}

je préfère faire des propriétés calculées que des méthodes sans argument (pour des tâches relativement légères). Vous avez besoin de fixer toutes les pièces à l'aide, mais vous pouvez écrire quelque chose comme ceci:

extension Int {
    var hexString: String {
        return ...
    }
}
extension Data {
    var hexString: String {
        let string = self.map{Int().hexString}.joined()
        return string
    }

    var MD5: Data {
        var result = Data(count: Int(CC_MD5_DIGEST_LENGTH))
        _ = result.withUnsafeMutableBytes {resultPtr in
            self.withUnsafeBytes {(bytes: UnsafePointer<UInt8>) in
                CC_MD5(bytes, CC_LONG(count), resultPtr)
            }
        }
        return result
    }

    /*
    ... nearly the same for `SHA1` and `SHA256`.
     */
}

extension String {
    var hexString: String {
        return self.data(using: .utf8)!.hexString
    }

    var MD5: String {
        return self.data(using: .utf8)!.MD5.hexString
    }

    /*
    ... nearly the same for `SHA1` and `SHA256`.
     */
}

il peut y avoir une solution plus rapide pour votre code en utilisant NSData, mais je vous recommande de vous déplacer à Data dans Swift 3.

16
répondu OOPer 2016-09-25 07:26:11
func MD5() -> String {

    let length = Int(CC_MD5_DIGEST_LENGTH)
    var digest = [UInt8](repeating: 0, count: length)
    if let d = self.data(using: String.Encoding.utf8) {
        d.withUnsafeBytes { (body: UnsafePointer<UInt8>) in
            CC_MD5(body, CC_LONG(d.count), &digest)
        }
    }
    return (0..<length).reduce("") {
         + String(format: "%02x", digest[])
    }

}
0
répondu Ali Raza 2017-04-21 20:46:48

je trouve la plupart de la réponse ok, mais si nous devrions avoir une VRAIE solution universelle, je pense que nous devons l'augmenter d'un niveau.

CC_LONG est juste un UInt32 et ne soutiendra pas vraiment de grandes structures de données.

C'est ma solution Swift 3:

tout d'abord, nous créons une fondation qui fonctionne avec Data:

struct Sha256 {
    let context = UnsafeMutablePointer<CC_SHA256_CTX>.allocate(capacity:1)

    init() {
        CC_SHA256_Init(context)
    }

    func update(data: Data) {
        data.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> Void in
            let end = bytes.advanced(by: data.count)
            for f in sequence(first: bytes, next: { .advanced(by: Int(CC_LONG.max)) }).prefix(while: { (current) -> Bool in current < end})  {
                _ = CC_SHA256_Update(context, f, CC_LONG(Swift.min(f.distance(to: end), Int(CC_LONG.max))))
            }
        }
    }

    func final() -> Data {
        var digest = [UInt8](repeating: 0, count:Int(CC_SHA256_DIGEST_LENGTH))
        CC_SHA256_Final(&digest, context)

        return Data(bytes: digest)
    }
}

Pour plus de commodité, nous faire une extension de Données:

extension Data {
    func sha256() -> Data {
        let s = Sha256()
        s.update(data: self)
        return s.final()
    }
}

et durer une extension pour Chaîne de caractères:

extension String {
    func sha256() -> Data {
        return self.data(using: .utf8)!.sha256()
    }
}

si nécessaire, convertissez le résultat de Data hex de chaîne ou autre chose selon votre cas d'utilisation.

cette solution peut être utilisée pour Sha512, MD5 etc. pour obtenir de vraies solutions universelles avec le CommonCrypto D'Apple qui sont faciles à étendre à de nombreux cas d'utilisation différents.

0
répondu Martin Carlberg 2017-07-03 11:01:39

pour l'achèvement, la solution la plus courte et la plus flexible dans Swift 4 est:

extension Data {

    var hexString: String {
        return map { String(format: "%02hhx", ) }.joined()
    }

    var md5: Data {
        var digest = [Byte](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        self.withUnsafeBytes({
            _ = CC_MD5(, CC_LONG(self.count), &digest)
        })
        return Data(bytes: digest)
    }

    var sha1: Data {
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
        self.withUnsafeBytes({
            _ = CC_SHA1(, CC_LONG(self.count), &digest)
        })
        return Data(bytes: digest)
    }

    var sha256: Data {
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
        self.withUnsafeBytes({
            _ = CC_SHA256(, CC_LONG(self.count), &digest)
        })
        return Data(bytes: digest)
    }

}

extension String {

    var md5: Data {
        return self.data(using: .utf8)!.md5
    }

    var sha1: Data {
        return self.data(using: .utf8)!.sha1
    }

    var sha256: Data {
        return self.data(using: .utf8)!.sha256
    }

}
0
répondu sundance 2018-02-23 21:52:04