Swift 3 делает функции sha1, sha256 и md5

В Swift 2 я использовал следующий код для расширения строковых переменных и для создания sha1, sha256 и md5.

После перехода на быстрый 3 код уже не работает! Я попытался преобразовать его, но столкнулся с непрерывными ошибками.

Любая идея, как я могу это решить?

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

}

Ответ 1

Лучше использовать Swift Data в Swift 3.

Data

И при работе с Data вам нужно использовать withUnsafeBytes(_:) или withUnsafeMutableBytes(_:), где вы использовали bytes или mutableBytes соответственно.

withUnsafeBytes (_:)

withUnsafeMutableBytes (_:)

extension Data {
    func hexString() -> String {
        let string = self.map{Int($0).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`.
     */
}

Я предпочитаю делать вычисляемые свойства, чем методы без аргументов (для относительно легких задач). Вам нужно исправить все части, используя их, но вы можете написать что-то вроде этого:

extension Int {
    var hexString: String {
        return ...
    }
}
extension Data {
    var hexString: String {
        let string = self.map{Int($0).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`.
     */
}

Может быть более быстрое исправление для вашего кода с помощью NSData, но я рекомендую вам перейти на Data в Swift 3.

Ответ 2

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("") {
        $0 + String(format: "%02x", digest[$1])
    }

}

Ответ 3

Я нахожу большую часть ответа в порядке, но если у нас должно быть истинное универсальное решение, я думаю, что нам нужно повысить его уровень.

CC_LONG - это просто UInt32 и не будет поддерживать действительно большие структуры данных.

Это мое решение в Swift 3:

Сначала мы создаем основу, которая работает с 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: { $0.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)
    }
}

Для удобства мы делаем расширение для Data:

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

И последнее расширение для String:

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

При необходимости преобразуйте результат из Data в шестнадцатеричную строку или что-то еще в зависимости от вашего варианта использования.

Это решение может использоваться для Sha512, MD5 и т.д., чтобы получить настоящие универсальные решения с Apple CommonCrypto, которые легко распространяться на множество различных случаев использования.

Ответ 4

Для завершения кратчайшее и наиболее гибкое решение в Swift 4:

extension Data {

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

    var md5: Data {
        var digest = [Byte](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        self.withUnsafeBytes({
            _ = CC_MD5($0, 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($0, 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($0, 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
    }

}

Ответ 5

Создание SHA-256 легко с этой функцией на AfriwanLib:

sha256(value: "value to convert")

это учебная ссылка: https://diponten.com/2019/07/10/sha/