Implementing Hmac and Sha1 Encryption in Swift

Implementing HMAC and SHA1 encryption in swift

Problem solved! First off i wasn't using the string function properly... I ended up with this:

    let hmacResult:String = "myStringToHMAC".hmac(HMACAlgorithm.SHA1, key: "myKey")

Then I had forgotten I needed to base64 encode the hmac result. So i modified the string function linked in my question to...

enum HMACAlgorithm {
case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

func toCCHmacAlgorithm() -> CCHmacAlgorithm {
var result: Int = 0
switch self {
case .MD5:
result = kCCHmacAlgMD5
case .SHA1:
result = kCCHmacAlgSHA1
case .SHA224:
result = kCCHmacAlgSHA224
case .SHA256:
result = kCCHmacAlgSHA256
case .SHA384:
result = kCCHmacAlgSHA384
case .SHA512:
result = kCCHmacAlgSHA512
}
return CCHmacAlgorithm(result)
}

func digestLength() -> Int {
var result: CInt = 0
switch self {
case .MD5:
result = CC_MD5_DIGEST_LENGTH
case .SHA1:
result = CC_SHA1_DIGEST_LENGTH
case .SHA224:
result = CC_SHA224_DIGEST_LENGTH
case .SHA256:
result = CC_SHA256_DIGEST_LENGTH
case .SHA384:
result = CC_SHA384_DIGEST_LENGTH
case .SHA512:
result = CC_SHA512_DIGEST_LENGTH
}
return Int(result)
}
}

extension String {
func hmac(algorithm: HMACAlgorithm, key: String) -> String {
let cKey = key.cStringUsingEncoding(NSUTF8StringEncoding)
let cData = self.cStringUsingEncoding(NSUTF8StringEncoding)
var result = [CUnsignedChar](count: Int(algorithm.digestLength()), repeatedValue: 0)
CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, strlen(cKey!), cData!, strlen(cData!), &result)
var hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))
var hmacBase64 = hmacData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding76CharacterLineLength)
return String(hmacBase64)
}
}

This is giving me the correct result of

lGCtbW+DNHFraNoxPGK3trgM/98=

HMAC SHA256 in Swift 4

I've been using this:

import Foundation

enum CryptoAlgorithm {
case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

var HMACAlgorithm: CCHmacAlgorithm {
var result: Int = 0
switch self {
case .MD5: result = kCCHmacAlgMD5
case .SHA1: result = kCCHmacAlgSHA1
case .SHA224: result = kCCHmacAlgSHA224
case .SHA256: result = kCCHmacAlgSHA256
case .SHA384: result = kCCHmacAlgSHA384
case .SHA512: result = kCCHmacAlgSHA512
}
return CCHmacAlgorithm(result)
}

var digestLength: Int {
var result: Int32 = 0
switch self {
case .MD5: result = CC_MD5_DIGEST_LENGTH
case .SHA1: result = CC_SHA1_DIGEST_LENGTH
case .SHA224: result = CC_SHA224_DIGEST_LENGTH
case .SHA256: result = CC_SHA256_DIGEST_LENGTH
case .SHA384: result = CC_SHA384_DIGEST_LENGTH
case .SHA512: result = CC_SHA512_DIGEST_LENGTH
}
return Int(result)
}
}

extension String {

func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
let str = self.cString(using: String.Encoding.utf8)
let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
let digestLen = algorithm.digestLength
let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
let keyStr = key.cString(using: String.Encoding.utf8)
let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8))

CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)

let digest = stringFromResult(result: result, length: digestLen)

result.deallocate(capacity: digestLen)

return digest
}

private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
let hash = NSMutableString()
for i in 0..<length {
hash.appendFormat("%02x", result[i])
}
return String(hash).lowercased()
}
}

You'll need to add #import <CommonCrypto/CommonHMAC.h> to your Objective-C bridging header.

Source: @thevalyreangroup on this github thread

How to do HMAC-SHA1 in swift

You should definitely use CommonCrypto because it is already available on every device, well tested and fast. You just need to add a bridging header containing

