rocra 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +59 -0
- data/Rakefile +5 -0
- data/lib/rocra.rb +217 -0
- data/lib/rocra/version.rb +3 -0
- data/rocra.gemspec +22 -0
- data/spec/rocra_spec.rb +86 -0
- metadata +78 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 phil
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/branch14/rocra.png?branch=master)](https://travis-ci.org/branch14/rocra)
|
2
|
+
|
3
|
+
_ __ ___ ___ _ __ __ _
|
4
|
+
| '__/ _ \ / __| '__/ _` |
|
5
|
+
| | | (_) | (__| | | (_| |
|
6
|
+
|_| \___/ \___|_| \__,_|
|
7
|
+
|
8
|
+
# Welcome to rocra
|
9
|
+
|
10
|
+
rocra is an OCRA (RFC 6287) implementation in Ruby.
|
11
|
+
|
12
|
+
see http://tools.ietf.org/html/rfc6287
|
13
|
+
|
14
|
+
It is based on the implementations found here https://github.com/SURFnet/ocra-implementations
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
gem 'rocra'
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install rocra
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
suite = 'OCRA-1:HOTP-SHA1-6:QN08' # string, mandatory
|
33
|
+
key = "3132333435363738393031323334353637383930" # hex, mandatory
|
34
|
+
counter = nil # hex, optional
|
35
|
+
question = '12345678'.to_i.to_s(16) # hex, mandatory
|
36
|
+
password = nil # hex, optional
|
37
|
+
session = nil # hex, optional
|
38
|
+
timestamp = nil # optional
|
39
|
+
|
40
|
+
Rocra.generate(suite, key, counter, question, password, session, timestamp)
|
41
|
+
|
42
|
+
## Specs
|
43
|
+
|
44
|
+
Run
|
45
|
+
|
46
|
+
rspec
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
1. Fork it
|
51
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
55
|
+
|
56
|
+
## Todo
|
57
|
+
|
58
|
+
- fix jruby issues
|
59
|
+
- make api more rubyesque
|
data/Rakefile
ADDED
data/lib/rocra.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
require "rocra/version"
|
4
|
+
|
5
|
+
class Rocra
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# This method generates an OCRA HOTP value for the given set of
|
10
|
+
# parameters.
|
11
|
+
#
|
12
|
+
# @param ocraSuite the OCRA Suite
|
13
|
+
# @param key the shared secret, HEX encoded
|
14
|
+
# @param counter the counter that changes
|
15
|
+
# on a per use basis,
|
16
|
+
# HEX encoded
|
17
|
+
# @param question the challenge question, HEX encoded
|
18
|
+
# @param password a password that can be used,
|
19
|
+
# HEX encoded
|
20
|
+
# @param sessionInformation
|
21
|
+
# Static information that identifies the
|
22
|
+
# current session, Hex encoded
|
23
|
+
# @param timestamp a value that reflects a time
|
24
|
+
#
|
25
|
+
# @return A numeric String in base 10 that includes
|
26
|
+
# {@link truncationDigits} digits
|
27
|
+
def generate(ocra_suite, key, counter, question, password, session_information, timestamp)
|
28
|
+
|
29
|
+
code_digits = 0
|
30
|
+
crypto = ""
|
31
|
+
result = nil
|
32
|
+
ocra_suite_length = ocra_suite.length
|
33
|
+
counter_length = 0
|
34
|
+
question_length = 0
|
35
|
+
password_length = 0
|
36
|
+
|
37
|
+
session_information_length = 0
|
38
|
+
timestamp_length = 0
|
39
|
+
|
40
|
+
# How many digits should we return
|
41
|
+
components = ocra_suite.split(':')
|
42
|
+
cryptoFunction = components[1]
|
43
|
+
dataInput = components[2].downcase # lower here so we can do case insensitive comparisons
|
44
|
+
|
45
|
+
crypto = 'sha1' if cryptoFunction.downcase.include?('sha1')
|
46
|
+
crypto = 'sha256' if cryptoFunction.downcase.include?('sha256')
|
47
|
+
crypto = 'sha512' if cryptoFunction.downcase.include?('sha512')
|
48
|
+
|
49
|
+
code_digits = cryptoFunction.split('-').last
|
50
|
+
|
51
|
+
# The size of the byte array message to be encrypted
|
52
|
+
|
53
|
+
# Counter
|
54
|
+
if dataInput[0,1] == "c"
|
55
|
+
# Fix the length of the HEX string
|
56
|
+
counter_length=8
|
57
|
+
counter = counter.rjust(16, '0')
|
58
|
+
end
|
59
|
+
|
60
|
+
# Question
|
61
|
+
if dataInput[0,1] == "q" || dataInput.include?('-q')
|
62
|
+
question = question.ljust(256, '0')
|
63
|
+
question_length = 128
|
64
|
+
end
|
65
|
+
|
66
|
+
# Password
|
67
|
+
if dataInput.include?("psha1")
|
68
|
+
password = password.ljust(40, '0')
|
69
|
+
password_length = 20
|
70
|
+
end
|
71
|
+
|
72
|
+
if dataInput.include?("psha256")
|
73
|
+
password = password.ljust(64, '0')
|
74
|
+
password_length = 32
|
75
|
+
end
|
76
|
+
|
77
|
+
if dataInput.include?("psha512")
|
78
|
+
password = password.ljust(128, '0')
|
79
|
+
password_length = 64
|
80
|
+
end
|
81
|
+
|
82
|
+
# session_information
|
83
|
+
if dataInput.include?("s064")
|
84
|
+
session_information = session_information.ljust(128, '0')
|
85
|
+
session_information_length = 64
|
86
|
+
end
|
87
|
+
|
88
|
+
if dataInput.include?("s128")
|
89
|
+
session_information = session_information.ljust(256, '0')
|
90
|
+
session_information_length = 128
|
91
|
+
end
|
92
|
+
|
93
|
+
if dataInput.include?("s256")
|
94
|
+
session_information = session_information.ljust(512, '0')
|
95
|
+
session_information_length = 256
|
96
|
+
end
|
97
|
+
|
98
|
+
if dataInput.include?("s512")
|
99
|
+
session_information = session_information.ljust(128, '0')
|
100
|
+
session_information_length = 64
|
101
|
+
end
|
102
|
+
|
103
|
+
# TimeStamp
|
104
|
+
if dataInput[0,1] == "t" || dataInput.include?("-t")
|
105
|
+
timestamp = timestamp.rjust(16, '0')
|
106
|
+
timestamp_length = 8
|
107
|
+
end
|
108
|
+
|
109
|
+
# Put the bytes of "ocra_suite" parameters into the message
|
110
|
+
length = ocra_suite_length +
|
111
|
+
counter_length +
|
112
|
+
question_length +
|
113
|
+
password_length +
|
114
|
+
session_information_length +
|
115
|
+
timestamp_length + 1
|
116
|
+
msg = "\0" * length
|
117
|
+
msg[0, ocra_suite.length] = ocra_suite
|
118
|
+
|
119
|
+
# Delimiter
|
120
|
+
# msg[ocra_suite.length] = hex2str("0")
|
121
|
+
|
122
|
+
# Put the bytes of "Counter" to the message
|
123
|
+
# Input is HEX encoded
|
124
|
+
if counter_length > 0
|
125
|
+
pos = ocra_suite_length + 1
|
126
|
+
msg[pos, counter.length] = hex2str(counter)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Put the bytes of "question" to the message
|
130
|
+
# Input is text encoded
|
131
|
+
if question_length > 0
|
132
|
+
pos = ocra_suite_length + 1 + counter_length
|
133
|
+
msg[pos, question.length] = hex2str(question)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Put the bytes of "password" to the message
|
137
|
+
# Input is HEX encoded
|
138
|
+
if password_length > 0
|
139
|
+
pos = ocra_suite_length + 1 + counter_length + question_length
|
140
|
+
msg[pos, password.length] = hex2str(password)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Put the bytes of "session_information" to the message
|
144
|
+
# Input is text encoded
|
145
|
+
if session_information_length > 0
|
146
|
+
pos = ocra_suite_length + 1 + counter_length + question_length + password_length
|
147
|
+
msg[pos, session_information.length] = hex2str(session_information)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Put the bytes of "time" to the message
|
151
|
+
# Input is text value of minutes
|
152
|
+
if timestamp_length > 0
|
153
|
+
pos = ocra_suite_length + 1 + counter_length + question_length +
|
154
|
+
password_length + session_information_length
|
155
|
+
msg[pos, timestamp.length] = hex2str(timestamp)
|
156
|
+
end
|
157
|
+
|
158
|
+
byteKey = hex2str(key)
|
159
|
+
hash = hmac_sha1(crypto, byteKey, msg)
|
160
|
+
oath_truncate(hash, code_digits)
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
# Truncate a result to a certain length
|
167
|
+
#
|
168
|
+
# - hash is a hex string
|
169
|
+
def oath_truncate(hash, length = 6)
|
170
|
+
|
171
|
+
# Convert to array of decimals
|
172
|
+
hmac_result = hash.scan(/../).map { |e| e.hex }
|
173
|
+
|
174
|
+
# Find offset
|
175
|
+
offset = hmac_result.last & 0xf
|
176
|
+
|
177
|
+
v =
|
178
|
+
(hmac_result[offset + 0] & 0x7f) << 24 |
|
179
|
+
(hmac_result[offset + 1] & 0xff) << 16 |
|
180
|
+
(hmac_result[offset + 2] & 0xff) << 8 |
|
181
|
+
(hmac_result[offset + 3] & 0xff)
|
182
|
+
|
183
|
+
r = v % 10 ** length.to_i
|
184
|
+
|
185
|
+
"%0#{length}d" % r
|
186
|
+
end
|
187
|
+
|
188
|
+
# This method uses the hmac_hash function to provide the crypto
|
189
|
+
# algorithm.
|
190
|
+
# HMAC computes a Hashed Message Authentication Code with the
|
191
|
+
# crypto hash algorithm as a parameter.
|
192
|
+
#
|
193
|
+
# @param String crypto the crypto algorithm (sha1, sha256 or sha512)
|
194
|
+
# @param String keyBytes the bytes to use for the HMAC key
|
195
|
+
# @param String text the message or text to be authenticated.
|
196
|
+
#
|
197
|
+
def hmac_sha1(crypto, keyBytes, text)
|
198
|
+
digest = OpenSSL::Digest::Digest.new(crypto)
|
199
|
+
str2hex(OpenSSL::HMAC.digest(digest, keyBytes, text))
|
200
|
+
end
|
201
|
+
|
202
|
+
# This method converts HEX string to Byte[]
|
203
|
+
#
|
204
|
+
# @param String hex the HEX string
|
205
|
+
#
|
206
|
+
# @return String a string with raw bytes
|
207
|
+
def hex2str(hex)
|
208
|
+
[hex].pack('H*')
|
209
|
+
end
|
210
|
+
|
211
|
+
def str2hex(str)
|
212
|
+
str.unpack('H*').first
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
data/rocra.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rocra/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "rocra"
|
8
|
+
gem.version = Rocra::VERSION
|
9
|
+
gem.authors = ["Phil Hofmann"]
|
10
|
+
gem.email = ["phil@branch14.org"]
|
11
|
+
gem.description = %q{An OCRA (RFC 6287) implementation in Ruby}
|
12
|
+
gem.summary = %q{An OCRA (RFC 6287) implementation in Ruby}
|
13
|
+
gem.homepage = "https://github.com/branch14/rocra"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rake'
|
21
|
+
gem.add_development_dependency 'rspec'
|
22
|
+
end
|
data/spec/rocra_spec.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.expand_path('../../lib/rocra', __FILE__)
|
2
|
+
|
3
|
+
describe Rocra do
|
4
|
+
|
5
|
+
it 'should nicely translate binary strings into hex strings' do
|
6
|
+
Rocra.send(:str2hex, 'ab').should == '6162'
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should nicely translate hex strings into binary strings' do
|
10
|
+
Rocra.send(:hex2str, '6162').should == 'ab'
|
11
|
+
end
|
12
|
+
|
13
|
+
# examples from http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
|
14
|
+
it 'should nicely calculate hmac_sha1' do
|
15
|
+
Rocra.send(:hmac_sha1, 'sha1', '', '').should == 'fbdb1d1b18aa6c08324b7d64b71fb76370690e1d'
|
16
|
+
Rocra.send(:hmac_sha1, 'sha1', "key", "The quick brown fox jumps over the lazy dog").should ==
|
17
|
+
'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9'
|
18
|
+
end
|
19
|
+
|
20
|
+
KEY_20 = "3132333435363738393031323334353637383930"
|
21
|
+
KEY_32 = "3132333435363738393031323334353637383930313233343536373839303132"
|
22
|
+
KEY_64 = "3132333435363738393031323334353637383930313233343536373839303132"+
|
23
|
+
"3334353637383930313233343536373839303132333435363738393031323334"
|
24
|
+
PIN_1234_HASH = "7110eda4d09e062aa5e4a390b0a572ac0d2c0220"
|
25
|
+
|
26
|
+
it 'should work for OCRA-1:HOTP-SHA1-6:QN08' do
|
27
|
+
suite = "OCRA-1:HOTP-SHA1-6:QN08"
|
28
|
+
Rocra.generate(suite, KEY_20, nil, '00000000'.to_i.to_s(16), nil, nil, nil).should == '237653'
|
29
|
+
Rocra.generate(suite, KEY_20, nil, '11111111'.to_i.to_s(16), nil, nil, nil).should == '243178'
|
30
|
+
Rocra.generate(suite, KEY_20, nil, '22222222'.to_i.to_s(16), nil, nil, nil).should == '653583'
|
31
|
+
Rocra.generate(suite, KEY_20, nil, '33333333'.to_i.to_s(16), nil, nil, nil).should == '740991'
|
32
|
+
Rocra.generate(suite, KEY_20, nil, '44444444'.to_i.to_s(16), nil, nil, nil).should == '608993'
|
33
|
+
Rocra.generate(suite, KEY_20, nil, '55555555'.to_i.to_s(16), nil, nil, nil).should == '388898'
|
34
|
+
Rocra.generate(suite, KEY_20, nil, '66666666'.to_i.to_s(16), nil, nil, nil).should == '816933'
|
35
|
+
Rocra.generate(suite, KEY_20, nil, '77777777'.to_i.to_s(16), nil, nil, nil).should == '224598'
|
36
|
+
Rocra.generate(suite, KEY_20, nil, '88888888'.to_i.to_s(16), nil, nil, nil).should == '750600'
|
37
|
+
Rocra.generate(suite, KEY_20, nil, '99999999'.to_i.to_s(16), nil, nil, nil).should == '294470'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should work with counter' do
|
41
|
+
suite = "OCRA-1:HOTP-SHA256-8:C-QN08-PSHA1"
|
42
|
+
Rocra.generate(suite, KEY_32, "0", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "65347737"
|
43
|
+
Rocra.generate(suite, KEY_32, "1", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "86775851"
|
44
|
+
Rocra.generate(suite, KEY_32, "2", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "78192410"
|
45
|
+
Rocra.generate(suite, KEY_32, "3", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "71565254"
|
46
|
+
Rocra.generate(suite, KEY_32, "4", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "10104329"
|
47
|
+
Rocra.generate(suite, KEY_32, "5", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "65983500"
|
48
|
+
Rocra.generate(suite, KEY_32, "6", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "70069104"
|
49
|
+
Rocra.generate(suite, KEY_32, "7", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "91771096"
|
50
|
+
Rocra.generate(suite, KEY_32, "8", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "75011558"
|
51
|
+
Rocra.generate(suite, KEY_32, "9", "12345678".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "08522129"
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should work for OCRA-1:HOTP-SHA256-8:QN08-PSHA1' do
|
55
|
+
suite = "OCRA-1:HOTP-SHA256-8:QN08-PSHA1"
|
56
|
+
Rocra.generate(suite, KEY_32, nil, "00000000".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "83238735"
|
57
|
+
Rocra.generate(suite, KEY_32, nil, "11111111".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "01501458"
|
58
|
+
Rocra.generate(suite, KEY_32, nil, "22222222".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "17957585"
|
59
|
+
Rocra.generate(suite, KEY_32, nil, "33333333".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "86776967"
|
60
|
+
Rocra.generate(suite, KEY_32, nil, "44444444".to_i.to_s(16), PIN_1234_HASH, nil, nil).should == "86807031"
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should work for OCRA-1:HOTP-SHA512-8:C-QN08' do
|
64
|
+
suite = "OCRA-1:HOTP-SHA512-8:C-QN08"
|
65
|
+
Rocra.generate(suite, KEY_64, "00000", "00000000".to_i.to_s(16), nil, nil, nil).should == "07016083"
|
66
|
+
Rocra.generate(suite, KEY_64, "00001", "11111111".to_i.to_s(16), nil, nil, nil).should == "63947962"
|
67
|
+
Rocra.generate(suite, KEY_64, "00002", "22222222".to_i.to_s(16), nil, nil, nil).should == "70123924"
|
68
|
+
Rocra.generate(suite, KEY_64, "00003", "33333333".to_i.to_s(16), nil, nil, nil).should == "25341727"
|
69
|
+
Rocra.generate(suite, KEY_64, "00004", "44444444".to_i.to_s(16), nil, nil, nil).should == "33203315"
|
70
|
+
Rocra.generate(suite, KEY_64, "00005", "55555555".to_i.to_s(16), nil, nil, nil).should == "34205738"
|
71
|
+
Rocra.generate(suite, KEY_64, "00006", "66666666".to_i.to_s(16), nil, nil, nil).should == "44343969"
|
72
|
+
Rocra.generate(suite, KEY_64, "00007", "77777777".to_i.to_s(16), nil, nil, nil).should == "51946085"
|
73
|
+
Rocra.generate(suite, KEY_64, "00008", "88888888".to_i.to_s(16), nil, nil, nil).should == "20403879"
|
74
|
+
Rocra.generate(suite, KEY_64, "00009", "99999999".to_i.to_s(16), nil, nil, nil).should == "31409299"
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should work for OCRA-1:HOTP-SHA512-8:QN08-T1M' do
|
78
|
+
suite = "OCRA-1:HOTP-SHA512-8:QN08-T1M"
|
79
|
+
Rocra.generate(suite, KEY_64, nil, "00000000".to_i.to_s(16), nil, nil, "132d0b6").should == "95209754"
|
80
|
+
Rocra.generate(suite, KEY_64, nil, "11111111".to_i.to_s(16), nil, nil, "132d0b6").should == "55907591"
|
81
|
+
Rocra.generate(suite, KEY_64, nil, "22222222".to_i.to_s(16), nil, nil, "132d0b6").should == "22048402"
|
82
|
+
Rocra.generate(suite, KEY_64, nil, "33333333".to_i.to_s(16), nil, nil, "132d0b6").should == "24218844"
|
83
|
+
Rocra.generate(suite, KEY_64, nil, "44444444".to_i.to_s(16), nil, nil, "132d0b6").should == "36209546"
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rocra
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Phil Hofmann
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &82726890 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *82726890
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &82726670 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *82726670
|
36
|
+
description: An OCRA (RFC 6287) implementation in Ruby
|
37
|
+
email:
|
38
|
+
- phil@branch14.org
|
39
|
+
executables: []
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- .gitignore
|
44
|
+
- .travis.yml
|
45
|
+
- Gemfile
|
46
|
+
- LICENSE.txt
|
47
|
+
- README.md
|
48
|
+
- Rakefile
|
49
|
+
- lib/rocra.rb
|
50
|
+
- lib/rocra/version.rb
|
51
|
+
- rocra.gemspec
|
52
|
+
- spec/rocra_spec.rb
|
53
|
+
homepage: https://github.com/branch14/rocra
|
54
|
+
licenses: []
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.8.15
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: An OCRA (RFC 6287) implementation in Ruby
|
77
|
+
test_files:
|
78
|
+
- spec/rocra_spec.rb
|