Files
hsmr/lib/key.rb
2011-03-30 21:54:22 +11:00

113 lines
3.4 KiB
Ruby

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