TOTP算法 基于时间的一次性密码

TOTP算法 基于时间的一次性密码TOTP 算法基于时间的一次性密码

/ Copyright (c) 2011 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with or without modification, is permitted pursuant to, and subject to the license terms contained in, the Simplified BSD License set forth in Section 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info). */ import java.lang.reflect.UndeclaredThrowableException; import java.security.GeneralSecurityException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger; import java.util.TimeZone; / * This is an example implementation of the OATH TOTP algorithm. Visit * www.openauthentication.org for more information. * * @author Johan Rydell, PortWise, Inc. */ public class TOTP { 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 converted byte[] bArray = new BigInteger("10" + hex, 16).toByteArray(); // Copy all the REAL bytes, not the "first" byte[] ret = new byte[bArray.length - 1]; for (int i = 0; i < ret.length; i++) ret[i] = bArray[i + 1]; return ret; } private static final int[] DIGITS_POWER // 0 1 2 3 4 5 6 7 8 = { 1, 10, 100, 1000, 10000, , , ,  }; / * 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 * {@link 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 * {@link 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 * {@link 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 返回长度 --6 * @param crypto * : the crypto function to use * * @return: a numeric String in base 10 that includes * {@link truncationDigits} digits */ public static String generateTOTP(String key, String time, String returnDigits, String crypto) { int codeDigits = Integer.decode(returnDigits).intValue(); String result = null; // Using the counter // First 8 bytes are for the movingFactor // Compliant with base RFC 4226 (HOTP) while (time.length() < 16) time = "0" + time; // 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 int 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); int otp = binary % DIGITS_POWER[codeDigits]; result = Integer.toString(otp); while (result.length() < codeDigits) { result = "0" + result; } return result; } public static void main(String[] args) { // Seed for HMAC-SHA1 - 20 bytes String seed = ""; // Seed for HMAC-SHA256 - 32 bytes String seed32 = "" + "32"; // Seed for HMAC-SHA512 - 64 bytes String seed64 = "" + "" + "" + ""; long T0 = 0; long X = 30; long testTime[] = { 59L, L, L, L, L, L }; String steps = "0"; DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); df.setTimeZone(TimeZone.getTimeZone("UTC")); try { System.out.println("+---------------+-----------------------+" + "------------------+--------+--------+"); System.out.println("| Time(sec) | Time (UTC format) " + "| Value of T(Hex) | TOTP | Mode |"); System.out.println("+---------------+-----------------------+" + "------------------+--------+--------+"); for (int i = 0; i < testTime.length; i++) { long T = (testTime[i] - T0) / X; steps = Long.toHexString(T).toUpperCase(); while (steps.length() < 16) steps = "0" + steps; String fmtTime = String.format("%1$-11s", testTime[i]); String utcTime = df.format(new Date(testTime[i] * 1000)); // seed System.out.print("| " + fmtTime + " | " + utcTime + " | " + steps + " |"); System.out.println(generateTOTP(seed, steps, "8", "HmacSHA1") + "| SHA1 |"); // seed32 System.out.print("| " + fmtTime + " | " + utcTime + " | " + steps + " |"); System.out.println(generateTOTP(seed32, steps, "8", "HmacSHA256") + "| SHA256 |"); // seed64 System.out.print("| " + fmtTime + " | " + utcTime + " | " + steps + " |"); System.out.println(generateTOTP(seed64, steps, "6", "HmacSHA512") + "| SHA512 |"); System.out.println("+---------------+-----------------------+" + "------------------+--------+--------+"); } } catch (final Exception e) { System.out.println("Error : " + e); } } }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/218343.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 上午7:29
下一篇 2026年3月18日 上午7:29


相关推荐

  • 腾讯AI布局:QClaw登场,元宝何去何从?

    腾讯AI布局:QClaw登场,元宝何去何从?

    2026年3月14日
    3
  • idea激活码永久(已测有效)

    idea激活码永久(已测有效),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    367
  • 3分钟搞定腾讯云一键部署DeepSeek-R1 教程,小白也能轻松用!

    3分钟搞定腾讯云一键部署DeepSeek-R1 教程,小白也能轻松用!

    2026年3月16日
    2
  • 深入浅出的讲解傅里叶变换(真正的通俗易懂)「建议收藏」

    深入浅出的讲解傅里叶变换(真正的通俗易懂)「建议收藏」我保证这篇文章和你以前看过的所有文章都不同,这是12年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者……  这篇文章的核心思想就是:  要让读者在不看任何数学公式的情况下理解傅里叶分析。  傅里叶分析不仅仅是一个数学工具,更是一种可以彻底颠覆一个人以前世界观的思维模式。但不幸的是,傅里叶分析的公式看起来太复杂了,所以很多大一新生上来就懵圈并从此对

    2022年7月17日
    20
  • Anaconda详细安装及使用教程(带图文)

    Anacond的介绍Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。 因为包含了大量的科学包,Anaconda 的下载文件比较大(约 531MB),如果只需要某些包,或者需要节省带宽或存储空间,也可以使用Miniconda这个较小的发行版(仅包含conda和 Python)。Conda是一个开源的包、环境管理器,可以用于…

    2022年4月7日
    63
  • 进程的挂起

    进程的挂起操作系统 精髓与设计原理 原书第 6 版 第 3 章进程描述和控制 本章讲述了典型操作系统中进程管理所使用到的数据结构和技术 本小节为大家介绍被挂起的进程 3 2 4 被挂起的进程交换的需要前面描述的三个基本状态 就绪态 运行态和阻塞态 提供了一种为进程行为建立模型的系统方法 并指导操作系统的实现 许多实际的操作系统都是按照这样的三种状态进行具体构造的 但是 可

    2026年3月20日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号