HMAC 생성기

키와 메시지로 HMAC 서명(SHA-1 / SHA-256 / SHA-384 / SHA-512)을 계산합니다. hex·base64 출력 전환을 지원하며 Web Crypto API로 브라우저 안에서 처리합니다.

Loading…

모든 처리는 브라우저 내부에서 실행됩니다 — 파일·입력은 서버로 전송되지 않습니다.

사용법

공유 비밀 키와 서명하려는 메시지를 입력하세요. 해시 알고리즘은 현대 기본값인 SHA-256을 중심으로, 레거시 연동용 SHA-1, 장수명 서명용 SHA-384·512 중에서 고를 수 있습니다. 출력 형식은 검증 측이 인쇄 가능 다이제스트를 기대하면 hex(소문자, SHA-256 기준 64글자), 프로토콜이 더 짧거나 URL 친화 형식을 쓰면 base64(SHA-256 기준 44글자)가 편합니다.

서버 측 서명을 손으로 재현하고 싶을 때 사용합니다. Stripe·GitHub·Slack의 웹훅을 로컬에서 검증하기, AWS 서명 v4의 정규화 요청을 만들기, Snowflake나 Twitter OAuth 1.0a를 손으로 서명하기 같은 상황입니다. 실제 서명은 브라우저의 WebCrypto subtle API가 수행하므로 키와 메시지가 기기 밖으로 나가지 않습니다. 입력에 따라 서명이 즉시 재계산되므로 한 번 붙여 넣고 갱신을 지켜보면 됩니다.

예제

Stripe 웹훅 헤더용 HMAC-SHA-256

입력
key:     whsec_test_secret_1234
message: 1709251200.{"id":"evt_xyz","type":"payment_intent.succeeded"}
algo:    SHA-256
format:  hex
출력
5cdf5b6cf2c4e6cba9c5b8c70e7d34b5cefdc2bd0e4a9e1a2f3b4c5d6e7f8091

Stripe는 타임스탬프 + "." + 페이로드를 웹훅 시크릿으로 서명합니다. 검증 측은 HMAC을 다시 계산해 `Stripe-Signature` 헤더의 `v1=` 값과 상수 시간으로 비교합니다. GitHub·Slack·대부분의 웹훅 제공자도 구분자만 다를 뿐 같은 패턴을 씁니다.

JWT HS256용 base64 형식 HMAC-SHA-256

입력
key:     your-256-bit-secret
message: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NSJ9
algo:    SHA-256
format:  base64
출력
wYRgz1g3dnAQq9TT3yz2qLnZcRLfPxc6Eq7p5W7Yt1A=

JWT HS256은 header.payload(둘 다 이미 base64url 인코드됨) 결합을 HMAC-SHA-256으로 서명하고 결과를 세 번째 세그먼트로 붙입니다. 실제 JWT에 맞추려면 base64를 base64url로 변환합니다(`+` → `-`, `/` → `_`, 끝의 `=` 제거).

AWS 서명 v2용 레거시 HMAC-SHA-1

입력
key:     wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
message: GET\nelasticmapreduce.amazonaws.com\n/\nAWSAccessKeyId=...
algo:    SHA-1
format:  base64
출력
i91nKc4PWAt0JJIdXwz9HxZCJDdg=

SHA-1은 충돌 내성이 깨졌지만 HMAC-SHA-1은 MAC 용도에서는 여전히 안전합니다. 공격 모델이 다르기 때문에 공격자는 키 없이 태그를 위조해야 하며 같은 평문 해시를 갖는 두 메시지를 찾는 것만으로는 부족합니다. 그래도 지금 이걸 고르는 것은 여전히 요구하는 레거시 서비스와의 상호 운용 시점으로 한정하세요(S3 SigV2는 2020년에 폐기됐지만 옛 클라이언트가 남아 있습니다).

자주 묻는 질문

HMAC과 일반 해시의 차이 — 메시지를 SHA-256만 하면 안 되나요?

일반 해시는 "메시지가 바뀌지 않았다"는 보장은 주지만 "특정 상대가 만들었다"는 보장은 주지 않습니다. 메시지를 가진 누구나 해시를 다시 계산할 수 있습니다. HMAC은 해시에 공유 비밀을 섞어 넣으므로 키를 아는 당사자만 태그를 생성·검증할 수 있습니다. "키를 아는 누군가에게서 왔다"는 보장이 본질이며, 웹훅 진위 검증, API 요청 서명, 세션 토큰 등에 유용합니다.

SHA-1이 깨졌는데도 HMAC-SHA-1이 남아 있는 이유는?

2017년 SHAttered 공격이 SHA-1 충돌(같은 해시 값을 갖는 두 메시지)을 발견했습니다. 이것은 디지털 서명(공격자가 양쪽 메시지를 통제할 수 있음)에서는 SHA-1을 깨지만, 키 없이 태그를 위조해야 하는 HMAC은 깨지 않습니다. NIST는 SP 800-107r1까지 HMAC-SHA-1을 MAC 용도로 승인했고, 다수의 레거시 프로토콜(옛 AWS 서명, 일부 Atlassian 웹훅, Kerberos 일부 등)이 여전히 사용합니다. 신규에는 SHA-256, SHA-1은 상호 운용 용도로만 사용하세요.

비밀 키는 얼마나 길어야 하나요?

