Я хочу использовать sha256 в своем проекте, но у меня возникли проблемы с переписыванием кода objC на быстрый код. Помоги мне, пожалуйста. Я использовал этот ответ: Как я могу вычислить хэш SHA-2 (в идеале SHA 256 или SHA 512) в iOS?
Вот мой код
var hash : [CUnsignedChar]
CC_SHA256(data.bytes, data.length, hash)
var res : NSData = NSData.dataWithBytes(hash, length: CC_SHA256_DIGEST_LENGTH)
это дает мне ошибку во всем, например, потому что swift не может преобразовать Int
в CC_LONG
.
CUnsignedChar[]
?Ответы:
Вы должны явно преобразовать между
Int
иCC_LONG
, потому что Swift не выполняет неявных преобразований, как в (Objective-) C.Также необходимо определить
hash
как массив необходимого размера.func sha256(data : NSData) -> NSData { var hash = [UInt8](count: Int(CC_SHA256_DIGEST_LENGTH), repeatedValue: 0) CC_SHA256(data.bytes, CC_LONG(data.length), &hash) let res = NSData(bytes: hash, length: Int(CC_SHA256_DIGEST_LENGTH)) return res }
В качестве альтернативы вы можете использовать
NSMutableData
для выделения необходимого буфера:func sha256(data : NSData) -> NSData { let res = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH)) CC_SHA256(data.bytes, CC_LONG(data.length), UnsafeMutablePointer(res.mutableBytes)) return res }
Обновление для Swift 3 и 4:
func sha256(data : Data) -> Data { var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) data.withUnsafeBytes { _ = CC_SHA256($0, CC_LONG(data.count), &hash) } return Data(bytes: hash) }
Обновление для Swift 5:
func sha256(data : Data) -> Data { var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) data.withUnsafeBytes { _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash) } return Data(hash) }
источник
CC_SHA256_DIGEST_LENGTH
,CC_SHA256
иCC_LONG
работы в Swift, вы должны добавить#import <CommonCrypto/CommonDigest.h>
к обводного файл заголовка.Главный ответ у меня не сработал. Я что-то нашел в сети, немного изменил и теперь работает: D. Это для Swift 3 и 4.
Поместите это расширение где-нибудь в своем проекте и используйте его в такой строке: mystring.sha256 ()
extension String { func sha256() -> String { if let stringData = self.data(using: String.Encoding.utf8) { return hexStringFromData(input: digest(input: stringData as NSData)) } return "" } private func digest(input : NSData) -> NSData { let digestLength = Int(CC_SHA256_DIGEST_LENGTH) var hash = [UInt8](repeating: 0, count: digestLength) CC_SHA256(input.bytes, UInt32(input.length), &hash) return NSData(bytes: hash, length: digestLength) } private func hexStringFromData(input: NSData) -> String { var bytes = [UInt8](repeating: 0, count: input.length) input.getBytes(&bytes, length: input.length) var hexString = "" for byte in bytes { hexString += String(format:"%02x", UInt8(byte)) } return hexString } }
Кстати, вам нужен заголовок моста, который импортирует CommonCrypto. Если у вас его нет, выполните следующие действия:
BridgingHeader
ProjectName/BridgingHeader.h
#import <CommonCrypto/CommonHMAC.h>
в свой заголовочный файлисточник
return hexStringFromData(input: digest(input: stringData))
Изменено:return hexStringFromData(input: digest(input: stringData as NSData))
let data = NSData(contentsOfFile: "/Users/danila/metaprogramming-ruby-2.pdf") data.sha256()
С
CryptoKit
добавлением в iOS13 у нас теперь есть собственный Swift API:import Foundation import CryptoKit // CryptoKit.Digest utils extension Digest { var bytes: [UInt8] { Array(makeIterator()) } var data: Data { Data(bytes) } var hexStr: String { bytes.map { String(format: "%02X", $0) }.joined() } } func example() { guard let data = "hello world".data(using: .utf8) else { return } let digest = SHA256.hash(data: data) print(digest.data) // 32 bytes print(digest.hexStr) // B94D27B9934D3E08A52E52D7DA7DABFAC484EFE37A5380EE9088F7ACE2EFCDE9 }
Поскольку утилиты определены для протокола
Digest
, вы можете использовать его для всех типов дайджестаCryptoKit
, напримерSHA384Digest
,SHA512Digest
,SHA1Digest
,MD5Digest
...источник
var hexString: String { self.map { String(format: "%02hhx", $0) }.joined() }
Функции, дающие SHA из
NSData
&String
(Swift 3):func sha256(_ data: Data) -> Data? { guard let res = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH)) else { return nil } CC_SHA256((data as NSData).bytes, CC_LONG(data.count), res.mutableBytes.assumingMemoryBound(to: UInt8.self)) return res as Data } func sha256(_ str: String) -> String? { guard let data = str.data(using: String.Encoding.utf8), let shaData = sha256(data) else { return nil } let rc = shaData.base64EncodedString(options: []) return rc }
Включите в заголовок моста:
#import "CommonCrypto/CommonCrypto.h"
источник
Версия для Swift 5, которая использует CryptoKit на iOS 13 и в противном случае возвращается к CommonCrypto:
import CommonCrypto import CryptoKit import Foundation private func hexString(_ iterator: Array<UInt8>.Iterator) -> String { return iterator.map { String(format: "%02x", $0) }.joined() } extension Data { public var sha256: String { if #available(iOS 13.0, *) { return hexString(SHA256.hash(data: self).makeIterator()) } else { var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) self.withUnsafeBytes { bytes in _ = CC_SHA256(bytes.baseAddress, CC_LONG(self.count), &digest) } return hexString(digest.makeIterator()) } } }
Применение:
let string = "The quick brown fox jumps over the lazy dog" let hexDigest = string.data(using: .ascii)!.sha256 assert(hexDigest == "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592")
Также доступно через диспетчер пакетов Swift:
https://github.com/ralfebert/TinyHashes
источник
import CryptoKit
перерыв на iOS 12? Это фреймворк только для iOS 13.0+.#if canImport(CryptoKit)
для условного импорта. Не забудьте установить набор-weak_framework CryptoKit
вOther Linker Flags
import CommonCrypto public extension String { var sha256: String { let data = Data(utf8) var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) data.withUnsafeBytes { buffer in _ = CC_SHA256(buffer.baseAddress, CC_LONG(buffer.count), &hash) } return hash.map { String(format: "%02hhx", $0) }.joined() } }
источник
Вот моя простая 3-строчная функция Swift 4 для этого с использованием API Security Transforms, который является частью Foundation на macOS. (К сожалению, программисты iOS не могут использовать эту технику.)
import Foundation extension Data { public func sha256Hash() -> Data { let transform = SecDigestTransformCreate(kSecDigestSHA2, 256, nil) SecTransformSetAttribute(transform, kSecTransformInputAttributeName, self as CFTypeRef, nil) return SecTransformExecute(transform, nil) as! Data } }
источник
Вот метод, который использует API-интерфейс CoreFoundation Security Transforms, поэтому вам даже не нужно ссылаться на CommonCrypto. По какой-то причине в 10.10 / Xcode 7 ссылка на CommmonCrypto с помощью Swift - это драма, поэтому я использовал это вместо этого.
Этот метод читает из
NSInputStream
файла, который вы можете получить из файла, или вы можете создать тот, который читаетNSData
, или вы можете сделать связанные потоки чтения / записи для буферизованного процесса.// digestType is from SecDigestTransform and would be kSecDigestSHA2, etc func digestForStream(stream : NSInputStream, digestType type : CFStringRef, length : Int) throws -> NSData { let transform = SecTransformCreateGroupTransform().takeRetainedValue() let readXform = SecTransformCreateReadTransformWithReadStream(stream as CFReadStreamRef).takeRetainedValue() var error : Unmanaged<CFErrorRef>? = nil let digestXform : SecTransformRef = try { let d = SecDigestTransformCreate(type, length, &error) if d == nil { throw error!.takeUnretainedValue() } else { return d.takeRetainedValue() } }() SecTransformConnectTransforms(readXform, kSecTransformOutputAttributeName, digestXform, kSecTransformInputAttributeName, transform, &error) if let e = error { throw e.takeUnretainedValue() } if let output = SecTransformExecute(transform, &error) as? NSData { return output } else { throw error!.takeUnretainedValue() } }
источник
Для Swift 5:
guard let data = self.data(using: .utf8) else { return nil } var sha256 = Data(count: Int(CC_SHA256_DIGEST_LENGTH)) sha256.withUnsafeMutableBytes { sha256Buffer in data.withUnsafeBytes { buffer in let _ = CC_SHA256(buffer.baseAddress!, CC_LONG(buffer.count), sha256Buffer.bindMemory(to: UInt8.self).baseAddress) } } return sha256
источник
Протестировано в Swift5.
Если вы хотите получить хеш в String ,
вот как я это сделал.
private func getHash(_ phrase:String) -> String{ let data = phrase.data(using: String.Encoding.utf8)! let length = Int(CC_SHA256_DIGEST_LENGTH) var digest = [UInt8](repeating: 0, count: length) data.withUnsafeBytes { _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &digest) } return digest.map { String(format: "%02x", $0) }.joined(separator: "") }
источник
Я исследовал множество ответов и резюмировал их:
import CryptoKit import CommonCrypto
extension String { func hash256() -> String { let inputData = Data(utf8) if #available(iOS 13.0, *) { let hashed = SHA256.hash(data: inputData) return hashed.compactMap { String(format: "%02x", $0) }.joined() } else { var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) inputData.withUnsafeBytes { bytes in _ = CC_SHA256(bytes.baseAddress, UInt32(inputData.count), &digest) } return digest.makeIterator().compactMap { String(format: "%02x", $0) }.joined() } } }
источник
Я предпочитаю использовать:
extension String { var sha256:String? { guard let stringData = self.data(using: String.Encoding.utf8) else { return nil } return digest(input: stringData as NSData).base64EncodedString(options: []) } private func digest(input : NSData) -> NSData { let digestLength = Int(CC_SHA256_DIGEST_LENGTH) var hash = [UInt8](repeating: 0, count: digestLength) CC_SHA256(input.bytes, UInt32(input.length), &hash) return NSData(bytes: hash, length: digestLength) } }
Закодированная строка имеет кодировку base64.
источник
В других ответах будут проблемы с производительностью для расчета дайджестов из больших объемов данных (например, больших файлов). Вам не захочется загружать в память сразу все данные. Рассмотрим следующий подход с использованием update / finalize:
final class SHA256Digest { enum InputStreamError: Error { case createFailed(URL) case readFailed } private lazy var context: CC_SHA256_CTX = { var shaContext = CC_SHA256_CTX() CC_SHA256_Init(&shaContext) return shaContext }() private var result: Data? = nil init() { } func update(url: URL) throws { guard let inputStream = InputStream(url: url) else { throw InputStreamError.createFailed(url) } return try update(inputStream: inputStream) } func update(inputStream: InputStream) throws { guard result == nil else { return } inputStream.open() defer { inputStream.close() } let bufferSize = 4096 let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize) defer { buffer.deallocate() } while true { let bytesRead = inputStream.read(buffer, maxLength: bufferSize) if bytesRead < 0 { //Stream error occured throw (inputStream.streamError ?? InputStreamError.readFailed) } else if bytesRead == 0 { //EOF break } self.update(bytes: buffer, length: bytesRead) } } func update(data: Data) { guard result == nil else { return } data.withUnsafeBytes { self.update(bytes: $0, length: data.count) } } func update(bytes: UnsafeRawPointer, length: Int) { guard result == nil else { return } _ = CC_SHA256_Update(&self.context, bytes, CC_LONG(length)) } func finalize() -> Data { if let calculatedResult = result { return calculatedResult } var resultBuffer = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) CC_SHA256_Final(&resultBuffer, &self.context) let theResult = Data(bytes: resultBuffer) result = theResult return theResult } } extension Data { private static let hexCharacterLookupTable: [Character] = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ] var hexString: String { return self.reduce(into: String(), { (result, byte) in let c1: Character = Data.hexCharacterLookupTable[Int(byte >> 4)] let c2: Character = Data.hexCharacterLookupTable[Int(byte & 0x0F)] result.append(c1) result.append(c2) }) } }
Вы можете использовать это следующим образом:
let digest = SHA256Digest() try digest.update(url: fileURL) let result = digest.finalize().hexString print(result)
источник
Пример проекта Swift 5 с открытым исходным кодом и Alert Copy
https://github.com/devzhr/Swift-CryptoSHA256
источник