CBC with AES : Encrypting in Perl and Decrypting in Java - java

I am encrypting a file in perl and want to decrypt in java. here is my encryption code:
== Encryption in Perl ==
$key = "1234567890123456";
$plain_text = "this is foo";
open ($fh, ">" . $output_file_path) || die ("open ($output_file_path):$!");
my $cipher = Crypt::CBC->new( -key => $key, -cipher => "Crypt::OpenSSL::AES");
$cipher->start("");
print $fh $cipher->crypt($plain_text);
And this is the decryption code I am using, but it is not working.
== Decryption in Java ==
String key = "1234567890123456";
byte[] encrypted_bytes = READ_DATA_FROM_FILE
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(key.getBytes());
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
String plain_text = new String(cipher.doFinal(encrypted_bytes));
Can someone help me in this?

You don't seem to be specifying the IV for the perl encryption, and you are not passing 'encrypt' to the perl start() method. those are the immediate problems that i notice.
this probably isn't the current problem, but will be a problem for working with "non-trivial" text: you are not being careful with your byte <-> char conversions in java (String.getBytes() and new String()). you are using methods in java which use the default platform character encoding, which may not be what you want. it's best to use an explicit charset.

Related

PHP AES-256-CBC encrypted data is different from JAVA AES/CBC/PKCS5PADDING

I have a java code working perfectly
public static String encrypt(String message, String sercretKey)
{
String base64EncryptedString = "";
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digestOfPassword = md.digest(sercretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
byte[] iv = Arrays.copyOf(digestOfPassword, 16);
SecretKey key = new SecretKeySpec(keyBytes, "AES");
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key, ivParameterSpec);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);
byte[] base64Bytes = Base64.getEncoder().encode(buf);
base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
I have tried using below code to recreate this above code in PHP
function encryptTest($sSecretKey,$sValue)
{
$key = hash('sha256', $sSecretKey,false);
$key = utf8_encode($key);
$key = substr($key, 0, 24);
$iv = substr($key, 0, 16);
$data = $sValue;
$outEnc = openssl_encrypt($data, "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($outEnc);
}
But showing different results. What I have missed.
(Same types of questions are available in StackOverflow, but pointing my issues)
There are the following issues:
In the PHP code, the key is currently returned hex encoded. Instead, it must be returned as bytes string. To do this, the third parameter in hash() must be switched from false to true.
In the Java code a 192 bits key is used, i.e. AES-192. Accordingly, in the PHP code "AES-192-CBC" must be applied (and not "AES-256-CBC").
The utf8_encode() call in the PHP code is to be removed, as this corrupts the key.
With these changes, both codes provide the same ciphertext.
Security:
Using SHA256 as key derivation is insecure. Instead apply a dedicated algorithm like Argon2 or PBKDF2. Also, using the key (or a part of it) as IV is insecure as it results in the reuse of key/IV pairs. Instead, a randomly generated IV should be applied for each encryption.

How can I use openssl_decrypt as a JAVA?

I would like to know that How can I use openssl_decrypt in JAVA?
Here is PHP code
<?php
$textToDecrypt = hex2bin("db3700cd861aee8215b3db514adde6c9"); // input is hexadecimal format
$key = "MbQeThWmZq4t7w1z";
$decrypted = openssl_decrypt($textToDecrypt, 'AES-128-CBC', $aesKey, OPENSSL_NO_PADDING);
echo "decrypt data is ". $decrypted
?>
And here is my JAVA code
byte[] textToDecrypt = inp.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] original = cipher.doFinal(textToDecrypt);
result = new String((original));
The PHP code can decrypt correctly but in JAVA I got the error "Parameters missing"
How can I solve this.
Thanks.
The PHP code implicitly uses a zero IV, which must be explicitly set in the Java code. In addition, in the Java Code the ciphertext must be hex decoded, e.g.:
byte[] textToDecrypt = hexStringToByteArray("db3700cd861aee8215b3db514adde6c9");
SecretKeySpec secretKeySpec = new SecretKeySpec("MbQeThWmZq4t7w1z".getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(new byte[16]));
byte[] original = cipher.doFinal(textToDecrypt);
String result = new String(original, StandardCharsets.UTF_8);
System.out.println(result); // hellotest
where hexStringToByteArray() is from here.
Please note that a static IV is insecure.

