developer tip

Python에서 Google Authenticator 구현

optionbox 2020. 8. 22. 08:40
반응형

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)을 시도했지만 secretGA 앱에서 제공된 키 동일합니다.

내가 가진 질문

내 질문은 다음과 같습니다.

  1. 내가 뭘 잘못하고 있죠?
  2. 파이썬에서 HOTP 및 / 또는 TOTP를 어떻게 생성 할 수 있습니까?
  3. 이에 대한 기존 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 토큰이 생성 될 때마다 증가하는 숫자 (과거에 마지막으로 성공한 정수를 확인한 후 한정된 정수 수를 확인하여 서버에서 해결해야 함)

사용 방법

  1. Generate secret (it must be correct parameter for base64.b32decode()) - preferably 16-char (no = signs), as it surely worked for both script and Google Authenticator.
  2. 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 of intervals_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 working intervals_no value (thus you should probably store it somewhere).
  3. 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).
  4. 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

반응형