HMAC Generator
SHA-256, SHA-384 또는 SHA-512를 사용한 HMAC 서명 생성
메시지
비밀 키
HMAC 서명
HMAC 서명이 여기 표시됩니다…
HMAC이란 무엇인가요?
HMAC(Hash-based Message Authentication Code)은 RFC 2104에 정의된 암호학적 구조로, 해시 함수와 비밀 키를 결합하여 고정 크기의 인증 태그를 생성합니다. 누구나 계산할 수 있는 일반 해시와 달리, HMAC은 비밀 키를 공유하는 당사자만 생성하고 검증할 수 있습니다. HMAC은 메시지의 무결성과 진위성을 모두 검증하는 표준 메커니즘으로, 데이터가 변조되지 않았으며 신뢰할 수 있는 발신자가 생성했음을 확인합니다.
HMAC 알고리즘은 SHA-256, SHA-384, SHA-512는 물론 SHA-1, MD5 같은 레거시 함수 등 모든 반복 해시 함수와 함께 동작합니다. 결과 구조는 기반 해시에 따라 HMAC-SHA256, HMAC-SHA384, HMAC-SHA512로 불립니다. HMAC의 보안 증명이 해시 함수의 충돌 저항성과 특정 의사 난수 특성에 의존하기 때문에, 새로운 시스템에는 SHA-2 계열 알고리즘을 권장합니다. HMAC-SHA256은 가장 널리 배포된 변형으로, AWS Signature V4, Stripe 웹훅, GitHub 웹훅 시크릿, Slack 요청 서명, JSON Web Tokens(HS256)에 사용됩니다.
HMAC의 설계는 일반 해싱이 제공하지 못하는 중요한 특성인 길이 확장 공격에 대한 저항성을 제공합니다. SHA-256만 사용할 경우, H(message)를 아는 공격자는 원래 메시지를 모르더라도 H(message || attacker_data)를 계산할 수 있습니다. HMAC의 이중 해싱 구조(서로 다른 패딩 키를 사용하는 내부 해시와 외부 해시)는 이 공격을 완전히 차단합니다. 이것이 API 서명 방식이 메시지에 비밀 키를 추가하고 해싱하는 방법 대신 HMAC을 사용하는 이유입니다.
온라인 HMAC 생성기를 사용하는 이유
HMAC 서명 계산은 일반적으로 코드 작성이나 CLI 도구 사용이 필요합니다. 이 브라우저 기반 HMAC 생성기를 사용하면 소프트웨어 설치나 터미널 전환 없이 HMAC-SHA256, HMAC-SHA384, HMAC-SHA512 서명을 즉시 생성할 수 있습니다.
HMAC 생성기 활용 사례
HMAC vs 일반 해시 vs 암호화
HMAC, 일반 해싱, 암호화는 각각 다른 목적을 제공합니다. HMAC은 메시지 인증을 제공하며, 비밀 키를 가진 누군가가 메시지를 생성했고 수정되지 않았음을 증명합니다. 일반 해시는 무결성을 제공하지만 인증은 제공하지 않습니다. 암호화는 기밀성을 제공합니다. 아래 표에서 차이점을 명확히 설명합니다.
| 속성 | HMAC | Plain Hash | Encryption |
|---|---|---|---|
| Purpose | Message authentication + integrity | Data integrity only (no key) | Confidentiality + integrity |
| Requires secret key | Yes | No | Yes |
| Verifiable by | Parties who share the secret | Anyone | Recipient with key |
| Reversible | No — digest only | No — digest only | Yes — decryption recovers data |
| Output size | Depends on hash (e.g. 256 bits) | Depends on hash | Variable (ciphertext) |
| Standard | RFC 2104 | FIPS 180-4 | NIST SP 800-38A (AES) |
| Use case example | Webhook signature verification | File checksum verification | Encrypting data at rest |
HMAC 알고리즘 비교
HMAC은 모든 해시 함수를 사용할 수 있지만, 기반 알고리즘 선택에 따라 출력 크기, 보안 수준, 브라우저 호환성이 결정됩니다. HMAC-SHA256이 새로운 시스템에서 가장 일반적인 선택입니다. 아래 표는 자주 접하게 될 변형들을 비교합니다.
| 알고리즘 | 다이제스트 크기 | 16진수 길이 | Web Crypto API | 최적 용도 |
|---|---|---|---|---|
| HMAC-SHA256 | 256 bits | 64 hex chars | Yes | API signing, webhooks, JWT (HS256) |
| HMAC-SHA384 | 384 bits | 96 hex chars | Yes | TLS 1.3 PRF, CNSA compliance |
| HMAC-SHA512 | 512 bits | 128 hex chars | Yes | High-security signatures, HKDF |
| HMAC-SHA1 | 160 bits | 40 hex chars | Yes | Legacy OAuth 1.0, TOTP (RFC 6238) |
| HMAC-MD5 | 128 bits | 32 hex chars | No | Legacy only — not recommended |
HMAC의 내부 동작 원리
HMAC은 두 가지 서로 다른 키 파생 패드를 사용하여 기반 해시 함수를 두 번 적용합니다. 이 구조는 RFC 2104에 정의되어 있으며 표준 암호학적 가정 하에서 PRF(의사 난수 함수)임이 증명되었습니다. 키는 먼저 패딩되거나 해시되어 해시 함수의 블록 크기(SHA-256은 64바이트, SHA-512는 128바이트)에 맞춰집니다.
where K' = key padded to block size, ipad = 0x36, opad = 0x5C
알고리즘은 패딩된 키를 내부 패드 상수(ipad, 0x36 반복)와 XOR하고, 메시지와 연결한 후 결과를 해싱합니다. 그런 다음 패딩된 키를 외부 패드 상수(opad, 0x5C 반복)와 XOR하고, 내부 해시 출력과 연결한 후 다시 해싱합니다. 이 이중 해싱 구조가 길이 확장 공격을 방지하고 비밀 키를 알지 못하면 HMAC 출력을 계산할 수 없도록 보장합니다.
HMAC 코드 예제
HMAC은 모든 주요 언어와 런타임에서 네이티브로 지원됩니다. Web Crypto API는 라이브러리 없이 브라우저에서 HMAC-SHA256, HMAC-SHA384, HMAC-SHA512를 제공합니다. 아래 예제는 웹훅 검증과 상수 시간 비교를 포함한 실제 사용 패턴을 보여줍니다.
async function hmacSHA256(message, secret) {
const enc = new TextEncoder()
const key = await crypto.subtle.importKey(
'raw', enc.encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false, ['sign']
)
const sig = await crypto.subtle.sign('HMAC', key, enc.encode(message))
return Array.from(new Uint8Array(sig))
.map(b => b.toString(16).padStart(2, '0')).join('')
}
await hmacSHA256('hello world', 'my-secret-key')
// → "90eb182d8396f16d4341d582047f45c0a97d73388c5377d9ced478a2212295ad"
// Node.js (built-in crypto module)
const crypto = require('crypto')
crypto.createHmac('sha256', 'my-secret-key')
.update('hello world').digest('hex')
// → "90eb182d8396f16d4341d582047f45c0a97d73388c5377d9ced478a2212295ad"import hmac
import hashlib
# HMAC-SHA256
sig = hmac.new(
b'my-secret-key',
b'hello world',
hashlib.sha256
).hexdigest()
print(sig)
# → "90eb182d8396f16d4341d582047f45c0a97d73388c5377d9ced478a2212295ad"
# Verify a webhook signature (constant-time comparison)
expected = "90eb182d8396f16d4341d582047f45c0a97d73388c5377d9ced478a2212295ad"
received = hmac.new(b'my-secret-key', b'hello world', hashlib.sha256).hexdigest()
if hmac.compare_digest(expected, received):
print("Signature valid")
# HMAC-SHA512
hmac.new(b'key', b'data', hashlib.sha512).hexdigest()package main
import (
"crypto/hmac"
"crypto/sha256"
"fmt"
)
func main() {
mac := hmac.New(sha256.New, []byte("my-secret-key"))
mac.Write([]byte("hello world"))
sig := mac.Sum(nil)
fmt.Printf("%x\n", sig)
// → 90eb182d8396f16d4341d582047f45c0a97d73388c5377d9ced478a2212295ad
// Verify: use hmac.Equal for constant-time comparison
expected := mac.Sum(nil)
fmt.Println(hmac.Equal(sig, expected)) // true
}# HMAC-SHA256 echo -n "hello world" | openssl dgst -sha256 -hmac "my-secret-key" # → SHA2-256(stdin)= 90eb182d8396f16d4341d582047f45c0a97d73388c5377d9ced478a2212295ad # HMAC-SHA512 echo -n "hello world" | openssl dgst -sha512 -hmac "my-secret-key" # Verify a file signature openssl dgst -sha256 -hmac "my-secret-key" release.tar.gz # HMAC with hex key (e.g. from a webhook secret) echo -n "payload" | openssl dgst -sha256 -hmac "$(echo -n '736563726574' | xxd -r -p)"