Quiero usar sha256 en mi proyecto, pero tuve algunos problemas para reescribir el código objC en código swift. Ayudame por favor. Usé esta respuesta: ¿Cómo puedo calcular un hash SHA-2 (idealmente SHA 256 o SHA 512) en iOS?
Aqui esta mi codigo
var hash : [CUnsignedChar]
CC_SHA256(data.bytes, data.length, hash)
var res : NSData = NSData.dataWithBytes(hash, length: CC_SHA256_DIGEST_LENGTH)
me da error de todo, porque no se puede convertir rápidamente Int
a CC_LONG
, por ejemplo.
CUnsignedChar[]
?Respuestas:
Tiene que convertir explícitamente entre
Int
yCC_LONG
, porque Swift no realiza conversiones implícitas, como en (Objective-) C.También debe definir
hash
como una matriz del tamaño requerido.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 }
Alternativamente, puede usar
NSMutableData
para asignar el búfer necesario: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 }
Actualización para Swift 3 y 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) }
Actualización para 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) }
fuente
CC_SHA256_DIGEST_LENGTH
,CC_SHA256
yCC_LONG
trabajar en Swift, debe agregar#import <CommonCrypto/CommonDigest.h>
al archivo de encabezado de puente.La respuesta principal no funcionó para mí. Encontré algo en la web y lo cambié un poco y ahora funciona: D. Es para Swift 3 y 4.
Coloque esta extensión en algún lugar de su proyecto y utilícela en una cadena como esta: 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 } }
Por cierto, necesita un encabezado puente que importe CommonCrypto. Si no tiene uno, siga estos pasos:
BridgingHeader
ProjectName/BridgingHeader.h
#import <CommonCrypto/CommonHMAC.h>
tu archivo de encabezadofuente
return hexStringFromData(input: digest(input: stringData))
Cambiar por:return hexStringFromData(input: digest(input: stringData as NSData))
let data = NSData(contentsOfFile: "/Users/danila/metaprogramming-ruby-2.pdf") data.sha256()
Con
CryptoKit
agregado en iOS13, ahora tenemos la API Swift nativa: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 }
Debido utilidades se definen para el protocolo
Digest
, que se puede utilizar para todos digerir tipo enCryptoKit
, comoSHA384Digest
,SHA512Digest
,SHA1Digest
,MD5Digest
...fuente
var hexString: String { self.map { String(format: "%02hhx", $0) }.joined() }
Funciones que dan el SHA de
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 }
Incluya en su encabezado puente:
#import "CommonCrypto/CommonCrypto.h"
fuente
Una versión para Swift 5 que usa CryptoKit en iOS 13 y, de lo contrario, recurre a 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()) } } }
Uso:
let string = "The quick brown fox jumps over the lazy dog" let hexDigest = string.data(using: .ascii)!.sha256 assert(hexDigest == "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592")
También disponible a través del administrador de paquetes Swift:
https://github.com/ralfebert/TinyHashes
fuente
import CryptoKit
embargo, ¿no será el salto en iOS 12? Es un marco exclusivo para iOS 13.0+.#if canImport(CryptoKit)
para la importación condicional. No olvides configurar el set-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() } }
fuente
Aquí está mi sencilla función Swift 4 de 3 líneas para esto usando la API Security Transforms, que es parte de Foundation en macOS. (Desafortunadamente, los programadores de iOS no pueden usar esta técnica).
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 } }
fuente
Aquí hay un método que usa la API de Transformaciones de seguridad de CoreFoundation, por lo que ni siquiera necesita vincularse a CommonCrypto. Por alguna razón, en 10.10 / Xcode 7, la vinculación a CommmonCrypto con Swift es un drama, así que usé esto en su lugar.
Este método lee de un
NSInputStream
, que puede obtener de un archivo, o puede hacer uno que lea unNSData
, o puede crear secuencias de lectura / escritura enlazadas para un proceso almacenado en búfer.// 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() } }
fuente
Para 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
fuente
Probado en Swift5.
En caso de que desee obtener el hash en String ,
así es como lo hice.
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: "") }
fuente
Investigué muchas respuestas y las resumí:
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() } } }
fuente
Prefiero usar:
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) } }
La cadena hash está codificada en base64.
fuente
Las otras respuestas tendrán problemas de rendimiento para calcular resúmenes de grandes cantidades de datos (por ejemplo, archivos grandes). No querrá cargar todos los datos en la memoria a la vez. Considere el siguiente enfoque usando actualizar / finalizar:
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) }) } }
Puedes usarlo de la siguiente manera:
let digest = SHA256Digest() try digest.update(url: fileURL) let result = digest.finalize().hexString print(result)
fuente
Proyecto de ejemplo de Swift 5 de código abierto con Alert Copy
https://github.com/devzhr/Swift-CryptoSHA256
fuente