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