#import <CommonCrypto/CommonCrypto.h>

As already stated, you can look up here how to add the bridging header.

To calculate the HMAC you just need this extension:

extension String {

func hmac(key: String) -> String {
var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), key, key.count, self, self.count, &digest)
let data = Data(bytes: digest, count: Int(CC_SHA1_DIGEST_LENGTH))
return data.map { String(format: "%02hhx", $0) }.joined()
}

}

Example:

let result = "test".hmac(key: "test")

Result:

0c94515c15e5095b8a87a50ba0df3bf38ed05fe6

How to create a HMAC MD5 Hex signature using SWIFT 4?

On the shoulders of giants etc., using this extension to split your key string up into pairs of characters:

// From https://stackoverflow.com/a/34454633/325366
extension Collection {
var pairs: [SubSequence] {
var startIndex = self.startIndex
let count = self.count
let n = count/2 + count % 2
return (0..<n).map { _ in
let endIndex = index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
defer { startIndex = endIndex }
return self[startIndex..<endIndex]
}
}
}

... we can turn your key String into a [UInt8]:

let keyBytes = key.pairs.map { byteStr -> UInt8 in
var value: UInt32 = 0
Scanner(string: String(byteStr)).scanHexInt32(&value)
return UInt8(clamping: value)
}

... and anticipating a desire to print the final hex value out we can write an extension on Array:

extension Array where Element == UInt8 {
var asHexString: String {
return self.map { String(format: "%0x", $0) }
.joined()
}
}

... which results in your original code:

let stringArr: Array<UInt8> = Array(string.utf8)
do {
let authenticator = HMAC(key: keyBytes, variant: .md5)
let hmac = try authenticator.authenticate(stringArr)

print("Message HMAC: \(hmac.asHexString)")
} catch { }

... printing out the value you are looking for:

Encrypted string: 7eda9d3c1356402e6fce39af3bc8d195

Swift SHA1 function without HMAC

I've got a solution, there was something wrong with the rotate function.

i have changed the rotate function to

func rotate(n: Int, _ s: Int) -> Int {
return ((n << s) & 0xFFFFFFFF) | (n >> (32 - s))
}

and now it works.

CommonHMAC in Swift

You can do it in Swift. Just make sure you add #import <CommonCrypto/CommonHMAC.h> to the bridging Objective-C bridging header.

Update: For Swift 4 see a much better solution using the Swift Package Manager here: https://github.com/jernejstrasner/SwiftCrypto

enum CryptoAlgorithm {
case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

var HMACAlgorithm: CCHmacAlgorithm {
var result: Int = 0
switch self {
case .MD5: result = kCCHmacAlgMD5
case .SHA1: result = kCCHmacAlgSHA1
case .SHA224: result = kCCHmacAlgSHA224
case .SHA256: result = kCCHmacAlgSHA256
case .SHA384: result = kCCHmacAlgSHA384
case .SHA512: result = kCCHmacAlgSHA512
}
return CCHmacAlgorithm(result)
}

var digestLength: Int {
var result: Int32 = 0
switch self {
case .MD5: result = CC_MD5_DIGEST_LENGTH
case .SHA1: result = CC_SHA1_DIGEST_LENGTH
case .SHA224: result = CC_SHA224_DIGEST_LENGTH
case .SHA256: result = CC_SHA256_DIGEST_LENGTH
case .SHA384: result = CC_SHA384_DIGEST_LENGTH
case .SHA512: result = CC_SHA512_DIGEST_LENGTH
}
return Int(result)
}
}

extension String {

func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
let str = self.cStringUsingEncoding(NSUTF8StringEncoding)
let strLen = Int(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
let digestLen = algorithm.digestLength
let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)
let keyStr = key.cStringUsingEncoding(NSUTF8StringEncoding)
let keyLen = Int(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))

CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)

let digest = stringFromResult(result, length: digestLen)

result.dealloc(digestLen)

return digest
}

