Skip to content

Instantly share code, notes, and snippets.

@sandys
Created September 20, 2012 10:56
Show Gist options
  • Save sandys/3755219 to your computer and use it in GitHub Desktop.
Save sandys/3755219 to your computer and use it in GitHub Desktop.
an example of Format Preserving Encryption in Ruby using RC4 and pack. The important thing is to keep key length to be a power of 2
require 'openssl'
c = OpenSSL::Cipher::Cipher.new("rc4-40")
serial = 4000987
puts " *********** SERIAL NUMBER = #{serial}"
c.encrypt
c.key = "fdkjgfdoi4tu45fkgkljfg9485439tkjfgnjdshfghwhe54350gfgklkgje34324nkjdfhk45845843543k5kdjfk3454958439kkfkglgkttpoeoidsad49584305ldkfsdjf42jkndfl"
padded_serial = "%015d" % serial
padded_serial_array = [padded_serial.slice(0,10).to_i, padded_serial.slice(10,15).to_i]
padded_serial_packed = padded_serial_array.pack("LS")
puts " #{ padded_serial.slice(0,10).to_i} and #{padded_serial.slice(10,15).to_i} "
puts "padded_serial_packed #{padded_serial_packed.unpack("LS").inspect} array = #{padded_serial_array.inspect} "
padded_serial_packed_encrypted = c.update(padded_serial_packed) + c.final
order_number_pre = padded_serial_packed_encrypted.unpack("LS")
puts "order_number_pre= #{ order_number_pre.inspect}"
order_number_pre_padded = [ ("%010d" % order_number_pre[0]).to_s, ("%05d" % order_number_pre[1]).to_s ]
#http://blog.anidear.com/2011/11/luhn-algorithm-implementation-in-ruby.html
def luhn(input)
10 - input.split(//).collect(&:to_i).zip((1..input.length).to_a).map{|v,i| i%2==0?(v*2<10?v*2:v*2-9):v}.inject(&:+)%10
end
order_number = [luhn( order_number_pre_padded[0]).to_s + order_number_pre_padded[0], luhn( order_number_pre_padded[1]).to_s + order_number_pre_padded[1] ]
puts " ************ ORDER NUMBER = #{order_number.inspect} or #{order_number} **************"
d = OpenSSL::Cipher::Cipher.new("rc4-40")
d.decrypt
d.key = "fdkjgfdoi4tu45fkgkljfg9485439tkjfgnjdshfghwhe54350gfgklkgje34324nkjdfhk45845843543k5kdjfk3454958439kkfkglgkttpoeoidsad49584305ldkfsdjf42jkndfl"
order_number_pre_checksum = [ order_number[0].slice(1,11).to_i, order_number[1].slice(1,5).to_i ]
puts "order_number_pre_checksum= #{order_number_pre_checksum.inspect}"
order_number_pre_checksum_packed = order_number_pre_checksum.pack("LS")
padded_serial_packed_decrypted = d.update(order_number_pre_checksum_packed ) + d.final
padded_serial_packed_decrypted_unpacked = padded_serial_packed_decrypted.unpack("LS")
padded_serial_packed_decrypted_unpacked_reformatted = ["%010d" %padded_serial_packed_decrypted_unpacked[0], "%05d" %padded_serial_packed_decrypted_unpacked[1] ]
puts " padded_serial_packed_decrypted = #{padded_serial_packed_decrypted_unpacked_reformatted.inspect}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment