Encrypt in Ruby and Decrypt in Java - Why is it not working?
This is the problem - or at least a problem:
byte[] result = cipher.doFinal(encryptedData);
return result.toString();
You're calling toString()
on a byte array. Arrays don't override toString()
. That won't give you what you want at all - as you can see. Instead, you need to write something like:
return new String(result, "UTF-8");
... but you need to know what encoding was used to turn the original string into bytes before encryption. It's not clear to me from the Ruby code what encoding is used, but if you can be explicit about it (ideally using UTF-8) it'll make your life a lot easier.
In short, I suspect this problem has nothing to do with encryption at all - it has everything to do with converting text to bytes in Ruby and then converting the same sequence of bytes back into a string in Java.
Of course the encryption may be failing as well but that's a different matter.
Java encryption / decryption to Ruby
You need to use the IV and Key from your Java Example, not a new/random IV/Key:
require "openssl"
require "base64"
require 'byebug'
include Base64
plain_text = "abceeffslaj"
key = 'Bar12345Bar12345'
iv = 'RandomInitVector'
cipher = OpenSSL::Cipher::AES128.new(:CBC)
cipher.encrypt
cipher.key = key
cipher.iv = iv
cipher_text = cipher.update(plain_text) + cipher.final
cipher = OpenSSL::Cipher::AES128.new(:CBC)
cipher.decrypt
cipher.key = key
cipher.iv = iv
decrypted_plain_text = cipher.update(cipher_text) + cipher.final
puts "AES128 in CBC mode"
puts "Key: " + urlsafe_encode64(key)
puts "Iv: " + urlsafe_encode64(iv)
puts "Plain text: " + plain_text
puts "Cipher text: " + urlsafe_encode64(cipher_text)
puts "Decrypted plain text: " + decrypted_plain_text
String encrypted in Ruby gives: 'BadPaddingException' when decrypted in Java
I wrote a very simple Java program to decrypt the output from that very simple Ruby program and it worked fine. Thus, not surprisingly, there's no inherent incompatibility between the ruby openssl module and standard Java cryptography. Without any more info about the Java side, all we can do is list some of the possibilities:
- Mismatched keys
The public key you are using must correspond to the private key the Java side is using. If not, you'll likely receive the BadPadding exception.
- Formatting issues
Obviously what you transmit, base64 encoded strings with embedded newlines, must be correctly parsed and decoded on the Java side. Getting a single byte wrong can cause the error you see. Most base64 decoders either choke on the newlines and throw an exception or ignore them. Neither explanation would result in a BadPaddingException. Perhaps the Java side is expecting Base64URL instead of Base64? If the Java side is expecting base64url encoding and if it ignores invalid characters then this could be the problem. It's worth trying to remove whitespace including newlines from the base64 output, and if that doesn't work then try encoding with a base64url encoder (again, remove any whitespace from the output).
Encrypt Ruby decrypt Java
The exact code that is produced by Ruby is not specified (which I would consider a bug), you can find the format by reading the source code, especially this part:
blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
blob = "#{blob}--#{::Base64.strict_encode64 cipher.auth_tag}" if aead_mode?
Where the IV is a random IV, generated using Cipher::new
of the openssl
module.
AES/CBC/PKCS5Padding encrypt in java decrypt in ruby
There's two problems with your Ruby code.
First, you're using AES 256 when you should be using AES 128. Java uses AES 128 or 256 based on the size of the key you use, and you're using a 128 bit key.
Second, you need to Hex decode your key
, iv
, and encrypted_string
values in Ruby. OpenSSL Cipher is expecting binary, not hex strings.
require 'openssl';
key = "97128424897797a166913557a6f4cc8e";
iv = "84e8c3ea8859a0e293941d1cb00a39c3";
encrypted_string = "395f6c0e8ad27f57c4a5a8975aa633e5b26f288d37ce18c6971779951f3b3527";
de_cipher = OpenSSL::Cipher::Cipher.new("AES-128-CBC");
de_cipher.decrypt;
de_cipher.key = [key].pack('H*');
de_cipher.iv = [iv].pack('H*');
puts de_cipher.update([encrypted_string].pack('H*')) << de_cipher.final;
Output:
{"timestamp":"1377499097199"}
AES ECB mode encrypt in java and decrypt in ruby
The Java implementation is sort of messed up.
The actual AES key used to encrypt in the java code is the SecretKey secretKey
generated with the following code using the String sKey
as input:
SecretKey secretKey = null;
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(sKey.getBytes());
kgen.init(128, secureRandom);
secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
To be able to decrypt in the ruby code, you need the content of SecretKey secretKey
. Try adding this trace statement after above code:
System.out.println("Key: " + ByteUtil.parseByte2HexStr(enCodeFormat));
And use that as the key in your ruby call.
Related Topics
How to Change a Textview's Style at Runtime
How to Get a Context in a Recycler View Adapter
Running Shell Commands Though Java Code on Android
How to Install Intellij Idea on Ubuntu
How to Convert Int[] to Integer[] in Java
Read Content from Files Which Are Inside Zip File
Covariance, Invariance and Contravariance Explained in Plain English
How to Write Console Output to a Txt File
Java Replace Line in Text File
Android: Sending Data >20 Bytes by Ble
Unexpected Top-Level Exception: Com.Android.Dex.Dexexception: Multiple Dex Files Define
Installing Oracle Jdk on Windows Subsystem for Linux
Why Does Priorityqueue.Tostring Return the Wrong Element Order
Is There a Java API That Can Create Rich Word Documents