Skip to content

Commit 8995169

Browse files
committed
chore: wip
1 parent 44d1da3 commit 8995169

2 files changed

Lines changed: 122 additions & 95 deletions

File tree

.vscode/dictionary.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ heroicons
2727
httx
2828
iconify
2929
imgx
30+
ipadding
3031
keychain
3132
Keychains
3233
Keypair
@@ -36,6 +37,7 @@ Longley
3637
Millis
3738
mkcert
3839
oids
40+
opadding
3941
openweb
4042
outdir
4143
outfile

src/hmac.ts

Lines changed: 120 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -7,144 +7,169 @@
77
*
88
* Copyright (c) 2010-2012 Digital Bazaar, Inc. All rights reserved.
99
*/
10-
const forge = require('./forge')
11-
require('./md')
12-
require('./util')
1310

14-
/* HMAC API */
15-
const hmac = module.exports = forge.hmac = forge.hmac || {}
11+
import { ByteStringBuffer, createBuffer } from "./utils"
12+
13+
type MessageDigest = {
14+
start: () => MessageDigest
15+
update: (msg: string | ByteStringBuffer, encoding?: string) => MessageDigest
16+
digest: () => ByteStringBuffer
17+
blockLength: number
18+
}
19+
20+
type NativeBuffer = Buffer | Uint8Array | ArrayBuffer
21+
22+
type HMACInput = string | ByteStringBuffer | NativeBuffer
23+
24+
interface HMAC {
25+
start: (md: MessageDigest, key: HMACInput) => void
26+
update: (bytes: HMACInput) => void
27+
getMac: () => ByteStringBuffer
28+
digest: () => ByteStringBuffer
29+
}
30+
31+
interface HMACModule {
32+
create: () => HMAC
33+
}
1634

