Last active
January 29, 2022 14:16
-
-
Save Martin91/15a3a29acd9d138b0d6e125d8fbd5ab0 to your computer and use it in GitHub Desktop.
OTP algorithms in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'openssl' | |
def hotp(secret, counter, digits = 6) | |
hash = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), secret, int_to_bytestring(counter)) | |
"%0#{digits}i" % (truncate(hash) % 10**digits) | |
end | |
def truncate(string) | |
offset = string.bytes.last & 0xf | |
partial = string.bytes[offset..offset+3] | |
partial.pack("C*").unpack("N").first & 0x7fffffff | |
end | |
def int_to_bytestring(int, padding = 8) | |
result = [] | |
until int == 0 | |
result << (int & 0xFF).chr | |
int >>= 8 | |
end | |
result.reverse.join.rjust(padding, 0.chr) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Appendix D - HOTP Algorithm: Test Values | |
The following test data uses the ASCII string | |
"12345678901234567890" for the secret: | |
Secret = 0x3132333435363738393031323334353637383930 | |
Table 1 details for each count, the intermediate HMAC value. | |
Count Hexadecimal HMAC-SHA-1(secret, count) | |
0 cc93cf18508d94934c64b65d8ba7667fb7cde4b0 | |
1 75a48a19d4cbe100644e8ac1397eea747a2d33ab | |
2 0bacb7fa082fef30782211938bc1c5e70416ff44 | |
3 66c28227d03a2d5529262ff016a1e6ef76557ece | |
4 a904c900a64b35909874b33e61c5938a8e15ed1c | |
5 a37e783d7b7233c083d4f62926c7a25f238d0316 | |
6 bc9cd28561042c83f219324d3c607256c03272ae | |
7 a4fb960c0bc06e1eabb804e5b397cdc4b45596fa | |
8 1b3c89f65e6c9e883012052823443f048b4332db | |
9 1637409809a679dc698207310c8c7fc07290d9e5 | |
Table 2 details for each count the truncated values (both in | |
hexadecimal and decimal) and then the HOTP value. | |
Truncated | |
Count Hexadecimal Decimal HOTP | |
0 4c93cf18 1284755224 755224 | |
1 41397eea 1094287082 287082 | |
2 82fef30 137359152 359152 | |
3 66ef7655 1726969429 969429 | |
4 61c5938a 1640338314 338314 | |
5 33c083d4 868254676 254676 | |
6 7256c032 1918287922 287922 | |
7 4e5b397 82162583 162583 | |
8 2823443f 673399871 399871 | |
9 2679dc69 645520489 520489 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'hotp' | |
def totp(secret, digits = 6, step = 30, initial_time = 0) | |
steps = (Time.now.to_i - initial_time) / step | |
hotp(secret, steps, digits) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment