YubiRuby 0.1.0 → 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.
- 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
|