In objective-c it looks like this:
#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
I need something like this with Swift, is it possible?
Please, show work example.
Your Objective-C code (using a NSString
category) can be directly translated to Swift (using a String
extension).
First you have to create a "bridging header" and add
#import <CommonCrypto/CommonCrypto.h>
Then:
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())
This can be written slightly shorter and Swifter as
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) } }
Update for 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("") } }
To return a Base-64 encoded string instead of a hex encoded string, just replace
let hexBytes = digest.map { String(format: "%02hhx", $0) } return hexBytes.joinWithSeparator("")
with
return NSData(bytes: digest, length: digest.count).base64EncodedStringWithOptions([])
Update for 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() } }
To return a Base-64 encoded string instead of a hex encoded string, just replace
let hexBytes = digest.map { String(format: "%02hhx", $0) } return hexBytes.joined()
by
return Data(bytes: digest).base64EncodedString()
Update for Swift 4:
The bridging header file is no longer needed, one can import CommonCrypto
instead:
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() } }
Update for Swift 5:
The Data.withUnsafeBytes()
method now calls the closure with an UnsafeRawBufferPointer
to, and baseAddress
is used to pass the initial address to the C function:
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() } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With