1. 什么是OTP

    一次性密码(One Time Password,简称OTP),又称“一次性口令”,是指只能使用一次的密码。

2. OTP原理

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

3.Java实现全代码TOTP

该代码可以直接运行

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.UndeclaredThrowableException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.util.Date;public class TOTP {public static void main(String[] args) {try {for (int j = 0; j < 10; j++) {String totp = generateMyTOTP("account01", "12345");System.out.println(String.format("加密后: %s", totp));Thread.sleep(1000);}} catch (final Exception e) {e.printStackTrace();}}/*** 共享密钥*/private static final String SECRET_KEY = "ga35sdia43dhqj6k3f0la";/*** 时间步长 单位:毫秒 作为口令变化的时间周期*/private static final long STEP = 5000;/*** 转码位数 [1-8]*/private static final int CODE_DIGITS = 8;/*** 初始化时间*/private static final long INITIAL_TIME = 0;/*** 柔性时间回溯*/private static final long FLEXIBILIT_TIME = 5000;/*** 数子量级*/private static final int[] DIGITS_POWER = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};private TOTP() {}/*** 生成一次性密码** @param code 账户* @param pass 密码* @return String*/public static String generateMyTOTP(String code, String pass) {//        if (EmptyUtil.isEmpty(code) || EmptyUtil.isEmpty(pass)) {//            throw new RuntimeException("账户密码不许为空");
//        }long now = new Date().getTime();String time = Long.toHexString(timeFactor(now)).toUpperCase();return generateTOTP(code + pass + SECRET_KEY, time);}/*** 刚性口令验证** @param code 账户* @param pass 密码* @param totp 待验证的口令* @return boolean*/public static boolean verifyTOTPRigidity(String code, String pass, String totp) {return generateMyTOTP(code, pass).equals(totp);}/*** 柔性口令验证** @param code 账户* @param pass 密码* @param totp 待验证的口令* @return boolean*/public static boolean verifyTOTPFlexibility(String code, String pass, String totp) {long now = new Date().getTime();String time = Long.toHexString(timeFactor(now)).toUpperCase();String tempTotp = generateTOTP(code + pass + SECRET_KEY, time);if (tempTotp.equals(totp)) {return true;}String time2 = Long.toHexString(timeFactor(now - FLEXIBILIT_TIME)).toUpperCase();String tempTotp2 = generateTOTP(code + pass + SECRET_KEY, time2);return tempTotp2.equals(totp);}/*** 获取动态因子** @param targetTime 指定时间* @return long*/private static long timeFactor(long targetTime) {return (targetTime - INITIAL_TIME) / STEP;}/*** 哈希加密** @param crypto   加密算法* @param keyBytes 密钥数组* @param text     加密内容* @return byte[]*/private static byte[] hmac_sha(String crypto, byte[] keyBytes, byte[] text) {try {Mac hmac;hmac = Mac.getInstance(crypto);SecretKeySpec macKey = new SecretKeySpec(keyBytes, "AES");hmac.init(macKey);return hmac.doFinal(text);} catch (GeneralSecurityException gse) {throw new UndeclaredThrowableException(gse);}}private static byte[] hexStr2Bytes(String hex) {byte[] bArray = new BigInteger("10" + hex, 16).toByteArray();byte[] ret = new byte[bArray.length - 1];System.arraycopy(bArray, 1, ret, 0, ret.length);return ret;}private static String generateTOTP(String key, String time) {return generateTOTP(key, time, "HmacSHA1");}private static String generateTOTP256(String key, String time) {return generateTOTP(key, time, "HmacSHA256");}private static String generateTOTP512(String key, String time) {return generateTOTP(key, time, "HmacSHA512");}private static String generateTOTP(String key, String time, String crypto) {StringBuilder timeBuilder = new StringBuilder(time);while (timeBuilder.length() < 16)timeBuilder.insert(0, "0");time = timeBuilder.toString();byte[] msg = hexStr2Bytes(time);byte[] k = key.getBytes();byte[] hash = hmac_sha(crypto, k, msg);return truncate(hash);}/*** 截断函数** @param target 20字节的字符串* @return String*/private static String truncate(byte[] target) {StringBuilder result;int offset = target[target.length - 1] & 0xf;int binary = ((target[offset] & 0x7f) << 24)| ((target[offset + 1] & 0xff) << 16)| ((target[offset + 2] & 0xff) << 8) | (target[offset + 3] & 0xff);int otp = binary % DIGITS_POWER[CODE_DIGITS];result = new StringBuilder(Integer.toString(otp));while (result.length() < CODE_DIGITS) {result.insert(0, "0");}return result.toString();}
}

