prabhu
prabhu

Reputation: 1206

Swift SHA256 encryption returns different encrypted string compare to Objective C

I am migrating some codes from objective c to swift. I want to encrypt a string with a key using SHA 256 algorithm in swift. But comparing to Objective C implementation swift code returns different encrypted string. Both codes looks same only the syntax is different. Can someone help me get the same result in swift as I used to get in Objective C? Below are the code samples from both languages.

Objective C:

NSString* key = @"1234567890123456789012345678901234567890123456789012345678901234";
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [@"message" cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *hash = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
 NSString* encryptedString = hash.base64Encoding;

Swift:

let key = "1234567890123456789012345678901234567890123456789012345678901234"
let cKey = key.cString(using: .ascii)!
let cData = "message".cString(using: .ascii)!
var digest = [CUnsignedChar](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), cKey, cKey.count, cData, cData.count, &digest)
let hash = Data(digest)
let encryptedString = hash.base64EncodedString()

Upvotes: 2

Views: 996

Answers (1)

Martin R
Martin R

Reputation: 539815

The problem is that cKey and cData include the terminating null character of the strings, and in the Swift version that is counted in cKey.count and cData.count, whereas in the Objective-C version strlen(cKey) and strlen(cData) do not count the terminating null character of the strings.

Doing

 CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), cKey, strlen(key), cData, strlen("message", &digest)

instead would fix the issue in your example, but is not safe for non-ASCII characters.

What I actually would do is to convert the strings to Data values (which do not include a terminating null byte) with the UTF-8 representation. Then pass the underlying byte buffers to the encryption method:

let key = "1234567890123456789012345678901234567890123456789012345678901234"
let cKey = Data(key.utf8)
let cData = Data("message".utf8)
var digest = [CUnsignedChar](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
cKey.withUnsafeBytes { keyPtr in
    cData.withUnsafeBytes { dataPtr in
    CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyPtr.baseAddress, cKey.count, dataPtr.baseAddress, cData.count, &digest)
    }
}
let hash = Data(digest)
let encryptedString = hash.base64EncodedString()

This produces the same result ZNjnsz2Uv5L0PvWIJjSh0BrOovuRXOSFWQ0s1Rd8VSM= as your Objective-C code.

Upvotes: 4

Related Questions