HMAC Generator
Generate HMAC (Hash-based Message Authentication Codes) using various hash algorithms
HMAC Generator
Generate HMAC (Hash-based Message Authentication Codes) using various hash algorithms
Quick Presets
HMAC Generation
✅ Recommended
⚠️ Legacy
📱 Use Cases
🔐 HMAC Security Tips
- • Strong Keys: Use cryptographically random keys with sufficient length
- • Key Management: Store keys securely, rotate regularly, never hardcode
- • Algorithm Choice: Use SHA-256 or SHA-512 for new applications
- • Constant-Time Comparison: Always use constant-time comparison for verification
- • Include Timestamps: Add timestamps to prevent replay attacks
About HMAC (Hash-based Message Authentication Code)
HMAC is a cryptographic mechanism that combines a secret key with a hash function to provide message authentication and data integrity verification. It's widely used in API authentication, JWT tokens, and secure communication protocols.
- Combines secret key with hash function for authentication
- Provides both data integrity and authenticity verification
- Resistant to length extension attacks (unlike simple keyed hashing)
- Used in OAuth, JWT, API signatures, and SSL/TLS protocols
- Supports multiple hash algorithms: SHA-256, SHA-512, MD5
HMAC vs Simple Hashing
HMAC Advantages
- Authentication: Verifies message sender identity
- Integrity: Detects message tampering
- Secret Key: Only parties with key can generate/verify
- Attack Resistant: Secure against length extension
- Standardized: FIPS 198 and RFC 2104 compliant
Simple Hash Limitations
- No Authentication: Anyone can compute hash
- Vulnerable: Simple key concatenation is insecure
- Length Extension: Attackers can extend messages
- No Secret: Hash values can be computed by anyone
- Limited Use: Only provides data integrity
Advertisement
Frequently Asked Questions
What's the difference between HMAC and digital signatures?
HMAC uses symmetric cryptography (same secret key for generation and verification), while digital signatures use asymmetric cryptography (private key signs, public key verifies). HMAC is faster but requires shared secrets, while signatures provide non-repudiation.
Which hash algorithm should I use with HMAC?
Use SHA-256 for most applications as it provides excellent security and performance. SHA-512 offers higher security for sensitive applications. Avoid MD5 and SHA-1 for new implementations due to known vulnerabilities, though they may be required for legacy system compatibility.
How should I manage HMAC keys securely?
Generate cryptographically random keys with sufficient length (at least 32 bytes for SHA-256). Store keys securely using key management systems, rotate them regularly, and never hardcode them in source code. Use environment variables or secure vaults for key storage.
Can I use the same HMAC key for multiple purposes?
It's better to use different keys for different purposes to limit the impact of key compromise. If you must reuse keys, ensure they're used only for the same type of data and security context. Consider key derivation functions to generate purpose-specific keys from a master key.
HMAC Examples
HMAC-SHA256 Example:
HMAC Process:
Sponsored Content
HMAC Implementation
JavaScript HMAC Generator:
class HMACGenerator {
constructor() {
this.supportedAlgorithms = [
'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512', 'MD5'
];
this.blockSizes = {
'SHA-1': 64,
'SHA-256': 64,
'SHA-384': 128,
'SHA-512': 128,
'MD5': 64
};
this.outputSizes = {
'SHA-1': 20,
'SHA-256': 32,
'SHA-384': 48,
'SHA-512': 64,
'MD5': 16
};
}
// Generate HMAC using Web Crypto API
async generateHMAC(message, key, algorithm = 'SHA-256') {
try {
if (typeof message !== 'string') {
return {
success: false,
error: 'Message must be a string'
};
}
if (typeof key !== 'string') {
return {
success: false,
error: 'Key must be a string'
};
}
if (!this.supportedAlgorithms.includes(algorithm)) {
return {
success: false,
error: `Unsupported algorithm: ${algorithm}`
};
}
const startTime = performance.now();
let hmac;
if (this.isWebCryptoSupported(algorithm)) {
hmac = await this.webCryptoHMAC(message, key, algorithm);
} else {
hmac = await this.fallbackHMAC(message, key, algorithm);
}
const endTime = performance.now();
return {
success: true,
message: message,
key: '***hidden***',
algorithm: algorithm,
hmac: hmac,
hmacUppercase: hmac.toUpperCase(),
length: hmac.length,
bytes: this.outputSizes[algorithm],
timing: {
duration: Math.round(endTime - startTime),
formatted: `${Math.round(endTime - startTime)}ms`
},
verification: this.generateVerificationInfo(message, hmac, algorithm),
formats: this.getHMACFormats(hmac)
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// Use Web Crypto API for HMAC generation
async webCryptoHMAC(message, key, algorithm) {
const encoder = new TextEncoder();
const keyData = encoder.encode(key);
const messageData = encoder.encode(message);
// Import the key
const cryptoKey = await crypto.subtle.importKey(
'raw',
keyData,
{
name: 'HMAC',
hash: algorithm
},
false,
['sign']
);
// Generate HMAC
const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);
const hashArray = Array.from(new Uint8Array(signature));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
// Check Web Crypto API support
isWebCryptoSupported(algorithm) {
const supported = ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'];
return supported.includes(algorithm);
}
// Fallback HMAC implementation
async fallbackHMAC(message, key, algorithm) {
if (algorithm === 'MD5') {
return this.hmacMD5(message, key);
}
throw new Error(`Fallback not implemented for ${algorithm}`);
}
// Simple HMAC-MD5 implementation (for demonstration)
async hmacMD5(message, key) {
const blockSize = this.blockSizes['MD5'];
const ipad = 0x36;
const opad = 0x5C;
// Prepare key
let keyBytes = this.stringToBytes(key);
// If key is longer than block size, hash it
if (keyBytes.length > blockSize) {
keyBytes = await this.simpleMD5Bytes(keyBytes);
}
// Pad key to block size
while (keyBytes.length < blockSize) {
keyBytes.push(0);
}
// Create inner and outer key pads
const innerKeyPad = keyBytes.map(b => b ^ ipad);
const outerKeyPad = keyBytes.map(b => b ^ opad);
// Inner hash: H(K ⊕ ipad || message)
const messageBytes = this.stringToBytes(message);
const innerData = innerKeyPad.concat(messageBytes);
const innerHash = await this.simpleMD5Bytes(innerData);
// Outer hash: H(K ⊕ opad || innerHash)
const outerData = outerKeyPad.concat(innerHash);
const finalHash = await this.simpleMD5Bytes(outerData);
return finalHash.map(b => b.toString(16).padStart(2, '0')).join('');
}
// Convert string to byte array
stringToBytes(str) {
const bytes = [];
for (let i = 0; i < str.length; i++) {
bytes.push(str.charCodeAt(i) & 0xFF);
}
return bytes;
}
// Simplified MD5 for demonstration (use proper library in production)
async simpleMD5Bytes(bytes) {
// This is a placeholder - use a proper MD5 implementation
const str = String.fromCharCode.apply(null, bytes);
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
const result = [];
for (let i = 0; i < 16; i++) {
result.push((hash >>> (i * 2)) & 0xFF);
}
return result;
}
// Verify HMAC
async verifyHMAC(message, key, expectedHMAC, algorithm = 'SHA-256') {
try {
const result = await this.generateHMAC(message, key, algorithm);
if (!result.success) {
return result;
}
const matches = this.constantTimeCompare(
result.hmac.toLowerCase(),
expectedHMAC.toLowerCase()
);
return {
success: true,
matches: matches,
message: message,
algorithm: algorithm,
expected: expectedHMAC.toLowerCase(),
actual: result.hmac.toLowerCase(),
verdict: matches ? 'VERIFIED' : 'FAILED',
timing: result.timing
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// Constant time comparison to prevent timing attacks
constantTimeCompare(a, b) {
if (a.length !== b.length) return false;
let result = 0;
for (let i = 0; i < a.length; i++) {
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return result === 0;
}
// Generate HMAC for multiple messages
async generateBatchHMAC(messages, key, algorithm = 'SHA-256') {
const results = [];
for (const message of messages) {
const result = await this.generateHMAC(message, key, algorithm);
results.push({
message: message,
...result
});
}
return {
success: true,
key: '***hidden***',
algorithm: algorithm,
count: messages.length,
results: results
};
}
// Generate JWT-style HMAC signature
async generateJWTSignature(header, payload, secret, algorithm = 'SHA-256') {
try {
// Encode header and payload
const encodedHeader = this.base64UrlEncode(JSON.stringify(header));
const encodedPayload = this.base64UrlEncode(JSON.stringify(payload));
// Create signing input
const signingInput = `${encodedHeader}.${encodedPayload}`;
// Generate HMAC
const hmacResult = await this.generateHMAC(signingInput, secret, algorithm);
if (!hmacResult.success) {
return hmacResult;
}
// Convert hex HMAC to base64url
const hmacBytes = this.hexToBytes(hmacResult.hmac);
const signature = this.base64UrlEncodeBytes(hmacBytes);
const jwt = `${signingInput}.${signature}`;
return {
success: true,
header: header,
payload: payload,
algorithm: algorithm,
signingInput: signingInput,
hmac: hmacResult.hmac,
signature: signature,
jwt: jwt,
parts: {
header: encodedHeader,
payload: encodedPayload,
signature: signature
}
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// Base64 URL encode
base64UrlEncode(str) {
return btoa(str)
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
// Base64 URL encode bytes
base64UrlEncodeBytes(bytes) {
const str = String.fromCharCode.apply(null, bytes);
return btoa(str)
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
// Convert hex string to bytes
hexToBytes(hex) {
const bytes = [];
for (let i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return bytes;
}
// Generate API signature (common pattern)
async generateAPISignature(httpMethod, uri, params, secret, algorithm = 'SHA-256') {
try {
// Sort parameters
const sortedParams = Object.keys(params)
.sort()
.map(key => `${key}=${params[key]}`)
.join('&');
// Create signature base string
const signatureBase = `${httpMethod.toUpperCase()}&${uri}&${sortedParams}`;
// Generate HMAC
const hmacResult = await this.generateHMAC(signatureBase, secret, algorithm);
if (!hmacResult.success) {
return hmacResult;
}
return {
success: true,
method: httpMethod.toUpperCase(),
uri: uri,
params: params,
sortedParams: sortedParams,
signatureBase: signatureBase,
hmac: hmacResult.hmac,
algorithm: algorithm,
usage: 'Add to request headers or query parameters'
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// Generate key from password (PBKDF2-like)
async generateKeyFromPassword(password, salt = 'default-salt', iterations = 1000) {
const encoder = new TextEncoder();
const passwordData = encoder.encode(password);
const saltData = encoder.encode(salt);
// Import password as key material
const keyMaterial = await crypto.subtle.importKey(
'raw',
passwordData,
'PBKDF2',
false,
['deriveBits']
);
// Derive key
const derivedKey = await crypto.subtle.deriveBits(
{
name: 'PBKDF2',
salt: saltData,
iterations: iterations,
hash: 'SHA-256'
},
keyMaterial,
256 // 32 bytes
);
const keyArray = Array.from(new Uint8Array(derivedKey));
const keyHex = keyArray.map(b => b.toString(16).padStart(2, '0')).join('');
return {
success: true,
password: '***hidden***',
salt: salt,
iterations: iterations,
key: keyHex,
keyBytes: keyArray,
usage: 'Use this derived key for HMAC generation'
};
}
// Get verification information
generateVerificationInfo(message, hmac, algorithm) {
return {
howToVerify: 'Generate HMAC with same message, key, and algorithm',
steps: [
'1. Use the same secret key',
'2. Apply same hash algorithm (' + algorithm + ')',
'3. Generate HMAC for the message',
'4. Compare results using constant-time comparison'
],
security: 'Never share the secret key used for HMAC generation'
};
}
// Get HMAC in different formats
getHMACFormats(hmac) {
return {
hex: hmac.toLowerCase(),
hexUpper: hmac.toUpperCase(),
base64: btoa(hmac.match(/.{2}/g)?.map(hex =>
String.fromCharCode(parseInt(hex, 16))).join('') || ''),
withColons: hmac.match(/.{2}/g)?.join(':'),
withSpaces: hmac.match(/.{2}/g)?.join(' '),
withDashes: hmac.match(/.{4}/g)?.join('-')
};
}
// Benchmark HMAC algorithms
async benchmarkHMAC(message = 'benchmark test', key = 'test-key', iterations = 100) {
const algorithms = ['SHA-1', 'SHA-256', 'SHA-512'];
const results = [];
for (const algorithm of algorithms) {
const startTime = performance.now();
for (let i = 0; i < iterations; i++) {
await this.generateHMAC(message + i, key, algorithm);
}
const endTime = performance.now();
const avgTime = (endTime - startTime) / iterations;
results.push({
algorithm: algorithm,
iterations: iterations,
totalTime: Math.round(endTime - startTime),
averageTime: Math.round(avgTime * 100) / 100,
hmacsPerSecond: Math.round(1000 / avgTime),
outputSize: this.outputSizes[algorithm],
blockSize: this.blockSizes[algorithm]
});
}
return {
success: true,
message: message,
key: '***hidden***',
iterations: iterations,
results: results.sort((a, b) => a.averageTime - b.averageTime),
recommendation: this.getRecommendation(results)
};
}
// Get algorithm recommendation
getRecommendation(benchmarkResults) {
const sha256 = benchmarkResults.find(r => r.algorithm === 'SHA-256');
return {
algorithm: 'SHA-256',
reason: 'Best balance of security, performance, and compatibility',
performance: sha256?.averageTime || 'unknown',
alternatives: {
'SHA-512': 'Higher security, larger output size',
'SHA-1': 'Legacy compatibility only (not recommended for new projects)'
}
};
}
}
// Usage examples
const hmac = new HMACGenerator();
// Generate HMAC
console.log('Generate HMAC:');
const message = 'Hello, World!';
const secretKey = 'my-secret-key-123';
const hmacResult = await hmac.generateHMAC(message, secretKey, 'SHA-256');
console.log(hmacResult);
// Verify HMAC
console.log('\nVerify HMAC:');
if (hmacResult.success) {
const verification = await hmac.verifyHMAC(message, secretKey, hmacResult.hmac, 'SHA-256');
console.log(verification);
}
// JWT Signature
console.log('\nJWT Signature:');
const header = { alg: 'HS256', typ: 'JWT' };
const payload = { sub: '1234567890', name: 'John Doe', iat: 1516239022 };
const jwt = await hmac.generateJWTSignature(header, payload, 'secret', 'SHA-256');
console.log(jwt);
// API Signature
console.log('\nAPI Signature:');
const apiSig = await hmac.generateAPISignature('GET', '/api/users',
{ id: '123', timestamp: '1609459200' }, 'api-secret');
console.log(apiSig);
console.log('HMAC generator ready!');
API Authentication with HMAC
Request Signing:
Verification Process:
HMAC Security Best Practices
- Strong Keys: Use cryptographically random keys with at least 32 bytes
- Key Management: Store keys securely, rotate regularly, never hardcode
- Algorithm Choice: Use SHA-256 or SHA-512, avoid MD5 and SHA-1
- Constant-Time Comparison: Prevent timing attacks when verifying HMACs
- Include Timestamps: Add timestamps to prevent replay attacks
- Separate Keys: Use different keys for different purposes
- Validate Input: Always validate message content before HMAC generation
Common Use Cases
- API request authentication and authorization
- JWT token signing and verification
- Webhook payload verification
- Message integrity in communications
- Session token generation and validation
- File integrity verification systems
- OAuth signature generation
- Database audit trail verification
Advertisement
