Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to hash NSString with SHA1 in Swift?

Tags:

swift

sha1

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.

like image 297
imike Avatar asked Sep 10 '14 09:09

imike


1 Answers

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()     } } 
like image 121
Martin R Avatar answered Oct 10 '22 01:10

Martin R