PostgreSQL学习之一次一密口令认证(TOTP)
TOTP定义:基于时间的一次性密码算法(英语:Time-based One-Time Password,简称:TOTP)是一种根据共享密钥
与当前时间
计算一次性密码的算法。
Google Authenticator,谷歌动态口令,Google身份验证器Google Authenticator是谷歌推出的基于时间的一次性密码(Time-based One-time Password,简称TOTP),只需要在手机上安装该APP,就可以生成一个随着时间变化的一次性密码,用于帐户验证。
微信小程序搜索TOTP也可以找到不少实现该功能的小程序。
根据TOTP定义以及谷歌动态口令APP,我们可以实现postgresql数据库基于TOTP的二次认证
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#define OTP_LENGTH 6
#define TIME_STEP 30
#define BASE32_LENGTH 32
// Base32 编码字符集
static const char base32_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
// Base32 解码函数
void base32_decode(const char* base32, unsigned char* output, size_t* output_len) {
size_t bit_index = 0;
int shift = 0;
*output_len = 0;
for (const char *ptr = base32; *ptr; ptr++) {
char value;
if (*ptr >= 'A' && *ptr <= 'Z') {
value = *ptr - 'A';
} else if (*ptr >= '2' && *ptr <= '7') {
value = *ptr - '2' + 26;
} else {
continue; // 非法字符跳过
}
bit_index += 5;
if (bit_index >= 8) {
output[*output_len] |= (value >> (bit_index - 8));
(*output_len)++;
output[*output_len] = 0; // 初始化下一个字节
bit_index -= 8;
}
output[*output_len] |= (value << (8 - bit_index));
}
}
// 计算时间间隔
long get_time_interval() {
return time(NULL) / TIME_STEP; // 获取当前时间步长
}
// HMAC-SHA1 计算
unsigned char* hmac_sha1(const unsigned char* key, int key_len,
const unsigned char* data, int data_len,
unsigned char* result, unsigned int* result_len) {
return HMAC(EVP_sha1(), key, key_len, data, data_len, result, result_len);
}
// 生成TOTP
int generate_totp(const unsigned char* key, int key_len) {
long time_interval = get_time_interval();
unsigned char time_bytes[8] = {0};
// 将时间步长转换为8字节大端格式
for (int i = 0; i < 8; i++) {
time_bytes[7 - i] = time_interval & 0xFF;
time_interval >>= 8;
}
// 生成HMAC-SHA1
unsigned char hmac_result[SHA_DIGEST_LENGTH];
unsigned int hmac_len = 0;
hmac_sha1(key, key_len, time_bytes, sizeof(time_bytes), hmac_result, &hmac_len);
// 计算动态截断的OTP
int offset = hmac_result[hmac_len - 1] & 0x0F;
int otp = (hmac_result[offset] & 0x7F) << 24 |
(hmac_result[offset + 1] & 0xFF) << 16 |
(hmac_result[offset + 2] & 0xFF) << 8 |
(hmac_result[offset + 3] & 0xFF);
otp %= (int)pow(10, OTP_LENGTH); // 限制OTP长度
return otp;
}
int main(int argc, char *argv[]) {
// 使用固定的Base32编码密钥
const char* secret = "JBSWY3DPEHPK3PXP"; // 这是 Base32 编码的密钥
unsigned char key[20] = {0}; // 用于存储解码后的密钥
size_t key_len;
if (argc > 1)
secret= argv[1];
// Base32 解码密钥
base32_decode(secret, key, &key_len);
int generated_otp = generate_totp(key, key_len);
printf("生成的OTP: %06d\n", generated_otp);
return 0;
}
将上述示例程序中的基础密钥"JBSWY3DPEHPK3PXP"输入到谷歌APP或微信小程序中,即可以查看生成的基于时间的一次性密码;把示例程序稍作改动即可做成totp客户端。