Encrypting/decrypting 3DES in Ruby - ruby

I have a key.bin file which content is something along the lines of:
-12, 110, 93, 14, -48, ...
This is being used by a service to decrypt 3DES content, but I need to encrypt it via Ruby.
I've tried loads of scenarios with how to set the key and what to do with it, but to no avail as of yet:
Tried splitting the key by , and converting each number to hex, concatenating the hex values to make the key
Tried converting the number string to binary
Tried converting the resulting hex to binary
I assume what I need to do is something simple like:
des = OpenSSL::Cipher::Cipher.new('des3')
des.decrypt
des.key = mistery # this step is where i'm having problems at
final = des.update(encrypted) + des.final
Any ideas on what I should do with this key?
Key sample:
-62,-53,124,-110,37,-88,-48,31,-57,93,70,-101,44,69,-88,-57,-123,-99,118,-119,110,55,11,14
Data sample:
NEb2b9sYXgod6mTvaRv+MRsTJvIiTTI9VjnDGcxjxcN5qBH7FXvxYI6Oj16FeKKsoQvjAmdju2SQ
ifJqPJTl97xeEbjdwm+W8XJnWs99ku85EznVBhzQxI1H2jPiZIcrqIVCWdd/OQun7AjK4w2+5yb7
DPN2OiCIEOz2zK6skJrBw3oTEHpXrSEhydOYxqI+c5hC4z3k5nktN6WSVLIo8EAjwenHPMDxboWF
ET8R+QM5EznVBhzQxI1H2jPiZIcrqIVCWdd/OQun7AjK4w2+5yb7DPN2OiCIFqk4LRwEVq16jvKE
vjz6T4/G34kx6CEx/JdZ1LdvxC3xYQIcwS0wVnmtxorFm4q5QQFHzNKQ5chrGZzDkFzAogsZ2l2B
vcvlwgajNGHmxuVU83Ldn1e5rin7QqpjASqeDGFQHkiSbp4x6axVce2OGgfFpZdzCM7y6jLPpOlX
LOC/Bs1vTwMzcBNRB/Fo4nsX9i4It8Spm228XQNUpQe4i9QGe/4AyKIhHoM8DkXwPZ6rWp0W0UMe
keXjg41cED1JwjAAQSP3RYITB78bu+CEZKPOt2tQ2BvSw55mnFcvjIAYVQxCHliQ4PwgceHrnsZz
5aagC0QJ3oOKw9O0dlkVE3IM6KTBMcuZOZF19nCqxMFacQoDxjJY8tOJoN0Fe4Boz2FPyuggfLz9
yhljVJhxqOlTd8eA34Ex8SdC+5NDByAMumjzcPcXL8YVpSN85gytfd+skXhz3npmJ0dmZZOouu0Z
vMmlaCqw96Sy0L1mHLKbjqmZ/W57OBNRB/Fo4nsX9i4It8Spm228XQNUpQe4i9QGe/4AyKIhHoM8
DkXwPZ5tXdq1dRG6IaS51oNzFFlOoP3wTJuOTpj+zQOBMMOi4ENFyyEwYbG/qE+uY8rVwBOUHv9b
Yd9byvOZbnHDuf4oaWRZ+4K3s2NkEblDF9wU6Mb0ZqnLEJsypjrorH1cNIodIDu8nME1nD5bIDF6
XNrWC6pk6AV6eYQvNJw2QDz0RBD15fz/fAXCvbaCLDnhBKpLXrRbQdV+jxx2ipeC2ceMLLRFRPuR
B+ycYht65lWh4jNjoEsBXGFKiT0bSX6Lx/ZQD3twJWbML8ifRhw7SW0jOkUF+dAfXYNaD6nqA6Xq
TkcsDGaJsVq8wwCIWNh6tDRSw7ba4c391147kmnqEgXdKmmnEzUfHtpRw88C0/u0qj809hB4qB0B
lxj/87aDo4VOz9S4jjtk849CxtA/a9+532A4YlXjsPt/f0KZ2drAGEr1VSWzaLh/sMwP5tznmPaK
uozS6C74gMNdhtNMFz0HONcYecS0hg4lrdRyljROgzC33QoBIHbQXJrG0OXE3+81uhJwusEnFaD9
8Eybjk6YeNk3oxL3C5fx/xXgFmhcLLGdxRe/am0jqA1gV6MyQFUKtzdnNOUYpHkYXT9Ea7YYln4Q
D96Z9AI5EznVBhzQxI1H2jPiZIcrqIVCWdd/OQun7AjK4w2+5yb7DPN2OiCIFqk4LRwEVq16jvKE
vjz6T4/G34kx6CEx/JdZ1LdvxC3iEcYTrEH9kKhPrmPK1cATlB7/W2HfW8rzmW5xw7n+KGlkWfuC
t7NjZBG5QxfcFOjG9GapyxCbMqY66Kx9XDSKHSA7vJzBNZw+WyAxelza1guqZOgFenmElSgtUOo7
TEunuphaMIEQgo0udojG6dm2FtRmA4yntNCnCDzGTY72nrFBz3EZmVXGEm6X3Xd5Ito=

