java和c#里的TOTP统一算法

这篇具有很好参考价值的文章主要介绍了java和c#里的TOTP统一算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基础说明

本文根据 RFC4226 和 RFC6238 文档,详细的介绍 HOTP 和 TOTP 算法的原理和实现。
两步验证已经被广泛应用于各种互联网应用当中,用来提供安全性。对于如何使用两步验证,大家并不陌生,无非是开启两步验证,然后出现一个二维码,使用支持两步验证的移动应用比如 Google Authenticator 或者 LassPass Authenticator 扫一下二维码。这时候应用会出现一个6位数的一次性密码,首次需要输入验证从而完成开启过程。以后在登陆的时候,除了输入用户名和密码外,还需要把当前的移动应用上显示的6位数编码输入才能完成登陆。
这个过程的背后主要由两个算法来支撑:HOTP 和 TOTP。也分别对应着两份 RFC 协议 RFC4266 和 RFC6238。前者是 HOTP 的标准,后者是 TOTP 的标准。本文将使用图文并茂的方式详细介绍 HOTP 和 TOTP 的算法原理,并在最后分析其安全性。当然所有内容都是基于协议的,通过自己的理解更加直观的表达出来。

为了确保在不同语言下生成相同的 TOTP 结果,你需要确保使用相同的密钥和相同的时间戳步长。同时,你还需要确保使用相同的哈希算法(通常是 HMAC-SHA1 或 HMAC-SHA256)。

参数解释

  • base32Key: 这是生成totp数字时的共享密钥
  • timeStep: 这是时间步长,作用是每隔多长时间(秒),你的totp数字变化一次,即一个totp数字的失效时间
  • digits: 这是生成多少位的totp数字
  • HMAC-SHA1: 是一种基于哈希函数的消息认证码算法,用于保护数据完整性和身份验证

HMAC-SHA1

HMAC-SHA1(Hash-based Message Authentication Code with SHA-1)是一种基于哈希函数的消息认证码算法,用于保护数据完整性和身份验证。它结合了两个主要的技术:哈希函数(SHA-1)和密钥(Key)。

下面是 HMAC-SHA1 算法的工作原理和说明:

  1. 输入数据:HMAC-SHA1 接受两个输入:消息数据(Message)和密钥(Key)。消息数据可以是任意长度的二进制数据。

  2. 密钥填充:如果密钥的长度小于哈希函数的块大小,HMAC-SHA1 会将密钥填充到相应的块大小,通常使用 0x00 字节。

  3. 内部填充:将密钥与常数 0x36 做异或操作,然后将结果与消息数据连接起来。

  4. 哈希计算:对连接后的数据进行 SHA-1 哈希计算。SHA-1 生成一个固定长度(160位或20字节)的哈希值。

  5. 外部填充:将密钥与常数 0x5C 做异或操作,然后将结果与内部哈希值连接起来。

  6. 二次哈希计算:对连接后的数据进行 SHA-1 哈希计算。这一次的哈希计算包括了内部哈希值和密钥。

  7. 结果:HMAC-SHA1 的最终结果是SHA-1 哈希的输出。

HMAC-SHA1 的主要目的是确保数据的完整性和身份验证。由于它需要密钥,因此只有知道密钥的实体才能生成正确的 HMAC 值。这使得 HMAC-SHA1 在加密通信和身份验证中非常有用,例如在数字签名、认证协议(如OAuth)、以及一次性密码算法(如TOTP和HOTP)中广泛使用。

需要注意的是,SHA-1 已经不再被视为安全的哈希算法,因为它存在碰撞漏洞。因此,安全敏感的应用程序应该使用更强大的哈希算法,如SHA-256或SHA-3,来代替 SHA-1。如果可能,也应该使用更安全的 HMAC 变种,如HMAC-SHA-256。

TOTP的生成过程

  1. 服务器和客户端都知道共享的密钥。
  2. 客户端获取当前时间戳,通常是以秒为单位。
  3. 客户端将当前时间戳除以时间步长并取整,以获得一个时间窗口(Time Window)的序号。
  4. 客户端使用哈希函数(如HMAC-SHA1)将密钥和时间窗口的序号作为输入来生成哈希值。
  5. 从哈希值中提取指定的位数作为一次性密码,通常是6位数字。
  6. 客户端将生成的一次性密码显示给用户,用户输入该密码进行身份验证。
  7. 服务器使用相同的密钥和时间戳计算一次性密码,以验证用户输入的密码是否匹配。

