一次性密码(英语:One Time Password,简称OTP),又称动态密码或单次有效密码,是指计算器系统或其他数字设备上只能使用一次的密码,有效期为只有一次登录会话或交易。OTP 避免了一些与传统基于(静态)密码认证相关系的缺点;一些实现还纳入了双因素认证,确保单次有效密码需要访问一个人有的某件事物(如内置 OTP 计算器的小钥匙挂件设备)以及一个人知道的某件事物(如 PIN)。

1.原理

动态密码的产生方式,主要是以时间差作为服务器与密码产生器的同步条件。在需要登录的时候,就利用密码产生器产生动态密码,OTP一般分为计次使用以及计时使用两种,计次使用的OTP产出后,可在不限时间内使用;计时使用的OTP则可设置密码有效时间,从30秒到两分钟不等,而OTP在进行认证之后即废弃不用,下次认证必须使用新的密码,增加了试图不经授权访问有限制资源的难度。

2.优势

动态密码的解决方案有以下几个优点:

  1. 解决用户在密码的记忆与保存上的困难性。
  2. 由于密码只能使用一次,而且因为是动态产生,所以不可预测,也只有一次的使用有效性,可以大为提升使用的安全程度。

3.形式

OTP从技术来分有三种形式, 时间同步、事件同步、挑战/应答。

  • 时间同步
    原理是基于 动态令牌和 动态口令验证服务器的时间比对,基于 时间同步的 令牌,一般每60秒产生一个新口令,要求服务器能够十分精确的保持正确的时钟,同时对其令牌的晶振频率有严格的要求,这种技术对应的终端是硬件令牌。

  • 事件同步
    基于事件同步的令牌,其原理是通过某一特定的事件次序及相同的种子值作为输入,通过HASH算法中运算出一致的密码。

  • 挑战/应答
    常用于的网上业务,在网站/应答上输入 服务端下发的 挑战码, 动态令牌输入该挑战码,通过内置的算法上生成一个6/8位的随机数字,口令一次有效,这种技术目前应用最为普遍,包括刮刮卡、短信密码、动态令牌也有挑战/应答形式。
    主流的动态令牌技术是时间同步和挑战/应答两种形式。