Got it working!
Here's how:
Decryption
def read_key(key_file)
File.read(key_file).split(',').map { |x| x.to_i }.pack('c*')
end
des = OpenSSL::Cipher::Cipher.new('des-ede3')
des.decrypt
des.key = read_key('key.bin')
result = des.update(decoded) + des.final
Encryption
def read_key(key_file)
File.read(key_file).split(',').map { |x| x.to_i }.pack('c*')
end
des2 = OpenSSL::Cipher::Cipher.new('des-ede3')
des2.encrypt
des2.key = read_key('key.bin')
result = des2.update(result) + des2.final
puts Base64.encode64(result)

Related

Ruby openssl encryption with DES-CBC incorrect result

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.
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.

Encrypt data with DES ECB in Ruby

I am implementing an encryption in a project that I has in another java project.
The code in java project is this:
public static String cifraDES(String chave, String dado) throws Exception {
DESKeySpec keySpec = new DESKeySpec(hexStringToByteArray(chave));
SecretKeyFactory kf = SecretKeyFactory.getInstance("DES");
SecretKey passwordKey = kf.generateSecret(keySpec);
Cipher c = Cipher.getInstance("DES");
c = Cipher.getInstance("DES/ECB/NoPadding");
c.init(Cipher.ENCRYPT_MODE, passwordKey);
return bytesToHex(c.doFinal(hexStringToByteArray(dado)));
}
In Ruby project i want implement this encrypt too. But this dont work:
dado = "53495A45303030386E6F7661313031305858585858585858"
chave = "3455189635541968"
des = OpenSSL::Cipher.new('des-ecb').encrypt
des.key = chave
s = des.update(dado) + des.final
Base64.encode64(s).gsub(/\n/, "")
In terminal I recive this message:
'key' be must 8 bytes
And i need this return: b42e3dbfffd4bb5487a27fd702f079e287e6325767bfdd20
View:
http://des.online-domain-tools.com/link/1145159gOjlrPNRkaT/
You haven’t converted the key and data from hex strings, you can do that using pack:
dado = ["53495A45303030386E6F7661313031305858585858585858"].pack('H*')
(When you do this to the key, it is converted from 16 hexidecimal characters to 8 bytes, so not doing this step is causing the error are getting).
You haven’t specified no padding:
des.padding = 0
And you want the result hex encoded, not base 64. You can use unpack:
puts s.unpack('H*')[0]
Putting it all together:
dado = ["53495A45303030386E6F7661313031305858585858585858"].pack('H*')
chave = ["3455189635541968"].pack('H*')
des = OpenSSL::Cipher.new('des-ecb').encrypt
des.key = chave
des.padding = 0
s = des.update(dado) + des.final
puts s.unpack('H*')[0]
Result is b42e3dbfffd4bb5487a27fd702f079e287e6325767bfdd20.
The error seems pretty clear to me. The key you're using chave is 16 bytes. Your key has to be 8 bytes. So reduce the length of the key to 8 chars then try.

In ruby, how do you do a DES encryption with a ECB mode and PKCS7 padding

