mirror of
https://github.com/dkam/hsmr.git
synced 2025-12-28 08:44:53 +00:00
Split Key out to separate class
This commit is contained in:
28
Gemfile.lock
Normal file
28
Gemfile.lock
Normal 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)
|
||||||
4
Rakefile
4
Rakefile
@@ -16,9 +16,11 @@ Jeweler::Tasks.new do |gem|
|
|||||||
gem.homepage = "http://github.com/dkam/hsmr"
|
gem.homepage = "http://github.com/dkam/hsmr"
|
||||||
gem.license = "MIT"
|
gem.license = "MIT"
|
||||||
gem.summary = %Q{HSM Functions in Ruby}
|
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.email = "d@nmilne.com"
|
||||||
gem.authors = ["Dan Milne"]
|
gem.authors = ["Dan Milne"]
|
||||||
|
gem.version = '0.0.1'
|
||||||
|
|
||||||
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
# 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)
|
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
||||||
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
||||||
|
|||||||
247
lib/hsmr.rb
247
lib/hsmr.rb
@@ -1,10 +1,7 @@
|
|||||||
require 'openssl'
|
require 'openssl'
|
||||||
|
|
||||||
module HSMR
|
module HSMR
|
||||||
VERSION = '1.0.0'
|
VERSION = '0.0.1'
|
||||||
#Decimalisation methods
|
|
||||||
IBM=0
|
|
||||||
VISA=1
|
|
||||||
|
|
||||||
# Key Lengths
|
# Key Lengths
|
||||||
SINGLE=64
|
SINGLE=64
|
||||||
@@ -38,14 +35,14 @@ module HSMR
|
|||||||
des = OpenSSL::Cipher::Cipher.new("des-cbc")
|
des = OpenSSL::Cipher::Cipher.new("des-cbc")
|
||||||
des.encrypt
|
des.encrypt
|
||||||
des.key=key.key
|
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
|
end
|
||||||
|
|
||||||
def self.decimalise(value, method=VISA, dtable="0123456789012345" )
|
def self.decimalise(value, method=:visa, dtable="0123456789012345" )
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
if method == IBM
|
if method == :ibm
|
||||||
##
|
##
|
||||||
# The IBM method
|
# The IBM method
|
||||||
##
|
##
|
||||||
@@ -53,7 +50,7 @@ module HSMR
|
|||||||
result << dtable[c.to_i(16),1].to_i
|
result << dtable[c.to_i(16),1].to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
elsif method == VISA
|
elsif method == :visa
|
||||||
|
|
||||||
value.each_char do |c|
|
value.each_char do |c|
|
||||||
result << c.to_i if numeric?(c)
|
result << c.to_i if numeric?(c)
|
||||||
@@ -75,7 +72,7 @@ module HSMR
|
|||||||
des.encrypt
|
des.encrypt
|
||||||
des.key=key.key
|
des.key=key.key
|
||||||
result = des.update(@tsp).unpack('H*').first.upcase
|
result = des.update(@tsp).unpack('H*').first.upcase
|
||||||
decimalise(result, VISA)[0..3].join
|
decimalise(result, :visa)[0..3].join
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.xor(component1, *rest)
|
def self.xor(component1, *rest)
|
||||||
@@ -102,239 +99,9 @@ module HSMR
|
|||||||
## Method to determine if an object is a numeric type.
|
## Method to determine if an object is a numeric type.
|
||||||
true if Float(object) rescue false
|
true if Float(object) rescue false
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
class String
|
class String
|
||||||
def xor(other)
|
def xor(other)
|
||||||
if other.empty?
|
if other.empty?
|
||||||
|
|||||||
112
lib/key.rb
Normal file
112
lib/key.rb
Normal 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
|
||||||
Reference in New Issue
Block a user