如何使用Swift将string隐藏到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.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
我需要用Swift这样的东西,可能吗?
请显示工作示例。
您的Objective-C代码(使用NSString
类别)可以直接转换为Swift(使用String
扩展)。
首先你必须创build一个“桥接头”并添加
#import <CommonCrypto/CommonCrypto.h>
然后:
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 output = NSMutableString(capacity: Int(CC_SHA1_DIGEST_LENGTH)) for byte in digest { output.appendFormat("%02x", byte) } return output as String } } println("Hello World".sha1())
这可以写得稍短,Swifter为
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("") } }
要返回Base-64编码的string而不是hex编码的string,只需replace即可
let hexBytes = digest.map { String(format: "%02hhx", $0) } return hexBytes.joinWithSeparator("")
同
return NSData(bytes: digest, length: digest.count).base64EncodedStringWithOptions([])
Swift 3的更新:
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编码的string而不是hex编码的string,只需replace即可
let hexBytes = digest.map { String(format: "%02hhx", $0) } return hexBytes.joined()
通过
return Data(bytes: digest).base64EncodedString()
为了得到NSData
的结果,假设你在桥接头文件中包含<CommonCrypto/CommonCrypto.h>
:
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) } }
也使用适当的指针分配。 像这样调用它:
myString.dataUsingEncoding(NSUTF8StringEncoding)?.sha1()
如果你需要NSData
的hex表示看看我的其他答案 。
我们可以使用sha1提取用于encryptionstring的逻辑,分为三个步骤:
- 将string转换为数据对象
- 使用SHA1函数将数据encryption到数据
- 转换数据对象为hexstring
恕我直言,它更可读,这个版本不需要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() } }
是的,这是可能的: 使快速访问的Objective-C代码
见文件 。
如果你没有得到任何好处(比如使用特定于swift的特性),我会避免在swift中重写它。
另外,在我正在开发的一个项目中,我使用了一些类似于你的Objective-C代码来处理哈希。 一开始我开始写速度很快,然后我意识到重新使用旧的好的obj-c会更容易,更好。