I am trying to convert some C# code into ruby. Here is a snippet of the C# code:
string Encrypt(string toEncrypt, string key) {
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
My biggest issue seems to be around getting the padding specification right.
Here is what I have so far...
des = OpenSSL::Cipher::Cipher.new('des-ecb')
des.encrypt # OpenSSL::PKCS7 has to passed in somewhere
des.key = '--The Key--'
update_value = des.update(val)
After running through all of the available OpenSSL ciphers and testing to see if any of the outputs resulted in the same encrypted string with no success, I then did the same thing, but this time passing in a padding integer (from 0 - 20), and iterated over all of the ciphers again.
This resulted in a success!
The final code:
def encrypt val
des = OpenSSL::Cipher::Cipher.new 'DES-EDE3'
des.encrypt
des.padding = 1
des.key = '--SecretKey--'
update_value = des.update(val)
up_final = update_value + des.final
Base64.encode64(up_final).gsub(/\n/, "")
end
The biggest thing to note is the I had to remove the newline characters, and had to put in a padding of 1.
I'm still confused on the padding...but, wanted to update everyone on what I found in case someone runs into this in the future
:Update: The padding didn't matter after all...if you take out that line it still encrypts the same as if you had any number in there...the big difference I was missing was taking out the newlines
Try 'des-ede3-ecb' or just '3des' as names instead. 'des-ecb' is unlikely to return a triple DES cipher.
PKCS#7 is normally the default for OpenSSL, so you may not have to specify it.
Make sure that your character-encoding (UTF-8, compatible with ASCII for values up to 7F) and encoding (base 64) matches as well.

How to convert UTF8 byte arrays to string in lua

I have a table like this
table = {57,55,0,15,-25,139,130,-23,173,148,-24,136,158}
it is utf8 encoded byte array by php unpack function
unpack('C*',$str);
how can I convert it to utf-8 string I can read in lua?
Lua doesn't provide a direct function for turning a table of utf-8 bytes in numeric form into a utf-8 string literal. But it's easy enough to write something for this with the help of string.char:
function utf8_from(t)
local bytearr = {}
for _, v in ipairs(t) do
local utf8byte = v < 0 and (0xff + v + 1) or v
table.insert(bytearr, string.char(utf8byte))
end
return table.concat(bytearr)
end
Note that none of lua's standard functions or provided string facilities are utf-8 aware. If you try to print utf-8 encoded string returned from the above function you'll just see some funky symbols. If you need more extensive utf-8 support you'll want to check out some of the libraries mention from the lua wiki.
Here's a comprehensive solution that works for the UTF-8 character set restricted by RFC 3629:
do
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
function utf8(decimal)
if decimal<128 then return string.char(decimal) end
local charbytes = {}
for bytes,vals in ipairs(bytemarkers) do
if decimal<=vals[1] then
for b=bytes+1,2,-1 do
local mod = decimal%64
decimal = (decimal-mod)/64
charbytes[b] = string.char(128+mod)
end
charbytes[1] = string.char(vals[2]+decimal)
break
end
end
return table.concat(charbytes)
end
end
function utf8frompoints(...)
local chars,arg={},{...}
for i,n in ipairs(arg) do chars[i]=utf8(arg[i]) end
return table.concat(chars)
end
print(utf8frompoints(72, 233, 108, 108, 246, 32, 8364, 8212))
--> Héllö €—

Which Cipher in Ruby OpenSSL API is equivalent to DES_ecb2_encrypt()?

Which Cipher in Ruby's OpenSSL API is equivalent to the OpenSSL C function DES_ecb2_encrypt()?
I see the following ciphers:
irb(main):003:0> OpenSSL::Cipher.ciphers
=> ["AES-128-CBC", "AES-128-CFB", "AES-128-CFB1", "AES-128-CFB8", "AES-128-ECB",
"AES-128-OFB", "AES-192-CBC", "AES-192-CFB", "AES-192-CFB1", "AES-192-CFB8",
"AES-192-ECB", "AES-192-OFB", "AES-256-CBC", "AES-256-CFB", "AES-256-CFB1",
"AES-256-CFB8", "AES-256-ECB", "AES-256-OFB", "AES128", "AES192", "AES256",
"BF", "BF-CBC", "BF-CFB", "BF-ECB", "BF-OFB", "CAMELLIA-128-CBC", "CAMELLIA-128-CFB",
"CAMELLIA-128-CFB1", "CAMELLIA-128-CFB8", "CAMELLIA-128-ECB", "CAMELLIA-128-OFB",
"CAMELLIA-192-CBC", "CAMELLIA-192-CFB", "CAMELLIA-192-CFB1", "CAMELLIA-192-CFB8",
"CAMELLIA-192-ECB", "CAMELLIA-192-OFB", "CAMELLIA-256-CBC", "CAMELLIA-256-CFB",
"CAMELLIA-256-CFB1", "CAMELLIA-256-CFB8", "CAMELLIA-256-ECB", "CAMELLIA-256-OFB",
"CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "CAST", "CAST-cbc", "CAST5-CBC",
"CAST5-CFB", "CAST5-ECB", "CAST5-OFB", "DES", "DES-CBC", "DES-CFB", "DES-CFB1",
"DES-CFB8", "DES-ECB", "DES-EDE", "DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-OFB",
"DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB", "DES-EDE3-CFB1", "DES-EDE3-CFB8",
"DES-EDE3-OFB", "DES-OFB", "DES3", "DESX", "DESX-CBC", "RC2", "RC2-40-CBC",
"RC2-64-CBC", "RC2-CBC", "RC2-CFB", "RC2-ECB", "RC2-OFB", "RC4", "RC4-40", "SEED",
"SEED-CBC", "SEED-CFB", "SEED-ECB", "SEED-OFB", "aes-128-cbc", "aes-128-cfb",
"aes-128-cfb1", "aes-128-cfb8", "aes-128-ecb", "aes-128-ofb", "aes-192-cbc",
"aes-192-cfb", "aes-192-cfb1", "aes-192-cfb8", "aes-192-ecb", "aes-192-ofb",
"aes-256-cbc", "aes-256-cfb", "aes-256-cfb1", "aes-256-cfb8", "aes-256-ecb",
"aes-256-ofb", "aes128", "aes192", "aes256", "bf", "bf-cbc", "bf-cfb", "bf-ecb",
"bf-ofb", "blowfish", "camellia-128-cbc", "camellia-128-cfb", "camellia-128-cfb1",
"camellia-128-cfb8", "camellia-128-ecb", "camellia-128-ofb", "camellia-192-cbc",
"camellia-192-cfb", "camellia-192-cfb1", "camellia-192-cfb8", "camellia-192-ecb",
"camellia-192-ofb", "camellia-256-cbc", "camellia-256-cfb", "camellia-256-cfb1",
"camellia-256-cfb8", "camellia-256-ecb", "camellia-256-ofb", "camellia128",
"camellia192", "camellia256", "cast", "cast-cbc", "cast5-cbc", "cast5-cfb",
"cast5-ecb", "cast5-ofb", "des", "des-cbc", "des-cfb", "des-cfb1", "des-cfb8",
"des-ecb", "des-ede", "des-ede-cbc", "des-ede-cfb", "des-ede-ofb", "des-ede3",
"des-ede3-cbc", "des-ede3-cfb", "des-ede3-cfb1", "des-ede3-cfb8", "des-ede3-ofb",
"des-ofb", "des3", "desx", "desx-cbc", "rc2", "rc2-40-cbc", "rc2-64-cbc", "rc2-cbc",
"rc2-cfb", "rc2-ecb", "rc2-ofb", "rc4", "rc4-40", "seed", "seed-cbc", "seed-cfb",
"seed-ecb", "seed-ofb"]
I basically need the Ruby equivalent of this function call in C:
DES_ecb2_encrypt((const_DES_cblock *)data, (DES_cblock *)data, &des_key1, &des_key2, 1);
I've never used this method, but it looks like it does 2 key 3DES encryption using des_key1 for the final encryption instead of a 3rd key. This is keying option 2 for 3DES. It looks like the option des-ede probably does what you want.
encrypt = OpenSSL::Cipher::Cipher.new("des-ede")
encrypt.encrypt
encrypt.key= des_key1+des_key2
ct = encrypt.update(plain_text) + encrypt.final
And of course a decrypt
decrypt = OpenSSL::Cipher::Cipher.new("des-ede")
decrypt.decrypt
decrypt.key= des_key1+des_key2
pt = decrypt.update(ct) + decrypt.final
I hate to answer my own question here, but I found the solution.
I had an encrypted piece of data which was encrypted with this C-code:
DES_ecb3_encrypt(input,output, key1, key2, key1, 1)
which according to the Tripple-DES documentation does this:
cipher_text =Encrypt(key1,Decrypt(key2,Encrypt(key1,plain_text)))
to decode the cipher_text in Ruby, I did this:
decrypt.OpenSSL::Cipher::Cipher.new('des-ede3')
decrypt.decrypt
decrypt.key = key1 + key2 + key1
plain_text = decrypt(cipher_text) # gives correct result, but decrypt.final gives errors
# plain_text = decrypt(cipher_text) + decrypt.final # DOES NOT WORK
# => OpenSSL::Cipher::CipherError: wrong final block length ; WHY??
I'd appreciate if somebody could comment on:
why decypt.final causes an error, although the result is correct

Resources