Skip to content

Instantly share code, notes, and snippets.

@zeta709
Last active August 29, 2015 14:04
Show Gist options
  • Save zeta709/4800897a2e17c2e92680 to your computer and use it in GitHub Desktop.
Save zeta709/4800897a2e17c2e92680 to your computer and use it in GitHub Desktop.
OTP
google-authenticator와 관련된 노트
https://code.google.com/p/google-authenticator/
google-authenticator는 RFC 6238의 TOTP와 RFC 4226의 HOTP를 지원한다.
HMAC-SHA-1 알고리즘을 사용하는 것 같고, 30초에 한 번씩 바꾸고, 결과는 6자리 숫자로 나온다.
그리고 base32로 인코딩된 키를 직접 입력하는 기능이 있다.
구글 2단계 인증 (https://accounts.google.com/b/0/SmsAuthSettings) 설정 시
바코드를 스캔하는 대신 키를 직접 입력하는 옵션이 있는데 base32로 인코딩된 32자리 문자열이 제공된다.
RFC 문서에서 OTP 알고리즘의 reference implementation을 찾을 수 있다.
http://tools.ietf.org/html/rfc6238
https://tools.ietf.org/html/rfc4226
RFC 6238의 reference implementation은 java로 되어있고,
HMAC-SHA-1의 경우 20 bytes key를 사용하는데 hex로 인코딩된 문자열을 사용하는 것으로 코딩되어 있다.
RFC 6238의 reference implementation을 거의 그대로 사용하되,
구글 2단계 인증에서 제공하는 base32로 인코딩된 32자리 문자열을 hex로 인코딩된 40자리 문자열로 바꾸어서 사용하면,
google-authenticator와 동일한 결과가 나오는 것을 확인하였다.
String mySeed = "0000000000000000000000000000000000000000";
System.out.println(
"+-google--------+-----------------------+" +
"------------------+--------+--------+");
System.out.println(
"| Time(sec) | Time (UTC format) " +
"| Value of T(Hex) | TOTP | Mode |");
System.out.println(
"+---------------+-----------------------+" +
"------------------+--------+--------+");
long Time = System.currentTimeMillis() / 1000L;
long T = (Time - T0)/30;
steps = Long.toHexString(T).toUpperCase();
while (steps.length() < 16) steps = "0" + steps;
String fmtTime = String.format("%1$-11s", Time);
String utcTime = df.format(new Date(Time*1000));
System.out.print("| " + fmtTime + " | " + utcTime +
" | " + steps + " | ");
System.out.println(generateTOTP(mySeed, steps, "6",
"HmacSHA1") + " | SHA1 |");
System.out.println(
"+---------------+-----------------------+" +
"------------------+--------+--------+");
System.out.println();
#!/usr/bin/env python
import base64
import hashlib
import hmac
import struct
import time
def hotp(secret, num, digits=6, algorithm=hashlib.sha1):
key = base64.b32decode(secret, True)
msg = struct.pack(">Q", num)
h = hmac.new(key, msg, algorithm).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % (10**digits)
return h
def totp(secret, digits=6, algorithm=hashlib.sha1, period=30, time=time.time()):
num = int(time // period)
return hotp(secret, num, digits, algorithm)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment