-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhmac.nim
154 lines (117 loc) · 4.49 KB
/
hmac.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import sequtils
import sha256, sha512
type
DigestMod* = enum
SHA256, SHA512
HmacContext* = object
digestMod*: DigestMod
sha256Ctx*: Sha256Context
sha512Ctx*: Sha512Context
oKeyPad, iKeyPad: seq[uint8]
proc copyHmacCtx*(toThisCtx: var HmacContext, fromThisCtx: HmacContext) {.inline.} =
toThisCtx.digestMod = fromThisCtx.digestMod
copyShaCtx(toThisCtx.sha256Ctx, fromThisCtx.sha256Ctx)
copyShaCtx(toThisCtx.sha512Ctx, fromThisCtx.sha512Ctx)
toThisCtx.oKeyPad = newSeq[uint8](fromThisCtx.oKeyPad.len)
toThisCtx.iKeyPad = newSeq[uint8](fromThisCtx.iKeyPad.len)
for idx, b in fromThisCtx.oKeyPad:
toThisCtx.oKeyPad[idx] = b
for idx, b in fromThisCtx.iKeyPad:
toThisCtx.iKeyPad[idx] = b
proc update*[T](ctx: var HmacContext, msg: openarray[T]) =
case ctx.digestMod
of SHA256:
ctx.sha256Ctx.update(msg)
of SHA512:
ctx.sha512Ctx.update(msg)
proc finalize*(ctx: var HmacContext) =
case ctx.digestMod
of SHA256:
ctx.sha256Ctx.finalize()
of SHA512:
ctx.sha512Ctx.finalize()
proc digest*(ctx: var HmacContext): seq[uint8] {.inline.} =
case ctx.digestMod
of SHA256:
var outerCtx = newSha256Ctx(ctx.oKeyPad)
outerCtx.update(ctx.sha256Ctx.digest())
return outerCtx.digest().toSeq()
of SHA512:
var outerCtx = newSha512Ctx(ctx.oKeyPad)
outerCtx.update(ctx.sha512Ctx.digest())
return outerCtx.digest().toSeq()
proc hexDigest*(ctx: HmacContext): string =
case ctx.digestMod
of SHA256:
var tempShaCtx = newSha256Ctx()
copyShaCtx(tempShaCtx, ctx.sha256Ctx)
var outerCtx = newSha256Ctx(ctx.oKeyPad)
outerCtx.update(tempShaCtx.digest())
return outerCtx.hexDigest()
of SHA512:
var tempShaCtx = newSha512Ctx()
copyShaCtx(tempShaCtx, ctx.sha512Ctx)
var outerCtx = newSha512Ctx(ctx.oKeyPad)
outerCtx.update(tempShaCtx.digest())
return outerCtx.hexDigest()
proc initHmac(ctx: var HmacContext, key: openarray[uint8]) =
case ctx.digestMod
of SHA256:
const blockSize = 64
# NOTE: normalize key
var keyBytes: array[blockSize, uint8]
# NOTE: hash key if it is larger than block size, otherwise copy it directly into keyBytes
if key.len > blockSize:
var hash = newSha256Ctx(key)
for i, b in hash.digest():
keyBytes[i] = b
else:
for i, b in key:
keyBytes[i] = b
# NOTE: create inner and outer padded keys
ctx.iKeyPad = newSeq[uint8](blockSize)
ctx.oKeyPad = newSeq[uint8](blockSize)
for i, b in keyBytes:
ctx.iKeyPad[i] = b xor 0x36
ctx.oKeyPad[i] = b xor 0x5c
# NOTE: init sha context
ctx.sha256Ctx = newSha256Ctx(ctx.iKeyPad)
of SHA512:
const blockSize = 128
# NOTE: normalize key
var keyBytes: array[blockSize, uint8]
# NOTE: hash key if it is larger than block size, otherwise copy it directly into keyBytes
if key.len > blockSize:
var hash = newSha512Ctx(key)
for i, b in hash.digest():
keyBytes[i] = b
else:
for i, b in key:
keyBytes[i] = b
# NOTE: create inner and outer padded keys
ctx.iKeyPad = newSeq[uint8](blockSize)
ctx.oKeyPad = newSeq[uint8](blockSize)
for i, b in keyBytes:
ctx.iKeyPad[i] = b xor 0x36
ctx.oKeyPad[i] = b xor 0x5c
# NOTE: init sha context
ctx.sha512Ctx = newSha512Ctx(ctx.iKeyPad)
proc newHmacCtx*(key: openarray[uint8], msg: openarray[uint8] = @[], digestMod: DigestMod): HmacContext =
result.digestMod = digestMod
result.initHmac(key)
if msg.len > 0:
result.update(msg)
return result
proc newHmacCtx*(key: string, msg: string = "", digestMod: DigestMod): HmacContext =
return newHmacCtx(key.toOpenArrayByte(0, key.len.pred), msg.toOpenArrayByte(0, msg.len.pred), digestMod)
when isMainModule:
let key = "your-secret-key"
let message = "your-message"
var hmac256 = newHmacCtx(key, message, digestMod=SHA256)
var hmac512 = newHmacCtx(key, message, digestMod=SHA512)
assert hmac256.hexDigest() == "85af3c047c3d807cb870748905d81ad4b1833e1928ba1dc59d45e84f546fbf9f"
assert hmac512.hexDigest() == "f3f9a54180e33ff0ca7cd1d563b98bb5cd75161bce2bbec2d9621fa96a9c47212eaa5c4208bfea68b3ccd79aa026d245affa200a21429b2a02b9be3fa663bccc"
hmac256.update("more-of-your-message")
hmac512.update("more-of-your-message")
assert hmac256.hexDigest() == "31458f4fea72ca51cab0151894589ac9d6ec6d569b53099405c9ad307f7825e0"
assert hmac512.hexDigest() == "de7f03db3638d7f8f45128b5a8633f71cc91073bf3b6cf4d7c9307cb767f8dfb0aa7def66788c17060938a92896923893a20ab0d18a41a2dd7cc0a7686932026"