mirror of
https://github.com/dkam/hsmr.git
synced 2025-12-28 08:44:53 +00:00
CVC & CVC2 working
This commit is contained in:
@@ -3,7 +3,6 @@ module HSMR
|
||||
include HSMR
|
||||
attr_reader :key
|
||||
attr_reader :length
|
||||
attr_reader :parity
|
||||
|
||||
def component
|
||||
@key
|
||||
@@ -22,15 +21,18 @@ module HSMR
|
||||
@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
|
||||
# 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
|
||||
# result = @a.zip(@b).map {|x,y| x^y}.map {|z| z.to_s(16) }.map {|c| c.length == 1 ? '0'+c : c }.join.upcase
|
||||
#
|
||||
# Key.new(result)
|
||||
# end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
80
lib/hsmr.rb
80
lib/hsmr.rb
@@ -27,6 +27,11 @@ module HSMR
|
||||
@key.unpack('H4'*(@key.length/2)).join(" ").upcase
|
||||
end
|
||||
|
||||
def parity
|
||||
'even' unless odd_parity?
|
||||
'odd'
|
||||
end
|
||||
|
||||
def odd_parity?
|
||||
# http://csrc.nist.gov/publications/nistpubs/800-67/SP800-67.pdf
|
||||
#
|
||||
@@ -49,6 +54,19 @@ module HSMR
|
||||
end
|
||||
end
|
||||
|
||||
def self.encrypt(data, key)
|
||||
unless key.length == 8 || key.length == 16 || key.length ==24
|
||||
raise TypeError, "key length should be 8, 16 or 24 bytes"
|
||||
end
|
||||
des = OpenSSL::Cipher::Cipher.new("des-cbc") if key.length == 8
|
||||
des = OpenSSL::Cipher::Cipher.new("des-ede-cbc") if key.length == 16
|
||||
des = OpenSSL::Cipher::Cipher.new("des-ede3-cbc") if key.length == 24
|
||||
|
||||
des.encrypt
|
||||
des.key=key.key
|
||||
to_hex( des.update(to_binary(data)) )
|
||||
end
|
||||
|
||||
def set_odd_parity
|
||||
return true if self.odd_parity? == true
|
||||
|
||||
@@ -81,8 +99,39 @@ module HSMR
|
||||
@key = working.join.unpack('a2'*(working.length)).map{|x| x.hex}.pack('c'*(working.length))
|
||||
end
|
||||
|
||||
def xor(other)
|
||||
other=Component.new(other) if other.is_a? String
|
||||
#other=Component.new(other.to_s) if other.is_a? Key
|
||||
|
||||
unless (other.is_a? Component ) or ( other.is_a? Key )
|
||||
raise TypeError, "Component argument expected"
|
||||
end
|
||||
|
||||
@a = @key.unpack('C2'*(@key.length/2))
|
||||
@b = other.key.unpack('C2'*(other.length/2))
|
||||
|
||||
resultant = Key.new( @a.zip(@b).
|
||||
map {|x,y| x^y}.
|
||||
map {|z| z.to_s(16) }.
|
||||
map {|c| c.length == 1 ? '0'+c : c }.
|
||||
join.upcase )
|
||||
resultant
|
||||
end
|
||||
|
||||
def xor!(_key)
|
||||
@key = xor(_key).key
|
||||
end
|
||||
|
||||
## Module Methods
|
||||
|
||||
def self.to_binary(data)
|
||||
data.unpack('a2'*(data.length/2)).map{|x| x.hex}.pack('c'*(data.length/2))
|
||||
end
|
||||
|
||||
def self.to_hex(data)
|
||||
data.unpack('H*').first.upcase
|
||||
end
|
||||
|
||||
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")
|
||||
@@ -150,8 +199,23 @@ module HSMR
|
||||
decimalise(result, :visa)[0..3].join
|
||||
end
|
||||
|
||||
def self.cvv(key_left, key_right, account, exp, service_code)
|
||||
def self.cvv(key_a, key_b, pan, exp, svc)
|
||||
# http://www.m-sinergi.com/hairi/doc.html
|
||||
# For CVV2 use SVC 000
|
||||
# For CVV3 SVC is 502
|
||||
# For iCVV use SVC of 999
|
||||
#
|
||||
#raise ArgumentError "PAN"
|
||||
|
||||
data1 = pan
|
||||
data2 = "#{exp}#{svc}".ljust(16, '0')
|
||||
|
||||
result = encrypt(data1, key_a)
|
||||
result = result.xor(data2)
|
||||
|
||||
result1 = encrypt(result, HSMR::Key.new(key_a.to_s + key_b.to_s) )
|
||||
|
||||
return HSMR.decimalise( result1 )[0,3].join
|
||||
end
|
||||
|
||||
def self.xor(component1, *rest)
|
||||
@@ -186,10 +250,16 @@ class String
|
||||
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*")
|
||||
a1 = self.unpack("a2"*(self.length/2)).map {|x| x.hex }
|
||||
a2 = other.unpack("a2"*(other.length/2)).map {|x| x.hex }
|
||||
#a2 *= 2 while a2.length < a1.length
|
||||
|
||||
#a1.zip(a2).collect{|c1,c2| c1^c2}.pack("C*")
|
||||
a1.zip(a2).
|
||||
map {|x,y| x^y}.
|
||||
map {|z| z.to_s(16) }.
|
||||
map {|c| c.length == 1 ? '0'+c : c }.
|
||||
join.upcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
38
lib/key.rb
38
lib/key.rb
@@ -4,7 +4,6 @@ module HSMR
|
||||
|
||||
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)
|
||||
@@ -30,21 +29,28 @@ module HSMR
|
||||
@length = @key.length
|
||||
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 xor(other)
|
||||
# other=Component.new(other) if other.is_a? String
|
||||
# other=Component.new(other.to_s) if other.is_a? Key
|
||||
#
|
||||
# puts "other is #{other.class} - #{other.key}"
|
||||
#
|
||||
# raise TypeError, "Component argument expected" unless other.is_a? Component
|
||||
#
|
||||
# @a = @key.unpack('C2'*(@key.length/2))
|
||||
# @b = other.component.unpack('C2'*(other.length/2))
|
||||
#
|
||||
# resultant = Key.new( @a.zip(@b).
|
||||
# map {|x,y| x^y}.
|
||||
# map {|z| z.to_s(16) }.
|
||||
# map {|c| c.length == 1 ? '0'+c : c }.
|
||||
# join.upcase )
|
||||
# resultant
|
||||
# end
|
||||
#
|
||||
# def xor!(_key)
|
||||
# @key = xor(_key).key
|
||||
# end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -131,7 +131,66 @@ class TestHSMR < Test::Unit::TestCase
|
||||
kl = "0123456789ABCDEF"
|
||||
kr = "FEDCBA1234567890"
|
||||
|
||||
HSMR.cvv(kl, kr, "4509494222049051", "0907", "1010")
|
||||
#HSMR.cvv(kl, kr, "4509494222049051", "0907", "1010")
|
||||
end
|
||||
|
||||
test "Test PIN, PVV, CVV and CVV2 generation" do
|
||||
cases=[]
|
||||
# Account Exp PIN PVV CVV2 CVV PGK1 PGK2 PVKI PVK1 PVK2 CVKA CVKB DEC
|
||||
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
cases << %W{ 5560501200002101 1010 4412 6183 134 317 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
||||
cases << %W{ 5560501200002111 1010 4784 0931 561 924 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
||||
cases << %W{ 5560501200002121 1010 1040 4895 462 673 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
||||
cases << %W{ 5560501200002131 1010 3680 6373 826 267 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
||||
cases << %W{ 5560501200002101 1110 4412 6183 900 155 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
||||
cases << %W{ 5560501200002111 1110 4784 0931 363 513 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
||||
cases << %W{ 5560501200002121 1110 1040 4895 952 937 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
||||
cases << %W{ 5560501200002131 1110 3680 6373 667 522 3737373737373737 0000000000000000 2 1111111111111111 1111111111111111 1111111111111111 1111111111111111 0123456789012345}
|
||||
cases << %W{ 5560501200002101 1010 9907 7527 777 473 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
||||
cases << %W{ 5560501200002111 1010 2345 0658 638 553 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
||||
cases << %W{ 5560501200002121 1010 8245 8196 085 480 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
||||
cases << %W{ 5560501200002131 1010 3812 2948 591 546 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
||||
cases << %W{ 5560501200002101 1110 9907 7527 349 994 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
||||
cases << %W{ 5560501200002111 1110 2345 0658 245 266 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
||||
cases << %W{ 5560501200002121 1110 8245 8196 441 115 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
||||
cases << %W{ 5560501200002131 1110 3812 2948 126 768 0123456789ABCDEF FEDCBA9876543210 2 7BB19E3D56A1237E 29F7C8FA379EE25C 007A5048DB9531B3 0322DA78AB2F85E1 0123456789012345}
|
||||
|
||||
cases.each do |c|
|
||||
ibm1=HSMR::Component.new(c[6])
|
||||
ibm2=HSMR::Component.new(c[7])
|
||||
ibm=ibm1.xor(ibm2)
|
||||
|
||||
pvk=HSMR::Key.new(c[9]+c[10])
|
||||
|
||||
pin = HSMR::ibm3624(ibm, c[0], 4, c[13]).join
|
||||
pvv = HSMR::pvv(pvk, c[0], c[8], pin)
|
||||
|
||||
assert_equal pin, c[2]
|
||||
assert_equal pin.to_i, c[2].to_i
|
||||
assert_equal pvv, c[3]
|
||||
assert_equal pvv.to_i, c[3].to_i
|
||||
|
||||
cvv = HSMR::cvv(HSMR::Key.new(c[11]), HSMR::Key.new(c[12]), c[0], c[1], '0')
|
||||
cvv2 = HSMR::cvv(HSMR::Key.new(c[11]), HSMR::Key.new(c[12]), c[0], c[1], '101')
|
||||
|
||||
assert_equal c[4].to_i, cvv2.to_i
|
||||
assert_equal c[5].to_i, cvv.to_i
|
||||
|
||||
#puts "#{pin} == #{c[2]} ? #{pin.to_i == c[2].to_i} | #{pvv} == #{c[3]} ? #{pvv.to_i == c[3].to_i}"
|
||||
#
|
||||
end
|
||||
end
|
||||
|
||||
#test "cvv generation" do
|
||||
# keya=HSMR::Key.new("0123456789ABCDEF")
|
||||
# keyb=HSMR::Key.new("FEDCBA1234567890")
|
||||
# key =HSMR::Key.new("0123456789ABCDEFFEDCBA1234567890")
|
||||
#
|
||||
# pan="4509494222049051"
|
||||
# exp="0907"
|
||||
# svc="101000000000"
|
||||
# res="271"
|
||||
# r=HSMR::cvv(keya, keyb, pan, exp, svc)
|
||||
# assert_equal res, r
|
||||
# end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user