Migrate to test::unit. Start moving functionality into HSMR Module and mixin to key and component models to reduce duplication.

This commit is contained in:
Dan Milne
2011-11-24 15:43:47 +11:00
parent 1d899d0b8a
commit 3c620201c6
10 changed files with 289 additions and 71 deletions

36
lib/component.rb Normal file
View File

@@ -0,0 +1,36 @@
module HSMR
class Component
include HSMR
attr_reader :key
attr_reader :length
attr_reader :parity
def component
@key
end
def initialize(key=nil, length=DOUBLE)
## Should check for odd parity
if key.nil?
key = generate(length)
else
key=key.gsub(/ /,'')
#raise TypeError, "Component argument expected" unless other.is_a? Component
end
@key = key.unpack('a2'*(key.length/2)).map{|x| x.hex}.pack('c'*(key.length/2))
@length = @key.length
@key = @key
end
def xor(other)
other = Component.new(other) unless other.is_a? Component
raise TypeError, "Component argument expected" unless other.is_a? Component
@a = @key.unpack('C2'*(@key.length/2))
@b = other.component.unpack('C2'*(other.component.length/2))
result = @a.zip(@b).map {|x,y| x^y}.map {|z| z.to_s(16) }.join.upcase
Key.new(result)
end
end
end

View File

@@ -8,6 +8,81 @@ module HSMR
DOUBLE=128
TRIPLE=192
## Mixin functionality
def kcv()
des = OpenSSL::Cipher::Cipher.new("des-cbc") if @key.length == 8
des = OpenSSL::Cipher::Cipher.new("des-ede-cbc") if @key.length == 16
des.encrypt
des.key=@key
des.update("\x00"*8).unpack('H*').first[0...6].upcase
end
def generate(length)
(0...(length/4)).collect { rand(16).to_s(16).upcase }.join
end
def to_s
@key.unpack('H4'*(@key.length/2)).join(" ").upcase
end
def odd_parity?
# http://csrc.nist.gov/publications/nistpubs/800-67/SP800-67.pdf
#
# The eight error detecting bits are set to make the parity of each 8-bit
# byte of the key odd. That is, there is an odd number of "1"s in each 8-bit byte.
#3.to_s(2).count('1')
#@key.unpack("H2").first.to_i(16).to_s(2)
working=@key.unpack('H2'*(@key.length))
working.each do |o|
freq = o.to_i(16).to_s(2).count('1').to_i
if( freq%2 == 0)
#puts "#{o} is #{o.to_i(16).to_s(2).count('1').to_i } - even"
return false
else
return true
#puts "#{o} is #{o.to_i(16).to_s(2).count('1').to_i } - odd"
end
end
end
def set_odd_parity
return true if self.odd_parity? == true
working=@key.unpack('H2'*(@key.length))
working.each_with_index do |o,i|
freq = o.to_i(16).to_s(2).count('1').to_i
if( freq%2 == 0)
c1 = o[0].chr
c2 = case o[1].chr
when "0" then "1"
when "1" then "0"
when "2" then "3"
when "3" then "2"
when "4" then "5"
when "5" then "4"
when "6" then "7"
when "7" then "6"
when "8" then "9"
when "9" then "8"
when "a" then "b"
when "b" then "a"
when "c" then "d"
when "d" then "c"
when "e" then "f"
when "f" then "e"
end
working[i]="#{c1}#{c2}"
end
end
@key = working.join.unpack('a2'*(working.length)).map{|x| x.hex}.pack('c'*(working.length))
end
## Module Methods
def self.encrypt_pin(key, pin)
@pin = pin.unpack('a2'*(pin.length/2)).map{|x| x.hex}.pack('c'*(pin.length/2))
des = OpenSSL::Cipher::Cipher.new("des-ede")
@@ -74,6 +149,10 @@ module HSMR
result = des.update(@tsp).unpack('H*').first.upcase
decimalise(result, :visa)[0..3].join
end
def self.cvv(key_left, key_right, account, exp, service_code)
end
def self.xor(component1, *rest)
return if rest.length == 0

View File

@@ -1,5 +1,7 @@
module HSMR
class Key
include HSMR
attr_reader :key
attr_reader :length
attr_reader :parity
@@ -22,20 +24,12 @@ module HSMR
key=init.gsub(/ /,'')
@key = key.unpack('a2'*(key.length/2)).map{|x| x.hex}.pack('c'*(key.length/2))
elsif key.nil?
key = (0...(length/4)).collect { rand(16).to_s(16).upcase }.join
key = generate(length)
@key = key.unpack('a2'*(key.length/2)).map{|x| x.hex}.pack('c'*(key.length/2))
end
@length = @key.length
end
def kcv()
des = OpenSSL::Cipher::Cipher.new("des-cbc") if @key.length == 8
des = OpenSSL::Cipher::Cipher.new("des-ede-cbc") if @key.length == 16
des.encrypt
des.key=@key
des.update("\x00"*8).unpack('H*').first[0...6].upcase
end
def xor(other)
other=Component.new(other) if other.is_a? String
other=Component.new(other.key) if other.is_a? Key
@@ -52,61 +46,5 @@ module HSMR
@key = xor(_key).key
end
def odd_parity?
# http://csrc.nist.gov/publications/nistpubs/800-67/SP800-67.pdf
#
# The eight error detecting bits are set to make the parity of each 8-bit
# byte of the key odd. That is, there is an odd number of "1"s in each 8-bit byte.
#3.to_s(2).count('1')
#@key.unpack("H2").first.to_i(16).to_s(2)
working=@key.unpack('H2'*(@key.length))
working.each do |o|
freq = o.to_i(16).to_s(2).count('1').to_i
if( freq%2 == 0)
#puts "#{o} is #{o.to_i(16).to_s(2).count('1').to_i } - even"
return false
else
return true
#puts "#{o} is #{o.to_i(16).to_s(2).count('1').to_i } - odd"
end
end
end
def set_odd_parity
return true if self.odd_parity? == true
working=@key.unpack('H2'*(@key.length))
working.each_with_index do |o,i|
freq = o.to_i(16).to_s(2).count('1').to_i
if( freq%2 == 0)
c1 = o[0].chr
c2 = case o[1].chr
when "0" then "1"
when "1" then "0"
when "2" then "3"
when "3" then "2"
when "4" then "5"
when "5" then "4"
when "6" then "7"
when "7" then "6"
when "8" then "9"
when "9" then "8"
when "a" then "b"
when "b" then "a"
when "c" then "d"
when "d" then "c"
when "e" then "f"
when "f" then "e"
end
working[i]="#{c1}#{c2}"
end
end
@key = working.join.unpack('a2'*(working.length)).map{|x| x.hex}.pack('c'*(working.length))
end
def to_s
@key.unpack('H4 '* (@length/2) ).join(" ").upcase
end
end
end