加密与安全_TOTP 一次性密码生成算法

devtools/2024/10/4 14:58:01/

文章目录

  • Pre
  • TOTP是什么
  • TOTP 算法工作原理
  • TOTP 生成公式
  • TOTP 与 HOTP 的对比
  • Code
    • 生成TOTP
    • 验证 TOTP
    • 使用场景
    • 小结
  • TOTP 与 HOTP 的主要区别
  • TOTP 与 HOTP应用场景比较
  • TOTP 与 HOTP安全性分析

在这里插入图片描述

Pre

加密与安全_HTOP 一次性密码生成算法

https://github.com/samdjstevens/java-totp

https://medium.com/@rakesh.open.source/time-based-one-time-password-totp-java-implementation-82a472bd6bf9

https://gist.github.com/rakeshopensource/def80fac825c3e65804e0d080d2fa9a7


TOTP是什么

TOTP (Time-based One-Time Password) 是基于时间的动态密码生成算法,是 HOTP (基于HMAC的一次性密码) 的一个扩展。它的主要区别在于,TOTP 使用当前时间戳作为动态因子,而不是计数器。因此,生成的密码随时间变化,通常在一段时间(如30秒或60秒)内有效。


TOTP 算法工作原理

TOTP 使用当前时间戳与共享的密钥结合,生成一次性密码。以下是 TOTP 生成密码的主要步骤:

  1. 共享密钥:客户端和服务端预先共享一个密钥(通常是 Base32 编码),这和 HOTP 中的密钥是相同的。

  2. 时间戳:TOTP 使用当前时间戳,按时间步长(例如 30 秒)划分成时间段。每个时间段对应一个唯一的密码。

  3. 时间步数:将当前时间戳除以时间步长,得到时间步数。这个步数类似于 HOTP 中的计数器。

  4. HMAC 计算:使用共享的密钥和时间步数,使用 HMAC-SHA1 算法计算出一个哈希值。

  5. 截取密码:从 HMAC 的输出中提取 6 位或 8 位的动态密码。

TOTP 生成公式

TOTP 的生成公式如下:

TOTP = Truncate(HMAC-SHA-1(K, T))

其中:

  • K 是客户端和服务端之间的共享密钥。
  • T 是当前的时间步数,用公式 T = (currentUnixTime - T0) / X 计算。
    • currentUnixTime 是当前时间戳(以秒为单位)。
    • T0 是时间的起始点(一般为0)。
    • X 是时间步长(通常为30秒)。
  • HMAC-SHA-1 使用 K 作为密钥,对时间步数 T 进行 HMAC 计算。
  • Truncate 是截取函数,将 HMAC 的结果截取为 6 位或 8 位的数字。

TOTP 与 HOTP 的对比

  • 时间敏感 vs 计数敏感:TOTP 使用当前时间生成密码,因此密码是时间敏感的,每个密码只有在特定时间段内有效。HOTP 则基于计数器,每个密码对应一个计数器值。
  • 同步问题:TOTP 依赖于时间戳,因此客户端和服务端的时间需要保持同步,而 HOTP 需要计数器同步。

Code

生成TOTP

下面是一个简单的 TOTP 实现,生成 6 位的一次性密码。代码依赖于 javax.crypto.Macjava.security.Key 类来处理 HMAC-SHA1。

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.util.Base32;
import java.util.TimeZone;
import java.time.Instant;
import java.time.Clock;public class TOTP {// TOTP 生成算法public static String generateTOTP(String secret, long time, int digits) throws Exception {// 使用时间步长30秒long timeStep = 30;// 计算时间步数long t = time / timeStep;// 将密钥解码为字节Base32 base32 = new Base32();byte[] key = base32.decode(secret);// 使用 HMAC-SHA1 计算Mac mac = Mac.getInstance("HmacSHA1");SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA1");mac.init(keySpec);// 将时间步数转换为 8 字节的大端字节数组byte[] timeBytes = ByteBuffer.allocate(8).putLong(t).array();// 计算 HMAC 值byte[] hash = mac.doFinal(timeBytes);// 提取动态截取码int 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);// 生成 OTP,取二进制数模10^digits,得到指定位数的OTPint otp = binary % (int) Math.pow(10, digits);// 格式化为指定位数return String.format("%0" + digits + "d", otp);}public static void main(String[] args) {try {// 示例密钥(注意:密钥应为 Base32 编码)String secret = "JBSWY3DPEHPK3PXP";// 获取当前 Unix 时间戳long currentTime = Instant.now().getEpochSecond();// 生成 TOTPString otp = generateTOTP(secret, currentTime, 6);System.out.println("生成的 OTP: " + otp);} catch (Exception e) {e.printStackTrace();}}
}