4.OTP实现源码

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.UndeclaredThrowableException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;/*** @author yuangang.lyg* @version TOTP.java, v 0.1 2022年01月11日 10:30 AM yuangang.lyg*/
public class TOTP {private static final int[] DIGITS_POWER// 0 1  2   3    4     5      6       7        8= {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};/*** This method generates a TOTP value for the given* set of parameters.** @param key:          the shared secret, HEX encoded* @param time:         a value that reflects a time* @param returnDigits: number of digits to return* @return: a numeric String in base 10 that include truncationDigits digits*/public static String generateTOTP(String key, String time, String returnDigits) {return generateTOTP(key, time, returnDigits, "HmacSHA1");}/*** This method generates a TOTP value for the given* set of parameters.** @param key:          the shared secret, HEX encoded* @param time:         a value that reflects a time* @param returnDigits: number of digits to return* @return: a numeric String in base 10 that includes truncationDigits digits*/public static String generateTOTP256(String key, String time, String returnDigits) {return generateTOTP(key, time, returnDigits, "HmacSHA256");}/*** This method generates a TOTP value for the given* set of parameters.** @param key:          the shared secret, HEX encoded* @param time:         a value that reflects a time* @param returnDigits: number of digits to return* @return: a numeric String in base 10 that includes truncationDigits digits*/public static String generateTOTP512(String key, String time, String returnDigits) {return generateTOTP(key, time, returnDigits, "HmacSHA512");}/*** This method generates a TOTP value for the given* set of parameters.** @param key:          the shared secret, HEX encoded* @param time:         a value that reflects a time* @param returnDigits: number of digits to return* @param crypto:       the crypto function to use* @return: a numeric String in base 10 that includes truncationDigits digits*/public static String generateTOTP(String key, String time, String returnDigits, String crypto) {int codeDigits = Integer.decode(returnDigits);StringBuilder result;// Using the counter// First 8 bytes are for the movingFactor// Compliant with base RFC 4226 (HOTP)StringBuilder timeBuilder = new StringBuilder(time);while (timeBuilder.length() < 16) {timeBuilder.insert(0, "0");}time = timeBuilder.toString();// Get the HEX in a Byte[]byte[] msg = hexStr2Bytes(time);byte[] k = hexStr2Bytes(key);byte[] hash = hmac_sha(crypto, k, msg);// put selected bytes into result intint offset = hash[hash.length - 1] & 0xf;int binary = ((hash[offset] & 0x7f) << 24) |((hash[offset + 1] & 0xff) << 16) |((hash[offset + 2] & 0xff) << 8) |(hash[offset + 3] & 0xff);int otp = binary % DIGITS_POWER[codeDigits];result = new StringBuilder(Integer.toString(otp));while (result.length() < codeDigits) {result.insert(0, "0");}return result.toString();}private TOTP() {}/*** This method uses the JCE to provide the crypto algorithm.* HMAC computes a Hashed Message Authentication Code with the* crypto hash algorithm as a parameter.** @param crypto:   the crypto algorithm (HmacSHA1, HmacSHA256,*                  HmacSHA512)* @param keyBytes: the bytes to use for the HMAC key* @param text:     the message or text to be authenticated*/private static byte[] hmac_sha(String crypto, byte[] keyBytes, byte[] text) {try {Mac hmac;hmac = Mac.getInstance(crypto);SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");hmac.init(macKey);return hmac.doFinal(text);} catch (GeneralSecurityException gse) {throw new UndeclaredThrowableException(gse);}}/*** This method converts a HEX string to Byte[]** @param hex: the HEX string* @return: a byte array*/private static byte[] hexStr2Bytes(String hex) {// Adding one byte to get the right conversion// Values starting with "0" can be convertedbyte[] bArray = new BigInteger("10" + hex, 16).toByteArray();// Copy all the REAL bytes, not the "first"byte[] ret = new byte[bArray.length - 1];System.arraycopy(bArray, 1, ret, 0, ret.length);return ret;}public static void main(String[] args) {// import org.apache.commons.lang3.RandomStringUtils// Seed for HMAC-SHA1 - 20 bytesString seed = RandomStringUtils.randomNumeric(40);// Seed for HMAC-SHA256 - 32 bytesString seed32 = RandomStringUtils.randomNumeric(64);// Seed for HMAC-SHA512 - 64 bytesString seed64 = RandomStringUtils.randomNumeric(128);long T0 = 0;long X = 30;String returnDigits = "6";long[] testTime = {59L, 1011217109L, 1121151171L, 1234567890L, 2008000000L, 20000700000L};StringBuilder steps;DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");df.setTimeZone(TimeZone.getTimeZone("UTC"));try {System.out.println("+------------------seed:" + seed);System.out.println("+------------------seed32:" + seed32);System.out.println("+------------------seed64:" + seed64);System.out.println("+---------------+-----------------------+" + "------------------+--------+--------+");System.out.println("|  Time(sec)    |   Time (UTC format)   " + "| Value of T(Hex)  |  TOTP  | Mode   |");System.out.println("+---------------+-----------------------+" + "------------------+--------+--------+");for (long l : testTime) {long T = (l - T0) / X;steps = new StringBuilder(Long.toHexString(T).toUpperCase());while (steps.length() < 16) {steps.insert(0, "0");}String fmtTime = String.format("%1$-11s", l);String utcTime = df.format(new Date(l * 1000));System.out.print("|  " + fmtTime + "  |  " + utcTime + "  | " + steps + " |");System.out.println(generateTOTP(seed, steps.toString(), returnDigits, "HmacSHA1") + "| SHA1   |");System.out.print("|  " + fmtTime + "  |  " + utcTime + "  | " + steps + " |");System.out.println(generateTOTP(seed32, steps.toString(), returnDigits, "HmacSHA256") + "| SHA256 |");System.out.print("|  " + fmtTime + "  |  " + utcTime + "  | " + steps + " |");System.out.println(generateTOTP(seed64, steps.toString(), returnDigits, "HmacSHA512") + "| SHA512 |");System.out.println("+---------------+-----------------------+" + "------------------+--------+--------+");}} catch (final Exception e) {System.out.println("Error : " + e);}}
}

