HMAC
Hash-based Message Authentication Code
The Hmac module provides support for creating cryptographic Hash-based Message Authentication Codes (HMAC). It uses a cryptographic hash function (like SHA-256) in combination with a secret key to verify both the integrity and authenticity of a message.
Table of Contents
Theory
A Message Authentication Code (MAC) allows two parties who share a secret key to verify that a message has not been tampered with.
- Sender: Computes
Tag = HMAC(Key, Message)and sends[Message, Tag]. - Receiver: Computes
ExpectedTag = HMAC(Key, ReceivedMessage). - Verify: If
Tag === ExpectedTag, the message is authentic.
HMAC is defined in RFC 2104. It avoids simple "length extension attacks" that plague naive constructions like Hash(Key + Message) by using a nested hashing structure:
Where:
His the hash function.K'is the key padded to block size.opadis the outer padding (0x5c repeated).ipadis the inner padding (0x36 repeated).
Class: Hmac
The Hmac class creates HMAC streams. Instances are created using createHmac().
hmac.update(data[, inputEncoding])
Updates the HMAC content with the given data. This method can be called multiple times.
Parameters:
Prop
Type
Returns: Hmac
Example:
hmac.update('part 1');
hmac.update('part 2');hmac.digest([encoding])
Calculates the HMAC digest of all of the data passed.
Parameters:
Prop
Type
Returns: Buffer | string
Example:
import { createHmac } from 'react-native-quick-crypto';
const hmac = createHmac('sha256', 'secret');
hmac.update('data');
const sig = hmac.digest('hex');Module Methods
createHmac(algorithm, key[, options])
Creates and returns an Hmac object.
Parameters:
Prop
Type
Returns: Hmac
Example:
import { createHmac } from 'react-native-quick-crypto';
const hmac = createHmac('sha256', 'super-secret-key');Real-World Examples
API Request Signing (AWS Style)
Rest APIs often use HMAC to authenticate requests.
import { createHmac } from 'react-native-quick-crypto';
function signApiRequest(
method: string,
path: string,
body: string,
timestamp: string,
secret: string
): string {
// Create the canonical string: method + path + timestamp + bodyHash
const bodyHash = createHmac('sha256', secret).update(body).digest('hex');
const stringToSign = `${method}\n${path}\n${timestamp}\n${bodyHash}`;
// Sign the canonical string with the secret
const hmac = createHmac('sha256', secret);
hmac.update(stringToSign);
return hmac.digest('hex');
}Webhook Signature Validation
When receiving a webhook (e.g., from Stripe or GitHub), you must verify it came from them using timingSafeEqual.
import { createHmac, timingSafeEqual } from 'react-native-quick-crypto';
function verifyWebhook(
payload: string,
signatureHeader: string,
secret: string
): boolean {
// Compute expected signature
const hmac = createHmac('sha256', secret);
hmac.update(payload);
const expectedInfo = hmac.digest('hex');
// Constants-time comparison
const expectedBuf = Buffer.from(expectedInfo, 'hex');
const receivedBuf = Buffer.from(signatureHeader, 'hex');
if (expectedBuf.length !== receivedBuf.length) {
return false;
}
return timingSafeEqual(expectedBuf, receivedBuf);
}TOTP (Google Authenticator)
Time-Based One-Time Passwords use HMAC-SHA1.
TOTP = Truncate(HMAC-SHA1(K, Floor(Time / 30)))import { createHmac } from 'react-native-quick-crypto';
function generateTOTP(secretBytes: Buffer): string {
const time = Math.floor(Date.now() / 1000 / 30);
const timeBuf = Buffer.alloc(8);
timeBuf.writeBigUInt64BE(BigInt(time));
const hmac = createHmac('sha1', secretBytes);
hmac.update(timeBuf);
const hash = hmac.digest();
// Dynamic Truncation
const offset = hash[hash.length - 1] & 0x0f;
const binary = ((hash[offset] & 0x7f) << 24) |
((hash[offset + 1] & 0xff) << 16) |
((hash[offset + 2] & 0xff) << 8) |
(hash[offset + 3] & 0xff);
const otp = binary % 1000000;
return otp.toString().padStart(6, '0');
}Security Considerations
Timing Attacks
When comparing HMAC signatures, never use standard string comparisons (=== or ==). This creates a timing side-channel where the comparison returns faster if the first byte is wrong, leaking information to an attacker. usage of crypto.timingSafeEqual() is mandatory for verifying signatures.
Key Strength
The security of the HMAC is directly tied to the strength of the secret key. If the key is weak (e.g., a short password), an attacker can brute-force the key offline by observing a single valid (message, tag) pair.