Home > Software engineering >  Ruby openssl encryption with DES-CBC incorrect result
Ruby openssl encryption with DES-CBC incorrect result

Time:09-23

I am trying to replicate the encryption result from here in Ruby using OpenSSL: https://emvlab.org/descalc/?key=18074F7ADD44C903&iv=18074F7ADD44C903&input=4E5A56564F4C563230313641454E5300&mode=cbc&action=Encrypt&output=25C843BA5C043FFFB50F76E43A211F8D

  • Original string = "NZVVOLV2016AENS"
  • String converted to hexadecimal = "4e5a56564f4c563230313641454e53"
  • iv = "18074F7ADD44C903"
  • key = "18074F7ADD44C903"
  • Expected result = "9B699B4C59F1444E8D37806FA9D15F81"

Here is my ruby code:

require 'openssl'
require "base64"
include Base64

iv = "08074F7ADD44C903"
cipher = "08074F7ADD44C903"

def encode(string)
  puts "Attempting encryption - Input: #{string}"
  encrypt = OpenSSL::Cipher.new('DES-CBC')
  encrypt.encrypt
  encrypt.key = ["18074F7ADD44C903"].pack('H*') #.scan(/../).map{|b|b.hex}.pack('c*')
  encrypt.iv = ["18074F7ADD44C903"].pack('H*')
  result = encrypt.update(string)   encrypt.final
  puts "Raw output: #{result.inspect}"
  unpacked = result.unpack('H*')[0]
  puts "Encrypted key is: #{unpacked}"
  puts "Encrypted Should be: 9B699B4C59F1444E8D37806FA9D15F81"
  return unpacked
end

res = encode("NZVVOLV2016AENS")
Output:
Encrypted key is:    9b699b4c59f1444ea723ab91e89c023a
Encrypted Should be: 9B699B4C59F1444E8D37806FA9D15F81

Interestingly, the first half of the result is correct, and the last 16 digits are incorrect.

CodePudding user response:

The web site uses Zero padding by default, while the Ruby code uses PKCS#7 padding by default.
Ruby does not seem to support Zero padding, so disable the default padding and implement Zero padding yourself.
Zero padding pads to the next full block size with 0x00 values. The block size for DES is 8 bytes. If the last block of the plaintext is already filled, no padding is done:

def zeroPad(string, blocksize)
  len = string.bytes.length
  padLen = (blocksize - len % blocksize) % blocksize
  string  = "\0" * padLen
  return string
end

In the encode() function (which should better be called encrypt() function) the following lines must be added before encryption:

encrypt.padding = 0         # disable PKCS#7 padding
string = zeroPad(string, 8) # enable Zero padding

The modified Ruby code then gives the same ciphertext as the web site.


Note that DES is insecure, also it' s insecure to use the key as IV (as well as a static IV). Furthermore, Zero padding is unreliable in contrast to PKCS#7 padding.

  • Related