5.OTP实现结果

+------------------seed:2572881420313506239229572394774390734264
+------------------seed32:7171838149487408940176086224127987212200599631352550591232454712
+------------------seed64:19880891091630914017193921493157236846471588454806106066014992004427631493340197961710656590274688793505864460624254023701200446
+---------------+-----------------------+------------------+--------+--------+
|  Time(sec)    |   Time (UTC format)   | Value of T(Hex)  |  TOTP  | Mode   |
+---------------+-----------------------+------------------+--------+--------+
|  59           |  1970-01-01 00:00:59  | 0000000000000001 |131174| SHA1   |
|  59           |  1970-01-01 00:00:59  | 0000000000000001 |692965| SHA256 |
|  59           |  1970-01-01 00:00:59  | 0000000000000001 |819515| SHA512 |
+---------------+-----------------------+------------------+--------+--------+
|  1011217109   |  2002-01-16 21:38:29  | 00000000020254E4 |120935| SHA1   |
|  1011217109   |  2002-01-16 21:38:29  | 00000000020254E4 |725330| SHA256 |
|  1011217109   |  2002-01-16 21:38:29  | 00000000020254E4 |686186| SHA512 |
+---------------+-----------------------+------------------+--------+--------+
|  1121151171   |  2005-07-12 06:52:51  | 00000000023A3F39 |000140| SHA1   |
|  1121151171   |  2005-07-12 06:52:51  | 00000000023A3F39 |353761| SHA256 |
|  1121151171   |  2005-07-12 06:52:51  | 00000000023A3F39 |419397| SHA512 |
+---------------+-----------------------+------------------+--------+--------+
|  1234567890   |  2009-02-13 23:31:30  | 000000000273EF07 |541300| SHA1   |
|  1234567890   |  2009-02-13 23:31:30  | 000000000273EF07 |314083| SHA256 |
|  1234567890   |  2009-02-13 23:31:30  | 000000000273EF07 |207428| SHA512 |
+---------------+-----------------------+------------------+--------+--------+
|  2008000000   |  2033-08-18 17:46:40  | 0000000003FD5255 |135366| SHA1   |
|  2008000000   |  2033-08-18 17:46:40  | 0000000003FD5255 |885322| SHA256 |
|  2008000000   |  2033-08-18 17:46:40  | 0000000003FD5255 |691781| SHA512 |
+---------------+-----------------------+------------------+--------+--------+
|  20000700000  |  2603-10-19 14:00:00  | 0000000027BCE1D0 |780526| SHA1   |
|  20000700000  |  2603-10-19 14:00:00  | 0000000027BCE1D0 |158658| SHA256 |
|  20000700000  |  2603-10-19 14:00:00  | 0000000027BCE1D0 |808290| SHA512 |
+---------------+-----------------------+------------------+--------+--------+

参考引用rfc6238:TOTP: Time-Based One-Time Password Algorithm