private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
var hash = NSMutableString()
for i in 0..<length {
hash.appendFormat("%02x", result[i])
}
return String(hash)
}

}

Swift hash a string using hash_hmac with ripemd160

Here is a (self-contained) pure Swift 5 implementation of the RIPEMD-160 hash function and the
corresponding HMAC-RIPEMD-160 message authentication code. It has been tested with
all test vectors on the RIPEMD-160 page (tested on
macOS, 32-bit iOS, 64-bit iOS).

The code for Swift 3 can be found in the edit history.

This is a translation of the reference implementation
rmd160.h,
rmd160.c
from the RIPEMD-160 page from C to Swift. I translated the helper macros and the compress()
function (the "heart" of the algorithm) as "verbatim" as possible. This allowed me to
copy/paste large C code segments and make only minor adjustments for Swift.

The update() and finalize() methods provide a streaming interface, similar to that
of the CommonCrypto functions.

RIPEMD160.swift:

import Foundation

public struct RIPEMD160 {

private var MDbuf: (UInt32, UInt32, UInt32, UInt32, UInt32)
private var buffer: Data
private var count: Int64 // Total # of bytes processed.

public init() {
MDbuf = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0)
buffer = Data()
count = 0
}

private mutating func compress(_ X: UnsafePointer<UInt32>) {

// *** Helper functions (originally macros in rmd160.h) ***

/* ROL(x, n) cyclically rotates x over n bits to the left */
/* x must be of an unsigned 32 bits type and 0 <= n < 32. */
func ROL(_ x: UInt32, _ n: UInt32) -> UInt32 {
return (x << n) | ( x >> (32 - n))
}

/* the five basic functions F(), G() and H() */

func F(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 {
return x ^ y ^ z
}

func G(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 {
return (x & y) | (~x & z)
}

func H(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 {
return (x | ~y) ^ z
}

func I(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 {
return (x & z) | (y & ~z)
}

func J(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 {
return x ^ (y | ~z)
}

/* the ten basic operations FF() through III() */

func FF(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ F(b, c, d) &+ x
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func GG(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ G(b, c, d) &+ x &+ 0x5a827999
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func HH(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ H(b, c, d) &+ x &+ 0x6ed9eba1
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func II(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ I(b, c, d) &+ x &+ 0x8f1bbcdc
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func JJ(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ J(b, c, d) &+ x &+ 0xa953fd4e
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func FFF(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ F(b, c, d) &+ x
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func GGG(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ G(b, c, d) &+ x &+ 0x7a6d76e9
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func HHH(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ H(b, c, d) &+ x &+ 0x6d703ef3
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func III(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ I(b, c, d) &+ x &+ 0x5c4dd124
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

func JJJ(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) {
a = a &+ J(b, c, d) &+ x &+ 0x50a28be6
a = ROL(a, s) &+ e
c = ROL(c, 10)
}

// *** The function starts here ***

var (aa, bb, cc, dd, ee) = MDbuf
var (aaa, bbb, ccc, ddd, eee) = MDbuf

/* round 1 */
FF(&aa, bb, &cc, dd, ee, X[ 0], 11)
FF(&ee, aa, &bb, cc, dd, X[ 1], 14)
FF(&dd, ee, &aa, bb, cc, X[ 2], 15)
FF(&cc, dd, &ee, aa, bb, X[ 3], 12)
FF(&bb, cc, &dd, ee, aa, X[ 4], 5)
FF(&aa, bb, &cc, dd, ee, X[ 5], 8)
FF(&ee, aa, &bb, cc, dd, X[ 6], 7)
FF(&dd, ee, &aa, bb, cc, X[ 7], 9)
FF(&cc, dd, &ee, aa, bb, X[ 8], 11)
FF(&bb, cc, &dd, ee, aa, X[ 9], 13)
FF(&aa, bb, &cc, dd, ee, X[10], 14)
FF(&ee, aa, &bb, cc, dd, X[11], 15)
FF(&dd, ee, &aa, bb, cc, X[12], 6)
FF(&cc, dd, &ee, aa, bb, X[13], 7)
FF(&bb, cc, &dd, ee, aa, X[14], 9)
FF(&aa, bb, &cc, dd, ee, X[15], 8)

/* round 2 */
GG(&ee, aa, &bb, cc, dd, X[ 7], 7)
GG(&dd, ee, &aa, bb, cc, X[ 4], 6)
GG(&cc, dd, &ee, aa, bb, X[13], 8)
GG(&bb, cc, &dd, ee, aa, X[ 1], 13)
GG(&aa, bb, &cc, dd, ee, X[10], 11)
GG(&ee, aa, &bb, cc, dd, X[ 6], 9)
GG(&dd, ee, &aa, bb, cc, X[15], 7)
GG(&cc, dd, &ee, aa, bb, X[ 3], 15)
GG(&bb, cc, &dd, ee, aa, X[12], 7)
GG(&aa, bb, &cc, dd, ee, X[ 0], 12)
GG(&ee, aa, &bb, cc, dd, X[ 9], 15)
GG(&dd, ee, &aa, bb, cc, X[ 5], 9)
GG(&cc, dd, &ee, aa, bb, X[ 2], 11)
GG(&bb, cc, &dd, ee, aa, X[14], 7)
GG(&aa, bb, &cc, dd, ee, X[11], 13)
GG(&ee, aa, &bb, cc, dd, X[ 8], 12)

/* round 3 */
HH(&dd, ee, &aa, bb, cc, X[ 3], 11)
HH(&cc, dd, &ee, aa, bb, X[10], 13)
HH(&bb, cc, &dd, ee, aa, X[14], 6)
HH(&aa, bb, &cc, dd, ee, X[ 4], 7)
HH(&ee, aa, &bb, cc, dd, X[ 9], 14)
HH(&dd, ee, &aa, bb, cc, X[15], 9)
HH(&cc, dd, &ee, aa, bb, X[ 8], 13)
HH(&bb, cc, &dd, ee, aa, X[ 1], 15)
HH(&aa, bb, &cc, dd, ee, X[ 2], 14)
HH(&ee, aa, &bb, cc, dd, X[ 7], 8)
HH(&dd, ee, &aa, bb, cc, X[ 0], 13)
HH(&cc, dd, &ee, aa, bb, X[ 6], 6)
HH(&bb, cc, &dd, ee, aa, X[13], 5)
HH(&aa, bb, &cc, dd, ee, X[11], 12)
HH(&ee, aa, &bb, cc, dd, X[ 5], 7)
HH(&dd, ee, &aa, bb, cc, X[12], 5)

/* round 4 */
II(&cc, dd, &ee, aa, bb, X[ 1], 11)
II(&bb, cc, &dd, ee, aa, X[ 9], 12)
II(&aa, bb, &cc, dd, ee, X[11], 14)
II(&ee, aa, &bb, cc, dd, X[10], 15)
II(&dd, ee, &aa, bb, cc, X[ 0], 14)
II(&cc, dd, &ee, aa, bb, X[ 8], 15)
II(&bb, cc, &dd, ee, aa, X[12], 9)
II(&aa, bb, &cc, dd, ee, X[ 4], 8)
II(&ee, aa, &bb, cc, dd, X[13], 9)
II(&dd, ee, &aa, bb, cc, X[ 3], 14)
II(&cc, dd, &ee, aa, bb, X[ 7], 5)
II(&bb, cc, &dd, ee, aa, X[15], 6)
II(&aa, bb, &cc, dd, ee, X[14], 8)
II(&ee, aa, &bb, cc, dd, X[ 5], 6)
II(&dd, ee, &aa, bb, cc, X[ 6], 5)
II(&cc, dd, &ee, aa, bb, X[ 2], 12)

/* round 5 */
JJ(&bb, cc, &dd, ee, aa, X[ 4], 9)
JJ(&aa, bb, &cc, dd, ee, X[ 0], 15)
JJ(&ee, aa, &bb, cc, dd, X[ 5], 5)
JJ(&dd, ee, &aa, bb, cc, X[ 9], 11)
JJ(&cc, dd, &ee, aa, bb, X[ 7], 6)
JJ(&bb, cc, &dd, ee, aa, X[12], 8)
JJ(&aa, bb, &cc, dd, ee, X[ 2], 13)
JJ(&ee, aa, &bb, cc, dd, X[10], 12)
JJ(&dd, ee, &aa, bb, cc, X[14], 5)
JJ(&cc, dd, &ee, aa, bb, X[ 1], 12)
JJ(&bb, cc, &dd, ee, aa, X[ 3], 13)
JJ(&aa, bb, &cc, dd, ee, X[ 8], 14)
JJ(&ee, aa, &bb, cc, dd, X[11], 11)
JJ(&dd, ee, &aa, bb, cc, X[ 6], 8)
JJ(&cc, dd, &ee, aa, bb, X[15], 5)
JJ(&bb, cc, &dd, ee, aa, X[13], 6)

/* parallel round 1 */
JJJ(&aaa, bbb, &ccc, ddd, eee, X[ 5], 8)
JJJ(&eee, aaa, &bbb, ccc, ddd, X[14], 9)
JJJ(&ddd, eee, &aaa, bbb, ccc, X[ 7], 9)
JJJ(&ccc, ddd, &eee, aaa, bbb, X[ 0], 11)
JJJ(&bbb, ccc, &ddd, eee, aaa, X[ 9], 13)
JJJ(&aaa, bbb, &ccc, ddd, eee, X[ 2], 15)
JJJ(&eee, aaa, &bbb, ccc, ddd, X[11], 15)
JJJ(&ddd, eee, &aaa, bbb, ccc, X[ 4], 5)
JJJ(&ccc, ddd, &eee, aaa, bbb, X[13], 7)
JJJ(&bbb, ccc, &ddd, eee, aaa, X[ 6], 7)
JJJ(&aaa, bbb, &ccc, ddd, eee, X[15], 8)
JJJ(&eee, aaa, &bbb, ccc, ddd, X[ 8], 11)
JJJ(&ddd, eee, &aaa, bbb, ccc, X[ 1], 14)
JJJ(&ccc, ddd, &eee, aaa, bbb, X[10], 14)
JJJ(&bbb, ccc, &ddd, eee, aaa, X[ 3], 12)
JJJ(&aaa, bbb, &ccc, ddd, eee, X[12], 6)

/* parallel round 2 */
III(&eee, aaa, &bbb, ccc, ddd, X[ 6], 9)
III(&ddd, eee, &aaa, bbb, ccc, X[11], 13)
III(&ccc, ddd, &eee, aaa, bbb, X[ 3], 15)
III(&bbb, ccc, &ddd, eee, aaa, X[ 7], 7)
III(&aaa, bbb, &ccc, ddd, eee, X[ 0], 12)
III(&eee, aaa, &bbb, ccc, ddd, X[13], 8)
III(&ddd, eee, &aaa, bbb, ccc, X[ 5], 9)
III(&ccc, ddd, &eee, aaa, bbb, X[10], 11)
III(&bbb, ccc, &ddd, eee, aaa, X[14], 7)
III(&aaa, bbb, &ccc, ddd, eee, X[15], 7)
III(&eee, aaa, &bbb, ccc, ddd, X[ 8], 12)
III(&ddd, eee, &aaa, bbb, ccc, X[12], 7)
III(&ccc, ddd, &eee, aaa, bbb, X[ 4], 6)
III(&bbb, ccc, &ddd, eee, aaa, X[ 9], 15)
III(&aaa, bbb, &ccc, ddd, eee, X[ 1], 13)
III(&eee, aaa, &bbb, ccc, ddd, X[ 2], 11)

/* parallel round 3 */
HHH(&ddd, eee, &aaa, bbb, ccc, X[15], 9)
HHH(&ccc, ddd, &eee, aaa, bbb, X[ 5], 7)
HHH(&bbb, ccc, &ddd, eee, aaa, X[ 1], 15)
HHH(&aaa, bbb, &ccc, ddd, eee, X[ 3], 11)
HHH(&eee, aaa, &bbb, ccc, ddd, X[ 7], 8)
HHH(&ddd, eee, &aaa, bbb, ccc, X[14], 6)
HHH(&ccc, ddd, &eee, aaa, bbb, X[ 6], 6)
HHH(&bbb, ccc, &ddd, eee, aaa, X[ 9], 14)
HHH(&aaa, bbb, &ccc, ddd, eee, X[11], 12)
HHH(&eee, aaa, &bbb, ccc, ddd, X[ 8], 13)
HHH(&ddd, eee, &aaa, bbb, ccc, X[12], 5)
HHH(&ccc, ddd, &eee, aaa, bbb, X[ 2], 14)
HHH(&bbb, ccc, &ddd, eee, aaa, X[10], 13)
HHH(&aaa, bbb, &ccc, ddd, eee, X[ 0], 13)
HHH(&eee, aaa, &bbb, ccc, ddd, X[ 4], 7)
HHH(&ddd, eee, &aaa, bbb, ccc, X[13], 5)

/* parallel round 4 */
GGG(&ccc, ddd, &eee, aaa, bbb, X[ 8], 15)
GGG(&bbb, ccc, &ddd, eee, aaa, X[ 6], 5)
GGG(&aaa, bbb, &ccc, ddd, eee, X[ 4], 8)
GGG(&eee, aaa, &bbb, ccc, ddd, X[ 1], 11)
GGG(&ddd, eee, &aaa, bbb, ccc, X[ 3], 14)
GGG(&ccc, ddd, &eee, aaa, bbb, X[11], 14)
GGG(&bbb, ccc, &ddd, eee, aaa, X[15], 6)
GGG(&aaa, bbb, &ccc, ddd, eee, X[ 0], 14)
GGG(&eee, aaa, &bbb, ccc, ddd, X[ 5], 6)
GGG(&ddd, eee, &aaa, bbb, ccc, X[12], 9)
GGG(&ccc, ddd, &eee, aaa, bbb, X[ 2], 12)
GGG(&bbb, ccc, &ddd, eee, aaa, X[13], 9)
GGG(&aaa, bbb, &ccc, ddd, eee, X[ 9], 12)
GGG(&eee, aaa, &bbb, ccc, ddd, X[ 7], 5)
GGG(&ddd, eee, &aaa, bbb, ccc, X[10], 15)
GGG(&ccc, ddd, &eee, aaa, bbb, X[14], 8)

/* parallel round 5 */
FFF(&bbb, ccc, &ddd, eee, aaa, X[12] , 8)
FFF(&aaa, bbb, &ccc, ddd, eee, X[15] , 5)
FFF(&eee, aaa, &bbb, ccc, ddd, X[10] , 12)
FFF(&ddd, eee, &aaa, bbb, ccc, X[ 4] , 9)
FFF(&ccc, ddd, &eee, aaa, bbb, X[ 1] , 12)
FFF(&bbb, ccc, &ddd, eee, aaa, X[ 5] , 5)
FFF(&aaa, bbb, &ccc, ddd, eee, X[ 8] , 14)
FFF(&eee, aaa, &bbb, ccc, ddd, X[ 7] , 6)
FFF(&ddd, eee, &aaa, bbb, ccc, X[ 6] , 8)
FFF(&ccc, ddd, &eee, aaa, bbb, X[ 2] , 13)
FFF(&bbb, ccc, &ddd, eee, aaa, X[13] , 6)
FFF(&aaa, bbb, &ccc, ddd, eee, X[14] , 5)
FFF(&eee, aaa, &bbb, ccc, ddd, X[ 0] , 15)
FFF(&ddd, eee, &aaa, bbb, ccc, X[ 3] , 13)
FFF(&ccc, ddd, &eee, aaa, bbb, X[ 9] , 11)
FFF(&bbb, ccc, &ddd, eee, aaa, X[11] , 11)

/* combine results */
MDbuf = (MDbuf.1 &+ cc &+ ddd,
MDbuf.2 &+ dd &+ eee,
MDbuf.3 &+ ee &+ aaa,
MDbuf.4 &+ aa &+ bbb,
MDbuf.0 &+ bb &+ ccc)
}

public mutating func update(data: Data) {
var X = [UInt32](repeating: 0, count: 16)
var pos = data.startIndex
var length = data.count

// Process remaining bytes from last call:
if buffer.count > 0 && buffer.count + length >= 64 {
let amount = 64 - buffer.count
buffer.append(data[..<amount])
X.withUnsafeMutableBytes {
_ = buffer.copyBytes(to: $0)
}
compress(X)
pos += amount
length -= amount
}

// Process 64 byte chunks:
while length >= 64 {
X.withUnsafeMutableBytes {
_ = data[pos..<pos+64].copyBytes(to: $0)
}
compress(X)
pos += 64
length -= 64
}

// Save remaining unprocessed bytes:
buffer = data[pos...]
count += Int64(data.count)
}

public mutating func finalize() -> Data {
var X = [UInt32](repeating: 0, count: 16)
/* append the bit m_n == 1 */
buffer.append(0x80)
X.withUnsafeMutableBytes {
_ = buffer.copyBytes(to: $0)
}

if (count & 63) > 55 {
/* length goes to next block */
compress(X)
X = [UInt32](repeating: 0, count: 16)
}

/* append length in bits */
let lswlen = UInt32(truncatingIfNeeded: count)
let mswlen = UInt32(UInt64(count) >> 32)
X[14] = lswlen << 3
X[15] = (lswlen >> 29) | (mswlen << 3)
compress(X)

buffer = Data()
let result = [MDbuf.0, MDbuf.1, MDbuf.2, MDbuf.3, MDbuf.4]
return result.withUnsafeBytes { Data($0) }
}
}

And here are "one-shot" functions to compute the hash of a message (given as Data
or as String):

RIPEMD160-Ext.swift:

import Foundation

public extension RIPEMD160 {

static func hash(message: Data) -> Data {
var md = RIPEMD160()
md.update(data: message)
return md.finalize()
}

static func hash(message: String) -> Data {
return RIPEMD160.hash(message: message.data(using: .utf8)!)
}
}

Finally, the corresponding message authentication code. The algorithm is taken
from the pseudo-code at
Wikipedia: Hash-based message authentication code:

RIPEMD160-HMAC.swift:

import Foundation

public extension RIPEMD160 {

static func hmac(key: Data, message: Data) -> Data {

var key = key
key.count = 64 // Truncate to 64 bytes or fill-up with zeros.

let outerKeyPad = Data(key.map { $0 ^ 0x5c })
let innerKeyPad = Data(key.map { $0 ^ 0x36 })

var innerMd = RIPEMD160()
innerMd.update(data: innerKeyPad)
innerMd.update(data: message)

var outerMd = RIPEMD160()
outerMd.update(data: outerKeyPad)
outerMd.update(data: innerMd.finalize())

return outerMd.finalize()
}

static func hmac(key: Data, message: String) -> Data {
return RIPEMD160.hmac(key: key, message: message.data(using: .utf8)!)
}

static func hmac(key: String, message: String) -> Data {
return RIPEMD160.hmac(key: key.data(using: .utf8)!, message: message)
}
}

Examples

To print the message digest as a hex-encoded string, the following method from
How to convert Data to hex string in swift
can be used:

extension Data {
func hexEncodedString() -> String {
return map { String(format: "%02hhx", $0) }.joined()
}
}

Example 1:

let msg = "Hello World"
let hash = RIPEMD160.hash(message: msg).hexEncodedString()
print(hash) // a830d7beb04eb7549ce990fb7dc962e499a27230

Example 2 (your example):

let hmac = RIPEMD160.hmac(key: "test", message: "string").hexEncodedString()
print(hmac) // 37241f2513c60ae4d9b3b8d0d30517445f451fa5


Related Topics



Leave a reply



Submit