mirror of
https://github.com/dkam/hsmr.git
synced 2025-12-28 16:54:52 +00:00
Migrating into new Gem repo
This commit is contained in:
7
CHANGES.md
Normal file
7
CHANGES.md
Normal file
@@ -0,0 +1,7 @@
|
||||
History
|
||||
=========
|
||||
|
||||
1.0.0
|
||||
-------
|
||||
|
||||
Initial release.
|
||||
28
README.md
Normal file
28
README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
HSMR
|
||||
===========
|
||||
|
||||
HSMR is a collection of cryptographic commands usually implemented on a HSM (Hardware Security Module). These
|
||||
are implemented for your education or for testing purposes and should not be used to replace an actual HSM.
|
||||
|
||||
Installation
|
||||
-------------
|
||||
|
||||
You install it just like any other Ruby gem:
|
||||
|
||||
gem install hsmr
|
||||
|
||||
Usage
|
||||
---------
|
||||
|
||||
require 'hsmr'
|
||||
|
||||
|
||||
Author
|
||||
==========
|
||||
|
||||
Dan Milne, http://da.nmilne.com
|
||||
|
||||
Copyright
|
||||
----------
|
||||
|
||||
Copyright (c) 2010 Dan Milne. See LICENSE for details.
|
||||
349
lib/hsmr.rb
349
lib/hsmr.rb
@@ -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
|
||||
@@ -1,7 +1,181 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
||||
|
||||
describe "Hsmr" do
|
||||
it "fails" do
|
||||
fail "hey buddy, you should probably rename this file and start specing for real"
|
||||
describe "Generate Component" do
|
||||
it "should generate a component" do
|
||||
component_1 = HSMR::Component.new(nil, HSMR::SINGLE)
|
||||
component_2 = HSMR::Component.new(nil, HSMR::DOUBLE)
|
||||
component_3 = HSMR::Component.new(nil, HSMR::TRIPLE)
|
||||
|
||||
component_1.length.should == 8
|
||||
component_2.length.should == 16
|
||||
component_3.length.should == 24
|
||||
end
|
||||
end
|
||||
|
||||
describe "Calculate component KCV" do
|
||||
|
||||
it "should calculate single length component KCV values" do
|
||||
component_1 = HSMR::Component.new("6DBF C180 4A01 5BAD")
|
||||
component_1.kcv.should == "029E60"
|
||||
|
||||
component_2 = HSMR::Component.new("5D80 0497 B319 8591")
|
||||
component_2.kcv.should == "3B86C3"
|
||||
|
||||
component_3 = HSMR::Component.new("B0C7 7CDC 7354 97C7")
|
||||
component_3.kcv.should == "7A77BC"
|
||||
|
||||
component_4 = HSMR::Component.new("DAE0 86FE D6EA 0BEA")
|
||||
component_4.kcv.should == "2E6191"
|
||||
|
||||
component_5 = HSMR::Component.new("682C 8315 F4BF FBC1")
|
||||
component_5.kcv.should == "62B336"
|
||||
|
||||
component_6 = HSMR::Component.new("5715 F289 04BC B62F")
|
||||
component_6.kcv.should == "3CBA88"
|
||||
|
||||
component_7 = HSMR::Component.new("D0C4 29AE C4A8 02B5")
|
||||
component_7.kcv.should == "33AF02"
|
||||
|
||||
component_8 = HSMR::Component.new("7049 D0F7 4A97 15B6")
|
||||
component_8.kcv.should == "AC1399"
|
||||
|
||||
component_9 = HSMR::Component.new("BC91 D698 157A A4E5")
|
||||
component_9.kcv.should == "295491"
|
||||
|
||||
component_10 = HSMR::Component.new("64AB 8568 7A0E 322F")
|
||||
component_10.kcv.should == "D9F7B3"
|
||||
end
|
||||
|
||||
it "should calculate double length component KCV values" do
|
||||
component_1 = HSMR::Component.new("ADE3 9B38 0DBC DF38 AE02 AECE 64B3 4373")
|
||||
component_1.kcv.should == "3002D5"
|
||||
|
||||
component_2 = HSMR::Component.new("B64A EF86 460D DF5B 57B3 D53D AD37 52A1")
|
||||
component_2.kcv.should == "1F7C07"
|
||||
|
||||
component_3 = HSMR::Component.new("5B89 6E29 76EC 9745 15B5 238C 8CFE 3D23")
|
||||
component_3.kcv.should == "DE78F2"
|
||||
|
||||
component_4 = HSMR::Component.new("5E61 CB20 D540 1FC7 58EC CDC8 B558 E9B9")
|
||||
component_4.kcv.should == "FED957"
|
||||
|
||||
component_5 = HSMR::Component.new("23DF CEB9 BF94 ADA8 91E9 580B 8C8F 5BEF")
|
||||
component_5.kcv.should == "902085"
|
||||
|
||||
component_6 = HSMR::Component.new("DFEF 61C8 2037 3DA4 CE9B 92CD 89E9 B334")
|
||||
component_6.kcv.should == "E45EB7"
|
||||
|
||||
component_7 = HSMR::Component.new("6746 9E4C FE83 F831 F23E 9D9E 9D9E 9DB3")
|
||||
component_7.kcv.should == "813B7B"
|
||||
|
||||
component_8 = HSMR::Component.new("23E5 496E DF94 0BD5 9734 B07A BF26 B9E6")
|
||||
component_8.kcv.should == "E7C48F"
|
||||
|
||||
component_9 = HSMR::Component.new("974F 26BC CB2A ECD5 434F 1CDC 64DF A275")
|
||||
component_9.kcv.should == "E27250"
|
||||
|
||||
component_10 = HSMR::Component.new("E57A DF5B CEA7 F42A DFD9 E554 07A2 F891")
|
||||
component_10.kcv.should == "50E3F8"
|
||||
end
|
||||
end
|
||||
|
||||
describe "Calculate key KCV" do
|
||||
|
||||
it "should calculate single length key KCV values" do
|
||||
key_1 = HSMR::Key.new("6DBF C180 4A01 5BAD")
|
||||
key_1.kcv.should == "029E60"
|
||||
|
||||
key_2 = HSMR::Key.new("5D80 0497 B319 8591")
|
||||
key_2.kcv.should == "3B86C3"
|
||||
|
||||
key_3 = HSMR::Key.new("B0C7 7CDC 7354 97C7")
|
||||
key_3.kcv.should == "7A77BC"
|
||||
|
||||
key_4 = HSMR::Key.new("DAE0 86FE D6EA 0BEA")
|
||||
key_4.kcv.should == "2E6191"
|
||||
|
||||
key_5 = HSMR::Key.new("682C 8315 F4BF FBC1")
|
||||
key_5.kcv.should == "62B336"
|
||||
|
||||
key_6 = HSMR::Key.new("5715 F289 04BC B62F")
|
||||
key_6.kcv.should == "3CBA88"
|
||||
|
||||
key_7 = HSMR::Key.new("D0C4 29AE C4A8 02B5")
|
||||
key_7.kcv.should == "33AF02"
|
||||
|
||||
key_8 = HSMR::Key.new("7049 D0F7 4A97 15B6")
|
||||
key_8.kcv.should == "AC1399"
|
||||
|
||||
key_9 = HSMR::Key.new("BC91 D698 157A A4E5")
|
||||
key_9.kcv.should == "295491"
|
||||
|
||||
key_10 = HSMR::Key.new("64AB 8568 7A0E 322F")
|
||||
key_10.kcv.should == "D9F7B3"
|
||||
end
|
||||
it "should calculate double length key KCV values" do
|
||||
key_1 = HSMR::Key.new("ADE3 9B38 0DBC DF38 AE02 AECE 64B3 4373")
|
||||
key_1.kcv.should == "3002D5"
|
||||
|
||||
key_2 = HSMR::Key.new("B64A EF86 460D DF5B 57B3 D53D AD37 52A1")
|
||||
key_2.kcv.should == "1F7C07"
|
||||
|
||||
key_3 = HSMR::Key.new("5B89 6E29 76EC 9745 15B5 238C 8CFE 3D23")
|
||||
key_3.kcv.should == "DE78F2"
|
||||
|
||||
key_4 = HSMR::Key.new("5E61 CB20 D540 1FC7 58EC CDC8 B558 E9B9")
|
||||
key_4.kcv.should == "FED957"
|
||||
|
||||
key_5 = HSMR::Key.new("23DF CEB9 BF94 ADA8 91E9 580B 8C8F 5BEF")
|
||||
key_5.kcv.should == "902085"
|
||||
|
||||
key_6 = HSMR::Key.new("DFEF 61C8 2037 3DA4 CE9B 92CD 89E9 B334")
|
||||
key_6.kcv.should == "E45EB7"
|
||||
|
||||
key_7 = HSMR::Key.new("6746 9E4C FE83 F831 F23E 9D9E 9D9E 9DB3")
|
||||
key_7.kcv.should == "813B7B"
|
||||
|
||||
key_8 = HSMR::Key.new("23E5 496E DF94 0BD5 9734 B07A BF26 B9E6")
|
||||
key_8.kcv.should == "E7C48F"
|
||||
|
||||
key_9 = HSMR::Key.new("974F 26BC CB2A ECD5 434F 1CDC 64DF A275")
|
||||
key_9.kcv.should == "E27250"
|
||||
|
||||
key_10 = HSMR::Key.new("E57A DF5B CEA7 F42A DFD9 E554 07A2 F891")
|
||||
key_10.kcv.should == "50E3F8"
|
||||
end
|
||||
end
|
||||
|
||||
describe "Calculate parity" do
|
||||
it "should detect odd_parity in a key" do
|
||||
odd_key = HSMR::Key.new("41A2AC14A90C583741A2AC14A90C5837")
|
||||
odd_key.odd_parity?.should == false
|
||||
end
|
||||
|
||||
it "should set double length key parity to odd" do
|
||||
odd_key = HSMR::Key.new("41A2AC14A90C583741A2AC14A90C5837")
|
||||
|
||||
odd_key.set_odd_parity
|
||||
|
||||
even_key = HSMR::Key.new("40A2AD15A80D583740A2AD15A80D5837")
|
||||
|
||||
odd_key.key.should == even_key.key
|
||||
|
||||
end
|
||||
|
||||
it "should detect odd_parity in a component" do
|
||||
odd_component = HSMR::Component.new("41A2AC14A90C583741A2AC14A90C5837")
|
||||
odd_component.odd_parity?.should == false
|
||||
end
|
||||
|
||||
it "should set double length component parity to odd" do
|
||||
odd_component = HSMR::Component.new("41A2AC14A90C583741A2AC14A90C5837")
|
||||
|
||||
odd_component.set_odd_parity
|
||||
|
||||
even_component = HSMR::Component.new("40A2AD15A80D583740A2AD15A80D5837")
|
||||
|
||||
odd_component.component.should == even_component.component
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user