0
# HMAC Operations
1
2
Hash-based Message Authentication Code (HMAC) functionality for creating and verifying message authenticity and integrity. jsSHA provides built-in HMAC support for all applicable SHA variants with flexible key input formats.
3
4
## Capabilities
5
6
### HMAC via Constructor Options (Recommended)
7
8
The preferred method for HMAC operations is to specify the HMAC key during object instantiation.
9
10
```typescript { .api }
11
/**
12
* HMAC options for TEXT input format with encoding support
13
*/
14
interface FixedLengthOptionsEncodingType {
15
hmacKey?: GenericInputType;
16
encoding?: EncodingType;
17
} | {
18
numRounds?: number;
19
encoding?: EncodingType;
20
}
21
22
/**
23
* HMAC options for non-TEXT input formats
24
*/
25
interface FixedLengthOptionsNoEncodingType {
26
hmacKey?: GenericInputType;
27
} | {
28
numRounds?: number;
29
}
30
31
/**
32
* Generic input specification for HMAC keys
33
*/
34
interface GenericInputType {
35
value: string;
36
format: "TEXT";
37
encoding?: EncodingType;
38
} | {
39
value: string;
40
format: "B64" | "HEX" | "BYTES";
41
} | {
42
value: ArrayBuffer;
43
format: "ARRAYBUFFER";
44
} | {
45
value: Uint8Array;
46
format: "UINT8ARRAY";
47
}
48
49
type EncodingType = "UTF8" | "UTF16BE" | "UTF16LE";
50
```
51
52
**Usage Examples:**
53
54
```typescript
55
import jsSHA from "jssha";
56
57
// HMAC with text key
58
const hmacText = new jsSHA("SHA-256", "TEXT", {
59
hmacKey: { value: "secret-key", format: "TEXT" },
60
encoding: "UTF8"
61
});
62
hmacText.update("Message to authenticate");
63
const hmac1 = hmacText.getHash("HEX");
64
65
// HMAC with hex key
66
const hmacHex = new jsSHA("SHA-512", "TEXT", {
67
hmacKey: { value: "deadbeef", format: "HEX" }
68
});
69
hmacHex.update("Another message");
70
const hmac2 = hmacHex.getHash("B64");
71
72
// HMAC with Base64 key
73
const hmacB64 = new jsSHA("SHA-1", "HEX", {
74
hmacKey: { value: "c2VjcmV0LWtleQ==", format: "B64" }
75
});
76
hmacB64.update("48656c6c6f"); // "Hello" in hex
77
const hmac3 = hmacB64.getHash("HEX");
78
79
// HMAC with ArrayBuffer key
80
const keyBuffer = new TextEncoder().encode("binary-key").buffer;
81
const hmacBuffer = new jsSHA("SHA-384", "ARRAYBUFFER", {
82
hmacKey: { value: keyBuffer, format: "ARRAYBUFFER" }
83
});
84
const messageBuffer = new TextEncoder().encode("Message").buffer;
85
hmacBuffer.update(messageBuffer);
86
const hmac4 = hmacBuffer.getHash("UINT8ARRAY");
87
88
// HMAC with Uint8Array key
89
const keyArray = new TextEncoder().encode("array-key");
90
const hmacArray = new jsSHA("SHA3-256", "UINT8ARRAY", {
91
hmacKey: { value: keyArray, format: "UINT8ARRAY" }
92
});
93
const messageArray = new TextEncoder().encode("Message");
94
hmacArray.update(messageArray);
95
const hmac5 = hmacArray.getHash("ARRAYBUFFER");
96
```
97
98
### Legacy setHMACKey Method (Deprecated)
99
100
The `setHMACKey` method is deprecated in favor of specifying the HMAC key in constructor options, but remains available for backward compatibility.
101
102
```typescript { .api }
103
/**
104
* Sets the HMAC key for TEXT format keys (DEPRECATED)
105
* @param key - The HMAC key as a string
106
* @param inputFormat - Must be "TEXT"
107
* @param options - Optional encoding configuration
108
*/
109
setHMACKey(key: string, inputFormat: "TEXT", options?: { encoding?: EncodingType }): void;
110
111
/**
112
* Sets the HMAC key for string-based formats (DEPRECATED)
113
* @param key - The HMAC key as a string
114
* @param inputFormat - Key format: B64, HEX, or BYTES
115
*/
116
setHMACKey(key: string, inputFormat: "B64" | "HEX" | "BYTES"): void;
117
118
/**
119
* Sets the HMAC key for ArrayBuffer format (DEPRECATED)
120
* @param key - The HMAC key as ArrayBuffer
121
* @param inputFormat - Must be "ARRAYBUFFER"
122
*/
123
setHMACKey(key: ArrayBuffer, inputFormat: "ARRAYBUFFER"): void;
124
125
/**
126
* Sets the HMAC key for Uint8Array format (DEPRECATED)
127
* @param key - The HMAC key as Uint8Array
128
* @param inputFormat - Must be "UINT8ARRAY"
129
*/
130
setHMACKey(key: Uint8Array, inputFormat: "UINT8ARRAY"): void;
131
```
132
133
**Usage Example (Deprecated Pattern):**
134
135
```typescript
136
import jsSHA from "jssha";
137
138
// Deprecated approach - avoid in new code
139
const shaObj = new jsSHA("SHA-256", "TEXT");
140
shaObj.setHMACKey("secret-key", "TEXT", { encoding: "UTF8" });
141
shaObj.update("Message to authenticate");
142
const hmac = shaObj.getHash("HEX"); // Use getHash, not getHMAC
143
```
144
145
### Legacy getHMAC Method (Deprecated)
146
147
The `getHMAC` method is deprecated in favor of using `getHash` after setting up HMAC in the constructor.
148
149
```typescript { .api }
150
/**
151
* Returns the HMAC in hexadecimal format (DEPRECATED)
152
* @param format - Must be "HEX"
153
* @param options - Optional formatting options
154
* @returns HMAC as hexadecimal string
155
*/
156
getHMAC(format: "HEX", options?: { outputUpper?: boolean }): string;
157
158
/**
159
* Returns the HMAC in Base64 format (DEPRECATED)
160
* @param format - Must be "B64"
161
* @param options - Optional formatting options
162
* @returns HMAC as Base64 string
163
*/
164
getHMAC(format: "B64", options?: { b64Pad?: string }): string;
165
166
/**
167
* Returns the HMAC as a byte string (DEPRECATED)
168
* @param format - Must be "BYTES"
169
* @returns HMAC as byte string
170
*/
171
getHMAC(format: "BYTES"): string;
172
173
/**
174
* Returns the HMAC as a Uint8Array (DEPRECATED)
175
* @param format - Must be "UINT8ARRAY"
176
* @returns HMAC as Uint8Array
177
*/
178
getHMAC(format: "UINT8ARRAY"): Uint8Array;
179
180
/**
181
* Returns the HMAC as an ArrayBuffer (DEPRECATED)
182
* @param format - Must be "ARRAYBUFFER"
183
* @returns HMAC as ArrayBuffer
184
*/
185
getHMAC(format: "ARRAYBUFFER"): ArrayBuffer;
186
```
187
188
## HMAC-Compatible Variants
189
190
HMAC is supported for the following SHA variants:
191
192
- **SHA-1**: HMAC-SHA1 (legacy, not recommended for new applications)
193
- **SHA-224**: HMAC-SHA224
194
- **SHA-256**: HMAC-SHA256 (most commonly used)
195
- **SHA-384**: HMAC-SHA384
196
- **SHA-512**: HMAC-SHA512
197
- **SHA3-224**: HMAC-SHA3-224
198
- **SHA3-256**: HMAC-SHA3-256
199
- **SHA3-384**: HMAC-SHA3-384
200
- **SHA3-512**: HMAC-SHA3-512
201
202
Note: HMAC is not applicable to variable-length variants (SHAKE, cSHAKE) or KMAC variants (which have their own keyed authentication mechanism).
203
204
## Key Format Considerations
205
206
### Text Keys
207
208
When using TEXT format keys, the encoding parameter determines how the string is converted to bytes:
209
210
```typescript
211
// UTF-8 encoding (default and recommended)
212
const hmac1 = new jsSHA("SHA-256", "TEXT", {
213
hmacKey: { value: "secret-key", format: "TEXT", encoding: "UTF8" }
214
});
215
216
// UTF-16 Big Endian encoding
217
const hmac2 = new jsSHA("SHA-256", "TEXT", {
218
hmacKey: { value: "secret-key", format: "TEXT", encoding: "UTF16BE" }
219
});
220
221
// UTF-16 Little Endian encoding
222
const hmac3 = new jsSHA("SHA-256", "TEXT", {
223
hmacKey: { value: "secret-key", format: "TEXT", encoding: "UTF16LE" }
224
});
225
```
226
227
### Binary Keys
228
229
For keys that are already in binary format or need specific byte representations:
230
231
```typescript
232
// Hexadecimal key (useful for keys generated as hex strings)
233
const hmacHex = new jsSHA("SHA-256", "TEXT", {
234
hmacKey: { value: "deadbeefcafebabe", format: "HEX" }
235
});
236
237
// Base64 key (useful for keys stored in Base64 format)
238
const hmacB64 = new jsSHA("SHA-256", "TEXT", {
239
hmacKey: { value: "c2VjcmV0LWtleQ==", format: "B64" }
240
});
241
242
// Raw bytes key (for precise byte control)
243
const hmacBytes = new jsSHA("SHA-256", "TEXT", {
244
hmacKey: { value: "\x00\x01\x02\x03", format: "BYTES" }
245
});
246
```
247
248
### Binary Object Keys
249
250
For keys provided as JavaScript binary objects:
251
252
```typescript
253
// ArrayBuffer key
254
const keyBuffer = new Uint8Array([0x00, 0x01, 0x02, 0x03]).buffer;
255
const hmacBuffer = new jsSHA("SHA-256", "TEXT", {
256
hmacKey: { value: keyBuffer, format: "ARRAYBUFFER" }
257
});
258
259
// Uint8Array key
260
const keyArray = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
261
const hmacArray = new jsSHA("SHA-256", "TEXT", {
262
hmacKey: { value: keyArray, format: "UINT8ARRAY" }
263
});
264
```
265
266
## Common HMAC Patterns
267
268
### API Request Authentication
269
270
```typescript
271
import jsSHA from "jssha";
272
273
function signRequest(method: string, url: string, body: string, secretKey: string): string {
274
const message = `${method}\n${url}\n${body}`;
275
const hmac = new jsSHA("SHA-256", "TEXT", {
276
hmacKey: { value: secretKey, format: "TEXT" }
277
});
278
hmac.update(message);
279
return hmac.getHash("B64");
280
}
281
282
const signature = signRequest("POST", "/api/users", '{"name":"John"}', "my-secret-key");
283
// Use signature in Authorization header
284
```
285
286
### Message Integrity Verification
287
288
```typescript
289
import jsSHA from "jssha";
290
291
function verifyMessage(message: string, expectedHmac: string, secretKey: string): boolean {
292
const hmac = new jsSHA("SHA-256", "TEXT", {
293
hmacKey: { value: secretKey, format: "TEXT" }
294
});
295
hmac.update(message);
296
const computedHmac = hmac.getHash("HEX");
297
298
// Constant-time comparison to prevent timing attacks
299
return computedHmac === expectedHmac;
300
}
301
302
const isValid = verifyMessage("Hello, World!", "expected-hmac-hex", "shared-secret");
303
```
304
305
### JWT-style Token Signing
306
307
```typescript
308
import jsSHA from "jssha";
309
310
function createToken(header: string, payload: string, secret: string): string {
311
const message = `${header}.${payload}`;
312
const hmac = new jsSHA("SHA-256", "TEXT", {
313
hmacKey: { value: secret, format: "TEXT" }
314
});
315
hmac.update(message);
316
const signature = hmac.getHash("B64");
317
return `${message}.${signature}`;
318
}
319
320
const token = createToken("eyJhbGciOiJIUzI1NiJ9", "eyJ1c2VyIjoiam9obiJ9", "jwt-secret");
321
```
322
323
## Security Considerations
324
325
1. **Key Length**: HMAC keys should be at least as long as the hash output length for optimal security
326
2. **Key Storage**: Store HMAC keys securely and never log or expose them
327
3. **Timing Attacks**: Use constant-time comparison when verifying HMAC values
328
4. **Algorithm Choice**: Prefer SHA-256 or stronger variants for new applications
329
5. **Key Rotation**: Implement regular key rotation for long-lived applications
330
331
## Error Handling
332
333
HMAC operations can fail if:
334
- Invalid key formats are provided
335
- The specified SHA variant doesn't support HMAC
336
- `numRounds` parameter is used with HMAC (not supported)
337
338
```typescript
339
// This will work correctly
340
const validHmac = new jsSHA("SHA-256", "TEXT", {
341
hmacKey: { value: "secret", format: "TEXT" }
342
});
343
344
// This will NOT work - numRounds cannot be used with HMAC
345
try {
346
const invalidHmac = new jsSHA("SHA-256", "TEXT", {
347
hmacKey: { value: "secret", format: "TEXT" },
348
numRounds: 5 // Error: numRounds not valid with HMAC
349
});
350
} catch (error) {
351
console.error("Invalid HMAC configuration");
352
}
353
```