TOTP的关键之处在于,只有在相同的时间窗口内才能生成相同的密码,因此它能够提供一定的安全性,即使密钥泄露,攻击者也只有在短时间内才能使用密码。另外,TOTP密码的生成依赖于共享密钥和时间,因此需要客户端和服务器之间的时间同步。

核心代码

以下是一个 Java 和 C# 中可以生成相同 TOTP 结果的示例代码,使用的是 HMAC-SHA1 哈希算法和 Joda-Time 库来处理时间:

Java 示例:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base32;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

public class TOTPGenerator {
    public static String generateTOTP(String base32Key, int timeStep, int digits) throws Exception {
        long counter = (System.currentTimeMillis() / 1000) / timeStep;
        byte[] key = new Base32().decode(base32Key);
        
        SecretKeySpec secretKey = new SecretKeySpec(key, "HmacSHA1");
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(secretKey);
        
        byte[] counterBytes = new byte[8];
        for (int i = 0; i < 8; i++) {
            counterBytes[7 - i] = (byte) (counter >> (8 * i));
        }
        
        byte[] hash = mac.doFinal(counterBytes);
        int offset = hash[hash.length - 1] & 0x0F;
        int binary = ((hash[offset] & 0x7F) << 24 | (hash[offset + 1] & 0xFF) << 16 | (hash[offset + 2] & 0xFF) << 8 | (hash[offset + 3] & 0xFF));
        
        int otp = binary % (int) Math.pow(10, digits);
        return String.format("%0" + digits + "d", otp);
    }
}

C# 示例:

using System;
using System.Security.Cryptography;
using System.Text;

public class TOTPGenerator
{
    public static string GenerateTOTP(string base32Key, int timeStep, int digits)
    {
        long counter = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds / timeStep;
        byte[] key = Base32Decode(base32Key);

        using (HMACSHA1 hmac = new HMACSHA1(key))
        {
            byte[] counterBytes = BitConverter.GetBytes(counter);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(counterBytes);
            }

            byte[] hash = hmac.ComputeHash(counterBytes);
            int offset = hash[hash.Length - 1] & 0x0F;
            int binary = (hash[offset] & 0x7F) << 24 | (hash[offset + 1] & 0xFF) << 16 | (hash[offset + 2] & 0xFF) << 8 | (hash[offset + 3] & 0xFF);
            
            int otp = binary % (int)Math.Pow(10, digits);
            return otp.ToString($"D{digits}");
        }
    }

    private static byte[] Base32Decode(string base32)
    {
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        var bits = base32.ToUpper().ToCharArray().Select(c => Convert.ToString(chars.IndexOf(c), 2).PadLeft(5, '0')).Aggregate((a, b) => a + b);
        return Enumerable.Range(0, bits.Length / 8).Select(i => Convert.ToByte(bits.Substring(i * 8, 8), 2)).ToArray();
    }
}

这两个示例使用了相同的密钥(base32Key)、时间戳步长(timeStep)和位数(digits),并使用相同的 HMAC-SHA1 哈希算法来生成 TOTP。确保在实际应用中提供相同的参数值,你将能够生成相同的 TOTP 结果。

测试代码

// C#
string totp = GenerateTOTP("pkulaw", 30, 8);
Console.WriteLine("Current TOTP:" + totp);
// 结果:30396996

// java
String totp=generateTOTP("pkulaw", 30, 8);
System.out.println(totp);
// 结果:30396996

上面的两种语言的测试代码,在30秒之内(一般使用UTC时间计算), 产生的totp码是相同的。文章来源地址https://www.toymoban.com/news/detail-711571.html

