Migrating into new Gem repo

This commit is contained in:
Dan Milne
2011-01-07 22:15:14 +11:00
parent a2aecfd44b
commit 8620a66d29
4 changed files with 561 additions and 3 deletions

View File

@@ -0,0 +1,349 @@
require 'openssl'
module HSMR
VERSION = '1.0.0'
#Decimalisation methods
IBM=0
VISA=1
# Key Lengths
SINGLE=64
DOUBLE=128
TRIPLE=192
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")
des.encrypt
des.key=key.key
return des.update(@pin).unpack('H*').first.upcase
end
def self.decrypt_pin(key, 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.key
result = des.update(@pinblock)
result << des.final
result.unpack('H*').first.upcase
end
def self.ibm3624(key, account, plength=4, dtable="0123456789012345" )
validation_data = account.unpack('a2'*(account.length/2)).map{|x| x.hex}.pack('c'*(account.length/2))
#des = OpenSSL::Cipher::Cipher.new("des-ede-cbc")
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]
end
def self.decimalise(value, method=VISA, dtable="0123456789012345" )
result = []
if method == IBM
##
# The IBM method
##
value.each_char do |c|
result << dtable[c.to_i(16),1].to_i
end
elsif method == VISA
value.each_char do |c|
result << c.to_i if numeric?(c)
end
value.upcase.each_char do |c|
result << dtable[c.to_i(16),1].to_i unless numeric?(c)
end
end
return result
end
def self.pvv(key, account, pvki, pin)
tsp = account.to_s[4,11] + pvki.to_s + pin.to_s
@tsp = tsp.unpack('a2'*(tsp.length/2)).map{|x| x.hex}.pack('c'*(tsp.length/2))
des = OpenSSL::Cipher::Cipher.new("des-ede")
des.encrypt
des.key=key.key
result = des.update(@tsp).unpack('H*').first.upcase
decimalise(result, VISA)[0..3].join
end
def self.xor(component1, *rest)
return if rest.length == 0
component1 = Component.new(component1) unless component1.is_a? Component
raise TypeError, "Component argument expected" unless component1.is_a? Component
#@components=[]
#rest.each {|c| components << ((c.is_a? HSMR::Component) ? c : HSMR::Component.new(c) ) }
#components.each {|c| raise TypeError, "Component argument expected" unless c.is_a? Component }
#resultant = component1.xor(components.pop)
#components.each {|c| resultant.xor!(c) }
rest.collect! {|c| ( (c.is_a? HSMR::Component) ? c : HSMR::Component.new(c) ) }
rest.each {|c| raise TypeError, "Component argument expected" unless c.is_a? HSMR::Component }
resultant = component1.xor(rest.pop)
rest.each {|c| resultant.xor!(c) }
return(resultant)
end
def self.numeric?(object)
## 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?
self
else
a1 = self.unpack("c*")
a2 = other.unpack("c*")
a2 *= 2 while a2.length < a1.length
a1.zip(a2).collect{|c1,c2| c1^c2}.pack("c*")
end
end
end