php实现TOTP
TOTP 简介
TOTP(Time-Based One-Time Password)是基于时间的一次性密码算法,常用于双因素认证(2FA)。其核心是结合共享密钥和当前时间戳生成动态密码,通常每30秒更新一次。
实现步骤
安装依赖库
确保已安装 PHP 的 hash_hmac 和 base64_decode 函数支持。推荐使用 Base32 编码库处理密钥(如 spomky-labs/base32):
composer require spomky-labs/base32
生成共享密钥 使用 Base32 编码生成一个随机密钥:

use Base32\Base32;
$secret = Base32::encode(random_bytes(10)); // 16字符的Base32密钥
计算时间窗口 TOTP 以30秒为一个时间窗口(Unix时间戳除以30取整):
$timestamp = time();
$timeWindow = floor($timestamp / 30);
生成HMAC-SHA1哈希
使用 hash_hmac 生成密钥和时间的哈希:

$hash = hash_hmac('sha1', pack('J', $timeWindow), Base32::decode($secret), true);
动态截断(DT) 取哈希最后一个字节的低4位作为偏移量,从该偏移量开始截取4字节:
$offset = ord(substr($hash, -1)) & 0x0F;
$binary = substr($hash, $offset, 4);
生成6位数字密码 将截取的二进制数据转换为无符号整数,取最后6位:
$otp = (unpack('N', $binary)[1] & 0x7FFFFFFF) % 1000000;
$otp = str_pad($otp, 6, '0', STR_PAD_LEFT);
完整代码示例
use Base32\Base32;
function generateTOTP($secret, $timestamp = null) {
$timestamp = $timestamp ?? time();
$timeWindow = floor($timestamp / 30);
$binarySecret = Base32::decode($secret);
$hash = hash_hmac('sha1', pack('J', $timeWindow), $binarySecret, true);
$offset = ord(substr($hash, -1)) & 0x0F;
$binary = substr($hash, $offset, 4);
$otp = (unpack('N', $binary)[1] & 0x7FFFFFFF) % 1000000;
return str_pad($otp, 6, '0', STR_PAD_LEFT);
}
// 使用示例
$secret = Base32::encode(random_bytes(10));
$otp = generateTOTP($secret);
echo "TOTP: $otp (Secret: $secret)";
验证注意事项
- 时间同步:服务器和客户端时间需同步(NTP协议推荐)。
- 容错窗口:验证时可检查前后1-2个时间窗口的密码以应对时钟偏差。
- 密钥存储:共享密钥需安全存储(如加密数据库)。
通过上述步骤可实现符合 RFC 6238 标准的 TOTP 生成器。






