Ich möchte sha256 in meinem Projekt verwenden, hatte jedoch einige Probleme beim Umschreiben von objC-Code in schnellen Code. Hilf mir bitte. Ich habe diese Antwort verwendet: Wie kann ich einen SHA-2-Hash (idealerweise SHA 256 oder SHA 512) in iOS berechnen?
Hier ist mein Code
var hash : [CUnsignedChar]
CC_SHA256(data.bytes, data.length, hash)
var res : NSData = NSData.dataWithBytes(hash, length: CC_SHA256_DIGEST_LENGTH)
es gibt mir Fehler alles da swift nicht umwandeln kann Int
zu CC_LONG
, zum Beispiel.
CUnsignedChar[]
?Antworten:
Sie müssen explizit zwischen
Int
und konvertierenCC_LONG
, da Swift keine impliziten Konvertierungen wie in (Objective-) C durchführt.Sie müssen auch
hash
ein Array mit der erforderlichen Größe definieren.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 }
Alternativ können Sie
NSMutableData
den erforderlichen Puffer zuweisen: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 }
Update für Swift 3 und 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) }
Update für 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) }
quelle
CC_SHA256_DIGEST_LENGTH
,CC_SHA256
undCC_LONG
Arbeit in Swift, müssen Sie hinzufügen ,#import <CommonCrypto/CommonDigest.h>
zu der Überbrückungs Header - Datei.Die beste Antwort hat bei mir nicht funktioniert. Ich habe etwas im Web gefunden und ein wenig geändert und jetzt funktioniert es: D. Es ist für Swift 3 und 4.
Fügen Sie diese Erweiterung irgendwo in Ihr Projekt ein und verwenden Sie sie für eine Zeichenfolge wie die folgende: 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 } }
Übrigens benötigen Sie einen Bridging-Header, der CommonCrypto importiert. Wenn Sie noch keine haben, gehen Sie folgendermaßen vor:
BridgingHeader
ProjectName/BridgingHeader.h
#import <CommonCrypto/CommonHMAC.h>
Ihre Header-Datei einquelle
return hexStringFromData(input: digest(input: stringData))
Änderung durch:return hexStringFromData(input: digest(input: stringData as NSData))
let data = NSData(contentsOfFile: "/Users/danila/metaprogramming-ruby-2.pdf") data.sha256()
Mit
CryptoKit
iOS13 haben wir jetzt die native 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 }
Da utils für Protokoll definiert sind
Digest
, können Sie es für alle Art in verdauenCryptoKit
, wieSHA384Digest
,SHA512Digest
,SHA1Digest
,MD5Digest
...quelle
var hexString: String { self.map { String(format: "%02hhx", $0) }.joined() }
Funktionen, die den SHA von
NSData
&String
(Swift 3) geben: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 }
Nehmen Sie in Ihren Bridging-Header auf:
#import "CommonCrypto/CommonCrypto.h"
quelle
Eine Version für Swift 5, die CryptoKit unter iOS 13 verwendet und ansonsten auf CommonCrypto zurückgreift:
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()) } } }
Verwendung:
let string = "The quick brown fox jumps over the lazy dog" let hexDigest = string.data(using: .ascii)!.sha256 assert(hexDigest == "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592")
Auch über den Swift-Paketmanager verfügbar:
https://github.com/ralfebert/TinyHashes
quelle
import CryptoKit
Pause nicht auf iOS 12 sein? Es ist ein Framework nur für iOS 13.0+.#if canImport(CryptoKit)
für den bedingten Import verwendet werden. Vergessen Sie nicht,-weak_framework CryptoKit
inOther 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() } }
quelle
Hier ist meine einfache 3-zeilige Swift 4-Funktion, die die Security Transforms-API verwendet, die Teil von Foundation unter macOS ist. (Leider können iOS-Programmierer diese Technik nicht verwenden.)
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 } }
quelle
Hier ist eine Methode, die die CoreFoundation Security Transforms-API verwendet, sodass Sie nicht einmal eine Verknüpfung zu CommonCrypto herstellen müssen. Aus irgendeinem Grund ist die Verknüpfung mit CommmonCrypto mit Swift in 10.10 / Xcode 7 ein Drama, daher habe ich dies stattdessen verwendet.
Diese Methode liest aus einer
NSInputStream
, die Sie entweder aus einer Datei abrufen können, oder Sie können eine erstellen, die eine liestNSData
, oder Sie können gebundene Lese- / Schreib-Streams für einen gepufferten Prozess erstellen.// 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() } }
quelle
Für 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
quelle
In Swift5 getestet.
Wenn Sie den Hash in String erhalten möchten ,
So habe ich es gemacht.
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: "") }
quelle
Ich bevorzuge:
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) } }
Der gehetzte String ist base64-codiert.
quelle
Die anderen Antworten haben Leistungsprobleme bei der Berechnung von Digests aus großen Datenmengen (z. B. großen Dateien). Sie möchten nicht alle Daten gleichzeitig in den Speicher laden. Betrachten Sie den folgenden Ansatz mit 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) }) } }
Sie können es wie folgt verwenden:
let digest = SHA256Digest() try digest.update(url: fileURL) let result = digest.finalize().hexString print(result)
quelle
Swift 5 Beispielprojekt Open Source mit Alert Copy
https://github.com/devzhr/Swift-CryptoSHA256
quelle
Ich habe viele Antworten recherchiert und zusammengefasst:
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() } } }
quelle