Convert Encrypt code in java to Ruby

I have been trying to convert a code for encrypt in java to ruby, but I am not able to do it completely. I getting different values.
passphrase = passphrase + STATIC_KEY;
byte[] key = passphrase.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
SecretKey secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec initialisationVector = new IvParameterSpec(
new byte[16]);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, initialisationVector);
byte[] encryptedData = cipher.doFinal(plainText.getBytes("UTF-8"));
return SimpleCrypto.toHex(encryptedData);
Can anyone let me know, how this can be done in it ruby.
unencrypted = "passphrase"
c = OpenSSL::Cipher.new("aes-128-cbc")
c.encrypt
c.key = Digest::SHA1.hexdigest('secret_key')[0...32]
e = c.update(unencrypted)
e << c.final
return e
require 'openssl'
Encrypt:
unencrypted = "I am a secret!"
initialize the Cipher for encrypt
cipher = OpenSSL::Cipher::AES.new(128, :CBC)
cipher.encrypt
create the key using SHA1
key = Digest::SHA1.hexdigest('secret_key')[0...32]
cipher.key = key
create the initialisationVector with an input
iv = Digest::SHA1.hexdigest('secret_iv')[0...32]
cipher.iv = iv
or create a random initialisationVector
iv = cipher.random_iv
run the encryption
encrypted = cipher.update(unencrypted) + cipher.final
Decrypt:
initialize the Cipher for decrypt
decipher = OpenSSL::Cipher::AES.new(128, :CBC)
decipher.decrypt
load the key and initialisationVector
decipher.key = key
decipher.iv = iv
decrypt the plaintext
plain = decipher.update(encrypted) + decipher.final
Does it match?
puts unencrypted == plain #=> true
For more information look at the Ruby Docs for the Class - OpenSSL::Cipher
Encrypt Code:
def aes(key,string)
cipher = OpenSSL::Cipher::Cipher.new("aes-128-cbc")
cipher.encrypt
cipher.padding = 1
cipher.key = hex_to_bin(Digest::SHA1.hexdigest('secret_key')[0..32])
cipher_text = cipher.update(string)
cipher_text << cipher.final
return bin_to_hex(cipher_text).upcase
end
Decrypt Code:
def aes_decrypt(key, encrypted)
encrypted = hex_to_bin(encrypted.downcase)
cipher = OpenSSL::Cipher::Cipher.new("aes-128-cbc")
cipher.decrypt
cipher.padding = 1
cipher.key = hex_to_bin(Digest::SHA1.hexdigest('secret_key')[0..32])
d = cipher.update(encrypted)
d << cipher.final
end
hex_to_bin and bin_to_hex
def hex_to_bin(str)
[str].pack "H*"
end
def bin_to_hex(s)
s.unpack('C*').map{ |b| "%02X" % b }.join('')
end
In My case, The java code was using default initialization vector, So I did not set any iv, Also, there was hex_to_bin was a missing piece there. So after that, all started working properly.
I hope it helps someone if they come across this issue.

Java encrypt/decript data from PHP to Java, IllegalBlockSizeException