RFC 2104은 해시 출력 이상의 길이의 키를 권장합니다 — SHA-256은 32바이트, SHA-384는 48바이트, SHA-512는 64바이트입니다. 더 짧은 키도 받지만(HMAC이 패딩) 실효 보안은 키 길이에서 멈춥니다. 해시의 *블록 크기*(SHA-1·256은 64바이트, SHA-384·512는 128바이트)보다 긴 키는 먼저 내부 해시로 압축되어 보안은 늘지 않고 계산만 낭비됩니다. 키는 `crypto.getRandomValues(new Uint8Array(32))` 같은 방식으로 생성하고 다른 비밀과 같은 신중함으로 보관하세요.

서버가 서명을 거부하지만 값은 일치해 보입니다 — 왜일까요?

두 가지 원인이 흔합니다. 첫째, 검증 측이 상수 시간 비교를 쓰는 경우입니다. `==`는 처음으로 다른 바이트에서 일찍 종료하며 어디까지 바이트가 일치하는지를 타이밍으로 흘립니다. 서버는 이를 공격으로 보고 거부할 수 있습니다. 둘째, 인코딩 불일치입니다. hex 대소문자, base64와 base64url 차이, 끝의 `=` 패딩 유무 같은 것들입니다. 명세 형식에 정확히 맞추세요. hex 대소문자가 한 글자만 달라도 흔한 실패 패턴입니다.

이 도구로 서명 검증도 되나요?

이 도구는 생성 전용입니다. 검증은 같은 입력으로 HMAC을 다시 계산해 기대 태그와 상수 시간 비교로 대조하는 작업입니다. 검증하려면 같은 키와 메시지를 여기에 붙여 넣고 출력을 기대 값과 한 글자씩 비교하거나, 코드에서 `crypto.subtle.verify`를 사용하세요. 브라우저에는 타이밍 안전 비교 함수가 내장되어 있지 않아서 운영 환경 검증에는 서버 측 라이브러리를 권장합니다.

HMAC·디지털 서명·KDF의 차이는?

**HMAC**은 하나의 공유 비밀로 태그를 만들며 검증 측에도 같은 비밀이 필요합니다. 키를 공유할 수 있는 두 당사자 사이에서 빠르고 표준적입니다. **디지털 서명**(RSA·ECDSA·Ed25519)은 비밀 키로 서명하고 공개 키로 검증합니다. 검증 측에 비밀이 필요 없으므로 발행자가 한 번 서명하면 임의의 독자가 검증할 수 있습니다. **KDF**(PBKDF2·HKDF·Argon2)는 비밀번호나 긴 비밀을 고정 길이의 키로 변환합니다. 서명 용도가 아니라 서명 전 구성 요소입니다. 많은 프로토콜이 이들을 겹쳐 씁니다. HKDF로 키를 파생하고, HMAC으로 메시지를 인증하고, 디지털 서명으로 신뢰의 시작점을 만드는 식입니다.

관련 개념

HMAC(Hash-based Message Authentication Code)은 RFC 2104(1997)에 정의되어 있고 FIPS 198-1(2008)로 표준화되었습니다. 기존 해시 함수를 고정 구성으로 감싸는 방식이며, 메시지에 대해 해시를 2번 패스하고 내·외부 패딩 상수에 키를 XOR합니다. 구성은 하부 해시에 대해 *범용*이라 HMAC-SHA-256·HMAC-SHA-512·이제는 권장되지 않는 HMAC-MD5까지 같은 템플릿을 따릅니다. 출력 크기는 하부 해시와 같습니다 — SHA-256은 32바이트, SHA-384는 48바이트, SHA-512는 64바이트입니다.

HMAC은 인접한 3가지 프리미티브의 중간에 위치합니다. **일반 해시**(`SHA-256(message)`)는 무결성을 증명하지만 출처는 증명하지 않습니다. 누구나 재계산할 수 있습니다. **HMAC**(`HMAC(key, message)`)은 무결성과 "키를 아는 누군가가 만들었다"는 보장을 모두 줍니다. 검증 측에도 같은 키가 필요합니다. **디지털 서명**(RSA·ECDSA·Ed25519)은 검증 측이 비밀을 갖지 않고도 출처와 무결성을 증명합니다. 대가는 100~10000배 느림과 더 큰 출력입니다. **AEAD**(AES-GCM·ChaCha20-Poly1305)는 인증과 암호화를 한 덩어리로 묶어 현대 프로토콜에서 "암호화 후 HMAC" 패턴을 대체합니다.

일상적 용도는 업계 전반에 걸쳐 놀랍도록 일관됩니다. **웹훅 서명** — Stripe `Stripe-Signature`, GitHub `X-Hub-Signature-256`, Slack `X-Slack-Signature`, Twilio `X-Twilio-Signature` 모두 HMAC-SHA-256(옛 버전은 HMAC-SHA-1)으로 타임스탬프 + 페이로드를 서명합니다. **API 요청 서명** — AWS Signature v4, Snowflake, Twitter OAuth 1.0a는 헤더와 파라미터의 정규화 문자열을 서명합니다. **JWT HS256·HS384·HS512**는 header.payload 결합을 HMAC으로 서명해 세 번째 세그먼트로 둡니다. **세션 토큰** — Rails의 `signed cookies`나 Django의 `signing`은 HMAC을 사용해 암호화 없이 변조 감지가 가능하게 합니다. 어느 경우든 위협 모델은 같으며, 키를 갖지 않은 제3자가 메시지를 위조하거나 변조하지 못하게 하는 것이 목적입니다.

관련 글

관련 도구