use Digest::HMAC_SHA1 qw(hmac_sha1); # usage: ./otp.pl <80-bit secret key in hex> # e.g.: ./otp.pl 0123456789abcdef0123 # note: you may need to convert the secret key from base32 notation to hex $key_hex_string = shift @ARGV; $key_bin = pack( 'H2' x 10, unpack("(A2)*", $key_hex_string) ); $time = int(time/30); $b = pack("q>",$time); # on 32-bit systems, change q to L and uncomment the next line # $b = pack("L>",0) . $b; $hash = hmac_sha1($b,$key_bin); $offset = ord(substr($hash,length($hash)-1,1)) & 0x0F; $truncatedHash = substr($hash,$offset,4); $code = unpack("L>",$truncatedHash); $code = $code & 0x7FFFFFFF; $code %= 1000000; while(length($code) < 6){ $code="0$code"; } print $code."\n";