我想在我的项目中使用sha256,但是我有一些麻烦将objC代码重写为swift代码。请帮帮我。我用了这个答案:How can I compute a SHA-2 (ideally SHA 256 or SHA 512) hash in 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
,例如。
答案 0 :(得分:84)
您必须在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)
}
答案 1 :(得分:59)
最佳答案对我不起作用。我在网上发现了一些东西,并稍微改了一下,现在它有效: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>
放入您的页眉文件答案 2 :(得分:15)
从myLink.com?id=12431312sdfs2143123&anotherValue
&amp; NSData
(斯威夫特3):
String
包含在您的桥接标题中:
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
}
答案 3 :(得分:11)
在iOS13中添加了CryptoKit
之后,我们现在有了本机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
定义了utils,因此您可以将其用于CryptoKit
中的所有摘要类型,例如SHA384Digest
,SHA512Digest
,SHA1Digest
,{ {1}} ...
答案 4 :(得分:5)
这是我使用安全转换API的简单3行Swift 4功能,它是基于macOS的Foundation的一部分。 (不幸的是,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
}
}
答案 5 :(得分:3)
这是一种使用CoreFoundation Security Transforms API的方法,因此您甚至不需要链接到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()
}
}
答案 6 :(得分:3)
Swift 5的一个版本,该版本在iOS 13上使用CryptoKit,否则回落到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
答案 7 :(得分:3)
在Swift5中进行了测试。
如果要在字符串中获取哈希值,
这就是我的做法。
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: "")
}
答案 8 :(得分:2)
对于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
答案 9 :(得分:1)
我研究了很多答案,并对其进行了总结:
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()
}
}
}
答案 10 :(得分:0)
我更喜欢使用:
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)
}
}
hasded String是base64编码。
答案 11 :(得分:0)
其他答案将存在从大量数据(例如大文件)中计算摘要的性能问题。您将不希望一次将所有数据加载到内存中。考虑使用更新/完成的以下方法:
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)
答案 12 :(得分:0)
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()
}
}
答案 13 :(得分:0)
带有Alert Copy的Swift 5示例项目开源