TOTP 算法实现:双因素认证的基石(C/C++代码实现)

双因素认证(Two-Factor Authentication, 2FA)扮演着至关重要的角色。它像是一道额外的防线,确保即便密码被窃取,不法分子也难以轻易突破。在众多双因素认证技术中,基于时间的一次性密码(Time-Based One-Time Password, TOTP)算法因其安全性高、使用便捷而受到广泛应用。

TOTP算法是一种基于时间的一次性密码生成算法,它的核心思想是利用时间作为变化的因子来生成动态的密码。这种算法通常与用户的个人信息结合使用,如用户名或电子邮件地址,以及一个共享的秘密密钥。这个秘密密钥在用户端和服务端预先共享,是生成正确OTP的关键。

TOTP是如何工作的呢?

让我们通过一个简单的比喻来理解其原理。想象一下,你有一本只属于你和你的朋友的书,书中记载了一连串的故事,每个故事都有一个编号。每当你想要和朋友传递一个秘密信息时,你会查找当前日期对应的故事编号,并从中选取特定的段落来传递信息。在这个例子中,书就像是秘密密钥,故事编号对应于时间戳,而传递的信息则是一次性密码。

具体到TOTP算法,它使用了哈希函数(如SHA-1、SHA-256等)和时间戳。当用户想要登录系统时,用户的设备会计算当前时间与预设时间步长的差值,然后将这个差值与共享的秘密密钥一起输入到哈希函数中。哈希函数处理后输出一串较长的二进制数据,这串数据再经过模运算,得到一个较短的数字,这个数字就是OTP。用户需要在规定的时间内将这个OTP输入到验证系统中,系统同样会根据相同的秘密密钥和时间差值计算出一个OTP,并与用户提供的OTP进行比对,若两者一致,则认证成功。

在实现上,TOTP算法需要考虑到时间同步的问题。由于网络延迟或者设备时钟不准确,可能导致用户设备与服务器之间的时间有偏差。因此,TOTP算法通常会有一个时间窗口(如30秒),允许在这个时间范围内的OTP都是有效的。

TOTP的优势在于其安全性和用户体验。由于OTP是基于时间和共享秘密密钥生成的,即使黑客截获了某个时刻的OTP,它也无法在其他时间点使用,因为OTP每隔一段时间就会变化。此外,用户可以不需要记忆复杂的密码,只需拥有注册时分配的密钥(通常存储在硬件令牌或软件应用中),就可以轻松完成身份验证。

TOTP的实现

Base32编码与解码

Base32编码原理:
Base32编码是一种将二进制数据转换成32种可打印字符的编码方式。它主要用于电子邮件和URL中传输二进制数据。Base32使用A-Z的大写字母(不使用C, E, G, I, O, Q, U, V)和数字2-7来表示数据。每8位二进制数据可以编码为5个Base32字符,这意味着编码后的数据长度是原始数据的大约1.33倍。

实现Base32编码:
编码过程涉及将输入的字节数据分成5位一组,每组转换为对应的Base32字符。例如,如果输入字节是0x9A,它对应于二进制的10011010,然后将其分成两组:10011010。每组转换为Base32字符,分别是SK

实现Base32解码:
解码过程与编码相反,它将Base32字符转换回原始的字节数据。解码函数需要处理输入的Base32字符串,跳过任何非Base32字符(如填充的等号),并将每个字符转换回相应的5位二进制值。然后,这些值被重新组合成字节数据。

HMAC-SHA1算法

HMAC-SHA1基本概念:
HMAC(Hash-based Message Authentication Code)是一种消息认证码,它使用哈希算法(如SHA-1)和密钥来提供消息的完整性保护和认证。SHA-1是一种广泛使用的加密哈希函数,它可以产生一个160位(20字节)的哈希值。

在TOTP中的应用:
在TOTP中,HMAC-SHA1用于生成一个基于密钥、时间戳和算法参数的哈希值。这个哈希值随后被用来生成6位数的一次性密码。通过使用HMAC-SHA1,TOTP确保了即使密钥被泄露,生成的密码也难以被预测。

时间戳处理

时间戳的重要性:
TOTP算法依赖于时间戳来生成密码,因此时间同步至关重要。如果客户端和服务器之间的时间不同步,生成的密码可能会无效。

确保时间同步:
为了确保时间同步,可以采取以下措施:

  • 使用网络时间协议(NTP)来同步客户端和服务器的时间。
  • 在用户设备上设置时间校验机制,确保时间偏差在可接受范围内。

密码生成逻辑

从HMAC-SHA1输出中提取密码:

  1. 使用HMAC-SHA1算法和当前时间戳生成一个20字节的哈希值。
  2. 对哈希值进行处理,提取出用于生成密码的部分。具体来说,取哈希值的最后一个字节的最低4位作为索引,从这个位置开始读取接下来的4个字节。
  3. 将这4个字节视为一个整数,然后对1000000取模,得到一个6位数的密码。