I'm trying to read a base64 encoded and AES 128-bit encrypted string from PHP, but I'm getting IllegalBlockSizeException.
PHP encrypt:
encrypt("My f awesome test !");
function encrypt($string){
$td = mcrypt_module_open('rijndael-128', '', 'cbc', "1cc251f602cf49f2");
mcrypt_generic_init($td, "f931c96c4a4e7e47", "1cc251f602cf49f2");
$enc = mcrypt_generic($td, $string);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return base64_encode($enc);
}
And the returned value is:
McBeY73GQ5fawxIunVKpqUupipeRlt9ntyMRzjbPfTI=
Now I want to read it in Java:
static public String decrypt(String data) throws Exception {
data = new String( Base64.decode(data, Base64.NO_WRAP) );
byte[] keyByte = "f931c96c4a4e7e47".getBytes("UTF-8");
byte[] ivByte = "1cc251f602cf49f2".getBytes("UTF-8");
Key key = new SecretKeySpec(keyByte, "AES");
IvParameterSpec iv = new IvParameterSpec(ivByte);
Cipher c = Cipher.getInstance("AES/CBC/NoPadding");
c.init(Cipher.DECRYPT_MODE, key, iv);
byte[] bval = c.doFinal( data.getBytes("UTF-8") );
return new String( bval );
}
And I'm getting an Exception:
javax.crypto.IllegalBlockSizeException: data not block size aligned
This might be caused by padding?
EDIT
Your error was caused by the conversion of the plaintext to and from a string. It's not necessary anyway - just use byte arrays:
byte[] data = Base64
.decodeBase64("McBeY73GQ5fawxIunVKpqUupipeRlt9ntyMRzjbPfTI=");
byte[] keyByte = "f931c96c4a4e7e47".getBytes("UTF-8");
byte[] ivByte = "1cc251f602cf49f2".getBytes("UTF-8");
Key key = new SecretKeySpec(keyByte, "AES");
IvParameterSpec iv = new IvParameterSpec(ivByte);
Cipher c = Cipher.getInstance("AES/CBC/NoPadding");
c.init(Cipher.DECRYPT_MODE, key, iv);
byte[] bval = c.doFinal(data);
System.out.println(new String(bval)); // Prints My f awesome test !
I recommend you use padding in your encryption, otherwise you cannot cope with arbitrarily-sized input.
the IllegalBlockSizeException thrown on call to doFinal() if: "cipher is a block cipher, no padding has been requested (only in encryption mode), and the total input length of the data processed by this cipher is not a multiple of block size; or if this encryption algorithm is unable to process the input data provided." -http://docs.oracle.com/javase/6/docs/api/javax/crypto/Cipher.html#doFinal%28%29. So its either bad input data or block size.
This is a working version of encryption/decryption between
https://github.com/chaudhuri-ab/CrossPlatformCiphers
Hope this helps someone as it took me a while to work through the little details between the platforms.

Encryption using AES-128 in Java

I have a problem with ecrypting data using AES-128/ecb/PKCS5Padding+base64. I am using the following code to encrypt my data:
String input = "{\"action\":\"getQuestion\"}";
String key = "4288f0b8060ca1b682bf795f2617cfdc";
byte[] data = input.getBytes();
byte[] encrypted = null;
byte[] keyBytes = new BigInteger(key, 16).toByteArray();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
encrypted = cipher.doFinal(data);
System.out.println(Base64.encodeBytes(encrypted));
I receive 6GuKXA6FFR+yMmO8ksAEOLL5e574a5tLob7tt5IG+jk= after encryption but I can't decrypt on the server using a PHP function.
When I encrypt this data using the PHP function:
function encrypt($encrypt, $key=null)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $encrypt, MCRYPT_MODE_ECB, $iv));
return $encrypted;
}
I receive 6Wc3LPWvfJ7T86iG0igmdQaeZ8xs9qY419mAVWfNH+M= and I can successfully do the decryption using the following PHP function:
function decrypt($decrypt, $key=null)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($decrypt), MCRYPT_MODE_ECB, $iv);
return $decrypted;
}
With base64 encryption and decryption there are no problems; I only encounter the issue when encrypting using AES-128.
The problem isn't with the IV or the padding as I initially thought. It is with how you are handling the key in the PHP code. If you are using the actual string 4288f0b8060ca1b682bf795f2617cfdc as the key passed into mcrypt_encrypt and mcrypt_decrypt then you aren't using the same key as in the Java code. You will need to convert that hex string into bytes. You can do this in the following way:
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, pack("H*", $key), base64_decode($decrypt), MCRYPT_MODE_ECB, $iv);
Notice the addition of pack("H*", $key) to convert the value. I found that here in the comments for the PHP bin2hex function. This will fix the current problem. You may run into padding troubles when working with data of different lengths since PHP doesn't do PKCS5 padding. See this comment about implementing that missing function. Also, I'd recommend looking into CBC instead of ECB due to ECB's unsuitability and weaknesses for data encryption.
You can validate the output from your Java method at the command line using openssl. Java will default your IV to 0 if unspecified.
The file "enc.txt" contains "6GuKXA6FFR+yMmO8ksAEOLL5e574a5tLob7tt5IG+jk=" [corrected]
Run
openssl aes-128-ecb -in enc.txt -a -K 4288f0b8060ca1b682bf795f2617cfdc -iv 0 -d
The result is:
{"action":"getQuestion"}
Try your mcrypt_decrypt with an $iv value of 0.

Categories