rotp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+ gemspec
3
+ gem 'rspec'
4
+ gem 'timecop'
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,8 @@
1
+ require 'rotp/otp'
2
+ require 'rotp/hotp'
3
+ require 'rotp/totp'
4
+ require 'base32'
5
+ require 'openssl'
6
+
7
+ module Rotp
8
+ end
@@ -0,0 +1,8 @@
1
+ module ROTP
2
+ class HOTP < OTP
3
+ def at(count)
4
+ generate_otp(count)
5
+ end
6
+ end
7
+
8
+ end
@@ -0,0 +1,37 @@
1
+ module ROTP
2
+ class OTP
3
+ attr_reader :secret, :digits, :digest
4
+
5
+ # Params: secret in base32
6
+ def initialize(s, options = {})
7
+ @digits = options[:digits] || 6
8
+ @digest = options[:digest] || "sha1"
9
+ @secret = options[:raw_secret] ? s : Base32.decode(s)
10
+ end
11
+
12
+ def generate_otp(count)
13
+ hmac = OpenSSL::HMAC.digest(
14
+ OpenSSL::Digest::Digest.new(digest),
15
+ secret,
16
+ int_to_bytestring(count)
17
+ )
18
+
19
+ offset = hmac[19] & 0xf
20
+ code = (hmac[offset] & 0x7f) << 24 |
21
+ (hmac[offset + 1] & 0xff) << 16 |
22
+ (hmac[offset + 2] & 0xff) << 8 |
23
+ (hmac[offset + 3] & 0xff)
24
+ code % 10 ** digits
25
+ end
26
+
27
+ def int_to_bytestring(int, padding = 8)
28
+ result = []
29
+ until int == 0
30
+ result << (int & 0xFF).chr
31
+ int >>= 8
32
+ end
33
+ result.reverse.join.rjust(8, 0.chr)
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ module ROTP
2
+ class TOTP < OTP
3
+
4
+ attr_reader :interval
5
+
6
+ def initialize(s, options = {})
7
+ @interval = options[:interval] || 30
8
+ super
9
+ end
10
+
11
+ def at(time)
12
+ unless time.class == Time
13
+ time = Time.at(time.to_i)
14
+ end
15
+ generate_otp(timehash(time))
16
+ end
17
+
18
+ def now
19
+ generate_otp(timehash(Time.now))
20
+ end
21
+
22
+ private
23
+
24
+ def timehash(time)
25
+ i = time.utc.to_i * 1000
26
+ i = i / (interval * 1000)
27
+ i
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Rotp
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rotp/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rotp"
7
+ s.version = Rotp::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Mark Percival"]
10
+ s.email = ["mark@markpercival.us"]
11
+ s.homepage = ""
12
+ s.summary = %q{A Ruby library for generating and verifying one time passwords}
13
+ s.description = %q{Works for both HOTP and TOTP, and include QR Code provisioning}
14
+
15
+ s.rubyforge_project = "rotp"
16
+
17
+ s.add_dependency('base32', '0.1.2')
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe "HOTP example values from the rfc" do
4
+ it "should match the RFC" do
5
+ # 12345678901234567890 in Bas32
6
+ # GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ
7
+ hotp = ROTP::HOTP.new("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ")
8
+ hotp.at(0).should ==(755224)
9
+ hotp.at(1).should ==(287082)
10
+ hotp.at(2).should ==(359152)
11
+ hotp.at(3).should ==(969429)
12
+ hotp.at(4).should ==(338314)
13
+ hotp.at(5).should ==(254676)
14
+ hotp.at(6).should ==(287922)
15
+ hotp.at(7).should ==(162583)
16
+ hotp.at(8).should ==(399871)
17
+ hotp.at(9).should ==(520489)
18
+ end
19
+ end
20
+
21
+ describe "TOTP example values from the rfc" do
22
+ it "should match the RFC" do
23
+ totp = ROTP::TOTP.new("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ")
24
+ totp.at(1111111111).should ==(50471)
25
+ totp.at(1234567890).should ==(5924)
26
+ totp.at(2000000000).should ==(279037)
27
+ end
28
+
29
+ it "should match the Google Authenticator output" do
30
+ totp = ROTP::TOTP.new("wrn3pqx5uqxqvnqr")
31
+ Timecop.freeze(Time.at(1297553958)) do
32
+ totp.now.should ==(102705)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'timecop'
4
+
5
+ require 'rotp'
6
+
7
+ RSpec.configure do |config|
8
+ # some (optional) config here
9
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rotp
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Mark Percival
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-12 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: base32
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: 31
30
+ segments:
31
+ - 0
32
+ - 1
33
+ - 2
34
+ version: 0.1.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: Works for both HOTP and TOTP, and include QR Code provisioning
38
+ email:
39
+ - mark@markpercival.us
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - Gemfile
49
+ - Rakefile
50
+ - lib/rotp.rb
51
+ - lib/rotp/hotp.rb
52
+ - lib/rotp/otp.rb
53
+ - lib/rotp/totp.rb
54
+ - lib/rotp/version.rb
55
+ - rotp.gemspec
56
+ - spec/base_spec.rb
57
+ - spec/spec_helper.rb
58
+ has_rdoc: true
59
+ homepage: ""
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options: []
64
+
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project: rotp
88
+ rubygems_version: 1.5.2
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: A Ruby library for generating and verifying one time passwords
92
+ test_files:
93
+ - spec/base_spec.rb
94
+ - spec/spec_helper.rb