Skip to content

Instantly share code, notes, and snippets.

@eungju
Last active December 21, 2022 11:16
Show Gist options
  • Save eungju/6411122 to your computer and use it in GitHub Desktop.
Save eungju/6411122 to your computer and use it in GitHub Desktop.
OTP
#!/usr/bin/env ruby
require 'base32'
require 'openssl'
require 'uri'
TOTP_INTERVAL = 30
def get_pasword(secret_key, t)
now = t / TOTP_INTERVAL
key = Base32.decode secret_key
sha = OpenSSL::Digest::Digest.new('sha1')
bytes = [ now ].pack('>q').reverse
hmac = OpenSSL::HMAC.digest(sha, key.to_s, bytes)
offset = nil
if RUBY_VERSION > '1.9'
offset = hmac[-1].ord & 0x0F
else
offset = hmac[-1] & 0x0F
end
hash = hmac[offset...offset + 4]
code = hash.reverse.unpack('L')[0]
code &= 0x7FFFFFFF
code %= 1000000
end
accounts = []
# Read ~/.otp file line by line.
# e.g. otpauth://totp/user@localhost?secret=SECRET
File.open(File.join(Dir.home(), '.otp')).each do |line|
uri = URI.parse(line)
accounts << {
:user => uri.path,
:secret => URI.decode_www_form(uri.query).assoc('secret').last.upcase
}
end
accounts.each {|account|
now = Time.now
current = get_pasword(account[:secret], now.to_i)
puts "%s, %06d, %02ds" % [account[:user], current, TOTP_INTERVAL - (now.to_i % TOTP_INTERVAL)]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment