如何在python中结合使用base32和hotp(一次性密码)?

时间:2019-06-07 16:22:59

标签: python python-3.x hmac one-time-password base32

对于一次大学练习,我想用python开发一个简单的hotp服务器-客户端系统。在这种情况下,客户端向服务器发送密码和一次性密码。服务器知道秘密,计算当前hotp并比较它接收的值。到目前为止,一切都很好。使用纯文本,这可以很好地工作,并且使用iOS应用程序“ OTP Auth”时得到的计算值相同。但是也有可能结合base32计算OTP。因此,我添加了几行代码将纯文本编码为base32,但是现在输出不正确。

假设我们使用的密码是“ 1234”,那么纯文本输出将是“ 110366”。很好但是,如果我将密码编码为base32,则输出应为“ 807244”,但我的程序计算为“ 896513”。有人知道为什么会这样吗?

我已经尝试使用其他机密,并在其他应用程序上进行了检查。结果总是一样。

import hmac
import hashlib
import array
import base64

counter = 0
digits = 6                      #Anzahl der Zeichen

def hotp(secret, c):
    global digits
    counter = extendCounter(c)
    hmac_sha1 = hmac.new(secret, counter, hashlib.sha1).hexdigest()
    return truncate(hmac_sha1)[-digits:]


def truncate(hmac_sha1):
    offset = int(hmac_sha1[-1], 16)
    binary = int(hmac_sha1[(offset * 2):((offset * 2) + 8)], 16) & 0x7fffffff
    return str(binary)


def extendCounter(long_num):
    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 main():
    secret = "1234"
    bSecret = secret.encode("UTF-8")
    bSecret = base64.b32encode(bSecret)
    otp = hotp(bSecret, counter)
    one_time_password = otp

我希望输出807244,但输出为896513

2 个答案:

答案 0 :(得分:1)

首先,必须指出secret.encode('UTF-8')的结果与base64.b32encode(bSecret)的结果具有完全相同的类型(就此而言,base64.b64encode(bSecret))—它们都返回{ {1}}个对象。另外值得注意的是,Python中的implementation of hmac没有提到base64 / base32编码。因此,简短的答案是,bytes的预期结果仅在共享密钥为base64 / UTF-8编码的blob时有效。

此简短代码段显示,实际上您可以给自己想要的任何字节807244,它会产生一些结果(因为在示例中,hotp被多次调用了,hotp已更改)

counter

如果您有更多关于为什么期望# ... everything from your example above ... secret = "1234" secret_bytes = secret.encode("UTF-8") secret_bytes >>> b'1234' b32_secret = base64.b32encode(bSecret) b32_secret >>> b'GEZDGNA=' b64_secret = base64.b64encode(bSecret) b64_secret >>> b'MTIzNA==' hotp(secret_bytes, counter) # just a UTF-8 blob works >>> '110366' hotp(b32_secret, counter) # base32/UTF-8 also works >>> '896513' hotp(b64_secret, counter) # base64/UTF-8 works as well >>> '806744' 用于base32 / UTF8 Blob的详细信息,我很乐意修改此答案。

答案 1 :(得分:0)

发现错误: 代替将机密转换为base32,该机密必须是Base32解码的值。同样,除了对这个值进行编码之外,还必须对其进行解码(“ base64.b32decode(bytes(saved_secret,'utf-8'))”)

所以正确的主体看起来像这样:

def main():
    secret = "V6X27L5P" #Base32 value
    secret = base64.b32decode(bytes(secret, 'utf-8'))
    one_time_password = hotp(secret, counter)