生成6位数的密码:

  • 将上述步骤得到的整数转换为字符串形式,并确保它是一个6位数的密码。如果需要,可以在前面补零。

TOTP 算法实现:双因素认证的基石(C/C++代码实现)

双因素认证(2FA)作为一种增强安全性的方法应运而生。基于时间的一次性密码(TOTP)是2FA的一种实现方式,它提供了一种动态生成、一次性使用的密码,极大地提高了账户的安全性。下面实现类似Google Authenticator这样的应用程序。


void hmac(
    void *dest,
    const void *key,
    uint32_t key_len,
    const void *msg,
    uint32_t msg_len,
    void (*hash)(char *dest, const char *str, int len),
    uint16_t block_size,
    uint16_t output_size
);
typedef struct
{
    uint32_t state[5];
    uint32_t count[2];
    unsigned char buffer[64];
} SHA1_CTX;

void sha1_transform(uint32_t state[5], const unsigned char buffer[64]);
void sha1_init(SHA1_CTX * context);
void sha1_update(SHA1_CTX * context, const unsigned char *data, uint32_t len);
void sha1_final(unsigned char digest[20], SHA1_CTX * context);
void sha1(char *hash_out, const char *str, int len);
void bytes_array_reverse(uint8_t* bytes, int size);
int bytes_array_to_int(const uint8_t* bytes, int start, int end);
int base32_decode(const uint8_t *encoded, uint8_t *result, int bufSize);
char* str_upper(char* str);
char* str_pad_left(char* str, char pad, int len);
char* str_pad_right(char* str, char pad, int len);
int int_to_str(int i, char *buf, int buf_len);

void get_2fa_code(char *secret, char code[7])
{
    char key[20];
    char hash[20];
    int key_len;
    uint64_t msg;

    str_upper(secret);  //转换为大写以获得有效的Base32格式
    key_len = base32_decode((uint8_t*)secret, (uint8_t*)key, 20);           // 将机密解码为字节数组
    msg = time(NULL) / 30;                                                  // TOTP是HOTP,种子为30秒。

    bytes_array_reverse((uint8_t*)&msg, 8);                                
    hmac(hash, key, key_len, (uint8_t*)&msg, 8, sha1, 64, 20);              // 生成hmac哈希

    int offset = hash[19] & 0xF;                                            
    int header = bytes_array_to_int((uint8_t*)hash, offset, offset + 4);    // 从偏移量开始截断4个字节
    header = header & 0x7fffffff;                                           // 删除最高有效位
    header = header % 1000000;                                              // 生成小于7位的余数

    int_to_str(header, code, 7);    // 将代码转换为字符串
    str_pad_left(code, '0', 6);     // 从左起用0填充代码,直到代码长度为6
}
int main(int argc, char **argv)
{
...

    if (argc != 2) {
        printf("./ga [secret]\n");
        return (0);
    }

    get_2fa_code(argv[1], code);
    printf("Code :\n%s\n", code);
    return (0);
}

运行结果:

If you need the complete source code, please add the WeChat number (c17865354792)

总结

Google Authenticator 的核心原理是利用共享密钥和一个随时间变化的因子来生成一次性密码,从而实现第二因素的身份验证。这种方法既方便又安全,因为它不需要额外的硬件令牌,只需要用户的智能设备即可。此外,由于 OTP 是一次性的,并且随时间变化,即使黑客截获了当前的 OTP,也无法在未来的时间点使用它来冒充用户。

We also undertake the development of program requirements here. If necessary, please follow the WeChat official account 【程序猿编码】and contact me

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/647236.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【古董技术】ms-dos应用程序的结构

序 制定一个MS-DOS应用程序计划需要认真分析程序的大小。这种分析可以帮助程序员确定MS-DOS支持的两种程序风格中哪一种最适合该应用程序。.EXE程序结构为大型程序提供了好处,因为所有.EXE文件之前都有额外的512字节(或更多)的文件头。另一方…

【MinIO学习】

OSS Docker podman MinIO服务器 MinIO客户端 Bucket Object 时间同步 The difference between the request time and the servers time is too large。 URL

AGI系列(1):掌握AI大模型提示词优化术,提问准确率飙升秘籍

当我们向AI大模型提问时,通常人们的做法是有什么问题,就直接去问,得到大模型的回复结果,时好时坏,完全没有可控性。 那么有没有一种方式或是一套方法,可以让我们向大模型提问时,得到的结果更准确…

二十九篇:构建未来:信息系统的核心框架与应用

构建未来:信息系统的核心框架与应用 1. 引言 在这个充满挑战和机遇的信息时代,信息系统已经成为现代组织不可或缺的神经中枢。它们不仅革新了我们处理信息的方式,更是极大地增强了决策制定的效率和质量。在这篇文章中,我将分享我…

