diff --git a/src/syndicate/private/hmacs.nim b/src/syndicate/private/hmacs.nim index cb49ee4..0c2ebe5 100644 --- a/src/syndicate/private/hmacs.nim +++ b/src/syndicate/private/hmacs.nim @@ -3,28 +3,43 @@ import nimSHA2 -proc hmacSha256*(key: openarray[byte]; msg: seq[byte]|string): seq[byte] = +proc fillPad(pad: var openarray[byte]; key: openarray[byte]; fillByte: byte) = + for i in 0..key.high: pad[i] = fillByte xor key[i].uint8 + for i in key.len..pad.high: pad[i] = fillByte + +proc hmacSha256*(key: openarray[byte]; msg: seq[byte]|string; outLength = 32): seq[byte] = const blockSize = 64 - assert(key.len <= blockSize) + assert(outLength <= 32) var - inner, outer: SHA256 + hash: SHA256 pad: array[blockSize, byte] block: const xorByte = 0x36'u8 - for i in 0..key.high: pad[i] = xorByte xor key[i] - for i in key.len..pad.high: pad[i] = xorByte - initSHA(inner) - update(inner, pad) - update(inner, msg) + if key.len < blockSize: + fillPad(pad, key, xorByte) + else: + initSHA(hash) + update(hash, key) + var keyDigest = final(hash) + fillPad(pad, keyDigest, xorByte) + initSHA(hash) + update(hash, pad) + update(hash, msg) + var digest = final(hash) block: const xorByte = 0x5c'u8 - for i in 0..key.high: pad[i] = xorByte xor key[i] - for i in key.len..pad.high: pad[i] = xorByte - initSHA(outer) - update(outer, pad) - update(outer, final(inner)) - var digest = final(outer) - result.setLen(digest.len) + if key.len < blockSize: + fillPad(pad, key, xorByte) + else: + initSHA(hash) + update(hash, key) + var keyDigest = final(hash) + fillPad(pad, keyDigest, xorByte) + initSHA(hash) + update(hash, pad) + update(hash, digest) + digest = final(hash) + result.setLen(outLength) copyMem(result[0].addr, digest[0].addr, result.len) when isMainModule: @@ -34,7 +49,54 @@ when isMainModule: var key: array[20,byte] for b in key.mitems: b = 0x0b'u8 var data = "Hi There" - check(data.toHex == "4869205468657265") - let hmac = cast[string](hmacSha256(key, data)).toHex.toLowerAscii - let control = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7" - check(hmac == control) + let a = cast[string](hmacSha256(key, data)).toHex.toLowerAscii + let b = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7" + check(a == b) + test "2": + var key = "Jefe" + var data = "what do ya want for nothing?" + let a = cast[string](hmacSha256(cast[seq[byte]](key), data)).toHex.toLowerAscii + let b = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" + check(a == b) + test "3": + var + key: array[20,byte] + data = newSeq[byte](50) + for b in key.mitems: b = 0xaa'u8 + for b in data.mitems: b = 0xdd'u8 + let a = cast[string](hmacSha256(key, data)).toHex.toLowerAscii + let b = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe" + check(a == b) + test "4": + var + key: array[25,byte] + data = newSeq[byte](50) + for i in key.low..key.high: key[i] = i.uint8.succ + for b in data.mitems: b = 0xcd'u8 + let a = cast[string](hmacSha256(key, data)).toHex.toLowerAscii + let b = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b" + check(a == b) + test "5": + var + key: array[20,byte] + data = "Test With Truncation" + for b in key.mitems: b = 0x0c'u8 + let a = cast[string](hmacSha256(key, data, 16)).toHex.toLowerAscii + let b = "a3b6167473100ee06e0c796c2955552b" + check(a == b) + test "6": + var + key: array[131,byte] + data = "Test Using Larger Than Block-Size Key - Hash Key First" + for b in key.mitems: b = 0xaa'u8 + let a = cast[string](hmacSha256(key, data)).toHex.toLowerAscii + let b = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54" + check(a == b) + test "7": + var + key: array[131,byte] + data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + for b in key.mitems: b = 0xaa'u8 + let a = cast[string](hmacSha256(key, data)).toHex.toLowerAscii + let b = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2" + check(a == b)