代码解析

  1. 密钥解码:使用 Base32 解码器将字符串密钥解码为字节数组。在 TOTP 中,密钥通常以 Base32 编码存储。
  2. 时间步长:时间步长设为 30 秒,即 TOTP 密码每 30 秒更新一次。
  3. HMAC 计算:使用 HMAC-SHA1 算法,结合密钥和当前时间步数来计算哈希值。
  4. 动态截取:从哈希值中截取出一个 6 位的密码。

验证 TOTP

验证 TOTP 时,客户端和服务端必须在同一时间段内生成相同的密码。为了处理客户端与服务端之间的时间不同步问题,服务端可以允许一个时间窗口范围(例如 ±1 个时间步长)来容错。

为了验证 TOTP,服务端会接收用户输入的 OTP,并根据当前时间戳生成自己的 TOTP,进行比对。如果两者匹配,验证成功,否则失败。为了容错,服务端通常会允许一定的时间窗口来处理客户端和服务端之间可能存在的轻微时间不同步问题。

TOTP 验证流程:

  1. 当前时间戳计算:服务端根据当前时间戳生成 TOTP。
  2. 时间窗口:为了容错,服务端可以生成多个不同时间步内的 TOTP,通常是当前时间步及前后时间步。用户输入的 OTP 与服务端生成的这些 OTP 进行匹配。
  3. 密钥共享:TOTP 的核心是基于一个共享的密钥,客户端和服务端都必须使用同样的密钥生成 OTP。

验证TOTP的Java代码

