hsmr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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~
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
@@ -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
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :test do
5
+ watch(%r{lib/(.+)\.rb}) { |m| "test/#{m[1]}_test.rb" }
6
+ watch(%r{test/.+_test\.rb})
7
+ watch('test/test_helper.rb') { "test" }
8
+ end
@@ -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.
@@ -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.
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/*_test.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :test
12
+
13
+ task :default => :test
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module HSMR
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,2 @@
1
+ require "test/unit"
2
+ require "hsmr"
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