我正在寻找一个简单的Perl实现,它验证使用服务器端密码创建的Google身份验证器令牌。例如,
以下Google网址允许您将base32格式的服务器密码(在下面的情况下秘密为 e4ytonjeim4hcsrhja5fe5kqfu )编码为可以从Google身份验证器应用中读取的QR码(参见下图) ):
https://chart.googleapis.com/chart?cht=qr&chs=100x100&chl=otpauth%3A%2F%2Ftotp%2Fmysite%3A29%3Fsecret%3De4ytonjeim4hcsrhja5fe5kqfu%26issuer%3Dmysite
将QR码扫描到验证器应用程序后,它会生成令牌,如:716340。如何验证令牌的正确性?
这个问题是这个Python问题的Perl等价物: Google Authenticator implementation in Python
答案 0 :(得分:7)
这是另一种解决方案,您可以验证它与this example
中生成的令牌相匹配use Authen::OATH;
use Convert::Base32;
my $oath = Authen::OATH->new();
my $secret = "JBSWY3DPEHPK3PXP";
my $otp = $oath->totp( decode_base32( $secret ) );
print $otp."\n";
答案 1 :(得分:6)
好吧花了一点时间,但我有一个Perl解决方案(希望这可以弥补一个稍微懒惰的问题:)感谢Borodin对此的帮助(Taking the SHA1 HMAC of hex strings in Perl)
#!/usr/bin/perl -w
use strict;
use warnings;
use Convert::Base32;
use Digest::HMAC_SHA1 qw/ hmac_sha1_hex /;
my $base_32_secret = "JBSWY3DPEHPK3PXP";
print "".totp_token($base_32_secret)."\n";
sub totp_token {
my $secret = shift;
my $key = unpack("H*", decode_base32($secret));
my $lpad_time = sprintf("%016x", int(time()/30));
my $hmac = hmac_sha1_hex_string($lpad_time, $key);
my $offset = sprintf("%d", hex(substr($hmac, -1)));
my $part1 = 0 + sprintf("%d", hex(substr($hmac, $offset*2, 8)));
my $part2 = 0 + sprintf("%d", hex("7fffffff"));
my $token = substr("".($part1 & $part2), -6);
return $token;
}
sub hmac_sha1_hex_string {
my ($data, $key) = map pack('H*', $_), @_;
hmac_sha1_hex($data, $key);
}
答案 2 :(得分:3)
Auth::GoogleAuthenticator会为您的目的而工作吗?
编辑:确实如此;这会验证JS生成的OTP。当计数器不再及时时,它返回一个空字符串;即假。使用URL会导致应用程序同步到JS:
use Data::Printer;
use Auth::GoogleAuthenticator;
my $auth = Auth::GoogleAuthenticator->new(secret_base32 => q/e4ytonjeim4hcsrhja5fe5kqfu/);
say $auth->registration_url;
p($auth->verify('252499'));
输出:
otpauth://totp/?secret=e4ytonjeim4hcsrhja5fe5kqfu
1
答案 3 :(得分:3)
对于后人,我从@Vijay的答案(感谢老兄)中获取了脚本,稍微简化了算法,从TOTP定义中添加了文档,并添加了一些示例代码。
我改编的数字生成代码只是@Vijay的答案的简化:
use Digest::HMAC_SHA1 qw/ hmac_sha1_hex /;
my $paddedTime = sprintf("%016x", int(time() / $TIME_STEP));
my $data = pack('H*', $paddedTime);
my $key = decode_base32($secret);
# encrypt the data with the key and return the SHA1 of it in hex
my $hmac = hmac_sha1_hex($data, $key);
# take the 4 least significant bits (1 hex char) from the encrypted string as an offset
my $offset = hex(substr($hmac, -1));
# take the 4 bytes (8 hex chars) at the offset (* 2 for hex), and drop the high bit
my $encrypted = hex(substr($hmac, $offset * 2, 8)) & 0x7fffffff;
# the token is then the last 6 digits in the number
my $token = $encrypted % 1000000;
# make sure it is 0 prefixed
return sprintf("%06d", $token);
可以从Github下载完整的TOTP 2 Factor Auth Perl script。