该OTP运行后,得到的是可以校验是否有效的口令,但是无法判断这个口令属于哪一个用户,像付款码,当使用人数不断增多时,单纯该数字无法确认哪一个人的付款码,则现在需要在这串数据中,融入用户ID,其计算公式可以:

4、付款码计算与提取

付款码=TOTP * 质数 +  用户ID
质数取值需要大于最大用户ID,如:当前系统设计最大承受用户有9900人,则质数可以设定必须大于9900的数值(9991).

提起用户ID

用户ID = 付款码 % 质数
“%”表示取余

提取TOTP

TOTP=付款码 / 质数
当付款码除质数后取整,则该数值为当前付款码中的OTP。

当服务器获取到付款码时:
1、首先提取TOTP,判断该口令是否有效,如果校验失败,则可以接口返回,付款码错误。
2、第一步校验通过后,查找缓存,判断在规定的一段时间内是否有使用过该付款码,并更新缓存,把该次记录写到缓存中。
3、第一步和第二步通过后,获取付款码中用户ID,将用户ID进行扣款操作。
4、服务器继续走剩下流程。

以上代码属于爱好研究属于原创,如需转载,请注明本文地址:
https://blog.csdn.net/qq_43655984/article/details/105598603

OTP:Java一次动态密码、付款码原理相关推荐

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

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

  2. BLE-NRF51822教程10—动态密码(配对码)

    本讲教程也是在 sdk中的的uart例子 的基础上修改实现动态密码(其实是配对码)的功能.Uart例子在以下目录中 XXX\Keil_v5\ARM\Pack\NordicSemiconductor\n ...

  3. javabean反射改字段内容_BAT程序员编写:深入理解 Java 反射和动态代理源码分析...

    什么是反射 反射(Reflection)是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. 通过反射机制,可以在运行时访问 Java ...

  4. Java多线程同步数据库,源码+原理+手写框架

    一.什么情况下会发生栈内存溢出? 1.栈是线程私有的,栈的生命周期和线程一样,每个方法在执行的时候就会创建一个栈帧,它包含局部变量表.操作数栈.动态链接.方法出口等信息,局部变量表又包括基本数据类型和 ...

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

    一次性密码(英语:One Time Password,简称OTP),又称动态密码或单次有效密码,是指计算器系统或其他数字设备上只能使用一次的密码,有效期为只有一次登录会话或交易.OTP 避免了一些与传 ...

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

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

  7. 动态密码 java_动态密码TOTP的Java实现

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

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

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

  9. 高级JAVA - 动态代理的实现原理和源码分析

    在之前的一篇文章中 , 我们简单了解了一下代理模式(JAVA设计模式 - 代理模式) , 本篇我们来学习一下动态代理的实现原理 , 以及源码是怎样的 . JDK动态代理的主要实现步骤如下 : 1 . ...

最新文章

  1. 软件体系架构模式之二分层体系结构
  2. QIIME 2用户文档. 19使用q2-vsearch聚类OTUs(2019.7)
  3. C#基础概念二十五问
  4. 手工编译Android程序
  5. 从零开始一步一步搭建Ubuntu Server服务器、修改数据源、安装Docker、配置镜像加速器、Compose部署Gitlab服务
  6. jquery学习之1.20-获取同辈元素和子元素
  7. leetcode 134. 加油站(Gas Station)
  8. python场景识别_python 场景
  9. IIS HTTP文件服务器搭建步骤
  10. Git下载并安装(完整、详细教程)
  11. 无线之minidwep-gtk
  12. 2011年国庆发布:(cppblog)C++博客十八罗汉造像
  13. 微信公众号申请需要哪些材料
  14. 微信小程序、公众号侵权投诉流程
  15. python,如何整体取消tab缩进【反方向缩进】
  16. War3快捷键大全—常用的键
  17. JAVA实现分治法的合并排序及解析
  18. libusb的简单使用
  19. 计算机再带word打不开,(电脑没有word 和excel)为什么我的电脑突然打不开EXCLE和WORD?...
  20. Mac的环境配置的详细步骤

热门文章

  1. ​金融风控的护航员——聊聊ERNIE在度小满用户风控的应用
  2. Microsoft Edge浏览器网页改为纯黑色(将浏览器网页底色改为黑色)
  3. 斩获微软offer后,我总结出这10个面试必备技巧(五星干货)
  4. 芜湖市计算机语言,2012年芜湖市小学计算机水平等级测评试卷(logo语言版)
  5. 关键字生成参考文案查找相似款,特卖淘宝达人有福了,自媒体时代的懒人助手
  6. WebGIS理论知识(七)—走进互联网地图
  7. 摩拜免押金是在阿里的哈罗猛烈攻击下的应对举措
  8. windows免安装版mysql
  9. python使用you-get下载视频
  10. 关于outlook签名图片大小的说明