rotp 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +33 -3
- data/Rakefile +10 -0
- data/lib/rotp.rb +1 -9
- data/lib/rotp/base32.rb +48 -0
- data/lib/rotp/otp.rb +5 -5
- data/lib/rotp/version.rb +1 -1
- data/rotp.gemspec +0 -2
- data/spec/base_spec.rb +3 -3
- metadata +8 -25
data/README.markdown
CHANGED
@@ -2,12 +2,18 @@
|
|
2
2
|
|
3
3
|
A ruby library for generating one time passwords according to [ RFC 4226 ](http://tools.ietf.org/html/rfc4226) and the [ HOTP RFC ](http://tools.ietf.org/html/draft-mraihi-totp-timebased-00)
|
4
4
|
|
5
|
-
This is compatible with Google Authenticator apps available for Android and iPhone
|
5
|
+
This is compatible with Google Authenticator apps available for Android and iPhone, and now in use on GMail
|
6
|
+
|
7
|
+
## Quick overview of using One Time Passwords on your phone
|
8
|
+
|
9
|
+
* OTP's involve a shared secret, stored both on the phone and the server
|
10
|
+
* OTP's can be generated on a phone without internet connectivity(AT&T mode)
|
11
|
+
* OTP's should always be used as a second factor of authentication(if your phone is lost, you account is still secured with a password)
|
12
|
+
* Google Authenticator allows you to store multiple OTP secrets and provision those using a QR Code(no more typing in the secret)
|
6
13
|
|
7
14
|
## Dependencies
|
8
15
|
|
9
16
|
* OpenSSL
|
10
|
-
* Base32
|
11
17
|
|
12
18
|
## Installation
|
13
19
|
|
@@ -40,7 +46,7 @@ This is compatible with Google Authenticator apps available for Android and iPho
|
|
40
46
|
|
41
47
|
ROTP.random_base32 # returns a 16 character base32 secret. Compatible with Google Authenticator
|
42
48
|
|
43
|
-
### Google Authenticator
|
49
|
+
### Google Authenticator Compatible
|
44
50
|
|
45
51
|
The library works with the Google Authenticator iPhone and Android app, and also
|
46
52
|
includes the ability to generate provisioning URI's for use with the QR Code scanner
|
@@ -51,3 +57,27 @@ built into the app.
|
|
51
57
|
|
52
58
|
This can then be rendered as a QR Code which can then be scanned and added to the users
|
53
59
|
list of OTP credentials.
|
60
|
+
|
61
|
+
#### Working example
|
62
|
+
|
63
|
+
Scan the following barcode with your phone, using Google Authenticator
|
64
|
+
|
65
|
+
![QR Code for OTP](http://chart.apis.google.com/chart?cht=qr&chs=250x250&chl=otpauth%3A%2F%2Ftotp%2Falice%40google.com%3Fsecret%3DJBSWY3DPEHPK3PXP)
|
66
|
+
|
67
|
+
Now run the following and compare the output
|
68
|
+
|
69
|
+
require 'rubygems'
|
70
|
+
require 'rotp'
|
71
|
+
totp = ROTP::TOTP.new("JBSWY3DPEHPK3PXP")
|
72
|
+
p "Current OTP: #{totp.now}"
|
73
|
+
|
74
|
+
### Changelog
|
75
|
+
|
76
|
+
####1.3.0
|
77
|
+
|
78
|
+
- Added support for Ruby 1.9.x
|
79
|
+
- Removed dependency on Base32
|
80
|
+
|
81
|
+
### See also:
|
82
|
+
|
83
|
+
PHP port of ROTP by [Le Lag](https://github.com/lelag) - [OTPHP](https://github.com/lelag/otphp)
|
data/Rakefile
CHANGED
@@ -1,2 +1,12 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
require 'rake/testtask'
|
6
|
+
Rake::TestTask.new(:test) do |test|
|
7
|
+
test.libs << 'lib' << 'test' << '.'
|
8
|
+
test.pattern = 'test/**/test_*.rb'
|
9
|
+
test.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task :default => :test
|
data/lib/rotp.rb
CHANGED
@@ -1,17 +1,9 @@
|
|
1
|
+
require 'rotp/base32'
|
1
2
|
require 'rotp/otp'
|
2
3
|
require 'rotp/hotp'
|
3
4
|
require 'rotp/totp'
|
4
|
-
require 'base32'
|
5
5
|
require 'uri'
|
6
6
|
require 'openssl'
|
7
7
|
|
8
8
|
module ROTP
|
9
|
-
BASE32 = 'abcdefghijklmnopqrstuvwxyz234567'
|
10
|
-
def self.random_base32(length=16)
|
11
|
-
b32 = ''
|
12
|
-
OpenSSL::Random.random_bytes(length).each_byte do |b|
|
13
|
-
b32 << BASE32[b % 32, 1]
|
14
|
-
end
|
15
|
-
b32
|
16
|
-
end
|
17
9
|
end
|
data/lib/rotp/base32.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module ROTP
|
2
|
+
class Base32
|
3
|
+
CHARS = "abcdefghijklmnopqrstuvwxyz234567".each_char.to_a
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def decode(str)
|
7
|
+
output = []
|
8
|
+
str.scan(/.{8}/).each do |block|
|
9
|
+
char_array = decode_block(block).map{|c| c.chr}
|
10
|
+
output << char_array
|
11
|
+
end
|
12
|
+
output.join
|
13
|
+
end
|
14
|
+
|
15
|
+
def random_base32(length=16)
|
16
|
+
b32 = ''
|
17
|
+
OpenSSL::Random.random_bytes(length).each_byte do |b|
|
18
|
+
b32 << CHARS[b % 32]
|
19
|
+
end
|
20
|
+
b32
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def decode_block(block)
|
26
|
+
return 0 unless (block.bytesize % 8 == 0) || (block.bytesize == 0)
|
27
|
+
length = block.scan(/[^=]/).length
|
28
|
+
quints = block.each_char.map {|c| decode_quint(c)}
|
29
|
+
bytes = []
|
30
|
+
bytes[0] = (quints[0] << 3) + (quints[1] >> 2)
|
31
|
+
return bytes if length < 3
|
32
|
+
bytes[1] = ((quints[1] & 3) << 6) + (quints[2] << 1) + (quints[3] >> 4)
|
33
|
+
return bytes if length < 5
|
34
|
+
bytes[2] = ((quints[3] & 15) << 4) + (quints[4] >> 1)
|
35
|
+
return bytes if length < 6
|
36
|
+
bytes[3] = ((quints[4] & 1) << 7) + (quints[5] << 2) + (quints[6] >> 3)
|
37
|
+
bytes[4] = ((quints[6] & 7) << 5) + quints[7]
|
38
|
+
bytes
|
39
|
+
end
|
40
|
+
|
41
|
+
def decode_quint(q)
|
42
|
+
CHARS.index(q.downcase)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/rotp/otp.rb
CHANGED
@@ -26,11 +26,11 @@ module ROTP
|
|
26
26
|
int_to_bytestring(input)
|
27
27
|
)
|
28
28
|
|
29
|
-
offset = hmac[19] & 0xf
|
30
|
-
code = (hmac[offset] & 0x7f) << 24 |
|
31
|
-
(hmac[offset + 1] & 0xff) << 16 |
|
32
|
-
(hmac[offset + 2] & 0xff) << 8 |
|
33
|
-
(hmac[offset + 3] & 0xff)
|
29
|
+
offset = hmac[19].ord & 0xf
|
30
|
+
code = (hmac[offset].ord & 0x7f) << 24 |
|
31
|
+
(hmac[offset + 1].ord & 0xff) << 16 |
|
32
|
+
(hmac[offset + 2].ord & 0xff) << 8 |
|
33
|
+
(hmac[offset + 3].ord & 0xff)
|
34
34
|
code % 10 ** digits
|
35
35
|
end
|
36
36
|
|
data/lib/rotp/version.rb
CHANGED
data/rotp.gemspec
CHANGED
@@ -14,8 +14,6 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
s.rubyforge_project = "rotp"
|
16
16
|
|
17
|
-
s.add_dependency('base32', '0.1.2')
|
18
|
-
|
19
17
|
s.files = `git ls-files`.split("\n")
|
20
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
data/spec/base_spec.rb
CHANGED
@@ -2,11 +2,11 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe "generating a random base32 secret" do
|
4
4
|
it "should be 16 characters by default" do
|
5
|
-
ROTP.random_base32.length.should == 16
|
6
|
-
ROTP.random_base32.should match /[a-z2-7].+/
|
5
|
+
ROTP::Base32.random_base32.length.should == 16
|
6
|
+
ROTP::Base32.random_base32.should match /[a-z2-7].+/
|
7
7
|
end
|
8
8
|
it "should be allow a specific length" do
|
9
|
-
ROTP.random_base32(32).length.should == 32
|
9
|
+
ROTP::Base32.random_base32(32).length.should == 32
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rotp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
4
|
+
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 1
|
8
|
-
-
|
7
|
+
- 3
|
9
8
|
- 0
|
10
|
-
version: 1.
|
9
|
+
version: 1.3.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Mark Percival
|
@@ -15,25 +14,10 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2011-
|
17
|
+
date: 2011-05-01 00:00:00 -07:00
|
19
18
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
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
|
19
|
+
dependencies: []
|
20
|
+
|
37
21
|
description: Works for both HOTP and TOTP, and include QR Code provisioning
|
38
22
|
email:
|
39
23
|
- mark@markpercival.us
|
@@ -68,6 +52,7 @@ files:
|
|
68
52
|
- doc/method_list.html
|
69
53
|
- doc/top-level-namespace.html
|
70
54
|
- lib/rotp.rb
|
55
|
+
- lib/rotp/base32.rb
|
71
56
|
- lib/rotp/hotp.rb
|
72
57
|
- lib/rotp/otp.rb
|
73
58
|
- lib/rotp/totp.rb
|
@@ -89,7 +74,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
74
|
requirements:
|
90
75
|
- - ">="
|
91
76
|
- !ruby/object:Gem::Version
|
92
|
-
hash: 3
|
93
77
|
segments:
|
94
78
|
- 0
|
95
79
|
version: "0"
|
@@ -98,14 +82,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
82
|
requirements:
|
99
83
|
- - ">="
|
100
84
|
- !ruby/object:Gem::Version
|
101
|
-
hash: 3
|
102
85
|
segments:
|
103
86
|
- 0
|
104
87
|
version: "0"
|
105
88
|
requirements: []
|
106
89
|
|
107
90
|
rubyforge_project: rotp
|
108
|
-
rubygems_version: 1.
|
91
|
+
rubygems_version: 1.3.7
|
109
92
|
signing_key:
|
110
93
|
specification_version: 3
|
111
94
|
summary: A Ruby library for generating and verifying one time passwords
|