到了这里,关于java和c#里的TOTP统一算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于TOTP算法的Github两步验证2FA(双因子)机制Python3.10实现

    从今年(2023)三月份开始,Github开始强制用户开启两步验证2FA(双因子)登录验证,毫无疑问,是出于安全层面的考虑,毕竟Github账号一旦被盗,所有代码仓库都会毁于一旦,关于双因子登录的必要性请参见:别让你的服务器(vps)沦为肉鸡(ssh暴力破解),密钥验证、双向因子登录值

    2024年02月08日
    浏览(36)
  • 安全开发:身份认证方案之 Google 身份验证器和基于时间的一次性密码 TOTP 算法

    参考资料在文末注明,如本文有错漏欢迎评论区指出👏 目前很多应用都逐步采用了双因子认证或者说MFA认证方案,因此本文介绍一下背后的机制和 TOTP算法 原理。使用TOTP算法,只要满足两个条件:1)基于相同的密钥;2)时钟同步;只需要事先约定好密钥,TOTP算法就可以保

    2024年02月04日
    浏览(40)
  • 微信小程序中生成普通二维码,并根据二维码里的参数跳转对应的页面

    找到开发目录下面的 》 【开发管理】 》【开发设置】找到【扫普通链接二维码打开小程序】模块, 如图: 点击【添加】 例如: 我的生成二维码的链接地址是 服务器请求地址+需要跳转的参数 第一步:对要传递的参数进行编码 我要跳转到资讯页面, 服务器域名:https://x

    2024年02月08日
    浏览(31)
  • 用html+javascript打造公文一键排版系统12:删除附件说明中“附件:”里的空格

    如果我们在输入附件说明时在“附件:”之间加入空格,那么排版时就要删除这些空格。 因为string对象replace()支持正则表达式,于是考虑用replace()来完成。 写了一段只有一个多余空格的代码来测试: 运行结果如下: 附件:河池市××关于××××××××××××××××××××××××

    2024年02月14日
    浏览(30)
  • 根据源码,模拟实现 RabbitMQ - 实现消息持久化,统一硬盘操作(3)

    目录 一、实现消息持久化 1.1、消息的存储设定 1.1.1、存储方式 1.1.2、存储格式约定 1.1.3、queue_data.txt 文件内容  1.1.4、queue_stat.txt 文件内容 1.2、实现 MessageFileManager 类 1.2.1、设计目录结构和文件格式 1.2.2、实现消息的写入 1.2.3、实现消息的删除(随机访问文件) 1.2.4、获取队

    2024年02月12日
    浏览(35)
  • 【华为OD机试】根据IP查找城市(贪心算法—Java&Python&C++&JS实现)

    本文收录于专栏:算法之翼 本专栏所有题目均包含优质解题思路,高质量解题代码(JavaPythonC++JS分别实现),详细代码讲解,助你深入学习,深度掌握!

    2024年04月15日
    浏览(33)
  • 含源码|基于MATLAB的去雾系统(5种去雾算法+1种本文的改进算法)

    去雾系统V2包括作者新加入的 多尺度Retinex去雾算法以及改进去雾算法 ,以及 4种 评价去雾效果的 客观指标 。 引言 去雾系统新增功能 结果分析 源码获取 展望 参考文献 在作者前面写过的文章中,已经介绍过图像去雾算法的应用价值及研究现状,并且也介绍了4种去雾算法的

    2024年01月23日
    浏览(68)
  • 【华为OD机考 统一考试机试C卷】特殊的加密算法(C++ Java JavaScript Python C语言)

    真题目录:华为OD机考机试 真题目录( D卷 +C卷 + B卷 + A卷) + 考点说明 在线OJ:点击立即刷题,模拟真实机考环境 华为OD面试真题精选:华为OD面试真题精选 有一种特殊的加密算法,明文为一段数字串,经过密码本查找转换,生成另一段密文数字串。 规则如下: 明文为一段

    2024年04月16日
    浏览(36)
  • Java【算法 04】HTTP的认证方式之DIGEST认证详细流程说明及举例

    详细的说明文档:WWW-Authenticate - HTTP | MDN (mozilla.org) 摘要认证(Digest Authentication)是一种用于在网络通信中验证用户身份的认证方法。它主要应用于HTTP和其他应用层协议中。 Digest认证相对于基本认证更加安全,因为它不直接传输明文密码。但它也不是完全的安全解决方案,因

    2024年02月13日
    浏览(30)
  • 【OD统一考试(C卷)考生抽中题】根据 IP 查找城市(200 分),用 C++ 编码,速通

    华为 od 2023 | 什么是华为 od,od 薪资待遇,od 机试题清单 其他 OD 统一考试试卷整理 【精选】华为OD 23年11月底新面试经验分享,一口气学习完 【精选】华为OD 23年11月新面经记录分享,看看其他人是怎么拿 offer 的 10月华为OD面经整理分享,感谢三位上岸考友分享经验 十一,中

    2024年02月20日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包