Reputation: 1
I'm struggling on this problem: I want to encrypt a password with openssl, and decrypt it in java.
Here's what I have for the moment:
String aesKeyBase64 = "BDC17ABE1F194C8DD49840C57A155013";
SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(aesKeyBase64), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// encrypt
byte[] cipherText = cipher.doFinal("password".getBytes());
String encodedPassword = Base64.getEncoder().encodeToString(cipherText); //returns ITmSsa+9aKeW776ABM5B+g==
System.out.println("encrypted password = " + encodedPassword);
// decrypt
cipher.init(Cipher.DECRYPT_MODE, secretKey);
cipherText = cipher.doFinal(Base64.getDecoder().decode("b3JCq/QmtKSmkQABYdbiVA==".getBytes()));
System.out.println("decrypted password = " + new String(cipherText));
Here's my openssl command:
openssl enc -nosalt -aes-128-ecb -base64 -K BDC17ABE1F194C8DD49840C57A155013 -in in.txt -out out.txt
which returns b3JCq/QmtKSmkQABYdbiVA== in the file out.txt
So I noticed that my two encryption are different, with aes-ecb there isn't IV, I haven't used salt, and pad is set to PKCS5 which is default pad with openssl enc
When I tried to decrypt openssl enc result here's my Java output:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
I made sure to use a generate my key in Java directly with a string key to ensure I'm using same key in both methods.
Thanks for the help!
Upvotes: 0
Views: 202
Reputation: 38990
Your key is not base64. It is hex (aka hexadecimal).
It's pretty obvious just looking at it, but you can also use logic: it is 32 characters, and a 16-byte key (for AES-128) in hex is 32 characters, but in base64 it would be 24 or 22 characters (depending whether you use one of the forms with or without padding). A 32-character base64 value with no padding would be 24-bytes which could be an AES-192 key but not a an AES-128 key. Plus openssl enc -K
(and -iv
if applicable, which it isn't here) uses hex -- read the man page.
In the old days you could just call java.xml.bind.DatatypeConverter to handle hex, but in modern Java (9 up) that is a nondefault module. Now you can (1) make your code modular, (2) use some other library, or (3) write your own -- for a simple SO post, I have done (3):
$ cat SO76396076.java
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
class SO76396076 {
public static void main (String[] args) throws Exception {
//String aesKeyBase64 = "BDC17ABE1F194C8DD49840C57A155013";
//SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(aesKeyBase64), "AES");
String aesKeyHEX = "BDC17ABE1F194C8DD49840C57A155013";
byte[] aesKeyBin = new byte[aesKeyHEX.length()/2];
for( int i = 0; i < aesKeyBin.length; i++ )
aesKeyBin[i] = (byte)Integer.parseInt(aesKeyHEX.substring(i*2,i*2+2),16);
SecretKeySpec secretKey = new SecretKeySpec(aesKeyBin,"AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// encrypt
byte[] cipherText = cipher.doFinal("password".getBytes());
String encodedPassword = Base64.getEncoder().encodeToString(cipherText); //returns ITmSsa+9aKeW776ABM5B+g==
System.out.println("encrypted password = " + encodedPassword);
// decrypt
cipher.init(Cipher.DECRYPT_MODE, secretKey);
cipherText = cipher.doFinal(Base64.getDecoder().decode("b3JCq/QmtKSmkQABYdbiVA==".getBytes()));
System.out.println("decrypted password = " + new String(cipherText));
}
}
$ java SO76396076.java
encrypted password = b3JCq/QmtKSmkQABYdbiVA==
decrypted password = password
Also: byte[] String.getBytes(/*noarg*/)
and new String(byte[])
use the JVM default charset, which in all versions until recently varied by platform and user, so if you tried to use your encrypted data in anything other than a test environment this was likely to mangle data containing any non-ASCII character(s) -- which your example value doesn't, and unlike most sensitive data passwords usually shouldn't (but sometimes do). Java 18 up makes the default consistent at UTF-8 -- unless changed by the user(s). Thus for data in general you should still specify a suitable charset -- usually UTF-8 unless there's an application or environment specific reason for something else -- in both places; for passwords it's a closer call.
Upvotes: 0