JMeter学习笔记二

面试题: 1.做接口测试时,你是怎么做的数据校验(返回值验证)?一般你会验证哪些数据? 校验code 200(说明后端接到了你的请求,并且给了应答) 返回信息 sucess 2.有1w个用户名密码需要登录&#xff…

搭建Harbor镜像仓库

前言 1、系统版本:CentOS9 2、harbor版本:v2.9.4 3、提前安装好docker和docker-compose,参考地址。我这里安装的版本是docker:26.1.3 docker-compose:v2.27.1 安装步骤 下载安装包 1、下载地址:ha…

基于门控的循环神经网络:GRU

门控循环单元(GatedRecurrentUnit,GRU)网络,也是一种基于门控的循环神经网络,但是名气不如LSTM大,GRU是对LSTM的一种改版,可以理解为是LSTM的简化版。LSTM有三个门,输入门&#xff0…

代码随想录-Day20

654. 最大二叉树 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums…

探索Python列表的奥秘:从零开始学习

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、列表简介与用途 二、列表的创建与访问 三、列表的增删改查 四、列表生成式与高级操作…

The view model in Acise

在FreeCAD中,借助于Boost Signals2实现了业务层、显示层的分层,但整个FreeCAD Gui层却采用了Coin3D进行渲染,很难在这方面进行扩展。 相较之下,在SALOME中,可以为不同的Module指定特定的ViewModel,支持Ope…

Sping源码(八)—Spring事件驱动

观察者模式 在介绍Spring的事件驱动之前,先简单的介绍一下设计模式中的观察者模式。 在一个简单的观察者模式只需要观察者和被观察者两个元素。简单举个栗子: 以警察盯梢犯罪嫌疑人的栗子来说: 其中犯罪嫌疑人为被观察者元素而 警察和军人为…

C++ List完全指南:使用方法与自定义实现

文章目录 list的使用几种构造函数 list的实现1.节点类的定义1.1节点类的构造函数 2.正向迭代器实现2.1operator*重载2.2operator->重载2.3operator重载2.4operator--2.5operator和operator! 3.反向迭代器实现3.1operator*重载3.2operator->重载3.3operator重载…

音视频入门基础:像素格式专题(3)——FFmpeg源码解析BMP格式图片的底层实现原理

音视频入门基础:像素格式专题系列文章: 音视频入门基础:像素格式专题(1)——RGB简介 音视频入门基础:像素格式专题(2)——不通过第三方库将RGB24格式视频转换为BMP格式图片 音视频…

每日一问-如何设置VS Code 中 Markdown粘贴图片的位置

VS Code内的markdown编辑器应该算是比较好用的,但是有一个问题一直困扰着我,就是在编辑markdown文件时,粘贴图片的位置问题。默认情况下,VS Code会将粘贴的图片放在markdown文件的同级目录下,这样会导致markdown文件的…

OWASP top10--SQL注入(二)

目录 06:SQL注入提交方式 6.1、get提交 6.2、post提交 6.3、cookie提交 6.4、HTTP Header头提交 07:注入攻击支持类型 7.1、union注入: 7.1.1、union操作符一般与order by语句配合使用 7.1.2、information_schema注入 7.2、基于函数…

AIGC语音交互

目录 一、总体介绍 二、环境设置与安装 三、语音识别 四、语音合成 五、GPT调用 六、信息关系 七、实现效果 一、总体介绍 达成效果:在ROS系统中实现用户语音提问得到智能语音回答 用到的技术:科大讯飞的语音识别、语音合成 GPT 操作系统&#x…

顶顶通呼叫中心中间件-自动外呼输入分机号(比如隐私号)(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-自动外呼输入分机号(比如隐私号)(mod_cti基于FreeSWITCH) 比如有些人的号码是这样的就需要用上自动外呼输入分机号了 号码1:182XXXX8111-1234 号码2:182XXXX8222 如果号码是这样的就根据以下步骤配置 注意使用这个需要:…

web如何做接口层面自动化测试?

接口层面约等于集成化测试,且需要启动web容器 一般web项目的,代码都是按照分层开发的,业务主要是集中在service和dao层,而我们如果仅仅是利用之前的单元测试,然后把依赖的代码直接mock掉,仅仅测试controller这一块是没…

如何将前端项目打包并部署到不同服务器环境

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学,可以点心心支持一下哈(笔记是根据b站尚硅谷的前端讲师【张天禹老师】整理的,用于自己复盘,有需要学习的可以去b站学习原版视频&…

【Spring】深入理解 Spring 状态机:简化复杂业务逻辑的利器

前言 在软件开发中,有许多场景需要处理状态转换和状态驱动的逻辑,比如订单处理、工作流程管理、游戏引擎等。Spring 状态机(Spring State Machine)是 Spring Framework 提供的一个强大的模块,用于帮助开发人员轻松构建…