Python에서 Google Authenticator 구현
Google Authenticator 애플리케이션을 사용하여 생성 할 수있는 일회용 비밀번호를 사용하려고 합니다 .
Google Authenticator의 기능
기본적으로 Google Authenticator는 두 가지 유형의 비밀번호를 구현합니다.
- HOTP - 암호를 의미 HMAC 기반의 일회용 비밀번호로 준수, 각 호출로 변경 RFC4226 하고,
- TOTP -30 초마다 변경되는 시간 기반 일회용 비밀번호입니다 (내가 아는 한).
Google Authenticator는 여기에서 오픈 소스로도 사용할 수 있습니다. code.google.com/p/google-authenticator
현재 코드
HOTP 및 TOTP 암호를 생성하는 기존 솔루션을 찾고 있었지만 많이 찾지 못했습니다. 내가 가진 코드는 HOTP 생성을 담당하는 다음 스 니펫입니다.
import hmac, base64, struct, hashlib, time
def get_token(secret, digest_mode=hashlib.sha1, intervals_no=None):
if intervals_no == None:
intervals_no = int(time.time()) // 30
key = base64.b32decode(secret)
msg = struct.pack(">Q", intervals_no)
h = hmac.new(key, msg, digest_mode).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return h
내가 직면 한 문제는 위 코드를 사용하여 생성 한 비밀번호가 Android 용 Google Authenticator 앱을 사용하여 생성 한 비밀번호와 동일하지 않다는 것입니다. 여러 intervals_no
값 (정확히 처음 10000,으로 시작 intervals_no = 0
)을 시도했지만 secret
GA 앱에서 제공된 키 와 동일합니다.
내가 가진 질문
내 질문은 다음과 같습니다.
- 내가 뭘 잘못하고 있죠?
- 파이썬에서 HOTP 및 / 또는 TOTP를 어떻게 생성 할 수 있습니까?
- 이에 대한 기존 Python 라이브러리가 있습니까?
요약하자면, Python 코드 내에서 Google Authenticator 인증을 구현하는 데 도움이되는 단서를 제공해주세요.
내 질문에 현상금을 설정하고 싶었지만 솔루션을 만드는 데 성공했습니다. 내 문제는 잘못된 secret
키 값과 관련된 것 같습니다 ( base64.b32decode()
기능에 대한 올바른 매개 변수 여야 함 ).
아래에 사용 방법에 대한 설명과 함께 전체 작업 솔루션을 게시합니다.
암호
다음 코드로 충분합니다. 또한 onetimepass 라는 별도의 모듈로 GitHub에 업로드했습니다 ( https://github.com/tadeck/onetimepass ).
import hmac, base64, struct, hashlib, time
def get_hotp_token(secret, intervals_no):
key = base64.b32decode(secret, True)
msg = struct.pack(">Q", intervals_no)
h = hmac.new(key, msg, hashlib.sha1).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return h
def get_totp_token(secret):
return get_hotp_token(secret, intervals_no=int(time.time())//30)
두 가지 기능이 있습니다.
get_hotp_token()
일회용 토큰 생성 (1 회 사용 후 무효화되어야 함)get_totp_token()
시간에 따라 토큰을 생성합니다 (30 초 간격으로 변경됨).
매개 변수
매개 변수와 관련하여 :
secret
서버 (위 스크립트)와 클라이언트 (Google Authenticator, 애플리케이션 내에서 비밀번호로 제공)에 알려진 비밀 값입니다.intervals_no
토큰이 생성 될 때마다 증가하는 숫자 (과거에 마지막으로 성공한 정수를 확인한 후 한정된 정수 수를 확인하여 서버에서 해결해야 함)
사용 방법
- Generate
secret
(it must be correct parameter forbase64.b32decode()
) - preferably 16-char (no=
signs), as it surely worked for both script and Google Authenticator. - Use
get_hotp_token()
if you want one-time passwords invalidated after each use. In Google Authenticator this type of passwords i mentioned as based on the counter. For checking it on the server you will need to check several values ofintervals_no
(as you have no quarantee that user did not generate the pass between the requests for some reason), but not less than the last workingintervals_no
value (thus you should probably store it somewhere). - Use
get_totp_token()
, if you want a token working in 30-second intervals. You have to make sure both systems have correct time set (meaning that they both generate the same Unix timestamp in any given moment in time). - Make sure to protect yourself from brute-force attack. If time-based password is used, then trying 1000000 values in less than 30 seconds gives 100% chance of guessing the password. In case of HMAC-based passowrds (HOTPs) it seems to be even worse.
Example
When using the following code for one-time HMAC-based password:
secret = 'MZXW633PN5XW6MZX'
for i in xrange(1, 10):
print i, get_hotp_token(secret, intervals_no=i)
you will get the following result:
1 448400
2 656122
3 457125
4 35022
5 401553
6 581333
7 16329
8 529359
9 171710
which is corresponding to the tokens generated by the Google Authenticator app (except if shorter than 6 signs, app adds zeros to the beginning to reach a length of 6 chars).
I wanted a python script to generate TOTP password. So, I wrote the python script. This is my implementation. I have this info on wikipedia and some knowledge about HOTP and TOTP to write this script.
import hmac, base64, struct, hashlib, time, array
def Truncate(hmac_sha1):
"""
Truncate represents the function that converts an HMAC-SHA-1
value into an HOTP value as defined in Section 5.3.
http://tools.ietf.org/html/rfc4226#section-5.3
"""
offset = int(hmac_sha1[-1], 16)
binary = int(hmac_sha1[(offset * 2):((offset * 2) + 8)], 16) & 0x7fffffff
return str(binary)
def _long_to_byte_array(long_num):
"""
helper function to convert a long number into a byte array
"""
byte_array = array.array('B')
for i in reversed(range(0, 8)):
byte_array.insert(0, long_num & 0xff)
long_num >>= 8
return byte_array
def HOTP(K, C, digits=6):
"""
HOTP accepts key K and counter C
optional digits parameter can control the response length
returns the OATH integer code with {digits} length
"""
C_bytes = _long_to_byte_array(C)
hmac_sha1 = hmac.new(key=K, msg=C_bytes, digestmod=hashlib.sha1).hexdigest()
return Truncate(hmac_sha1)[-digits:]
def TOTP(K, digits=6, window=30):
"""
TOTP is a time-based variant of HOTP.
It accepts only key K, since the counter is derived from the current time
optional digits parameter can control the response length
optional window parameter controls the time window in seconds
returns the OATH integer code with {digits} length
"""
C = long(time.time() / window)
return HOTP(K, C, digits=digits)
참고URL : https://stackoverflow.com/questions/8529265/google-authenticator-implementation-in-python
'developer tip' 카테고리의 다른 글
C #에 JWT (JSON Web Token) 예제가 있습니까? (0) | 2020.08.22 |
---|---|
Visual Studio 2013 git, 마스터 분기 만 나열 됨 (0) | 2020.08.22 |
PHP cURL 대 file_get_contents (0) | 2020.08.22 |
SQL 대신 XML을 언제 사용합니까? (0) | 2020.08.22 |
C ++ 가상 함수를 안전하게 재정의 (0) | 2020.08.22 |