hsmr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +44 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +11 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +20 -0
- data/README.md +67 -0
- data/Rakefile +13 -0
- data/hsmr.gemspec +28 -0
- data/lib/hsmr.rb +267 -0
- data/lib/hsmr/component.rb +38 -0
- data/lib/hsmr/key.rb +56 -0
- data/lib/hsmr/version.rb +3 -0
- data/spec/hsmr_spec.rb +181 -0
- data/spec/spec_helper.rb +12 -0
- data/test/hsmr_test.rb +182 -0
- data/test/test_helper.rb +2 -0
- metadata +113 -0
data/.gitignore
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
|
4
|
+
# rdoc generated
|
5
|
+
rdoc
|
6
|
+
|
7
|
+
# yard generated
|
8
|
+
doc
|
9
|
+
.yardoc
|
10
|
+
|
11
|
+
# bundler
|
12
|
+
.bundle
|
13
|
+
Gemfile.lock
|
14
|
+
|
15
|
+
# jeweler generated
|
16
|
+
pkg
|
17
|
+
|
18
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
19
|
+
#
|
20
|
+
# * Create a file at ~/.gitignore
|
21
|
+
# * Include files you want ignored
|
22
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
23
|
+
#
|
24
|
+
# After doing this, these files will be ignored in all your git projects,
|
25
|
+
# saving you from having to 'pollute' every project you touch with them
|
26
|
+
#
|
27
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
28
|
+
#
|
29
|
+
# For MacOS:
|
30
|
+
#
|
31
|
+
#.DS_Store
|
32
|
+
#
|
33
|
+
# For TextMate
|
34
|
+
#*.tmproj
|
35
|
+
#tmtags
|
36
|
+
#
|
37
|
+
# For emacs:
|
38
|
+
#*~
|
39
|
+
#\#*
|
40
|
+
#.\#*
|
41
|
+
#
|
42
|
+
# For vim:
|
43
|
+
*.swp
|
44
|
+
*.un~
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
## v0.0.1
|
2
|
+
|
3
|
+
* Initial release
|
4
|
+
* Key / Componet features
|
5
|
+
* Create Keys and Components
|
6
|
+
* XOR Keys and Components together
|
7
|
+
* Find Key Check Values (kcv)
|
8
|
+
* Determine and change key parity
|
9
|
+
* Encrypt / Decrypt PIN Blocks
|
10
|
+
* Generate IBM3624 PINs
|
11
|
+
* Generate PVV, CVV & CVV2 values
|
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in hsmr.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
#group :development do
|
7
|
+
# gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
|
8
|
+
# gem 'growl', :require => false if RUBY_PLATFORM =~ /darwin/i
|
9
|
+
# gem 'guard-test'
|
10
|
+
# gem 'factory_girl'
|
11
|
+
#end
|
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Dan Milne
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
HSMR [![Build Status](https://secure.travis-ci.org/dkam/hsmr.png)](http://travis-ci.org/dkam/hsmr)
|
2
|
+
===========
|
3
|
+
|
4
|
+
HSMR is a collection of cryptographic commands usually implemented on a HSM (Hardware Security Module). These
|
5
|
+
are implemented for your education or for testing purposes and should not be used to replace an actual HSM.
|
6
|
+
|
7
|
+
Installation
|
8
|
+
-------------
|
9
|
+
|
10
|
+
One day I'll learn how to make gems. Until then, git clone is the only way to use this softawre.
|
11
|
+
|
12
|
+
Usage
|
13
|
+
---------
|
14
|
+
|
15
|
+
require './lib/hsmr'
|
16
|
+
require './lib/key'
|
17
|
+
require './lib/component'
|
18
|
+
|
19
|
+
# Create a Key
|
20
|
+
> key=HSMR::Key.new("4CA2161637D0133E5E151AEA45DA2A12")
|
21
|
+
=> 4CA2 1616 37D0 133E 5E15 1AEA 45DA 2A12
|
22
|
+
> key.key
|
23
|
+
=> "L\xA2\x16\x167\xD0\x13>^\x15\x1A\xEAE\xDA*\x12"
|
24
|
+
> key.to_s
|
25
|
+
=> "4CA2 1616 37D0 133E 5E15 1AEA 45DA 2A12"
|
26
|
+
> key.kcv
|
27
|
+
=> "7B0898"
|
28
|
+
> key.parity
|
29
|
+
=> "odd"
|
30
|
+
|
31
|
+
# Generate a PVV
|
32
|
+
|
33
|
+
pan="5999997890123412"
|
34
|
+
pin="1234"
|
35
|
+
pvki="1"
|
36
|
+
pvv = HSMR.pvv(key, pan, pvki, pin)
|
37
|
+
=> "0798"
|
38
|
+
|
39
|
+
Features
|
40
|
+
---------
|
41
|
+
|
42
|
+
* Key / Componet features
|
43
|
+
* Create Keys and Components
|
44
|
+
* XOR Keys and Components together
|
45
|
+
* Find Key Check Values (kcv)
|
46
|
+
* Determine and change key parity
|
47
|
+
* Encrypt / Decrypt PIN Blocks
|
48
|
+
* Generate IBM3624 PINs
|
49
|
+
* Generate PVV, CVV & CVV2 values
|
50
|
+
|
51
|
+
|
52
|
+
Development
|
53
|
+
-----------
|
54
|
+
|
55
|
+
* Source hosted on GitHub.
|
56
|
+
* Report issues on GitHub Issues.
|
57
|
+
* Pull requests are awesome! Please include test::unit tests
|
58
|
+
|
59
|
+
Author
|
60
|
+
==========
|
61
|
+
|
62
|
+
Dan Milne, http://da.nmilne.com, http://booko.com.au
|
63
|
+
|
64
|
+
Copyright
|
65
|
+
----------
|
66
|
+
|
67
|
+
Copyright (c) 2010 Dan Milne. See LICENSE for details.
|
data/Rakefile
ADDED
data/hsmr.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "hsmr/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "hsmr"
|
7
|
+
s.version = HSMR::VERSION
|
8
|
+
s.authors = ["Dan Milne"]
|
9
|
+
s.email = ["d@nmilne.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{HSM commands in Ruby}
|
12
|
+
s.description = %q{A collection of methods usually implemented in a HSM (Hardware Security Module)}
|
13
|
+
|
14
|
+
s.rubyforge_project = "hsmr"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
|
25
|
+
s.add_development_dependency "rake"
|
26
|
+
s.add_development_dependency "guard-test"
|
27
|
+
s.add_development_dependency "factory_girl"
|
28
|
+
end
|
data/lib/hsmr.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'hsmr/component'
|
3
|
+
require 'hsmr/key'
|
4
|
+
|
5
|
+
module HSMR
|
6
|
+
# Key Lengths
|
7
|
+
SINGLE=64
|
8
|
+
DOUBLE=128
|
9
|
+
TRIPLE=192
|
10
|
+
|
11
|
+
## Mixin functionality
|
12
|
+
|
13
|
+
def kcv()
|
14
|
+
des = OpenSSL::Cipher::Cipher.new("des-cbc") if @key.length == 8
|
15
|
+
des = OpenSSL::Cipher::Cipher.new("des-ede-cbc") if @key.length == 16
|
16
|
+
des.encrypt
|
17
|
+
des.key=@key
|
18
|
+
des.update("\x00"*8).unpack('H*').first[0...6].upcase
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate(length)
|
22
|
+
(0...(length/4)).collect { rand(16).to_s(16).upcase }.join
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
@key.unpack('H4'*(@key.length/2)).join(" ").upcase
|
28
|
+
end
|
29
|
+
|
30
|
+
def parity
|
31
|
+
'even' unless odd_parity?
|
32
|
+
'odd'
|
33
|
+
end
|
34
|
+
|
35
|
+
def odd_parity?
|
36
|
+
# http://www.cryptosys.net/3des.html
|
37
|
+
# http://csrc.nist.gov/publications/nistpubs/800-67/SP800-67.pdf
|
38
|
+
#
|
39
|
+
# The eight error detecting bits are set to make the parity of each 8-bit
|
40
|
+
# byte of the key odd. That is, there is an odd number of "1"s in each 8-bit byte.
|
41
|
+
|
42
|
+
#3.to_s(2).count('1')
|
43
|
+
#@key.unpack("H2").first.to_i(16).to_s(2)
|
44
|
+
|
45
|
+
working=@key.unpack('H2'*(@key.length))
|
46
|
+
working.each do |o|
|
47
|
+
freq = o.to_i(16).to_s(2).count('1').to_i
|
48
|
+
if( freq%2 == 0)
|
49
|
+
#puts "#{o} is #{o.to_i(16).to_s(2).count('1').to_i } - even"
|
50
|
+
return false
|
51
|
+
else
|
52
|
+
return true
|
53
|
+
#puts "#{o} is #{o.to_i(16).to_s(2).count('1').to_i } - odd"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.encrypt(data, key)
|
59
|
+
unless key.length == 8 || key.length == 16 || key.length ==24
|
60
|
+
raise TypeError, "key length should be 8, 16 or 24 bytes"
|
61
|
+
end
|
62
|
+
des = OpenSSL::Cipher::Cipher.new("des-cbc") if key.length == 8
|
63
|
+
des = OpenSSL::Cipher::Cipher.new("des-ede-cbc") if key.length == 16
|
64
|
+
des = OpenSSL::Cipher::Cipher.new("des-ede3-cbc") if key.length == 24
|
65
|
+
|
66
|
+
des.encrypt
|
67
|
+
des.key=key.key
|
68
|
+
to_hex( des.update(to_binary(data)) )
|
69
|
+
end
|
70
|
+
|
71
|
+
def set_odd_parity
|
72
|
+
return self if self.odd_parity? == true
|
73
|
+
|
74
|
+
working=@key.unpack('H2'*(@key.length))
|
75
|
+
working.each_with_index do |o,i|
|
76
|
+
freq = o.to_i(16).to_s(2).count('1').to_i
|
77
|
+
if( freq%2 == 0)
|
78
|
+
c1 = o[0].chr
|
79
|
+
c2 = case o[1].chr
|
80
|
+
when "0" then "1"
|
81
|
+
when "1" then "0"
|
82
|
+
when "2" then "3"
|
83
|
+
when "3" then "2"
|
84
|
+
when "4" then "5"
|
85
|
+
when "5" then "4"
|
86
|
+
when "6" then "7"
|
87
|
+
when "7" then "6"
|
88
|
+
when "8" then "9"
|
89
|
+
when "9" then "8"
|
90
|
+
when "a" then "b"
|
91
|
+
when "b" then "a"
|
92
|
+
when "c" then "d"
|
93
|
+
when "d" then "c"
|
94
|
+
when "e" then "f"
|
95
|
+
when "f" then "e"
|
96
|
+
end
|
97
|
+
working[i]="#{c1}#{c2}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
@key = working.join.unpack('a2'*(working.length)).map{|x| x.hex}.pack('c'*(working.length))
|
101
|
+
return self
|
102
|
+
end
|
103
|
+
|
104
|
+
def xor(other)
|
105
|
+
other=Component.new(other) if other.is_a? String
|
106
|
+
#other=Component.new(other.to_s) if other.is_a? Key
|
107
|
+
|
108
|
+
unless (other.is_a? Component ) or ( other.is_a? Key )
|
109
|
+
raise TypeError, "Component argument expected"
|
110
|
+
end
|
111
|
+
|
112
|
+
@a = @key.unpack('C2'*(@key.length/2))
|
113
|
+
@b = other.key.unpack('C2'*(other.length/2))
|
114
|
+
|
115
|
+
resultant = Key.new( @a.zip(@b).
|
116
|
+
map {|x,y| x^y}.
|
117
|
+
map {|z| z.to_s(16) }.
|
118
|
+
map {|c| c.length == 1 ? '0'+c : c }.
|
119
|
+
join.upcase )
|
120
|
+
resultant
|
121
|
+
end
|
122
|
+
|
123
|
+
def xor!(_key)
|
124
|
+
@key = xor(_key).key
|
125
|
+
end
|
126
|
+
|
127
|
+
## Module Methods
|
128
|
+
|
129
|
+
def self.to_binary(data)
|
130
|
+
data.unpack('a2'*(data.length/2)).map{|x| x.hex}.pack('c'*(data.length/2))
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.to_hex(data)
|
134
|
+
data.unpack('H*').first.upcase
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.encrypt_pin(key, pin)
|
138
|
+
@pin = pin.unpack('a2'*(pin.length/2)).map{|x| x.hex}.pack('c'*(pin.length/2))
|
139
|
+
des = OpenSSL::Cipher::Cipher.new("des-ede")
|
140
|
+
des.encrypt
|
141
|
+
des.key=key.key
|
142
|
+
return des.update(@pin).unpack('H*').first.upcase
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.decrypt_pin(key, pinblock)
|
146
|
+
@pinblock = pinblock.unpack('a2'*(pinblock.length/2)).map{|x| x.hex}.pack('c'*(pinblock.length/2))
|
147
|
+
des = OpenSSL::Cipher::Cipher.new("des-ede")
|
148
|
+
des.decrypt
|
149
|
+
des.padding=0
|
150
|
+
des.key=key.key
|
151
|
+
result = des.update(@pinblock)
|
152
|
+
result << des.final
|
153
|
+
result.unpack('H*').first.upcase
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.ibm3624(key, account, plength=4, dtable="0123456789012345" )
|
157
|
+
|
158
|
+
validation_data = account.unpack('a2'*(account.length/2)).map{|x| x.hex}.pack('c'*(account.length/2))
|
159
|
+
|
160
|
+
#des = OpenSSL::Cipher::Cipher.new("des-ede-cbc")
|
161
|
+
des = OpenSSL::Cipher::Cipher.new("des-cbc")
|
162
|
+
des.encrypt
|
163
|
+
des.key=key.key
|
164
|
+
return HSMR::decimalise(des.update(validation_data).unpack('H*').first, :ibm, dtable)[0...plength]
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.decimalise(value, method=:visa, dtable="0123456789012345" )
|
169
|
+
|
170
|
+
result = []
|
171
|
+
if method == :ibm
|
172
|
+
##
|
173
|
+
# The IBM method
|
174
|
+
##
|
175
|
+
value.each_char do |c|
|
176
|
+
result << dtable[c.to_i(16),1].to_i
|
177
|
+
end
|
178
|
+
|
179
|
+
elsif method == :visa
|
180
|
+
|
181
|
+
value.each_char do |c|
|
182
|
+
result << c.to_i if numeric?(c)
|
183
|
+
end
|
184
|
+
|
185
|
+
value.upcase.each_char do |c|
|
186
|
+
result << dtable[c.to_i(16),1].to_i unless numeric?(c)
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
return result
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.pvv(key, account, pvki, pin)
|
195
|
+
tsp = account.to_s[4,11] + pvki.to_s + pin.to_s
|
196
|
+
@tsp = tsp.unpack('a2'*(tsp.length/2)).map{|x| x.hex}.pack('c'*(tsp.length/2))
|
197
|
+
des = OpenSSL::Cipher::Cipher.new("des-ede")
|
198
|
+
des.encrypt
|
199
|
+
des.key=key.key
|
200
|
+
result = des.update(@tsp).unpack('H*').first.upcase
|
201
|
+
decimalise(result, :visa)[0..3].join
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.cvv(key_a, key_b, pan, exp, svc)
|
205
|
+
# http://www.m-sinergi.com/hairi/doc.html
|
206
|
+
# For CVV2 use SVC 000
|
207
|
+
# For CVV3 SVC is 502
|
208
|
+
# For iCVV use SVC of 999
|
209
|
+
#
|
210
|
+
#raise ArgumentError "PAN"
|
211
|
+
|
212
|
+
data1 = pan
|
213
|
+
data2 = "#{exp}#{svc}".ljust(16, '0')
|
214
|
+
|
215
|
+
result = encrypt(data1, key_a)
|
216
|
+
result = result.xor(data2)
|
217
|
+
|
218
|
+
result1 = encrypt(result, HSMR::Key.new(key_a.to_s + key_b.to_s) )
|
219
|
+
|
220
|
+
return HSMR.decimalise( result1 )[0,3].join
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.xor(component1, *rest)
|
224
|
+
return if rest.length == 0
|
225
|
+
|
226
|
+
component1 = Component.new(component1) unless component1.is_a? Component
|
227
|
+
raise TypeError, "Component argument expected" unless component1.is_a? Component
|
228
|
+
|
229
|
+
#@components=[]
|
230
|
+
#rest.each {|c| components << ((c.is_a? HSMR::Component) ? c : HSMR::Component.new(c) ) }
|
231
|
+
#components.each {|c| raise TypeError, "Component argument expected" unless c.is_a? Component }
|
232
|
+
#resultant = component1.xor(components.pop)
|
233
|
+
#components.each {|c| resultant.xor!(c) }
|
234
|
+
|
235
|
+
rest.collect! {|c| ( (c.is_a? HSMR::Component) ? c : HSMR::Component.new(c) ) }
|
236
|
+
rest.each {|c| raise TypeError, "Component argument expected" unless c.is_a? HSMR::Component }
|
237
|
+
resultant = component1.xor(rest.pop)
|
238
|
+
rest.each {|c| resultant.xor!(c) }
|
239
|
+
|
240
|
+
return(resultant)
|
241
|
+
end
|
242
|
+
|
243
|
+
def self.numeric?(object)
|
244
|
+
## Method to determine if an object is a numeric type.
|
245
|
+
true if Float(object) rescue false
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
class String
|
251
|
+
def xor(other)
|
252
|
+
if other.empty?
|
253
|
+
self
|
254
|
+
else
|
255
|
+
a1 = self.unpack("a2"*(self.length/2)).map {|x| x.hex }
|
256
|
+
a2 = other.unpack("a2"*(other.length/2)).map {|x| x.hex }
|
257
|
+
#a2 *= 2 while a2.length < a1.length
|
258
|
+
|
259
|
+
#a1.zip(a2).collect{|c1,c2| c1^c2}.pack("C*")
|
260
|
+
a1.zip(a2).
|
261
|
+
map {|x,y| x^y}.
|
262
|
+
map {|z| z.to_s(16) }.
|
263
|
+
map {|c| c.length == 1 ? '0'+c : c }.
|
264
|
+
join.upcase
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module HSMR
|
2
|
+
class Component
|
3
|
+
include HSMR
|
4
|
+
attr_reader :key
|
5
|
+
attr_reader :length
|
6
|
+
|
7
|
+
def component
|
8
|
+
@key
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(key=nil, length=DOUBLE)
|
12
|
+
## Should check for odd parity
|
13
|
+
if key.nil?
|
14
|
+
key = generate(length)
|
15
|
+
else
|
16
|
+
key=key.gsub(/ /,'')
|
17
|
+
#raise TypeError, "Component argument expected" unless other.is_a? Component
|
18
|
+
end
|
19
|
+
@key = key.unpack('a2'*(key.length/2)).map{|x| x.hex}.pack('c'*(key.length/2))
|
20
|
+
@length = @key.length
|
21
|
+
@key = @key
|
22
|
+
end
|
23
|
+
|
24
|
+
# def xor(other)
|
25
|
+
# other = Component.new(other) unless other.is_a? Component
|
26
|
+
# raise TypeError, "Component argument expected" unless other.is_a? Component
|
27
|
+
#
|
28
|
+
# @a = @key.unpack('C2'*(@key.length/2))
|
29
|
+
# @b = other.component.unpack('C2'*(other.component.length/2))
|
30
|
+
#
|
31
|
+
# #result = @a.zip(@b).map {|x,y| x^y}.map {|z| z.to_s(16) }.join.upcase
|
32
|
+
# result = @a.zip(@b).map {|x,y| x^y}.map {|z| z.to_s(16) }.map {|c| c.length == 1 ? '0'+c : c }.join.upcase
|
33
|
+
#
|
34
|
+
# Key.new(result)
|
35
|
+
# end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/hsmr/key.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module HSMR
|
2
|
+
class Key
|
3
|
+
include HSMR
|
4
|
+
|
5
|
+
attr_reader :key
|
6
|
+
attr_reader :length
|
7
|
+
|
8
|
+
def initialize(init=nil, length=DOUBLE)
|
9
|
+
return nil if (init.is_a? Array ) && (init.length == 0)
|
10
|
+
|
11
|
+
init = init.first if (init.is_a? Array) && (init.length == 1)
|
12
|
+
|
13
|
+
if init.is_a? Array
|
14
|
+
init.collect! {|c| ( (c.is_a? HSMR::Component) ? c : HSMR::Component.new(c) ) }
|
15
|
+
|
16
|
+
raise TypeError, "Component argument expected" unless init.first.is_a? Component
|
17
|
+
|
18
|
+
@key=HSMR::xor(init.pop, init).key
|
19
|
+
|
20
|
+
elsif init.is_a? Component
|
21
|
+
@key = init.component
|
22
|
+
elsif init.is_a? String
|
23
|
+
key=init.gsub(/ /,'')
|
24
|
+
@key = key.unpack('a2'*(key.length/2)).map{|x| x.hex}.pack('c'*(key.length/2))
|
25
|
+
elsif key.nil?
|
26
|
+
key = generate(length)
|
27
|
+
@key = key.unpack('a2'*(key.length/2)).map{|x| x.hex}.pack('c'*(key.length/2))
|
28
|
+
end
|
29
|
+
@length = @key.length
|
30
|
+
end
|
31
|
+
|
32
|
+
#def xor(other)
|
33
|
+
# other=Component.new(other) if other.is_a? String
|
34
|
+
# other=Component.new(other.to_s) if other.is_a? Key
|
35
|
+
#
|
36
|
+
# puts "other is #{other.class} - #{other.key}"
|
37
|
+
#
|
38
|
+
# raise TypeError, "Component argument expected" unless other.is_a? Component
|
39
|
+
#
|
40
|
+
# @a = @key.unpack('C2'*(@key.length/2))
|
41
|
+
# @b = other.component.unpack('C2'*(other.length/2))
|
42
|
+
#
|
43
|
+
# resultant = Key.new( @a.zip(@b).
|
44
|
+
# map {|x,y| x^y}.
|
45
|
+
# map {|z| z.to_s(16) }.
|
46
|
+
# map {|c| c.length == 1 ? '0'+c : c }.
|
47
|
+
# join.upcase )
|
48
|
+
# resultant
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# def xor!(_key)
|
52
|
+
# @key = xor(_key).key
|
53
|
+
# end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/hsmr/version.rb
ADDED
data/spec/hsmr_spec.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Generate Component" do
|
4
|
+
it "should generate a component" do
|
5
|
+
component_1 = HSMR::Component.new(nil, HSMR::SINGLE)
|
6
|
+
component_2 = HSMR::Component.new(nil, HSMR::DOUBLE)
|
7
|
+
component_3 = HSMR::Component.new(nil, HSMR::TRIPLE)
|
8
|
+
|
9
|
+
component_1.length.should == 8
|
10
|
+
component_2.length.should == 16
|
11
|
+
component_3.length.should == 24
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "Calculate component KCV" do
|
16
|
+
|
17
|
+
it "should calculate single length component KCV values" do
|
18
|
+
component_1 = HSMR::Component.new("6DBF C180 4A01 5BAD")
|
19
|
+
component_1.kcv.should == "029E60"
|
20
|
+
|
21
|
+
component_2 = HSMR::Component.new("5D80 0497 B319 8591")
|
22
|
+
component_2.kcv.should == "3B86C3"
|
23
|
+
|
24
|
+
component_3 = HSMR::Component.new("B0C7 7CDC 7354 97C7")
|
25
|
+
component_3.kcv.should == "7A77BC"
|
26
|
+
|
27
|
+
component_4 = HSMR::Component.new("DAE0 86FE D6EA 0BEA")
|
28
|
+
component_4.kcv.should == "2E6191"
|
29
|
+
|
30
|
+
component_5 = HSMR::Component.new("682C 8315 F4BF FBC1")
|
31
|
+
component_5.kcv.should == "62B336"
|
32
|
+
|
33
|
+
component_6 = HSMR::Component.new("5715 F289 04BC B62F")
|
34
|
+
component_6.kcv.should == "3CBA88"
|
35
|
+
|
36
|
+
component_7 = HSMR::Component.new("D0C4 29AE C4A8 02B5")
|
37
|
+
component_7.kcv.should == "33AF02"
|
38
|
+
|
39
|
+
component_8 = HSMR::Component.new("7049 D0F7 4A97 15B6")
|
40
|
+
component_8.kcv.should == "AC1399"
|
41
|
+
|
42
|
+
component_9 = HSMR::Component.new("BC91 D698 157A A4E5")
|
43
|
+
component_9.kcv.should == "295491"
|
44
|
+
|
45
|
+
component_10 = HSMR::Component.new("64AB 8568 7A0E 322F")
|
46
|
+
component_10.kcv.should == "D9F7B3"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should calculate double length component KCV values" do
|
50
|
+
component_1 = HSMR::Component.new("ADE3 9B38 0DBC DF38 AE02 AECE 64B3 4373")
|
51
|
+
component_1.kcv.should == "3002D5"
|
52
|
+
|
53
|
+
component_2 = HSMR::Component.new("B64A EF86 460D DF5B 57B3 D53D AD37 52A1")
|
54
|
+
component_2.kcv.should == "1F7C07"
|
55
|
+
|
56
|
+
component_3 = HSMR::Component.new("5B89 6E29 76EC 9745 15B5 238C 8CFE 3D23")
|
57
|
+
component_3.kcv.should == "DE78F2"
|
58
|
+
|
59
|
+
component_4 = HSMR::Component.new("5E61 CB20 D540 1FC7 58EC CDC8 B558 E9B9")
|
60
|
+
component_4.kcv.should == "FED957"
|
61
|
+
|
62
|
+
component_5 = HSMR::Component.new("23DF CEB9 BF94 ADA8 91E9 580B 8C8F 5BEF")
|
63
|
+
component_5.kcv.should == "902085"
|
64
|
+
|
65
|
+
component_6 = HSMR::Component.new("DFEF 61C8 2037 3DA4 CE9B 92CD 89E9 B334")
|
66
|
+
component_6.kcv.should == "E45EB7"
|
67
|
+
|
68
|
+
component_7 = HSMR::Component.new("6746 9E4C FE83 F831 F23E 9D9E 9D9E 9DB3")
|
69
|
+
component_7.kcv.should == "813B7B"
|
70
|
+
|
71
|
+
component_8 = HSMR::Component.new("23E5 496E DF94 0BD5 9734 B07A BF26 B9E6")
|
72
|
+
component_8.kcv.should == "E7C48F"
|
73
|
+
|
74
|
+
component_9 = HSMR::Component.new("974F 26BC CB2A ECD5 434F 1CDC 64DF A275")
|
75
|
+
component_9.kcv.should == "E27250"
|
76
|
+
|
77
|
+
component_10 = HSMR::Component.new("E57A DF5B CEA7 F42A DFD9 E554 07A2 F891")
|
78
|
+
component_10.kcv.should == "50E3F8"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "Calculate key KCV" do
|
83
|
+
|
84
|
+
it "should calculate single length key KCV values" do
|
85
|
+
key_1 = HSMR::Key.new("6DBF C180 4A01 5BAD")
|
86
|
+
key_1.kcv.should == "029E60"
|
87
|
+
|
88
|
+
key_2 = HSMR::Key.new("5D80 0497 B319 8591")
|
89
|
+
key_2.kcv.should == "3B86C3"
|
90
|
+
|
91
|
+
key_3 = HSMR::Key.new("B0C7 7CDC 7354 97C7")
|
92
|
+
key_3.kcv.should == "7A77BC"
|
93
|
+
|
94
|
+
key_4 = HSMR::Key.new("DAE0 86FE D6EA 0BEA")
|
95
|
+
key_4.kcv.should == "2E6191"
|
96
|
+
|
97
|
+
key_5 = HSMR::Key.new("682C 8315 F4BF FBC1")
|
98
|
+
key_5.kcv.should == "62B336"
|
99
|
+
|
100
|
+
key_6 = HSMR::Key.new("5715 F289 04BC B62F")
|
101
|
+
key_6.kcv.should == "3CBA88"
|
102
|
+
|
103
|
+
key_7 = HSMR::Key.new("D0C4 29AE C4A8 02B5")
|
104
|
+
key_7.kcv.should == "33AF02"
|
105
|
+
|
106
|
+
key_8 = HSMR::Key.new("7049 D0F7 4A97 15B6")
|
107
|
+
key_8.kcv.should == "AC1399"
|
108
|
+
|
109
|
+
key_9 = HSMR::Key.new("BC91 D698 157A A4E5")
|
110
|
+
key_9.kcv.should == "295491"
|
111
|
+
|
112
|
+
key_10 = HSMR::Key.new("64AB 8568 7A0E 322F")
|
113
|
+
key_10.kcv.should == "D9F7B3"
|
114
|
+
end
|
115
|
+
it "should calculate double length key KCV values" do
|
116
|
+
key_1 = HSMR::Key.new("ADE3 9B38 0DBC DF38 AE02 AECE 64B3 4373")
|
117
|
+
key_1.kcv.should == "3002D5"
|
118
|
+
|
119
|
+
key_2 = HSMR::Key.new("B64A EF86 460D DF5B 57B3 D53D AD37 52A1")
|
120
|
+
key_2.kcv.should == "1F7C07"
|
121
|
+
|
122
|
+
key_3 = HSMR::Key.new("5B89 6E29 76EC 9745 15B5 238C 8CFE 3D23")
|
123
|
+
key_3.kcv.should == "DE78F2"
|
124
|
+
|
125
|
+
key_4 = HSMR::Key.new("5E61 CB20 D540 1FC7 58EC CDC8 B558 E9B9")
|
126
|
+
key_4.kcv.should == "FED957"
|
127
|
+
|
128
|
+
key_5 = HSMR::Key.new("23DF CEB9 BF94 ADA8 91E9 580B 8C8F 5BEF")
|
129
|
+
key_5.kcv.should == "902085"
|
130
|
+
|
131
|
+
key_6 = HSMR::Key.new("DFEF 61C8 2037 3DA4 CE9B 92CD 89E9 B334")
|
132
|
+
key_6.kcv.should == "E45EB7"
|
133
|
+
|
134
|
+
key_7 = HSMR::Key.new("6746 9E4C FE83 F831 F23E 9D9E 9D9E 9DB3")
|
135
|
+
key_7.kcv.should == "813B7B"
|
136
|
+
|
137
|
+
key_8 = HSMR::Key.new("23E5 496E DF94 0BD5 9734 B07A BF26 B9E6")
|
138
|
+
key_8.kcv.should == "E7C48F"
|
139
|
+
|
140
|
+
key_9 = HSMR::Key.new("974F 26BC CB2A ECD5 434F 1CDC 64DF A275")
|
141
|
+
key_9.kcv.should == "E27250"
|
142
|
+
|
143
|
+
key_10 = HSMR::Key.new("E57A DF5B CEA7 F42A DFD9 E554 07A2 F891")
|
144
|
+
key_10.kcv.should == "50E3F8"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "Calculate parity" do
|
149
|
+
it "should detect odd_parity in a key" do
|
150
|
+
odd_key = HSMR::Key.new("41A2AC14A90C583741A2AC14A90C5837")
|
151
|
+
odd_key.odd_parity?.should == false
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should set double length key parity to odd" do
|
155
|
+
odd_key = HSMR::Key.new("41A2AC14A90C583741A2AC14A90C5837")
|
156
|
+
|
157
|
+
odd_key.set_odd_parity
|
158
|
+
|
159
|
+
even_key = HSMR::Key.new("40A2AD15A80D583740A2AD15A80D5837")
|
160
|
+
|
161
|
+
odd_key.key.should == even_key.key
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should detect odd_parity in a component" do
|
166
|
+
odd_component = HSMR::Component.new("41A2AC14A90C583741A2AC14A90C5837")
|
167
|
+
odd_component.odd_parity?.should == false
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should set double length component parity to odd" do
|
171
|
+
odd_component = HSMR::Component.new("41A2AC14A90C583741A2AC14A90C5837")
|
172
|
+
|
173
|
+
odd_component.set_odd_parity
|
174
|
+
|
175
|
+
even_component = HSMR::Component.new("40A2AD15A80D583740A2AD15A80D5837")
|
176
|
+
|
177
|
+
odd_component.component.should == even_component.component
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'hsmr'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
|
12
|
+
end
|
data/test/hsmr_test.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestHSMR < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_generate_a_component
|
6
|
+
component_1 = HSMR::Component.new(nil, HSMR::SINGLE)
|
7
|
+
component_2 = HSMR::Component.new(nil, HSMR::DOUBLE)
|
8
|
+
component_3 = HSMR::Component.new(nil, HSMR::TRIPLE)
|
9
|
+
|
10
|
+
assert_equal 8, component_1.length
|
11
|
+
assert_equal 16, component_2.length
|
12
|
+
assert_equal 24, component_3.length
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_caclulation_of_single_length_component_KCV_values
|
16
|
+
component_1 = HSMR::Component.new("6DBF C180 4A01 5BAD")
|
17
|
+
assert_equal "029E60", component_1.kcv
|
18
|
+
|
19
|
+
component_2 = HSMR::Component.new("5D80 0497 B319 8591")
|
20
|
+
assert_equal "3B86C3", component_2.kcv
|
21
|
+
|
22
|
+
component_3 = HSMR::Component.new("B0C7 7CDC 7354 97C7")
|
23
|
+
assert_equal "7A77BC", component_3.kcv
|
24
|
+
|
25
|
+
component_4 = HSMR::Component.new("DAE0 86FE D6EA 0BEA")
|
26
|
+
assert_equal "2E6191", component_4.kcv
|
27
|
+
|
28
|
+
component_5 = HSMR::Component.new("682C 8315 F4BF FBC1")
|
29
|
+
assert_equal "62B336", component_5.kcv
|
30
|
+
|
31
|
+
component_6 = HSMR::Component.new("5715 F289 04BC B62F")
|
32
|
+
assert_equal "3CBA88", component_6.kcv
|
33
|
+
|
34
|
+
component_7 = HSMR::Component.new("D0C4 29AE C4A8 02B5")
|
35
|
+
assert_equal "33AF02", component_7.kcv
|
36
|
+
|
37
|
+
component_8 = HSMR::Component.new("7049 D0F7 4A97 15B6")
|
38
|
+
assert_equal "AC1399", component_8.kcv
|
39
|
+
|
40
|
+
component_9 = HSMR::Component.new("BC91 D698 157A A4E5")
|
41
|
+
assert_equal "295491", component_9.kcv
|
42
|
+
|
43
|
+
component_10 = HSMR::Component.new("64AB 8568 7A0E 322F")
|
44
|
+
assert_equal "D9F7B3", component_10.kcv
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_should_calculate_double_length_key_KCV_values
|
48
|
+
key_1 = HSMR::Key.new("ADE3 9B38 0DBC DF38 AE02 AECE 64B3 4373")
|
49
|
+
assert_equal "3002D5", key_1.kcv
|
50
|
+
|
51
|
+
key_2 = HSMR::Key.new("B64A EF86 460D DF5B 57B3 D53D AD37 52A1")
|
52
|
+
assert_equal "1F7C07", key_2.kcv
|
53
|
+
|
54
|
+
key_3 = HSMR::Key.new("5B89 6E29 76EC 9745 15B5 238C 8CFE 3D23")
|
55
|
+
assert_equal "DE78F2", key_3.kcv
|
56
|
+
|
57
|
+
key_4 = HSMR::Key.new("5E61 CB20 D540 1FC7 58EC CDC8 B558 E9B9")
|
58
|
+
assert_equal "FED957", key_4.kcv
|
59
|
+
|
60
|
+
key_5 = HSMR::Key.new("23DF CEB9 BF94 ADA8 91E9 580B 8C8F 5BEF")
|
61
|
+
assert_equal "902085", key_5.kcv
|
62
|
+
|
63
|
+
key_6 = HSMR::Key.new("DFEF 61C8 2037 3DA4 CE9B 92CD 89E9 B334")
|
64
|
+
assert_equal "E45EB7", key_6.kcv
|
65
|
+
|
66
|
+
key_7 = HSMR::Key.new("6746 9E4C FE83 F831 F23E 9D9E 9D9E 9DB3")
|
67
|
+
assert_equal "813B7B", key_7.kcv
|
68
|
+
|
69
|
+
key_8 = HSMR::Key.new("23E5 496E DF94 0BD5 9734 B07A BF26 B9E6")
|
70
|
+
assert_equal "E7C48F", key_8.kcv
|
71
|
+
|
72
|
+
key_9 = HSMR::Key.new("974F 26BC CB2A ECD5 434F 1CDC 64DF A275")
|
73
|
+
assert_equal "E27250", key_9.kcv
|
74
|
+
|
75
|
+
key_10 = HSMR::Key.new("E57A DF5B CEA7 F42A DFD9 E554 07A2 F891")
|
76
|
+
assert_equal "50E3F8", key_10.kcv
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_should_detect_odd_parity_in_a_key
|
80
|
+
parity=[]
|
81
|
+
# Odd Even
|
82
|
+
parity << %W{ 0123456789ABCDEF 0022446688AACCEE }
|
83
|
+
parity << %W{ FEDCBA9876543210 FFDDBB9977553311 }
|
84
|
+
parity << %W{ 89ABCDEF01234567 88AACCEE00224466 }
|
85
|
+
parity << %W{ 40A2AD15A80D583740A2AD15A80D5837 41A2AC14A90C583741A2AC14A90C5837 }
|
86
|
+
|
87
|
+
# Test determining the parity
|
88
|
+
parity.each do |pair|
|
89
|
+
assert_equal true, HSMR::Key.new(pair[0]).odd_parity?
|
90
|
+
assert_equal false, HSMR::Key.new(pair[1]).odd_parity?
|
91
|
+
|
92
|
+
assert_equal true, HSMR::Component.new(pair[0]).odd_parity?
|
93
|
+
assert_equal false, HSMR::Component.new(pair[1]).odd_parity?
|
94
|
+
end
|
95
|
+
|
96
|
+
# Test converting even to odd parity
|
97
|
+
parity.each do |pair|
|
98
|
+
odd_key = HSMR::Key.new(pair[0])
|
99
|
+
even_key = HSMR::Key.new(pair[0])
|
100
|
+
|
101
|
+
even_key.set_odd_parity
|
102
|
+
assert_equal odd_key, odd_key
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_converting_string_to_ascii_works
|
107
|
+
key_string = "E57A DF5B CEA7 F42A DFD9 E554 07A2 F891"
|
108
|
+
key = HSMR::Key.new(key_string)
|
109
|
+
|
110
|
+
assert_equal key.to_s, key_string
|
111
|
+
|
112
|
+
key_string = "E57A DF5B CEA7 F42A DFD9 E554 07A2 F891"
|
113
|
+
comp = HSMR::Component.new(key_string)
|
114
|
+
|
115
|
+
assert_equal comp.to_s, key_string
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_CVC_CVC2_calculations
|
119
|
+
cases = []
|
120
|
+
# Component 1 Component 2 PAN EXP SCode CVC
|
121
|
+
cases << %W{ 1234567890ABCDEF FEDCBA1234567890 5656565656565656 1010 ___ 922 }
|
122
|
+
cases << %W{ 1234567890ABCDEF FEDCBA1234567890 5656565656565656 1010 000 922 }
|
123
|
+
cases << %W{ 1234567890ABCDEF FEDCBA1234567890 5683739237489383838 1010 000 367 }
|
124
|
+
cases << %W{ 1234567890ABCDEF FEDCBA1234567890 568367393472639 1010 000 067 }
|
125
|
+
cases << %W{ 1234567890ABCDEF FEDCBA1234567890 5683673934726394 1010 000 409 }
|
126
|
+
cases << %W{ 1234567890ABCDEF FEDCBA1234567890 5683673934726394 1010 050 CVV248 or CVC409 }
|
127
|
+
cases << %W{ 1234567890ABCDEF FEDCBA1234567890 5683673934726394 1010 101 CVV501 or CVC409 }
|
128
|
+
cases << %W{ 1234567890ABCDEF FEDCBA1234567890 5683673934726394 1010 102 CVV206 or CVC409 }
|
129
|
+
|
130
|
+
kl = "0123456789ABCDEF"
|
131
|
+
kr = "FEDCBA1234567890"
|
132
|
+
|
133
|
+
|
134
|
+
#HSMR.cvv(kl, kr, "4509494222049051", "0907", "1010")
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_PIN_PVV_CVV_and_CVV2_generation
|
138
|
+
cases=[]
|
139
|
+
# Account Exp PIN PVV CVV2 CVV PGK1 PGK2 PVKI PVK1 PVK2 CVKA CVKB DEC
|
140
|
+
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
141
|
+
cases << %W{ 5560501200002101 1010 4412 6183 134 317 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
142
|
+
cases << %W{ 5560501200002111 1010 4784 0931 561 924 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
143
|
+
cases << %W{ 5560501200002121 1010 1040 4895 462 673 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
144
|
+
cases << %W{ 5560501200002131 1010 3680 6373 826 267 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
145
|
+
cases << %W{ 5560501200002101 1110 4412 6183 900 155 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
146
|
+
cases << %W{ 5560501200002111 1110 4784 0931 363 513 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
147
|
+
cases << %W{ 5560501200002121 1110 1040 4895 952 937 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
148
|
+
cases << %W{ 5560501200002131 1110 3680 6373 667 522 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
149
|
+
cases << %W{ 5560501200002101 1010 9907 7527 777 473 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
150
|
+
cases << %W{ 5560501200002111 1010 2345 0658 638 553 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
151
|
+
cases << %W{ 5560501200002121 1010 8245 8196 085 480 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
152
|
+
cases << %W{ 5560501200002131 1010 3812 2948 591 546 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
153
|
+
cases << %W{ 5560501200002101 1110 9907 7527 349 994 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
154
|
+
cases << %W{ 5560501200002111 1110 2345 0658 245 266 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
155
|
+
cases << %W{ 5560501200002121 1110 8245 8196 441 115 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
156
|
+
cases << %W{ 5560501200002131 1110 3812 2948 126 768 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
157
|
+
|
158
|
+
cases.each do |c|
|
159
|
+
ibm1=HSMR::Component.new(c[6])
|
160
|
+
ibm2=HSMR::Component.new(c[7])
|
161
|
+
ibm=ibm1.xor(ibm2)
|
162
|
+
|
163
|
+
pvk=HSMR::Key.new(c[9]+c[10])
|
164
|
+
|
165
|
+
pin = HSMR::ibm3624(ibm, c[0], 4, c[13]).join
|
166
|
+
pvv = HSMR::pvv(pvk, c[0], c[8], pin)
|
167
|
+
|
168
|
+
assert_equal pin, c[2]
|
169
|
+
assert_equal pin.to_i, c[2].to_i
|
170
|
+
assert_equal pvv, c[3]
|
171
|
+
assert_equal pvv.to_i, c[3].to_i
|
172
|
+
|
173
|
+
cvv = HSMR::cvv(HSMR::Key.new(c[11]), HSMR::Key.new(c[12]), c[0], c[1], '0')
|
174
|
+
cvv2 = HSMR::cvv(HSMR::Key.new(c[11]), HSMR::Key.new(c[12]), c[0], c[1], '101')
|
175
|
+
|
176
|
+
assert_equal c[4].to_i, cvv2.to_i
|
177
|
+
assert_equal c[5].to_i, cvv.to_i
|
178
|
+
|
179
|
+
#puts "#{pin} == #{c[2]} ? #{pin.to_i == c[2].to_i} | #{pvv} == #{c[3]} ? #{pvv.to_i == c[3].to_i}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hsmr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dan Milne
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2012-01-15 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: guard-test
|
28
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: factory_girl
|
39
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *id003
|
48
|
+
description: A collection of methods usually implemented in a HSM (Hardware Security Module)
|
49
|
+
email:
|
50
|
+
- d@nmilne.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- .travis.yml
|
60
|
+
- CHANGELOG.md
|
61
|
+
- Gemfile
|
62
|
+
- Gemfile.lock
|
63
|
+
- Guardfile
|
64
|
+
- LICENSE.txt
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- hsmr.gemspec
|
68
|
+
- lib/hsmr.rb
|
69
|
+
- lib/hsmr/component.rb
|
70
|
+
- lib/hsmr/key.rb
|
71
|
+
- lib/hsmr/version.rb
|
72
|
+
- spec/hsmr_spec.rb
|
73
|
+
- spec/spec_helper.rb
|
74
|
+
- test/hsmr_test.rb
|
75
|
+
- test/test_helper.rb
|
76
|
+
homepage: ""
|
77
|
+
licenses: []
|
78
|
+
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: -754850866914746297
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
hash: -754850866914746297
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
requirements: []
|
103
|
+
|
104
|
+
rubyforge_project: hsmr
|
105
|
+
rubygems_version: 1.8.8
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: HSM commands in Ruby
|
109
|
+
test_files:
|
110
|
+
- spec/hsmr_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
- test/hsmr_test.rb
|
113
|
+
- test/test_helper.rb
|