如何在Swift中使用SHA1散列NSString?

如何在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

在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.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加密字符串的逻辑:

  • 将字符串转换为数据对象
  • 使用SHA1函数对数据进行加密
  • 将数据对象转换为十六进制字符串
  • IMHO它的可读性更强,并且这个版本不需要NSData

        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
    也应该可以工作(感谢底层迭代器),在服务器上也可以正常工作:)