Split Key out to separate class

This commit is contained in:
Dan Milne
2011-03-30 21:54:22 +11:00
parent 8620a66d29
commit 6d87a387e0
4 changed files with 151 additions and 242 deletions

28
Gemfile.lock Normal file
View File

@@ -0,0 +1,28 @@
GEM
remote: http://rubygems.org/
specs:
diff-lcs (1.1.2)
git (1.2.5)
jeweler (1.5.2)
bundler (~> 1.0.0)
git (>= 1.2.5)
rake
rake (0.8.7)
rcov (0.9.9)
rspec (2.3.0)
rspec-core (~> 2.3.0)
rspec-expectations (~> 2.3.0)
rspec-mocks (~> 2.3.0)
rspec-core (2.3.1)
rspec-expectations (2.3.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.3.0)
PLATFORMS
ruby
DEPENDENCIES
bundler (~> 1.0.0)
jeweler (~> 1.5.2)
rcov
rspec (~> 2.3.0)

View File

@@ -16,9 +16,11 @@ Jeweler::Tasks.new do |gem|
gem.homepage = "http://github.com/dkam/hsmr"
gem.license = "MIT"
gem.summary = %Q{HSM Functions in Ruby}
gem.description = %Q{TODO: longer description of your gem}
gem.description = gem.summary
gem.email = "d@nmilne.com"
gem.authors = ["Dan Milne"]
gem.version = '0.0.1'
# Include your dependencies below. Runtime dependencies are required when using your gem,
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
# gem.add_runtime_dependency 'jabber4r', '> 0.1'

View File

@@ -1,10 +1,7 @@
require 'openssl'
module HSMR
VERSION = '1.0.0'
#Decimalisation methods
IBM=0
VISA=1
VERSION = '0.0.1'
# Key Lengths
SINGLE=64
@@ -38,14 +35,14 @@ module HSMR
des = OpenSSL::Cipher::Cipher.new("des-cbc")
des.encrypt
des.key=key.key
return HSMR::decimalise(des.update(validation_data).unpack('H*').first, IBM, dtable)[0...plength]
return HSMR::decimalise(des.update(validation_data).unpack('H*').first, :ibm, dtable)[0...plength]
end
def self.decimalise(value, method=VISA, dtable="0123456789012345" )
def self.decimalise(value, method=:visa, dtable="0123456789012345" )
result = []
if method == IBM
if method == :ibm
##
# The IBM method
##
@@ -53,7 +50,7 @@ module HSMR
result << dtable[c.to_i(16),1].to_i
end
elsif method == VISA
elsif method == :visa
value.each_char do |c|
result << c.to_i if numeric?(c)
@@ -75,7 +72,7 @@ module HSMR
des.encrypt
des.key=key.key
result = des.update(@tsp).unpack('H*').first.upcase
decimalise(result, VISA)[0..3].join
decimalise(result, :visa)[0..3].join
end
def self.xor(component1, *rest)
@@ -102,239 +99,9 @@ module HSMR
## Method to determine if an object is a numeric type.
true if Float(object) rescue false
end
class Component
attr_reader :component
attr_reader :length
attr_reader :parity
def initialize(component=nil, length=DOUBLE)
## Should check for odd parity
if component.nil?
component = (0...(length/4)).collect { rand(16).to_s(16).upcase }.join
else
component=component.gsub(/ /,'')
#raise TypeError, "Component argument expected" unless other.is_a? Component
end
@component = component.unpack('a2'*(component.length/2)).map{|x| x.hex}.pack('c'*(component.length/2))
@length = @component.length
end
def kcv()
des = OpenSSL::Cipher::Cipher.new("des-cbc") if @component.length == 8
des = OpenSSL::Cipher::Cipher.new("des-ede-cbc") if @component.length == 16
des.encrypt
des.key=@component
des.update("\x00"*8).unpack('H*').first[0...6].upcase
end
def xor(other)
other = Component.new(other) unless other.is_a? Component
raise TypeError, "Component argument expected" unless other.is_a? Component
@a = @component.unpack('C2'*(@component.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
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=@component.unpack('H2'*(@component.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=@component.unpack('H2'*(@component.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
@component = working.join.unpack('a2'*(working.length)).map{|x| x.hex}.pack('c'*(working.length))
end
def to_s
@component.unpack('H4'*(@component.length/2)).join(" ").upcase
end
end
class Key
attr_reader :key
attr_reader :length
attr_reader :parity
def initialize(init=nil, length=DOUBLE)
return nil if (init.is_a? Array ) && (init.length == 0)
init = init.first if (init.is_a? Array) && (init.length == 1)
if init.is_a? Array
init.collect! {|c| ( (c.is_a? HSMR::Component) ? c : HSMR::Component.new(c) ) }
raise TypeError, "Component argument expected" unless init.first.is_a? Component
@key=HSMR::xor(init.pop, init).key
elsif init.is_a? Component
@key = init.component
elsif init.is_a? String
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 = 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 encpin(pin)
@pin = pin.unpack('a2'*(pin.length/2)).map{|x| x.hex}.pack('c'*(pin.length/2))
des = OpenSSL::Cipher::Cipher.new("des-ede")
des.encrypt
des.key=@key
return des.update(@pin).unpack('H*').first.upcase
end
def decryptpin(pinblock)
@pinblock = pinblock.unpack('a2'*(pinblock.length/2)).map{|x| x.hex}.pack('c'*(pinblock.length/2))
des = OpenSSL::Cipher::Cipher.new("des-ede")
des.decrypt
des.padding=0
des.key=@key
result = des.update(@pinblock)
result << des.final
result.unpack('H*').first.upcase
end
def xor(other)
other=Component.new(other) if other.is_a? String
other=Component.new(other.key) if other.is_a? Key
raise TypeError, "Component argument expected" unless other.is_a? Component
@a = @key.unpack('C2'*(@key.length/2))
@b = other.component.unpack('C2'*(@key.length/2))
resultant = Key.new( @a.zip(@b).map {|x,y| x^y}.map {|z| z.to_s(16) }.join.upcase )
end
def xor!(_key)
@key = xor(_key).key
end
def pvv(account, pvki, pin)
HSMR::pvv(self, account, pvi, pin)
end
def to_s
@key.unpack('H4 '* (@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
end
end
class String
def xor(other)
if other.empty?
@@ -346,4 +113,4 @@ class String
a1.zip(a2).collect{|c1,c2| c1^c2}.pack("c*")
end
end
end
end

112
lib/key.rb Normal file
View File

@@ -0,0 +1,112 @@
module HSMR
class Key
attr_reader :key
attr_reader :length
attr_reader :parity
def initialize(init=nil, length=DOUBLE)
return nil if (init.is_a? Array ) && (init.length == 0)
init = init.first if (init.is_a? Array) && (init.length == 1)
if init.is_a? Array
init.collect! {|c| ( (c.is_a? HSMR::Component) ? c : HSMR::Component.new(c) ) }
raise TypeError, "Component argument expected" unless init.first.is_a? Component
@key=HSMR::xor(init.pop, init).key
elsif init.is_a? Component
@key = init.component
elsif init.is_a? String
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 = 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
raise TypeError, "Component argument expected" unless other.is_a? Component
@a = @key.unpack('C2'*(@key.length/2))
@b = other.component.unpack('C2'*(@key.length/2))
resultant = Key.new( @a.zip(@b).map {|x,y| x^y}.map {|z| z.to_s(16) }.join.upcase )
end
def xor!(_key)
@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