1735
/**
1836
* Creates an HMAC object that uses the given message digest object.
1937
*
2038
* @return an HMAC object.
2139
*/
22-
hmac.create = function () {
40+
function create(): HMAC {
2341
// the hmac key to use
24-
let _key = null
42+
let _key: ByteStringBuffer | null = null
2543

2644
// the message digest to use
27-
let _md = null
45+
let _md: MessageDigest | null = null
2846

2947
// the inner padding
30-
let _ipadding = null
48+
let _ipadding: string | null = null
3149

3250
// the outer padding
33-
let _opadding = null
51+
let _opadding: string | null = null
3452

3553
// hmac context
36-
const ctx = {}
37-
38-
/**
39-
* Starts or restarts the HMAC with the given key and message digest.
40-
*
41-
* @param md the message digest to use, null to reuse the previous one,
42-
* a string to use builtin 'sha1', 'md5', 'sha256'.
43-
* @param key the key to use as a string, array of bytes, byte buffer,
44-
* or null to reuse the previous key.
45-
*/
46-
ctx.start = function (md, key) {
47-
if (md !== null) {
48-
if (typeof md === 'string') {
49-
// create builtin message digest
50-
md = md.toLowerCase()
51-
if (md in forge.md.algorithms) {
52-
_md = forge.md.algorithms[md].create()
53-
}
54-
else {
55-
throw new Error(`Unknown hash algorithm "${md}"`)
56-
}
54+
const ctx: HMAC = {
55+
start: (md: MessageDigest, key: HMACInput) => {
56+
if (!md) {
57+
throw new TypeError('"md" argument is required')
5758
}
58-
else {
59-
// store message digest
60-
_md = md
59+
60+
_md = md
61+
62+
if (key === null) {
63+
if (!_key) {
64+
throw new TypeError('Key is required for first call to start()')
65+
}
66+
key = _key
6167
}
62-
}
6368

64-
if (key === null) {
65-
// reuse previous key
66-
key = _key
67-
}
68-
else {
69+
// convert key to ByteStringBuffer
70+
let keyBuffer: ByteStringBuffer
6971
if (typeof key === 'string') {
70-
// convert string into byte buffer
71-
key = forge.util.createBuffer(key)
72+
keyBuffer = createBuffer(key)
73+
}
74+
else if (key instanceof ByteStringBuffer) {
75+
keyBuffer = key
7276
}
73-
else if (forge.util.isArray(key)) {
74-
// convert byte array into byte buffer
75-
var tmp = key
76-
key = forge.util.createBuffer()
77-
for (var i = 0; i < tmp.length; ++i) {
78-
key.putByte(tmp[i])
77+
else if (key instanceof Uint8Array || key instanceof Buffer || key instanceof ArrayBuffer) {
78+
keyBuffer = createBuffer()
79+
const view = key instanceof ArrayBuffer ? new Uint8Array(key) : key
80+
for (let i = 0; i < view.length; ++i) {
81+
keyBuffer.putByte(view[i])
7982
}
8083
}
84+
else {
85+
throw new TypeError(
86+
'"key" must be a string, ByteStringBuffer, Buffer, Uint8Array, or ArrayBuffer',
87+
)
88+
}
8189

8290
// if key is longer than blocksize, hash it
83-
let keylen = key.length()
91+
let keylen = keyBuffer.length()
8492
if (keylen > _md.blockLength) {
8593
_md.start()
86-
_md.update(key.bytes())
87-
key = _md.digest()
94+
_md.update(keyBuffer)
95+
keyBuffer = _md.digest()
8896
}
8997

9098
// mix key into inner and outer padding
9199
// ipadding = [0x36 * blocksize] ^ key
92100
// opadding = [0x5C * blocksize] ^ key
93-
_ipadding = forge.util.createBuffer()
94-
_opadding = forge.util.createBuffer()
95-
keylen = key.length()
96-
for (var i = 0; i < keylen; ++i) {
97-
var tmp = key.at(i)
98-
_ipadding.putByte(0x36 ^ tmp)
99-
_opadding.putByte(0x5C ^ tmp)
101+
const ipadding = createBuffer()
102+
const opadding = createBuffer()
103+
keylen = keyBuffer.length()
104+
105+
for (let i = 0; i < keylen; ++i) {
106+
const tmp = keyBuffer.at(i)
107+
ipadding.putByte(0x36 ^ tmp)
108+
opadding.putByte(0x5C ^ tmp)
100109
}
101110

102111
// if key is shorter than blocksize, add additional padding
103112
if (keylen < _md.blockLength) {
104-
var tmp = _md.blockLength - keylen
105-
for (var i = 0; i < tmp; ++i) {
106-
_ipadding.putByte(0x36)
107-
_opadding.putByte(0x5C)
113+
const remaining = _md.blockLength - keylen
114+
for (let i = 0; i < remaining; ++i) {
115+
ipadding.putByte(0x36)
116+
opadding.putByte(0x5C)
108117
}
109118
}
110-
_key = key
111-
_ipadding = _ipadding.bytes()
112-
_opadding = _opadding.bytes()
113-
}
114119

115-
// digest is done like so: hash(opadding | hash(ipadding | message))
120+
_key = keyBuffer
121+
_ipadding = ipadding.bytes()
122+
_opadding = opadding.bytes()
116123

117-
// prepare to do inner hash
118-
// hash(ipadding | message)
119-
_md.start()
120-
_md.update(_ipadding)
121-
}
124+
// digest is done like so: hash(opadding | hash(ipadding | message))
125+
// prepare to do inner hash
126+
// hash(ipadding | message)
127+
_md.start()
128+
_md.update(_ipadding)
129+
},
122130

123-
/**
124-
* Updates the HMAC with the given message bytes.
125-
*
126-
* @param bytes the bytes to update with.
127-
*/
128-
ctx.update = function (bytes) {
129-
_md.update(bytes)
130-
}
131+
update: (bytes: HMACInput) => {
132+
if (!_md) {
133+
throw new Error('HMAC not started. Call start() first.')
134+
}
135+
136+
// convert bytes to ByteStringBuffer if needed
137+
if (bytes instanceof ByteStringBuffer || typeof bytes === 'string') {
138+
_md.update(bytes)
139+
}
140+
else {
141+
const buffer = createBuffer()
142+
const view = bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : bytes
143+
for (let i = 0; i < view.length; ++i) {
144+
buffer.putByte(view[i])
145+
}
146+
_md.update(buffer.bytes())
147+
}
148+
},
149+
150+
getMac: () => {
151+
if (!_md || !_opadding) {
152+
throw new Error('HMAC not started. Call start() first.')
153+
}
131154

132-
/**
133-
* Produces the Message Authentication Code (MAC).
134-
*
135-
* @return a byte buffer containing the digest value.
136-
*/
137-
ctx.getMac = function () {
138-
// digest is done like so: hash(opadding | hash(ipadding | message))
139-
// here we do the outer hashing
140-
const inner = _md.digest().bytes()
141-
_md.start()
142-
_md.update(_opadding)
143-
_md.update(inner)
144-
return _md.digest()
155+
// digest is done like so: hash(opadding | hash(ipadding | message))
156+
// here we do the outer hashing
157+
const inner = _md.digest().bytes()
158+
_md.start()
159+
_md.update(_opadding)
160+
_md.update(inner)
161+
return _md.digest()
162+
},
163+
164+
digest() {
165+
return this.getMac()
166+
}
145167
}
146-
// alias for getMac
147-
ctx.digest = ctx.getMac
148168

149169
return ctx
150170
}
171+
172+
// Export the HMAC implementation
173+
export const hmac: HMACModule = {
174+
create,
175+
}

0 commit comments

Comments
 (0)