Skip to content

Commit 4a89ce8

Browse files
authored
Merge pull request #2 from guzba/ryan
add hmac-sha256 and pbkdf2
2 parents c99f3dc + fed8068 commit 4a89ce8

File tree

3 files changed

+111
-1
lines changed

3 files changed

+111
-1
lines changed

crunchy.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version = "0.1.1"
1+
version = "0.1.2"
22
author = "Ryan Oldenburg"
33
description = "SIMD-optimized hashing, checksums and CRCs"
44
license = "MIT"

src/crunchy/sha256.nim

+77
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,83 @@ proc sha256*(data: openarray[byte]): array[32, uint8] {.inline.} =
134134
proc sha256*(data: string): array[32, uint8] {.inline.} =
135135
sha256(data.cstring, data.len)
136136

137+
proc hmacSha256*(key, data: openarray[uint8]): array[32, uint8] =
138+
const
139+
blockSize = 64
140+
ipad = 0x36
141+
opad = 0x5c
142+
143+
var blockSizeKey: array[blockSize, uint8]
144+
if key.len > blockSize:
145+
let hash = sha256(key)
146+
copyMem(blockSizeKey[0].addr, hash[0].unsafeAddr, hash.len)
147+
else:
148+
copyMem(blockSizeKey[0].addr, key[0].unsafeAddr, key.len)
149+
150+
proc applyXor(s: array[64, uint8], value: uint8): array[64, uint8] =
151+
result = s
152+
for c in result.mitems:
153+
c = (c xor value)
154+
155+
let ipadXor = applyXor(blockSizeKey, ipad)
156+
157+
let h1 =
158+
if data.len > 0:
159+
var s = newString(ipadXor.len + data.len)
160+
copyMem(s[0].addr, ipadXor[0].unsafeAddr, ipadXor.len)
161+
copyMem(s[ipadXor.len].addr, data[0].unsafeAddr, data.len)
162+
sha256(s)
163+
else:
164+
sha256(ipadXor)
165+
166+
let opadXor = applyXor(blockSizeKey, opad)
167+
168+
var s2 = newString(opadXor.len + 32)
169+
copyMem(s2[0].addr, opadXor[0].unsafeAddr, opadXor.len)
170+
copyMem(s2[opadXor.len].addr, h1[0].unsafeAddr, 32)
171+
172+
sha256(s2)
173+
174+
proc hmacSha256*(
175+
key, data: string
176+
): array[32, uint8] {.inline.} =
177+
hmacSha256(
178+
key.toOpenArrayByte(0, key.high),
179+
data.toOpenArrayByte(0, data.high)
180+
)
181+
182+
proc hmacSha256*(
183+
key: string,
184+
data: openarray[byte]
185+
): array[32, uint8] {.inline.} =
186+
hmacSha256(
187+
key.toOpenArrayByte(0, key.high),
188+
data
189+
)
190+
191+
proc hmacSha256*(
192+
key: openarray[byte],
193+
data: string
194+
): array[32, uint8] {.inline.} =
195+
hmacSha256(
196+
key,
197+
data.toOpenArrayByte(0, data.high)
198+
)
199+
200+
proc pbkdf2*(password, salt: string, iterations: int): array[32, uint8] =
201+
## PBKDF2-HMAC-SHA256
202+
203+
result = hmacSha256(password, salt & "\0\0\0\1")
204+
205+
var
206+
buf1 = result
207+
buf2: array[32, uint8]
208+
for _ in 1 ..< iterations:
209+
swap(buf1, buf2)
210+
buf1 = hmacSha256(password, buf2)
211+
for i in 0 ..< 32:
212+
result[i] = result[i] xor buf1[i]
213+
137214
proc toHex*(a: array[32, uint8]): string =
138215
result = newStringOfCap(64)
139216
for i in 0 ..< a.len:

tests/test_sha256.nim

+33
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,36 @@ const sha256Tests = [
2525

2626
for (a, b) in sha256Tests:
2727
doAssert sha256(a).toHex() == b
28+
29+
const hmacSha256Tests = [
30+
(
31+
"abc",
32+
"def",
33+
"20ebc0f09344470134f35040f63ea98b1d8e414212949ee5c500429d15eab081"
34+
),
35+
(
36+
"asdf3q5q23rfasf3a",
37+
"dfasdfasfd3qr3fqfaefa3fa3rfasadfasfdasdfasdfasdfasfdasd",
38+
"a1629e21b02776e7eacef6f615165d08894963a12dfbd304a47e7a8aff0a2dc5"
39+
),
40+
(
41+
"awjieops;oi4etaawjieops;oi4etaawjieops;oi4etaawjieops;oi4etaawjieops;oi4",
42+
"p890y6t3q9ah2pqh8t6q3pth8qa3whu",
43+
"a1b7d6b597ae74f950dad4eb4dc1700420281b186abfaa321f728f38d675b099"
44+
)
45+
]
46+
47+
for (a, b, c) in hmacSha256Tests:
48+
doAssert hmacSha256(a, b).toHex() == c
49+
50+
const pbkdf2Tests = [
51+
(
52+
"password",
53+
"salt",
54+
30000,
55+
"76639c203f99c73c1151d8dee2ca9d5055c932a2b0a4708c10dc21b60c921ca7"
56+
)
57+
]
58+
59+
for (a, b, c, d) in pbkdf2Tests:
60+
doAssert pbkdf2(a, b, c).toHex() == d

0 commit comments

Comments
 (0)