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
제가 직면한 문제는 위의 코드를 사용하여 생성한 암호가 안드로이드용 Google Authenticator 앱을 사용하여 생성한 암호와 다르다는 것입니다. 번 ,intervals_no
처음 10000을 값(10000으로 )으로 시작함, intervals_no = 0
, , , secret
GA 앱 내에서 제공되는 키와 동일합니다.
질문이 있습니다.
제 질문은 다음과 같습니다.
- 내가 뭘 잘못하고 있는 거지?
- 파이썬에서 HOTP 및/또는 TOTP를 생성하려면 어떻게 해야 합니까?
- 이를 위한 기존 파이썬 라이브러리가 있습니까?
요약: 제 파이썬 코드 내에서 구글 인증기 인증을 구현하는 데 도움이 될 단서를 주세요.
저는 제 질문에 현상금을 걸고 싶었지만, 해결책을 만드는 데 성공했습니다.나의 문제는 잘못된 값과 연결되어 있는 것처럼 보였습니다.secret
는 올(키바매변야함여수개른함)▁for▁be야)이어야 함)base64.b32decode()
함수)를 선택합니다.
아래에 사용 방법에 대한 설명과 함께 전체 작동 솔루션을 게시합니다.
코드
다음 코드로 충분합니다.저는 원타임패스라는 별도의 모듈로 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()
토큰을 사용 후 되어야 함).get_totp_token()
토큰을 간격으로 됨).
매개변수
매개 변수의 경우:
secret
는 서버 스크립트)및 Authenticator, 프로그램)에 입니다.intervals_no
토큰의 각 생성 후에 증가한 수입니다(이것은 아마도 과거에 마지막으로 성공한 정수를 확인한 후에 서버에서 일부 유한한 정수를 확인함으로써 해결되어야 합니다).)
사용방법
- 생성
secret
(에 대한 올바른 매개 변수여야 합니다.base64.b32decode()
) - 가급적이면 16-char(아니오)=
signs), 스크립트와 Google Authenticator 모두에 대해 확실히 작동했기 때문입니다. - 사용하다
get_hotp_token()
매번 사용한 후 일회성 암호를 무효화하려는 경우.Google Authenticator에서 카운터를 기준으로 이 유형의 암호를 언급했습니다.서버에서 확인하려면 다음의 여러 값을 확인해야 합니다.intervals_no
(사용자가 어떤 이유로 요청 간의 통과를 생성하지 않은 검역자가 없기 때문에) 마지막 작업보다 작지 않습니다.intervals_no
value(아마도 어딘가에 저장해야 할 경우). - 사용하다
get_totp_token()
토큰이 30초 간격으로 작동하기를 원하는 경우.두 시스템 모두 시간 설정이 올바른지 확인해야 합니다. 즉, 두 시스템 모두 지정된 시점에 동일한 Unix 타임스탬프를 생성합니다. - 무차별 공격으로부터 자신을 보호해야 합니다.시간 기반 암호를 사용하는 경우 30초 이내에 1000000 값을 시도하면 암호를 100% 추측할 수 있습니다.HMAC 기반 암호(HOTP)의 경우에는 더욱 악화된 것으로 보입니다.
예
일회성 HMAC 기반 암호에 대해 다음 코드를 사용하는 경우:
secret = 'MZXW633PN5XW6MZX'
for i in xrange(1, 10):
print i, get_hotp_token(secret, intervals_no=i)
다음과 같은 결과를 얻을 수 있습니다.
1 448400
2 656122
3 457125
4 35022
5 401553
6 581333
7 16329
8 529359
9 171710
이는 Google Authenticator 앱에서 생성된 토큰에 해당합니다(6자 미만인 경우 제외). 앱은 시작 부분에 0을 추가하여 6자 길이에 도달합니다.
저는 파이썬 스크립트가 TOTP 비밀번호를 생성하기를 원했습니다.그래서 저는 파이썬 스크립트를 작성했습니다.이것이 제 구현입니다.저는 위키피디아에 이 정보와 이 스크립트를 작성하기 위한 HOTP와 TOTP에 대한 약간의 지식을 가지고 있습니다.
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)
@tadeck와 @Anish-Shah의 정답을 따름으로써, 사용하지 않고 코드를 얻는 더 간단한 방법이 있습니다.struct
추가 수입 방지:
""" TOTP """
import hmac
import time
def totp(key: bytes):
""" Calculate TOTP using time and key """
now = int(time.time() // 30)
msg = now.to_bytes(8, "big")
digest = hmac.new(key, msg, "sha1").digest()
offset = digest[19] & 0xF
code = digest[offset : offset + 4]
code = int.from_bytes(code, "big") & 0x7FFFFFFF
code = code % 1000000
return "{:06d}".format(code)
이것은 Python 3과 함께 작동합니다.
전화로 현재 TOTP 코드를 얻을 수 있습니다.totp(key)
여기서 "열쇠"는bytes
(기본 32 디코딩 키 포함).
언급URL : https://stackoverflow.com/questions/8529265/google-authenticator-implementation-in-python
'source' 카테고리의 다른 글
ADB 셸 입력 이벤트 (0) | 2023.08.15 |
---|---|
MySQL의 SELECT 문에 열을 올바르게 추가하는 방법은 무엇입니까? (0) | 2023.08.15 |
/usr/bin/codesign이 종료 코드 1과 함께 실패했습니다. (0) | 2023.08.15 |
Spring @Value 주석에서 기본값을 올바르게 지정하는 방법은 무엇입니까? (0) | 2023.08.15 |
jquery click on anchor 요소 힘을 맨 위로 스크롤하시겠습니까? (0) | 2023.08.15 |