如何在Swift中使用SHA1散列NSString?
在objective-c中,如下所示:如何在Swift中使用SHA1散列NSString?,swift,sha1,Swift,Sha1,在objective-c中,如下所示: #include <sys/xattr.h> @implementation NSString (reverse) -(NSString*)sha1 { NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding]; uint8_t digest[CC_SHA1_DIGEST_LENGTH]; CC_SHA1(data.bytes, (int)data.le
#include <sys/xattr.h>
@implementation NSString (reverse)
-(NSString*)sha1
{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (int)data.length, digest);
NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
[output appendFormat:@"%02x", digest[i]];
return output;
}
@end
myString.dataUsingEncoding(NSUTF8StringEncoding)?.sha1()
#包括
@实现NSString(反向)
-(NSString*)sha1
{
NSData*data=[自数据使用编码:NSUTF8StringEncoding];
uint8_t摘要[抄送摘要长度];
CC_SHA1(data.bytes,(int)data.length,摘要);
NSMutableString*输出=[NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH*2];
for(int i=0;i
我需要像斯威夫特这样的东西,可能吗
请出示工作示例。是的,有可能:使objective-c代码可以从swift访问
看
如果你得不到任何好处(比如使用特定于swift的功能),我会避免在swift中重写它
另外,在我正在进行的一个项目中,我使用了一些类似于您的objective-c代码来处理哈希。起初我开始用swift编写,后来我意识到重用旧的好obj-c更容易更好。您的Objective-c代码(使用NSString
类别)可以直接翻译成swift
(使用字符串
扩展名)
首先,您必须创建一个“桥接头”并添加
这可以写得稍微短一些,也可以写得更快一些
extension String {
func sha1() -> String {
let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = map(digest) { String(format: "%02hhx", $0) }
return "".join(hexBytes)
}
}
Swift 2的更新:
extension String {
func sha1() -> String {
let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joinWithSeparator("")
}
}
extension String {
func sha1() -> String {
let data = self.data(using: String.Encoding.utf8)!
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA1($0, CC_LONG(data.count), &digest)
}
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
}
}
要返回Base-64编码字符串而不是十六进制编码字符串,
替换
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joinWithSeparator("")
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
与
Swift 3的更新:
extension String {
func sha1() -> String {
let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joinWithSeparator("")
}
}
extension String {
func sha1() -> String {
let data = self.data(using: String.Encoding.utf8)!
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA1($0, CC_LONG(data.count), &digest)
}
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
}
}
要返回Base-64编码字符串而不是十六进制编码字符串,
替换
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joinWithSeparator("")
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
借
Swift 4的更新:
extension String {
func sha1() -> String {
let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joinWithSeparator("")
}
}
extension String {
func sha1() -> String {
let data = self.data(using: String.Encoding.utf8)!
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA1($0, CC_LONG(data.count), &digest)
}
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
}
}
不再需要桥接头文件,可以导入CommonCrypto
:
import CommonCrypto
extension String {
func sha1() -> String {
let data = Data(self.utf8)
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA1($0, CC_LONG(data.count), &digest)
}
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
}
}
Swift 5的更新:
extension String {
func sha1() -> String {
let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joinWithSeparator("")
}
}
extension String {
func sha1() -> String {
let data = self.data(using: String.Encoding.utf8)!
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA1($0, CC_LONG(data.count), &digest)
}
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
}
}
Data.withUnsafeBytes()
方法现在使用UnsafeRawBufferPointer
to调用闭包,并且baseAddress
用于将初始地址传递给C函数:
import CommonCrypto
extension String {
func sha1() -> String {
let data = Data(self.utf8)
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA1($0.baseAddress, CC_LONG(data.count), &digest)
}
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
}
}
要将结果作为
NSData
,前提是在桥接头中包含
:
extension NSData {
func sha1() -> NSData? {
let len = Int(CC_SHA1_DIGEST_LENGTH)
let digest = UnsafeMutablePointer<UInt8>.alloc(len)
CC_SHA1(bytes, CC_LONG(length), digest)
return NSData(bytesNoCopy: UnsafeMutablePointer<Void>(digest), length: len)
}
}
如果您需要NSData的十六进制表示形式,请查看我的另一个。我们可以通过三个步骤提取使用sha1加密字符串的逻辑:
extension String {
var sha1: String {
guard let data = data(using: .utf8, allowLossyConversion: false) else {
// Here you can just return empty string or execute fatalError with some description that this specific string can not be converted to data
}
return data.digestSHA1.hexString
}
}
fileprivate extension Data {
var digestSHA1: Data {
var bytes: [UInt8] = Array(repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
withUnsafeBytes {
_ = CC_SHA1($0, CC_LONG(count), &bytes)
}
return Data(bytes: bytes)
}
var hexString: String {
return map { String(format: "%02x", UInt8($0)) }.joined()
}
}
是的,有可能,把这个类复制到你的项目中。 这很容易,就像:
SHA1.hexString(from: "myPhrase" )!
针对swift 3和swift 4进行了测试。在iOS13中添加了
加密工具包
,我们现在有了本机swift API:
<代码>导入基础
导入加密套件
//CryptoKit.Digest utils
扩展摘要{
变量字节:[UInt8]{Array(makeIterator())}
变量数据:数据{data(字节)}
var-hextr:String{
bytes.map{String(格式:'%02X',$0)}.joined()
}
}
func示例(){
guard let data=“hello world”。数据(使用:.utf8)else{return}
let digest=unsecure.SHA1.hash(数据:数据)
打印(摘要.数据)//20字节
打印(digest.hexStr)//2AE6C35C94FCFB415DBE95F408B9CE91EE846ED
}
Swift 5的一个版本,在iOS 13上使用CryptoKit,否则会退回到CommonCrypto:
导入公共加密
导入加密套件
进口基金会
私有func hexString(iterator:Array.iterator)->String{
返回iterator.map{String(格式:'%02x',$0)}.joined()
}
扩展数据{
公共变量sha1:字符串{
如果可用(iOS 13.0,*){
返回hexString(unsecure.SHA1.hash(数据:self.makeIterator())
}否则{
变量摘要=[UInt8](重复:0,计数:Int(CC\u SHA1\u摘要\u长度))
self.withUnsafeBytes{bytes in
_=CC_SHA1(bytes.baseAddress、CC_LONG(self.count)和摘要)
}
返回hextString(digest.makeIterator())
}
}
}
用法:
let string = "The quick brown fox jumps over the lazy dog"
let hexDigest = string.data(using: .ascii)!.sha1
assert(hexDigest == "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12")
也可通过Swift软件包管理器获得:是否可以不使用obj-c桥接头?我在寻找干净快捷的解决方案。@MihaelIsaev:你说的“干净快捷的解决方案”是什么意思?是否要在Swift中重新实现算法?我不推荐它,因为CommonCrypto是一个行之有效的解决方案。但是你可以看看。是的,我想要一些没有obj-c桥接的库。不幸的是,它也在使用obj-c桥接:(为什么%02x和%02hhx中的差异?Swift 3的更新在Xcode 8 beta 5中不起作用。似乎存在内存泄漏。您必须解除锁定
摘要
,或使用NSData(bytesNoCopy:…)
。使用最新的Swift版本,您现在可以在Swift文件顶部添加import CommonCrypto。不再需要手动创建模块映射或桥接头,因为它现在是SDK的一部分。请注意,转换为UTF-8不会失败。您能提供更多代码吗?我应该导入什么来调用SHA1.hexString(from:“myPhrase”)!
?下载此代码并将其粘贴到您的项目中。这就足够使用它了@MihaelIsaevIt不仅仅是关于iOS的,例如,我还在Linux上使用Swift作为服务器端代码,并且没有办法使用Obj-C桥接。顺便说一句,当时已经有很多本机Swift的哈希解决方案:)好的,让我们等几年再使用它(因为iSO13+)@imike sure,在hexStr
上,您不需要使用bytes.map
,self.map
也应该可以工作(感谢底层迭代器),在服务器上也可以正常工作:)