Encrypt data with DES ECB in Ruby - 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.

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.

Steganography program - converting python 2 to 3, syntax error in: base64.b64decode("".join(chars))

I have problem with the syntax in the last part of steg program. I tried to convert python 2 version (of the working code) to python 3, and this is the last part of it:
flag = base64.b64decode("".join(chars)) <- error
print(flag)
The program 1. encrypts the message in the Last Significiant Bits of the image as saves it as a new image. Then 2.decrypts the message, which is stored in "flag", and prints it.
* can the error be caused by the wrong type of input?:
message = input("Your message: ")
BELOW: UNHIDING PROGRAM
#coding: utf-8
import base64
from PIL import Image
image = Image.open("after.png")
extracted = ''
pixels = image.load()
#Iterating in 1st row
for x in range(0,image.width):
r,g,b = pixels[x,0]
# Storing LSB of each color
extracted += bin(r)[-1]
extracted += bin(g)[-1]
extracted += bin(b)[-1]
chars = []
for i in range(len(extracted)/8):
byte = extracted[i*8:(i+1)*8]
chars.append(chr(int(''.join([str(bit) for bit in byte]), 2)))
flag = base64.b64decode(''.join(chars))
print flag
BELOW: HIDING PROGRAM:
import bitarray
import base64
from PIL import Image
with Image.open('before.png') as im:
pixels=im.load()
message = input("Your message: ")
encoded_message = base64.b64encode(message.encode('utf-8'))
#Convert the message into an array of bits
ba = bitarray.bitarray()
ba.frombytes(encoded_message)
bit_array = [int(i) for i in ba]
#Duplicate the original picture
im = Image.open("before.png")
im.save("after.png")
im = Image.open("after.png")
width, height = im.size
pixels = im.load()
#Hide message in the first row
i = 0
for x in range(0,width):
r,g,b = pixels[x,0]
#print("[+] Pixel : [%d,%d]"%(x,0))
#print("[+] \tBefore : (%d,%d,%d)"%(r,g,b))
#Default values in case no bit has to be modified
new_bit_red_pixel = 255
new_bit_green_pixel = 255
new_bit_blue_pixel = 255
if i<len(bit_array):
#Red pixel
r_bit = bin(r)
r_last_bit = int(r_bit[-1])
r_new_last_bit = r_last_bit & bit_array[i]
new_bit_red_pixel = int(r_bit[:-1]+str(r_new_last_bit),2)
i += 1
if i<len(bit_array):
#Green pixel
g_bit = bin(g)
g_last_bit = int(g_bit[-1])
g_new_last_bit = g_last_bit & bit_array[i]
new_bit_green_pixel = int(g_bit[:-1]+str(g_new_last_bit),2)
i += 1
if i<len(bit_array):
#Blue pixel
b_bit = bin(b)
b_last_bit = int(b_bit[-1])
b_new_last_bit = b_last_bit & bit_array[i]
new_bit_blue_pixel = int(b_bit[:-1]+str(b_new_last_bit),2)
i += 1
pixels[x,0] = (new_bit_red_pixel,new_bit_green_pixel,new_bit_blue_pixel)
#print("[+] \tAfter: (%d,%d,%d)"%(new_bit_red_pixel,new_bit_green_pixel,new_bit_blue_pixel))
im.save('after.png')
error
ValueError: string argument should contain only ASCII characters
help for base64.b64decode says:
b64decode(s, altchars=None, validate=False)
Decode the Base64 encoded bytes-like object or ASCII string s.
...
Considering that in Python 2 there were "normal" strs and unicode-strs (u-prefixed), I suggest taking closer look at what produce "".join(chars). Does it contain solely ASCII characters?
I suggest adding:
print("Codes:",[ord(c) for c in chars])
directly before:
flag = base64.b64decode("".join(chars))
If there will be number >127 inside codes, that mean it might not work as it is fit only for pure ASCII strs.

How to LM Hash in Powershell

