Encrypt in Ruby and Decrypt in Java - Why Is It Not Working

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:

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


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



Leave a reply



Submit