OTP一次性动态密码工具Java实现相关推荐

  1. OTP一次性动态密码工具实现

    对于企业内部信息安全或行业安全合规性需求,3A认证.授权.审计是必要的基础安全审查项.认证安全机制要求双因素认证,从技术要可使用基于数字证书和OTP来实现满足. OTP分为两种技术算法HOTP(基于次 ...

  2. 【TOTP】TOTP算法(基于时间的一次性动态密码)原理介绍 简要逻辑实现说明

    什么是TOTP(Time-base One-Time Password)? Time-base One-Time Password翻译过来是基于时间的一次性密码.这里以QQ令牌为例,解释下TOTP. ...

  3. OTP:Java一次动态密码、付款码原理

    1. 什么是OTP 一次性密码(One Time Password,简称OTP),又称"一次性口令",是指只能使用一次的密码. 2. OTP原理 动态密码的产生方式,主要是以时间差 ...

  4. java 动态密码错误_什么是OTP:Java一次动态密码、付款码原理

    1. 什么是OTP 一次性密码(One Time Password,简称OTP),又称"一次性口令",是指只能使用一次的密码. 1 2. OTP原理 动态密码的产生方式,主要是以时 ...

  5. OWA动态密码短信认证方案,解决outlook邮件双因子认证问题

    OWA(Outlook Web Access),是Exchange邮件的Web访问形式.OWA作为Exchange的Web访问客户端,负责提供邮件Web访问页面.用户只需要使用浏览器通过互联网就能访问 ...

  6. java 手机动态口令_动态密码TOTP的Java实现

    一.HOTP HOTP 算法,全称是"An HMAC-Based One-Time Password Algorithm",是一种基于事件计数的一次性密码生成算法,详细的算法介绍可 ...

  7. 【IoT】加密与安全:动态密码 OTP 算法详解

    动态密码,亦称一次性密码(One Time Password, 简称 OTP),是一种高效简单又比较安全的密码生成算法,在我们的生活以及工作中随处可见. 1.动态密码背景介绍 动态密码是指随着某一事件 ...

  8. OTP动态口令的Java实现

    最近项目需要在应用中在登录时增加otp动态口令,作为二次密码的验证,原谅本人的孤陋寡闻居然是初次听说这技术,然后各种在网上查相关资料,发现想研究透此中算法时间太紧迫.鉴于此本人就不细说这个技术原理了( ...

  9. OTP动态口令之Java实现双重认证

    前言 双重认证(英语:Two-factor authentication,缩写为2FA),又译为双重验证.双因素认证.二元认证,又称两步骤验证(2-Step Verification,又译两步验证), ...

最新文章

  1. 【CVPR 2022】只用一张图+相机走位,AI就能脑补周围环境
  2. H3C——BGP联盟配置
  3. JetBrains WebStorm 快捷键失效
  4. 使用maven导入任意jar包
  5. TypeScript 的类型检查和类型保护
  6. MsXml创建和解析XML示例
  7. vSphere7.0添加第三方驱动
  8. ClassCastException: XXX are in unnamed module of loader ‘app‘异常分析
  9. IOS-Touch ID的简单使用
  10. Unity中自制Animation+播放完毕相应事件
  11. vscode搭建c++开发环境
  12. 我们平常习惯讲的手机容量-运行内存(RAM)和机身内存(ROM)的理解
  13. 计算机系统使用寿命,笔记本电脑的使用寿命是多久,你了解吗?
  14. 揭穿微信朋友圈卖东西月入几万的真相
  15. 少林寺、孔子网站被黑
  16. java-net-php-python-jsp房屋出租网站-视频演示计算机毕业设计程序
  17. JAVA和SQL中时间的格式化 (yyyy-MM-dd HH:mm:ss转换规则)知识总结
  18. 研究生的压力应对与心理健康期末考试答案
  19. Electron理论知识 8 - 工具神器(Fiddle)
  20. 【软件工程】UML必知必会

热门文章

  1. 痞子衡嵌入式:利用i.MXRT1060,1010上新增的FlexSPI地址重映射(Remap)功能可安全OTA...
  2. mysql提示Your password does not satisfy the current policy requirements的解决方案
  3. Day127.JUC:线程间通信(Conditon)、并发容器类(CopyOnWrite)、JUC强大辅助类、Callable
  4. 小皮面板使用PHP,phpstudy-linux面板(小皮面板)1.0 评测
  5. 代码随想录Day62
  6. windows安装docker desktop
  7. TGP和UDP的区别
  8. adg不同系统_ADG 增强数据治理
  9. 跟涛哥一起学嵌入式 第10集:关于校招,应届生都应该看一看
  10. 数据可视化:一张图胜过千言万语