OK so i have been working on this for a bit, and i cant see how to get any further. I keep running into roadblocks with the DESCryptoServiceProvider and somehow it just doesnt seem to be comming out with the right answers.
the sudo code version of LM_Hash is:
LMHASH = concat(DES(Upper(PWD)[0..7],KGS!##$%),DES(Upper(PWD)[8..13],KGS!##$%))
First issue is the LM Key I keep seeing the atleast two variants its either "KGS!##$%" or "KGS!+#$%" neither gets me the right answers but both dont seem to fit with the origin story (its KGS and SHIFT 12345 assuming a US keyboard
on a UK thats "KGS!"£$%")
I am pretty sure i have the parameters set up correctly now, but my understanding seems to be failing me. here's what i have so far, any help is appreciated I am running Powershell V5.1 on Win 10, the string to encrypt is passed in as $string
$plaintext = "KGS!##$%"
$OEM = [System.Text.Encoding]::GetEncoding($Host.CurrentCulture.TextInfo.OEMCodePage)
$str1 = $OEM.GetBytes($string.substring(0,7)) +[Byte]$null
$str2 = $OEM.GetBytes($string.Substring(7)) +[Byte]$null
$IV = new-object "System.Byte[]" 8
$hasher = New-Object -TypeName System.Security.Cryptography.DESCryptoServiceProvider -Property #{key=$str1; IV = $IV; mode = [System.Security.Cryptography.CipherMode]::ECB; Padding=[System.Security.Cryptography.PaddingMode]::None}
$outbyte = new-object "System.Byte[]" 8
$encrypter1 = $hasher.CreateEncryptor()
$outbyte = $encrypter1.TransformFinalBlock($OEM.GetBytes($plaintext),0,8)
$data1 = [System.BitConverter]::ToString($outbyte).replace("-","")
$encrypter1.Dispose()
In theory this should encrypt the Key (which ever one it is) with DES using the first 7 characters of the string ($str1) as the key (with a null byte on the end) and then we do this to the second half ($str2) and concat them back together to get the LMHASH.
The ASCII-encoded string KGS!##$% is the correct magic constant to use
using the first 7 characters of the string ($str1) as the key (with a null byte on the end)
This, however, is incorrect. The key is not composed by padding the 7 bytes of partial input with a single 0-byte at the end, but by partitioning the input into 8 7-bit chunks and left-shifting them once (resulting in 8 bytes).
The easiest way to implement this in PowerShell is probably with strings, so I'd likely do something like this:
# Convert string to byte array
$inBytes = $OEM.GetBytes($str1)
# Create a binary string from our bytes
$bitString = ''
foreach($byte in $inBytes){
$bitstring += [convert]::ToString($byte, 2).PadLeft(8, '0')
}
# Partition the byte string into 7-bit chunks
[byte[]]$key = $bitString -split '(?<=\G.{7}(?<!$))' |ForEach-Object {
# Insert 0 as the least significant bit in each chunk
# Convert resulting string back to [byte]
[convert]::ToByte("${_}0", 2)
}
try{
# Create the first encryptor from our new key, and an empty IV
[byte[]]$iv = ,0 * 8
$enc = $hasher.GetEncryptor($key, $iv)
# Calculate half of the hash
$block1 = $enc.TransformFinalBlock($plaintext, 0, 8)
}
finally{
# Dispose of the encryptor
$enc.Dispose()
}
Then repeat for $str2 and concatenate the resulting blocks for the full LM hash
anyone having issues, based on #mathias R. Jessen
's answer above, here is a fuction that computes half the LM-Hash takes in 7 character string and outputs the hash as Hex.
Function LM-hash {
Param(
[Parameter(mandatory=$true,ValueFromPipeline=$true,position=0)]
[ValidateLength(7,7)]
[String]$Invalue
)
$plaintext = "KGS!##$%"
$OEM = [System.Text.Encoding]::GetEncoding($Host.CurrentCulture.TextInfo.OEMCodePage)
$inBytes = $OEM.GetBytes($invalue)
$bitString = ''
foreach($byte in $inBytes){
$bitstring += [convert]::ToString($byte, 2).PadLeft(8, '0')
}
[byte[]]$key = $bitString -split '(?<=\G.{7}(?<!$))' |ForEach-Object { [convert]::ToByte("${_}0", 2)}
$iv = new-object "System.Byte[]" 8
$DESCSP = New-Object -TypeName System.Security.Cryptography.DESCryptoServiceProvider -Property #{key=$key; IV = $IV; mode = [System.Security.Cryptography.CipherMode]::ECB; Padding=[System.Security.Cryptography.PaddingMode]::None}
$enc = $DESCSP.CreateEncryptor()
$block1 = $enc.TransformFinalBlock($OEM.GetBytes($plaintext), 0, 8)
return [System.BitConverter]::ToString($block1).replace("-","")
$enc.Dispose()
}
this gives the correct result for half the hash, so feeding each half in seperatley and concatenating the strings gives you a full LM hash

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.

Encrypting/decrypting 3DES in 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)

Resources