TOTP 시간 단계 계산 쉽게 이해하기 — 개념과 원리
TOTP(시간 기반 일회용 비밀번호)는 인증 앱에서 30초마다 바뀌는 여섯 자리 코드입니다. 휴대폰과 서버가 같은 비밀키와 현재 시각으로 각각 코드를 만듭니다. 이 계산기는 그중 시간 부분, 즉 양쪽이 알고리즘에 넣는 카운터 T, 현재 코드의 남은 초, 8바이트 카운터의 16진수 값을 보여 줍니다. 코드가 계속 틀린다고 나올 때 시계 오차를 확인하는 데 유용합니다.
계산 방법
RFC 6238은 T = ⌊(유닉스 시간 − T0) / X⌋로 정의하며, T0 = 0, 간격 X는 보통 30초입니다.
- 시간 단계 카운터 T: 유닉스 시간을 간격으로 나눈 뒤 소수점 아래를 버립니다.
- 남은 초: X − (유닉스 시간 mod X)입니다.
- 16진수 카운터: T를 16자리 16진수로 쓴 값으로, HOTP가 해시하는 8바이트 빅엔디언 값입니다.
0을 넣으면 기기의 현재 시각을 쓰고, 특정 유닉스 시간(초)을 넣을 수도 있습니다.
원리
TOTP는 HOTP(RFC 4226)의 카운터를 시간으로 바꾼 것입니다. HOTP는 HMAC-SHA1(비밀키, 카운터)을 계산하고, 결과에서 '동적 절단'으로 4바이트를 골라 10⁶으로 나눈 나머지를 여섯 자리 코드로 씁니다. 30초 구간마다 카운터가 하나로 정해지므로 시계만 맞으면 서버와 앱이 서로 통신하지 않고도 같은 코드를 만듭니다. 서버는 시계 오차와 입력 지연을 고려해 보통 앞뒤 한 단계 정도를 함께 허용합니다.
예제 풀이
기본값은 실시간 시계를 쓰므로 볼 때마다 숫자가 바뀝니다. 아래는 유닉스 시간 1,794,165,215(2026-11-08 19:13:35 UTC)에 계산된 결과입니다.
- 입력값은 유닉스 시간 = 현재(1,794,165,215초), 간격 = 30초입니다.
- T = ⌊1,794,165,215 / 30⌋ = 59,805,507입니다.
- 1,794,165,215 mod 30 = 5이므로 남은 초는 30 − 5 = 25입니다.
- 59,805,507을 16진수로 쓰면 3908F43이고, 16자리로 채우면 0000000003908f43입니다.
| 주기 (s) | 시간 단계 카운터 T |
|---|---|
| 7.5 | 239,225,030 |
| 15 | 119,612,515 |
| 22.5 | 79,741,676 |
| 30 | 59,806,257 |
| 37.5 | 47,845,006 |
| 45 | 39,870,838 |
| 60 | 29,903,128 |
결과 해석
코드가 거부되면 휴대폰 시계로 구한 T와 서버 시계로 구한 T를 비교해 보십시오. 한 단계 차이는 시계가 약 30초 어긋났다는 뜻이므로 기기의 자동 시간 설정을 켭니다. 남은 초가 거의 없다면 새 코드가 나올 때까지 기다렸다 입력하는 편이 안전합니다.
흔한 실수
- 유닉스 시간 대신 현지 시각을 넣습니다. 유닉스 시간은 항상 UTC 기준입니다.
- 한쪽만 간격을 60초로 바꾸어 카운터가 서로 맞지 않습니다.
- 비밀키가 유출되어도 코드는 안전하다고 생각합니다. 비밀키를 가진 사람은 누구나 유효한 코드를 만들 수 있습니다.
자주 묻는 질문
인증 앱 코드가 왜 맞지 않습니까?
대부분 기기 시계가 어긋난 경우입니다. 날짜와 시간 자동 설정을 켜고 다시 시도해 보십시오.
다른 해시나 자릿수도 쓸 수 있습니까?
됩니다. RFC 6238은 HMAC-SHA256, HMAC-SHA512와 6~8자리를 허용하지만, 대부분의 앱은 SHA-1, 6자리, 30초를 씁니다.
출처: IETF RFC 6238, TOTP: Time-Based One-Time Password Algorithm · IETF RFC 4226, HOTP: An HMAC-Based One-Time Password Algorithm