package com.artisan.otp.totp;import org.apache.commons.codec.binary.Base32;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.time.Instant;/*** @author 小工匠* @version 1.0* @date 2024/10/2 9:37* @mark: show me the code , change the world*/public class TOTPValidator {/*** TOTP 生成算法(和生成 OTP 的算法一致)** @param secret* @param time* @param digits* @return* @throws Exception*/public static String generateTOTP(String secret, long time, int digits) throws Exception {// 时间步长,通常为30秒long timeStep = 30;// 将时间转换为时间步数long t = time / timeStep;// Base32 解码密钥Base32 base32 = new Base32();byte[] key = base32.decode(secret);// 使用 HMAC-SHA1Mac mac = Mac.getInstance("HmacSHA1");SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA1");mac.init(keySpec);// 将时间步数转换为8字节的大端字节数组byte[] timeBytes = ByteBuffer.allocate(8).putLong(t).array();// 生成 HMAC 哈希值byte[] hash = mac.doFinal(timeBytes);// 提取动态截取码int 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);// 生成指定位数的 OTPint otp = binary % (int) Math.pow(10, digits);// 格式化 OTP,确保是6位return String.format("%0" + digits + "d", otp);}/*** TOTP 验证算法* @param secret* @param inputOTP* @param window* @param digits* @return* @throws Exception*/public static boolean validateTOTP(String secret, String inputOTP, int window, int digits) throws Exception {// 当前时间戳long currentTime = Instant.now().getEpochSecond();// 在前后时间步长的窗口内验证for (int i = -window; i <= window; i++) {String generatedOTP = generateTOTP(secret, currentTime + (i * 30), digits);System.out.println("Generated OTP: " + generatedOTP);if (generatedOTP.equals(inputOTP)) {// 验证成功return true;}}// 验证失败return false;}public static void main(String[] args) {try {// 示例密钥(注意:应为 Base32 编码)String secret = "JBSWY3DPEHPK3PXP";// 假设用户输入的 OTP(通常由客户端生成的 TOTP)// 示例 OTP,需要实际生成 TOTPString inputOTP = "306461";// 获取当前 Unix 时间戳long currentTime = Instant.now().getEpochSecond();// 生成 TOTPinputOTP = generateTOTP(secret, currentTime, 6);System.out.println("inputOTP: " +inputOTP);// 验证 OTP    容错窗口为1,6位OTPboolean isValid = validateTOTP(secret, inputOTP, 1, 6);if (isValid) {System.out.println("OTP 验证成功!");} else {System.out.println("OTP 验证失败!");}} catch (Exception e) {e.printStackTrace();}}
}

代码说明

  1. generateTOTP: 生成 TOTP 的算法,使用当前时间戳和共享密钥生成一次性密码。
  2. validateTOTP: 验证用户输入的 OTP 是否有效。此函数允许一个时间窗口(window),比如前后 30 秒范围内的 OTP 都可接受。默认 6 位 OTP。
  3. Base32 解码: Base32 编码用于解码密钥,因为密钥通常以 Base32 编码形式存储。
  4. 时间步长: TOTP 的时间步长通常是 30 秒。代码中以当前时间为基准,根据时间步长计算时间步数,生成 OTP。
  5. 容错窗口: 允许服务端生成当前时间步以及前后若干步内的 OTP,防止客户端与服务端时间不同步。

如何使用

  1. 密钥一致: 确保客户端和服务端使用同一个共享密钥。密钥通常是 Base32 编码的字符串。
  2. 验证 OTP: 服务端使用当前时间步生成 TOTP,并与用户输入的 OTP 进行比对。如果在设定的时间窗口内有匹配的 OTP,验证成功。

调试步骤

  1. 打印调试信息: 在生成和验证过程中打印 OTP 和相关的时间步,帮助确认时间步数和生成的 OTP 是否一致。
  2. 调整时间窗口: 如果客户端和服务端的时间差异较大,尝试增加 window 的大小,允许更大的容错范围。
    在这里插入图片描述

这个实现适用于 TOTP 的典型应用场景,例如双因素认证 (2FA)【基于时间的一次性密码生成和验证】。

使用场景

  • 双因素认证 (2FA):TOTP 是常见的 2FA 算法之一,用户使用手机中的身份验证器(如 Google Authenticator)生成一次性密码进行登录验证。
  • 安全性系统:银行、电子商务网站等需要额外的安全措施,使用 TOTP 来防止密码泄露和账户被劫持。

小结

TOTP 是一种基于时间的动态密码算法,通过时间戳和共享密钥生成一次性密码,常用于双因素身份验证场景。相比于 HOTP,TOTP 不需要计数器同步,使用更加便捷,但要求客户端和服务端的时间同步。


TOTP 与 HOTP 的主要区别

特点HOTPTOTP
依赖性计数器时间戳
密码有效性永久有效,直到被使用短时间内有效(30 或 60 秒)
生成方式每次生成后计数器递增每个时间周期内自动生成
安全密码可能长期有效,安全性较低动态更新,安全性更高
适用场景适用于基于事件的认证系统适用于二次身份验证系统

TOTP 与 HOTP应用场景比较

  • HOTP 适用场景

    • 基于事件触发的认证系统:每次用户请求认证时,系统会递增计数器生成密码。这类系统适用于需要物理令牌或硬件设备的场景(如早期银行安全令牌)。
    • 设备或网络不稳定环境:由于 HOTP 不依赖时间,客户端和服务器的时间不同步问题不会影响认证。
  • TOTP 适用场景

    • 二次身份验证(2FA):TOTP 在大多数现代的二次身份验证系统中使用,如 Google Authenticator、Microsoft Authenticator 等。用户每 30 秒生成一个新密码,确保密码及时失效。
    • 需要更高安全性和频繁登录的系统:由于 TOTP 密码动态更新且过期较快,适合频繁使用和安全性要求较高的应用。

TOTP 与 HOTP安全性分析

  • HOTP 的安全性弱点:由于 HOTP 密码在未使用前一直有效,攻击者可以通过拦截未被使用的密码进行重放攻击,或暴力猜测计数器值。
  • TOTP 的安全优势:TOTP 基于时间戳生成,密码的有效期较短(通常 30 秒)。即使攻击者截获密码,也很难在其
    过期前使用,因此 TOTP 提供了更强的安全性。

在这里插入图片描述


http://www.ppmy.cn/devtools/121313.html

相关文章

Docker Compose 部署大模型GPU集群:高效分配与管理算力资源

Docker Compose 部署大模型GPU集群&#xff1a;高效分配与管理算力资源 文章目录 Docker Compose 部署大模型GPU集群&#xff1a;高效分配与管理算力资源一 Dockerfile 编写二 Dockerfile 示例三 分配GPU资源1&#xff09;GPU分配&#xff1a;指定count2&#xff09;GPU分配&am…

科技赋能,商贸物流新速度 —— 智慧供应链商城加速企业成长

科技赋能&#xff0c;商贸物流新速度 —— 智慧供应链商城加速企业成长 随着科技的飞速发展&#xff0c;AI&#xff08;人工智能&#xff09;、大数据、物联网等先进技术正深刻重塑着商贸物流行业&#xff0c;推动其向更高效、更智能、更环保的方向迈进。这些技术的应用不仅提…

[数据结构] 二叉树题目 (二)

目录 一. 另一颗树的子树 1.1 题目 1.2 示例 1.3 分析 1.4 解决 二. 平衡二叉树 2.1 题目 2.2 示例 2.3 分析 2.4 解决 三. 二叉树的遍历和创建 3.1 题目 3.2 示例 3.3 解决 一. 另一颗树的子树572. 另一棵树的子树 - 力扣&#xff08;LeetCode&#xff09; 1.1…

硬件-开关电源-结构组成及元件作用

文章目录 一&#xff1a;开关电源组成1.1 开关电源是什么&#xff1f;1.2 开关电源六个组成部分 二&#xff1a;六个组成部分的作用2.1 EMC区域2.2 输入整流滤波区域2.3 控制区域2.4 变压器2.5 输出整流滤波区域2.6 反馈电路区域道友:勿以小恶弃人大美&#xff0c;勿以小怨忘人…

2-2.Jetpack 之 Room 简单编码模板(优化版)(Entity、DAO、Database、Repository)

一、Room 1、Room 概述 Room 是 Jetpack 中的一个重要成员&#xff0c;它是一个持久化库&#xff0c;它为管理数据库提供了简单强大的方法 2、Room 引入 在模块级 build.gradle 中引入相关依赖 implementation "androidx.room:room-runtime:2.2.5" annotationPr…

华为OD机试 - 区间交叠问题 - 贪心算法(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

vue基于Spring Boot框架的高校实验室预约管理系统

目录 毕设制作流程功能和技术介绍系统实现截图开发核心技术介绍&#xff1a;使用说明开发步骤编译运行代码执行流程核心代码部分展示可行性分析软件测试详细视频演示源码获取 毕设制作流程 &#xff08;1&#xff09;与指导老师确定系统主要功能&#xff1b; &#xff08;2&am…

行为设计模式 -观察者模式- JAVA

观察者模式 一.简介二. 案例2.1 抽象主题&#xff08;Subject&#xff09;2.2 具体主题&#xff08;Concrete Subject&#xff09;2.3 抽象观察者&#xff08;Observer&#xff09;2.4 具体观察者&#xff08;Concrete Observer&#xff09;2.5 测试 三. 结论3.1 优缺点3.2 使用…