• 动态令牌-(OTP,HOTP,TOTP)-基本原理


    名词解释和基本介绍

    OTP 是 One-Time Password的简写,表示一次性密码。

    HOTP 是HMAC-based One-Time Password的简写,表示基于HMAC算法加密的一次性密码。

      是事件同步,通过某一特定的事件次序及相同的种子值作为输入,通过HASH算法运算出一致的密码。

    TOTP 是Time-based One-Time Password的简写,表示基于时间戳算法的一次性密码。

      是时间同步,基于客户端的动态口令和动态口令验证服务器的时间比对,一般每60秒产生一个新口令,要求客户端和服务器能够十分精确的保持正确的时钟,客户端和服务端基于时间计算的动态口令才能一致。  

    原理介绍

    OTP基本原理

    计算OTP串的公式

    1. OTP(K,C) = Truncate(HMAC-SHA-1(K,C))

    其中,

    K表示秘钥串;

    C是一个数字,表示随机数;

    HMAC-SHA-1表示使用SHA-1做HMAC;

    Truncate是一个函数,就是怎么截取加密后的串,并取加密后串的哪些字段组成一个数字。

    对HMAC-SHA-1方式加密来说,Truncate实现如下。

    • HMAC-SHA-1加密后的长度得到一个20字节的密串;
    • 取这个20字节的密串的最后一个字节,取这字节的低4位,作为截取加密串的下标偏移量;
    • 按照下标偏移量开始,获取4个字节,按照大端方式组成一个整数;
    • 截取这个整数的后6位或者8位转成字符串返回。

    python代码

        def generate_otp(self, input):
            """
            :param input: the HMAC counter value to use as the OTP input.
                Usually either the counter, or the computed integer based on the Unix timestamp
            :type input: int
            """
            if input < 0:
                raise ValueError('input must be positive integer')
            hasher = hmac.new(self.byte_secret(), self.int_to_bytestring(input), self.digest)
            hmac_hash = bytearray(hasher.digest())
            offset = hmac_hash[-1] & 0xf
            code = ((hmac_hash[offset] & 0x7f) << 24 |
                    (hmac_hash[offset + 1] & 0xff) << 16 |
                    (hmac_hash[offset + 2] & 0xff) << 8 |
                    (hmac_hash[offset + 3] & 0xff))
            str_code = str(code % 10 ** self.digits)
            while len(str_code) < self.digits:
                str_code = '0' + str_code
    
            return str_code
    

      

    返回的结果就是看到一个数字的动态密码。

    HOTP基本原理

    知道了OTP的基本原理,HOTP只是将其中的参数C变成了随机数

    公式修改一下

    1. HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

    HOTP: Generates the OTP for the given count

    即:C作为一个参数,获取动态密码。

    HOTP的python代码片段:

    class HOTP(OTP):
        def at(self, count):
            """
            Generates the OTP for the given count
            @param [Integer] count counter
            @returns [Integer] OTP
            """
            return self.generate_otp(count)
    

      

    一般规定HOTP的散列函数使用SHA2,即:基于SHA-256 or SHA-512 [SHA2] 的散列函数做事件同步验证;

    TOTP基本原理

    TOTP只是将其中的参数C变成了由时间戳产生的数字。

    1. TOTP(K,C) = HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

    不同点是TOTP中的C是时间戳计算得出。

    1. C = (T - T0) / X;

    T 表示当前Unix时间戳

    T0一般取值为 0.

    X 表示时间步数,也就是说多长时间产生一个动态密码,这个时间间隔就是时间步数X,系统默认是30秒;

    例如:

    T0 = 0;

    X = 30;

    T = 30 ~ 59, C = 1; 表示30 ~ 59 这30秒内的动态密码一致。

    T = 60 ~ 89, C = 2; 表示30 ~ 59 这30秒内的动态密码一致。

    不同厂家使用的时间步数不同;

    • 阿里巴巴的身份宝使用的时间步数是60秒;
    • 宁盾令牌使用的时间步数是60秒;
    • Google的 身份验证器的时间步数是30秒;
    • 腾讯的Token时间步数是60秒;

    TOTP的python代码片段:

    class TOTP(OTP):
        def __init__(self, *args, **kwargs):
            """
            @option options [Integer] interval (30) the time interval in seconds
                for OTP This defaults to 30 which is standard.
            """
            self.interval = kwargs.pop('interval', 30)
            super(TOTP, self).__init__(*args, **kwargs)
        def now(self):
            """
            Generate the current time OTP
            @return [Integer] the OTP as an integer
            """
            return self.generate_otp(self.timecode(datetime.datetime.now()))
     
        def timecode(self, for_time):
            i = time.mktime(for_time.timetuple())
            return int(i / self.interval)
    

      

    代码说明

    self.interval 是时间步数X

    datetime.datetime.now()为当前的Unix时间戳

    timecode表示(T - T0) / X,即获取获取动态密码计算的随机数。

    TOTP 的实现可以使用HMAC-SHA-256或者HMAC-SHA-512散列函数;

    python的otp实现

    https://pypi.python.org/pypi/pyotp

    https://github.com/pyotp/pyotp

    基于pyotp的简单应用

    >> import base64
    >>> base64.b32encode('This is my secret key')
    'KRUGS4ZANFZSA3LZEBZWKY3SMV2CA23FPE======'
    >>> secretKey = base64.b32encode('This is my secret key')
    >>> import pyotp
    >>> totp = pyotp.TOTP(secretKey)
    >>> totp.now()
    423779
    

      

    程序的简单说明

    加载base64的模块,将我的秘钥做一下base32的加密,加载pyotp模块,otp使用base32加密后的秘钥传作为种子,生成随机数字验证的。

    可以使用pyotp和expect一起实现基于google authenticator的自动登录(免去每次双认证,输入密码和动态密码)。

    pyotp的TOTP的使用说明(官网)

    totp = pyotp.TOTP('base32secret3232')
    totp.now() # => 492039
     
    # OTP verified for current time
    totp.verify(492039) # => True
    time.sleep(30)
    totp.verify(492039) # => False
    

      pyotp的HOTP的使用说明(官网)

    hotp = pyotp.HOTP('base32secret3232')
    hotp.at(0) # => 260182
    hotp.at(1) # => 55283
    hotp.at(1401) # => 316439
     
    # OTP verified with a counter
    hotp.verify(316439, 1401) # => True
    hotp.verify(316439, 1402) # => False
    

      

    使用场景

    • 服务器登录动态密码验证(如阿里云ECS登录,腾讯机房服务器登录等);
    • 公司VPN登录双因素验证;
    • 网络接入radius动态密码;
    • 银行转账动态密码;
    • 网银、网络游戏的实体动态口令牌;
    • 等动态密码验证的应用场景。

    市面上基于HOTP的产品

    Google基于TOTP的开源实现

    https://github.com/google/google-authenticator

    RFC6238中TOTP基于java代码的实现。

    golang的一个otp做的不错的实现

    https://github.com/gitchs/gootp

    RFC参考

    RFC 4226 One-Time Password and HMAC-based One-Time Password.

    RFC 6238 Time-based One-Time Password.

    RFC 2104 HMAC Keyed-Hashing for Message Authentication.

    Done.

  • 相关阅读:
    Singleton(单例模式)的一种实现 -- 基于【惰性】适用于【大对象】的一种生产实践
    001.Getting Started -- 【入门指南】
    SparkStreaming高级算子应用【combineByKey、transform,checkpoint】
    Solr基础理论【相关度计算】
    Solr基础理论【排名检索、查准率、查全率】
    Solr基础理论【倒排索引,模糊查询】
    Impala快速入门
    Redis特点分析及性能优化
    电力系统【第八章:电力系统不对称故障的分析与计算】
    SparkStreaming之checkpoint检查点
  • 原文地址:https://www.cnblogs.com/navysummer/p/11943319.html
Copyright © 2020-2023  润新知