YubiRuby 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/Manifest +13 -3
- data/README +44 -0
- data/Rakefile +8 -2
- data/YubiRuby.gemspec +19 -7
- data/bin/yubikey +39 -0
- data/ext/libyubikey/libyubikey.c +26 -7
- data/lib/exceptions.rb +52 -0
- data/lib/fake_yubikey.rb +209 -0
- data/lib/hex.rb +36 -5
- data/lib/yubiruby.rb +2 -0
- data/tasks/yard_doc.rake +50 -0
- data/test/fake_yubikey_spec.rb +155 -0
- data/test/hex_spec.rb +52 -0
- data/test/modhex_spec.rb +81 -0
- data/{tests/ts_yubiruby.rb → test/path_loader.rb} +2 -2
- data/test/tc_crc16.rb +10 -0
- data/test/tc_fake_yubikey.rb +89 -0
- data/test/tc_hex.rb +29 -0
- data/test/tc_modhex.rb +36 -0
- data/test/test_helper.rb +8 -0
- metadata +84 -12
- data/tests/tc_modhex.rb +0 -13
data/lib/hex.rb
CHANGED
@@ -47,7 +47,16 @@ module YubiRuby
|
|
47
47
|
#
|
48
48
|
def self.encode( obj )
|
49
49
|
s = obj.to_str
|
50
|
-
s.unpack('U'*s.length).collect {|x| x.to_s 16}.join
|
50
|
+
s.unpack('U'*s.length).collect {|x| tmp = x.to_s 16; tmp.length == 1 ? "0#{tmp}" : tmp }.join
|
51
|
+
rescue ArgumentError
|
52
|
+
#non UTF-8 string
|
53
|
+
s = obj.to_str
|
54
|
+
out = []
|
55
|
+
0.upto(s.length-1) do |i|
|
56
|
+
tmp = s[i].to_s 16
|
57
|
+
out << (tmp.length == 1 ? "0#{tmp}" : tmp )
|
58
|
+
end
|
59
|
+
out.join
|
51
60
|
end
|
52
61
|
|
53
62
|
# call-seq:
|
@@ -59,17 +68,19 @@ module YubiRuby
|
|
59
68
|
end
|
60
69
|
|
61
70
|
# call-seq:
|
62
|
-
# YubiRuby::HEX.decode("hex string") -> "string"
|
71
|
+
# YubiRuby::HEX.decode("hex string") -> "string"
|
63
72
|
#
|
64
73
|
# Decodes <tt>obj.to_str</tt> into a <tt>string</tt>.
|
65
74
|
#
|
66
|
-
# An <tt>hex string</tt> length must be pair, if not
|
67
|
-
#
|
75
|
+
# An <tt>hex string</tt> length must be pair, if not a
|
76
|
+
# NoHexEncodedError excpetion is raised
|
68
77
|
def self.decode( obj )
|
69
78
|
s = obj.to_str
|
70
79
|
dec = ""
|
71
|
-
if (s
|
80
|
+
if hex?(s)
|
72
81
|
(s.length/2).times { |i| dec << s[i*2,2].hex.chr }
|
82
|
+
else
|
83
|
+
raise NoHexEncodedError.new
|
73
84
|
end
|
74
85
|
|
75
86
|
return dec
|
@@ -82,5 +93,25 @@ module YubiRuby
|
|
82
93
|
def hex_decode
|
83
94
|
HEX.decode(self)
|
84
95
|
end
|
96
|
+
|
97
|
+
# call-seq:
|
98
|
+
# YubiRuby::HEX.hex?("hex string") -> true or false
|
99
|
+
#
|
100
|
+
# Tests if <tt>obj.to_str</tt> is a valid a <tt>hex string</tt>.
|
101
|
+
#
|
102
|
+
# An <tt>hex string</tt> length must be pair.
|
103
|
+
def self.hex?( obj )
|
104
|
+
s = obj.to_str
|
105
|
+
return false unless (s.length % 2 == 0)
|
106
|
+
return (s.upcase =~ /[^A-F0-9]/).nil?
|
107
|
+
end
|
108
|
+
|
109
|
+
# call-seq:
|
110
|
+
# hex? -> true or false
|
111
|
+
#
|
112
|
+
# Invokes YubiRuby::HEX.hex? on +self+.
|
113
|
+
def hex?
|
114
|
+
HEX.hex?(self)
|
115
|
+
end
|
85
116
|
end
|
86
117
|
end
|
data/lib/yubiruby.rb
CHANGED
@@ -27,8 +27,10 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
+
require 'exceptions'
|
30
31
|
require 'libyubikey'
|
31
32
|
require 'hex'
|
33
|
+
require 'fake_yubikey'
|
32
34
|
|
33
35
|
module YubiRuby
|
34
36
|
# C code version
|
data/tasks/yard_doc.rake
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# =======================
|
2
|
+
# = Documentation tasks =
|
3
|
+
# =======================
|
4
|
+
begin
|
5
|
+
require 'yard'
|
6
|
+
require 'yard/rake/yardoc_task'
|
7
|
+
|
8
|
+
task :documentation => :'documentation:generate'
|
9
|
+
namespace :documentation do
|
10
|
+
YARD::Rake::YardocTask.new :generate do |t|
|
11
|
+
t.files = ['lib/**/*.rb', 'ext/**/*.c']
|
12
|
+
t.options = ['--output-dir', File.join('meta', 'documentation'),
|
13
|
+
'--readme', 'README']
|
14
|
+
end
|
15
|
+
|
16
|
+
YARD::Rake::YardocTask.new :dotyardoc do |t|
|
17
|
+
t.files = ['lib/**/*.rb', 'ext/**/*.c']
|
18
|
+
t.options = ['--no-output',
|
19
|
+
'--readme', 'README']
|
20
|
+
end
|
21
|
+
|
22
|
+
class Numeric
|
23
|
+
def pretty_inspect(decimal_points = 3)
|
24
|
+
bits = self.to_s.split('.')
|
25
|
+
bits[0] = bits[0].reverse.scan(/\d{1,3}/).join(',').reverse
|
26
|
+
bits[1] = bits[1][0...decimal_points] if bits[1]
|
27
|
+
bits.join('.')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
task :verify do
|
32
|
+
documentation_threshold = 50.0
|
33
|
+
doc = YARD::CLI::Yardoc.new; doc.generate = false; doc.run
|
34
|
+
|
35
|
+
percent_documented = (
|
36
|
+
YARD::Registry.all.select {|o| !o.docstring.empty? }.size /
|
37
|
+
YARD::Registry.all.size.to_f
|
38
|
+
) * 100
|
39
|
+
puts "Documentation coverage: #{percent_documented.pretty_inspect(1)}% (threshold: #{documentation_threshold.pretty_inspect(1)}%)"
|
40
|
+
end
|
41
|
+
|
42
|
+
task :open do
|
43
|
+
system 'open ' + File.join('meta', 'documentation', 'index.html') if PLATFORM['darwin']
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
rescue LoadError
|
48
|
+
desc 'You need the `yard` gem to generate documentation'
|
49
|
+
task :documentation
|
50
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'test/path_loader'
|
2
|
+
|
3
|
+
describe 'YubiRuby::FakeYubikey' do
|
4
|
+
@@UID = 'ffa4f1fa55e0'
|
5
|
+
@@KEY = '884b1fc18da3888b59460f6e33acabf5'
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
@key = YubiRuby::FakeYubikey.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should start in a valid state" do
|
12
|
+
@key.uid.should == "000000000000"
|
13
|
+
@key.session_use.should == 0
|
14
|
+
@key.session_counter.should == 1
|
15
|
+
@key.public_id.should == ""
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be serializable" do
|
19
|
+
@key.public_id = 'hehkhbhv'
|
20
|
+
@key.key = @@KEY
|
21
|
+
@key.uid = @@UID
|
22
|
+
3.times { @key.init }
|
23
|
+
File.open('key.dump', 'w+') do |f|
|
24
|
+
Marshal.dump(@key, f)
|
25
|
+
end
|
26
|
+
|
27
|
+
key2 = nil
|
28
|
+
File.open('key.dump') do |f|
|
29
|
+
key2 = Marshal.load(f)
|
30
|
+
end
|
31
|
+
|
32
|
+
key2.public_id.should == @key.public_id
|
33
|
+
key2.uid.should == @key.uid
|
34
|
+
key2.data.session_counter.should == @key.session_counter+1
|
35
|
+
key2.key.should == @key.key
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#set_random_uid" do
|
39
|
+
it "should generate a hex valid string" do
|
40
|
+
@key.set_random_uid
|
41
|
+
@key.uid.hex?.should == true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#set_random_key" do
|
46
|
+
it "should generate a hex valid string" do
|
47
|
+
@key.set_random_key
|
48
|
+
@key.key.hex?.should == true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#otp' do
|
53
|
+
it "should generate valid otp" do
|
54
|
+
aes = @key.set_random_key
|
55
|
+
@key.set_random_uid
|
56
|
+
|
57
|
+
validator = YubiRuby::Yubikey.new aes
|
58
|
+
validator.parse(@key.otp).should == true
|
59
|
+
validator.uid.should == @key.uid
|
60
|
+
validator.session_use.should == @key.session_use
|
61
|
+
validator.session_counter.should == @key.session_counter
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should produce a session overflow after 2**8 generations" do
|
65
|
+
@key = YubiRuby::FakeYubikey.new
|
66
|
+
aes = @key.set_random_key
|
67
|
+
uid = @key.set_random_uid
|
68
|
+
session = @key.session_counter
|
69
|
+
1.upto(2**8-1) do |i|
|
70
|
+
@key.otp
|
71
|
+
@key.session_counter.should == session
|
72
|
+
@key.session_use.should == i
|
73
|
+
end
|
74
|
+
@key.otp
|
75
|
+
@key.session_counter.should == session+1
|
76
|
+
@key.session_use.should == 0
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise YubiRuby::YubikeySessionCounterOverflow after SESSION_COUNTER_OVERFLOW initialization" do
|
80
|
+
key = YubiRuby::FakeYubikey.new
|
81
|
+
aes = key.set_random_key
|
82
|
+
uid = key.set_random_uid
|
83
|
+
(session = key.session_counter).should == 1
|
84
|
+
2.upto(YubiRuby::FakeYubikey::Data::SESSION_COUNTER_OVERFLOW) do |i|
|
85
|
+
lambda { key.init }.should_not raise_error(YubiRuby::YubikeySessionCounterOverflow)
|
86
|
+
end
|
87
|
+
lambda { key.init }.should raise_error(YubiRuby::YubikeySessionCounterOverflow)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should starts with public_id" do
|
91
|
+
@key = YubiRuby::FakeYubikey.new
|
92
|
+
@key.key = @@KEY
|
93
|
+
@key.uid = @@UID
|
94
|
+
@key.public_id = 'hehkhbhv'
|
95
|
+
@key.otp[0,8].should == 'hehkhbhv'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#generate_specific_otp_and_fake_yubikey' do
|
100
|
+
it "should work ;)" do
|
101
|
+
aes = 'df5b9d7591b0b3c2819f7a0dd7d1547d'
|
102
|
+
session = 53
|
103
|
+
tsl = 31716
|
104
|
+
tsh = 106
|
105
|
+
counter = 0
|
106
|
+
random = 30172
|
107
|
+
crc = 58822
|
108
|
+
uid = "6d8dec078841"
|
109
|
+
check_otp = 'rfechkcdkjrflgrjlirdgivnedbbtcik'
|
110
|
+
result = YubiRuby::FakeYubikey.generate_specific_otp_and_fake_yubikey(
|
111
|
+
aes, uid, session, tsl, tsh, counter, random)
|
112
|
+
mycrc = YubiRuby::CRC16.calculate(result[1].to_s[0...-2]).ones_complement 16
|
113
|
+
|
114
|
+
lambda {
|
115
|
+
YubiRuby::Yubikey.new(aes).parse(result[0]).should == true
|
116
|
+
}.should_not raise_error(TypeError)
|
117
|
+
result[1].key.should == aes
|
118
|
+
result[1].session_counter.should == session
|
119
|
+
result[1].timestamp_low.should == tsl
|
120
|
+
result[1].timestamp_high.should == tsh
|
121
|
+
result[1].session_use.should == counter
|
122
|
+
result[1].random.should == random
|
123
|
+
result[1].crc.should == crc
|
124
|
+
result[1].uid.should == uid
|
125
|
+
result[0].should == check_otp
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "#public_id=" do
|
130
|
+
it "should accepts modhex strings" do
|
131
|
+
id = 'rfechkcdkjrflgrjlirdgivnedbbtcik'
|
132
|
+
@key.public_id = id
|
133
|
+
@key.public_id.should == id
|
134
|
+
id = 'hehkhbhv'
|
135
|
+
@key.public_id = id
|
136
|
+
@key.public_id.should == id
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should accepts only modhex strings" do
|
140
|
+
id = @key.public_id
|
141
|
+
lambda {@key.public_id = "pluto"}.should raise_error(YubiRuby::NoModHexEncodedError)
|
142
|
+
@key.public_id.should == id
|
143
|
+
lambda{@key.public_id = "pip!8"}.should raise_error(YubiRuby::NoModHexEncodedError)
|
144
|
+
@key.public_id.should == id
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should truncate longer string" do
|
148
|
+
id = 'rfechkcdkjrflgrjlirdgivnedbbtcikrfechkcdkjrflgrjlirdgivnedbbtcik'
|
149
|
+
(id.length > 32).should == true
|
150
|
+
|
151
|
+
@key.public_id = id
|
152
|
+
@key.public_id.should == id[0,32]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/test/hex_spec.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test/path_loader'
|
2
|
+
|
3
|
+
describe 'YubiRuby::HEX' do
|
4
|
+
describe '#encode' do
|
5
|
+
it 'should work as expected' do
|
6
|
+
str = "ciao\n"
|
7
|
+
hex = "6369616f0a"
|
8
|
+
YubiRuby::HEX.encode(str).should == hex
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should be a reversible operation' do
|
12
|
+
str = "ciao\n"
|
13
|
+
hex = YubiRuby::HEX.encode(str)
|
14
|
+
YubiRuby::HEX.decode(hex).should == str
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#decode' do
|
19
|
+
it 'should work as expected' do
|
20
|
+
str = "ciao\n"
|
21
|
+
hex = "6369616f0a"
|
22
|
+
YubiRuby::HEX.decode(hex).should == str
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should be a reversible operation' do
|
26
|
+
hex = "6369616f0a"
|
27
|
+
str = YubiRuby::HEX.decode(hex)
|
28
|
+
YubiRuby::HEX.encode(str).should == hex
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should raise NoHexEncodedError if decoding non Hex string' do
|
32
|
+
lambda { YubiRuby::HEX.decode('a') }.should raise_error(YubiRuby::NoHexEncodedError)
|
33
|
+
lambda {YubiRuby::HEX.decode('zebr') }.should raise_error(YubiRuby::NoHexEncodedError)
|
34
|
+
lambda {YubiRuby::HEX.decode('!af5') }.should raise_error(YubiRuby::NoHexEncodedError)
|
35
|
+
lambda {YubiRuby::HEX.decode('0x12ff') }.should raise_error(YubiRuby::NoHexEncodedError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#hex?' do
|
40
|
+
it 'should recognize valid hex' do
|
41
|
+
YubiRuby::HEX.hex?('7af5').should == true
|
42
|
+
YubiRuby::HEX.hex?('12fF').should == true
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should recognize invalid hex' do
|
46
|
+
YubiRuby::HEX.hex?('a').should == false
|
47
|
+
YubiRuby::HEX.hex?('zebr').should == false
|
48
|
+
YubiRuby::HEX.hex?('!af5').should == false
|
49
|
+
YubiRuby::HEX.hex?('0x12ff').should == false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/modhex_spec.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'test/path_loader'
|
2
|
+
|
3
|
+
describe 'YubiRuby::ModHex' do
|
4
|
+
|
5
|
+
it 'should be a reversible operation' do
|
6
|
+
str = "test"
|
7
|
+
hex = "ifhgieif"
|
8
|
+
YubiRuby::ModHex.decode(YubiRuby::ModHex.encode(str)).should == str
|
9
|
+
YubiRuby::ModHex.encode(YubiRuby::ModHex.decode(hex)).should == hex
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#encode' do
|
13
|
+
it 'should work as expected' do
|
14
|
+
str = "test"
|
15
|
+
hex = "ifhgieif"
|
16
|
+
YubiRuby::ModHex.encode(str).should == hex
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should double the string lenght" do
|
20
|
+
str = '1234zz567890'
|
21
|
+
str.size.should == 12
|
22
|
+
str.modhex_encode.size.should == 24
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#decode' do
|
28
|
+
it 'should work as expected' do
|
29
|
+
str = "test"
|
30
|
+
hex = "ifhgieif"
|
31
|
+
YubiRuby::ModHex.decode(hex).should == str
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should raise NoModHexEncodedError if decoding non ModHex string' do
|
35
|
+
lambda { YubiRuby::ModHex.decode('a') }.should raise_error(YubiRuby::NoModHexEncodedError)
|
36
|
+
lambda {YubiRuby::ModHex.decode('zebr') }.should raise_error(YubiRuby::NoModHexEncodedError)
|
37
|
+
lambda {YubiRuby::ModHex.decode('!af5') }.should raise_error(YubiRuby::NoModHexEncodedError)
|
38
|
+
lambda {YubiRuby::ModHex.decode('0x12ff') }.should raise_error(YubiRuby::NoModHexEncodedError)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should halves the string lenght" do
|
42
|
+
otp = 'dbkutdgrnlvrhdiregebvkkrgtuefjru'
|
43
|
+
otp.size.should == 32
|
44
|
+
otp.modhex_decode.size.should == 16
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#hex?' do
|
49
|
+
it 'should recognize valid hex' do
|
50
|
+
YubiRuby::ModHex.modhex?('ifhgieif').should == true
|
51
|
+
YubiRuby::ModHex.modhex?('ichkicichv').should == true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should recognize invalid hex' do
|
55
|
+
YubiRuby::ModHex.modhex?('a').should == false
|
56
|
+
YubiRuby::ModHex.modhex?('zebr').should == false
|
57
|
+
YubiRuby::ModHex.modhex?('!af5').should == false
|
58
|
+
YubiRuby::ModHex.modhex?('0x12ff').should == false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'String' do
|
64
|
+
describe '#modhex_decode' do
|
65
|
+
it "should call YubiRuby::ModHex#decode once" do
|
66
|
+
otp = 'dbkutdgrnlvrhdiregebvkkrgtuefjru'
|
67
|
+
YubiRuby::ModHex.should_receive(:decode).once.with(otp)
|
68
|
+
YubiRuby::ModHex.should_not_receive(:encode)
|
69
|
+
otp.modhex_decode
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#modhex_encode' do
|
74
|
+
it "should call YubiRuby::ModHex#encode once" do
|
75
|
+
str = 'ciaociao ciao'
|
76
|
+
YubiRuby::ModHex.should_receive(:encode).once.with(str)
|
77
|
+
YubiRuby::ModHex.should_not_receive(:decode)
|
78
|
+
str.modhex_encode
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/test/tc_crc16.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
class TestCRC16 < Test::Unit::TestCase
|
2
|
+
def test_crc_calculate
|
3
|
+
str = YubiRuby::HEX.decode '6d8dec07884101002216a1041b7c'
|
4
|
+
otp_decoded = YubiRuby::HEX.decode '6d8dec07884101002216a1041b7c105e'
|
5
|
+
crc = 24080
|
6
|
+
assert_equal(0xF0B8, YubiRuby::CRC16.calculate(otp_decoded))
|
7
|
+
assert_equal(crc, YubiRuby::CRC16.calculate(str).ones_complement(16))
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
class TestFakeYubikey < Test::Unit::TestCase
|
2
|
+
def test_init
|
3
|
+
key = YubiRuby::FakeYubikey.new
|
4
|
+
assert_equal("000000000000", key.uid )
|
5
|
+
assert_equal(0, key.session_use)
|
6
|
+
assert_equal(1, key.session_counter)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_otp
|
10
|
+
key = YubiRuby::FakeYubikey.new
|
11
|
+
aes = key.set_random_key
|
12
|
+
uid = key.set_random_uid
|
13
|
+
assert(aes.hex?)
|
14
|
+
assert(uid.hex?)
|
15
|
+
validator = YubiRuby::Yubikey.new aes
|
16
|
+
assert(validator.parse(key.otp))
|
17
|
+
assert_equal(validator.uid, uid)
|
18
|
+
assert_equal(validator.session_use, key.session_use)
|
19
|
+
assert_equal(validator.session_counter, key.session_counter)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_generate_random_uid
|
23
|
+
key = YubiRuby::FakeYubikey.new
|
24
|
+
assert_equal(key.set_random_uid, key.uid)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_generate_random_key
|
28
|
+
key = YubiRuby::FakeYubikey.new
|
29
|
+
assert_equal(key.set_random_key, key.key)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_generate_specific_otp_and_fake_yubikey
|
33
|
+
aes = 'df5b9d7591b0b3c2819f7a0dd7d1547d'
|
34
|
+
session = 53
|
35
|
+
tsl = 31716
|
36
|
+
tsh = 106
|
37
|
+
counter = 0
|
38
|
+
random = 30172
|
39
|
+
crc = 58822
|
40
|
+
uid = "6d8dec078841"
|
41
|
+
check_otp = 'rfechkcdkjrflgrjlirdgivnedbbtcik'
|
42
|
+
result = YubiRuby::FakeYubikey.generate_specific_otp_and_fake_yubikey(aes, uid, session,
|
43
|
+
tsl, tsh, counter, random)
|
44
|
+
mycrc = YubiRuby::CRC16.calculate(result[1].to_s[0...-2]).ones_complement 16
|
45
|
+
|
46
|
+
|
47
|
+
YubiRuby::Yubikey.new(aes).parse(result[0])
|
48
|
+
assert_equal(aes,result[1].key)
|
49
|
+
assert_equal(session,result[1].session_counter)
|
50
|
+
assert_equal(tsl,result[1].timestamp_low)
|
51
|
+
assert_equal(tsh,result[1].timestamp_high)
|
52
|
+
assert_equal(counter,result[1].session_use)
|
53
|
+
assert_equal(random,result[1].random)
|
54
|
+
assert_equal(crc,result[1].crc)
|
55
|
+
assert_equal(uid,result[1].uid)
|
56
|
+
assert_equal(check_otp,result[0])
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_session_use_overflow
|
60
|
+
key = YubiRuby::FakeYubikey.new
|
61
|
+
aes = key.set_random_key
|
62
|
+
uid = key.set_random_uid
|
63
|
+
session = key.session_counter
|
64
|
+
1.upto(2**8-1) do |i|
|
65
|
+
key.otp
|
66
|
+
assert_equal(session, key.session_counter)
|
67
|
+
assert_equal(i, key.session_use)
|
68
|
+
end
|
69
|
+
key.otp
|
70
|
+
assert_equal(session+1, key.session_counter)
|
71
|
+
assert_equal(0, key.session_use)
|
72
|
+
end
|
73
|
+
|
74
|
+
# ruby(71000) malloc: *** error for object 0x101aa6e70:
|
75
|
+
# incorrect checksum for freed object - object was probably modified after being freed.
|
76
|
+
# def test_session_counter_overflow
|
77
|
+
# key = YubiRuby::FakeYubikey.new
|
78
|
+
# aes = key.set_random_key
|
79
|
+
# uid = key.set_random_uid
|
80
|
+
# session = key.session_counter
|
81
|
+
# assert_equal(1, session)
|
82
|
+
# 2.upto(YubiRuby::FakeYubikey::Data::SESSION_COUNTER_OVERFLOW) do |i|
|
83
|
+
# key.init
|
84
|
+
# end
|
85
|
+
# assert_raise YubiRuby::YubikeySessionCounterOverflow do
|
86
|
+
# key.init
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
end
|