Java openssl encryption / decryption key generation [duplicate] - java

This question already has answers here:
How to decrypt file in Java encrypted with openssl command using AES?
(4 answers)
AES 256 Encryption Issue
(1 answer)
Closed 7 years ago.
I'm using Java 8 and I'm attempting to emulate the following openssl calls with Java.
Encrypt:
echo -n 'hello world' | openssl enc -a -aes-256-cbc -md sha256 -pass pass:97DE:4F76
U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc=
Decrypt:
echo U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc= | openssl enc -d -a -aes-256-cbc -md sha256 -pass pass:97DE:4F76
hello world
Questions:
My implementation doesn't work. I've visited many other StackOverflow answers but wasn't able to figure out the right implementation. Can anyone point me out in the right direction for solving this?
The openssl system call in the example above uses digest sha256. If I were to use sha1, instead in the Java implemementation, would it be just a matter of changing PBKDF2WithHmacSHA256 with PBKDF2WithHmacSHA1?
Test.java
package test;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class Test {
public static final String PASSWORD = "97DE:4F76";
public static String encryptString(String clearText, String password) {
return "";
}
// echo U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc= | openssl enc -d -a -aes-256-cbc -md sha256 -pass pass:97DE:4F76
//
// see https://stackoverflow.com/a/992413, https://stackoverflow.com/a/15595200,
// https://stackoverflow.com/a/22445878, https://stackoverflow.com/a/11786924
public static String decryptString(String cypherText, String password) {
byte[] dataBase64 = DatatypeConverter.parseBase64Binary(cypherText);
byte[] salt = {
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0
};
try {
// generate the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); // "PBKDF2WithHmacSHA1"
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
// decrypt the message
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] decrypted = cipher.doFinal(dataBase64);
String answer = new String(decrypted, "UTF-8");
return answer;
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
public static void main(String[] args) {
System.out.println(decryptString("U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc=", PASSWORD));
}
}
this is the current output of running the code above:
java.security.InvalidKeyException: Illegal key size at
javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039) at
javax.crypto.Cipher.init(Cipher.java:1393) at
javax.crypto.Cipher.init(Cipher.java:1327) at
test.Test.decryptString(Test.java:42) at
test.Test.main(Test.java:55)
Update:
this is the code I ended up implementing after I used this answer: https://stackoverflow.com/a/11786924 -> has the rest of the constants and implementation of EVP_BytesToKey
public static String decryptString(String cypherText, String password) {
try {
// decode the base64 cypherText into salt and encryptedString
byte[] dataBase64 = DatatypeConverter.parseBase64Binary(cypherText);
byte[] salt = Arrays.copyOfRange(dataBase64, SALT_OFFSET, SALT_OFFSET + SALT_SIZE);
byte[] encrypted = Arrays.copyOfRange(dataBase64, CIPHERTEXT_OFFSET, dataBase64.length);
System.out.println("dataBase64 = " + new String(dataBase64));
System.out.println("salt: " + new BigInteger(1, salt).toString(16));
System.out.println("encrypted: " + new BigInteger(1, encrypted).toString(16));
// --- specify cipher and digest for EVP_BytesToKey method ---
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
MessageDigest sha1 = MessageDigest.getInstance("SHA-256");
// create key and IV
final byte[][] keyAndIV = EVP_BytesToKey(
KEY_SIZE_BITS / Byte.SIZE,
cipher.getBlockSize(),
sha1,
salt,
password.getBytes("ASCII"),
ITERATIONS);
SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);
// initialize the Encryption Mode
cipher.init(Cipher.DECRYPT_MODE, key, iv);
// decrypt the message
byte[] decrypted = cipher.doFinal(encrypted);
String answer = new String(decrypted, "UTF-8"); // should this be "ASCII"?
return answer;
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}

Related

Node JS encryption code to Java encryption code

I'm trying to find the similar java code for the below Node JS code,
Node JS Code:
var crypto = require('crypto');
var mykey = crypto.createCipher('aes-128-ecb', 'XXXXXXXX00000000');
var mystr = mykey.update('HelloWorld', 'utf8', 'hex')
mystr += mykey.final('hex');
console.log(mystr);
Encryption Result: ce25d577457cf8113fa4d9eb16379529
Java Code:
public static String toHex(String arg) throws UnsupportedEncodingException {
return String.format("%x", new BigInteger(1, arg.getBytes("UTF-8")));
}
public static void main(String args[]) throws Exception{
byte[] key = "XXXXXXXX".getBytes();
String message = "HelloWorld";
try {
key = Arrays.copyOf(key, 16);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte encstr[] = cipher.update(message.getBytes());
String encData = new String(encstr, "UTF-8");
encData = toHex(encData);
byte encstr2[] = cipher.doFinal();
String encData2 = new String(encstr2);
encData = encData + toHex(encData2);
System.out.println(encData);
} catch (NoSuchAlgorithmException nsae) {
throw new Exception("Invalid Java Version");
} catch (NoSuchPaddingException nse) {
throw new Exception("Invalid Key");
}
}
Encryption Result: 056efbfbdefbfbd7c7760efbfbdefbfbdefbfbd39262cefbfbdefbfbd5166
Taking up the comments of #Robert and #Topaco I wrote a simple decryption program that is working for the given password 'XXXXXXXX00000000'.
Please keep in mind that this progrsm is using UNSECURE AES ECB mode and UNSECURE MD5 hash algorithm.
The program does NOT provide any proper exception handling.
This is the result:
ciphertext Java: ce25d577457cf8113fa4d9eb16379529
ciphertext NodeJS: ce25d577457cf8113fa4d9eb16379529
My code:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MainSo {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
System.out.println("https://stackoverflow.com/questions/63263081/node-js-encryption-code-to-java-encryption-code");
String plaintext = "HelloWorld";
String keyString = "XXXXXXXX00000000"; // 16 chars
byte[] key = keyString.getBytes(StandardCharsets.UTF_8);
// md5 hashing is unsecure !!
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] keyMd5 = md.digest(key);
// aes ecb mode encryption is unsecure
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(keyMd5, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
System.out.println("ciphertext Java: " + bytesToHex(ciphertext));
System.out.println("ciphertext NodeJS: " + "ce25d577457cf8113fa4d9eb16379529");
}
private static String bytesToHex(byte[] bytes) {
// service method for displaying a byte array as hex string
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}

Converting a Java encryption method to Php

I am trying to generate an encrypted message to send to a remote server and when I do it in Java I succeed but when I try it in PHP, I fail.
I would like your help in pointing out where I am going wrong in the php version. Below is the Java and php version of my code.
private String encryptMessage() {
String msg = "";
String message = "this is the message to send";
String modulus = "xxxxxxxxxxxxxxx";
String exponent = "111";
Security.addProvider(new BouncyCastleProvider());
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(modulus, 16), new BigInteger(exponent, 16));
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(publicKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] messageDataBytes = cipher.doFinal(message.getBytes("UTF8"));
msg = Base64.getEncoder().encodeToString(messageDataBytes).replaceAll("\\r|\\n", "");
return msg;
}
The php version that fails
private function encryptMessage()
{
$message = "this is the message to send";
$modulus = "xxxxxxxxxxxxxxx";
$exponent = "111";
$rsa = new RSA();
$exponent = new BigInteger( $exponent, 16);
$modulus = new BigInteger($modulus, 16);
$rsa->loadKey(['n' => $modulus, 'e'=>$exponent]);
$rsa->setPublicKey();
$publicKey = $rsa->getPublicKey();
openssl_public_encrypt($message, $encryptedData, $publicKey);
return base64_encode($encryptedData);
}
For Java,I am using the Bouncy Castle Library while I am using phpseclib version 2 library.
Thanks.
Result from the Java method: VU06XTAFfNfBSjhWz+deqVt/cZw7YBG1nfl0g/c8GwInVTiW1oOwX53z2+Sxp3o65kNztwRSA4ARVKjnrH4M/ygJ+9jrHLvKWt2mmKbcTF9tkmd3Ezdd429s44azulFNRwH0lqQNy80mPTpNzRN4QDkeuRp1mUqDlNHQ70T7BdWwCvjMXZ/kBjXEHocYE+fNmXjgxCQFDCkek1CZQ+IDvxRyW5MtsuQDzAphUO3Kj5epMTJkzUuekV1RzCUErerfUUb83HAo3hh6IGuqhSw3MKjVY7g7AlO0P/0n1pI2+fi/g0EojK7MJt8mzx/WrWxQH2fiMo0GuTb4+YB4+YS9dQ==
Result from PHP:
U1pWl/ohAkP+1+L25vCMwVeQ3bkRJwwWocDn/lWgIkFYM6V8/Wn+LHVbm/ku0ZV0we1tXUkQE784xH7q7Cd9h4P2mGA5XWHdtGHTzQaxHgT31DN/60I5rDsC8A3OJORNbJk/6rBh8PuDEi33vqtayE7v4rqIYXTxAwDWUgjvnBtJOQtZXgfhrnCb/jKiLP5WY2yBfa5/3eHoLCtmButGy2GgrEmg08OnvJlqSTQd/Xtc+1NhWVlha8+vk2e/rZZn/aOzvYAOoUZQbWRUhlonObfom/1HtRJrBJGfJxv2zLFNPP6RrDgoYptMhsNs4r8OVSxj6qiEYFx9tjNqp9c1xA==
My solution consists of 3 files to get a complete testing environment with full working encryption and decryption in Java
and encryption only in PHP.
The test environment I'm working on is on Java-side 11.0.6+8-b520.43 (without any dependencies, e.g. Bouncy Castle)
and on PHP-side php version 7.4.6, openssl version: OpenSSL 1.1.1g 21 Apr 2020 and phpseclib 2.0.27.
GenerateKeysSo.java: generates an RSA private/public keypair in modulus/exponent-presentation. I use the insecure 512 bit keylength just to keep the string length a little bit shorter - in production you should use a minimum of 2048 bit keylength.
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
public class GenerateKeysSo {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
System.out.println("https://stackoverflow.com/questions/53947613/rsa-public-key-generated-in-java-is-not-valid-in-php");
System.out.println("Generate RSA keys");
System.out.println("java version: " + Runtime.version());
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
//kpGen.initialize(2048, new SecureRandom());
kpGen.initialize(512, new SecureRandom()); // don't use 512 bitlength as it is insecure !
KeyPair keyPair = kpGen.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
byte[] privateKeyEncoded = privateKey.getEncoded();
byte[] publicKeyEncoded = publicKey.getEncoded();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
BigInteger modulus = rsaPublicKey.getModulus();
BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
BigInteger publicKeyExponent = rsaPublicKey.getPublicExponent();
System.out.println("privateKey Base64: " + Base64.getEncoder().encodeToString(privateKeyEncoded));
System.out.println("publicKey Base64: " + Base64.getEncoder().encodeToString(publicKeyEncoded));
System.out.println("modulus : " + modulus);
System.out.println("privateExponent : " + privateExponent);
System.out.println("publicExponent : " + publicKeyExponent);
}
}
The result is short and you need to copy the 3 values of modulus, privateExponent and publicExponent with copy/paste to EncryptSo.java and to
EncryptSo.php:
Generate RSA keys
java version: 11.0.6+8-b520.43
privateKey Base64: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAgKpP+4e9D3r5Mbw4VBaQQG/LRw7nqDOWOU6p+teU2c+mTPE2apPzYUku9AaNf+BiPyjzmkWh/9d7E5jUDWfS9QIDAQABAkA9Ia5y0eFwE3uGt+kDetz64KLylhBXCHudqtR0TC169s4UfGr6EquaqX9YKmQ4ApC5mkO65Rha8V0WzV6PEUlBAiEA6XtDObkbbhAMaDXpLkzqu0I5O2e3cpTMGwCTaK/0GVkCIQCNExoakOZ1+0f5UuiztmGo7UqBpZEieiybL25H/iI2/QIhANPubzcWLy/YoWp2hRLh/q+7jPe/TWVUa3CXNTbxgEEBAiAyA22jsW8isJ0JlQ0OeUASJV3erJXRhUK/GYedWklC+QIgLnxzZVDSNNEGYFpUER0v2bIFWqVXlnm87y5LRbzWn/I=
publicKey Base64: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAICqT/uHvQ96+TG8OFQWkEBvy0cO56gzljlOqfrXlNnPpkzxNmqT82FJLvQGjX/gYj8o85pFof/XexOY1A1n0vUCAwEAAQ==
modulus : 6738747659637003090018178263545882875809887577706500222853194115214616163418986509701683514500084328991941041539147237736316411294805049495944982937719541
privateExponent : 3201720015041533823900789397901821886674218828976379815054133670438877551559197501362784700723343540531608097210070472157677675484894343978127401531033921
publicExponent : 65537
File 2 is the encryption/decryption routine in Java (EncryptSo.java). Paste the 3 values from GenerateSo to the three string variables modulusString,
privateExponentString and publicExponentString. Run the program and it will encrypt a message and decrypt it. After running the PHP-encryption (file 3)
you have an output there - you can paste this output to line 42 (variable ciphertextFromPhp). This string will get decrypted as well.
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
public class EncryptSo {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException, IOException {
System.out.println("https://stackoverflow.com/questions/61966418/converting-a-java-encryption-method-to-php");
System.out.println("encrypt and decrypt with Java with key generation via modulus and exponent");
String modulusString = "7655411376708364139873444642436134423578239360576333940175884244078181837546293928220019721607335417517025652060442851820596480386882812189086919617782503";
String privateExponentString = "6181379361775076881056852519774102589787650800051550108278185489542231510128103539355646657479306697213227070361180012317478947328351699562861534356668225";
String publicExponentString = "65537";
BigInteger modulusBI = new BigInteger(modulusString);
BigInteger publicExponentBI = new BigInteger(publicExponentString,10); // 10 = numeric string
BigInteger privateExponentBI = new BigInteger(privateExponentString,10); // 16 = hex string
// generate private & public keys
KeyFactory factory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulusBI, privateExponentBI);
PrivateKey privateKeyBI = factory.generatePrivate(rsaPrivateKeySpec);
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulusBI, publicExponentBI);
PublicKey publicKeyBI = factory.generatePublic(rsaPublicKeySpec);
// encryption
String message = "this is the message to send";
System.out.println("message Original : " + message);
String ciphertext = encryptMessageEnc(message, publicKeyBI);
System.out.println("message encrypted: " + ciphertext);
// decryption
String decryptedtext = decryptMessageEnc(ciphertext, privateKeyBI);
System.out.println("message decrypted: " + decryptedtext);
System.out.println("decryption of a encrypted message from PHP");
String ciphertextFromPhp = "B3a1v8oGVYqRpRwRwGP5KRaqaNiiXFRfTdWnz0LsI4Ek63BpXIrWsEXsVNaj1jSu4XIQNrvYHIpwdxwKQrBUUfXXwq6Pix0YfuOmz7mUJMyTerHMcVzcXIpEGAD/L0gGomfCbkahed/CimThPSO527ulazHVirOY173JjMTrWdqyFLS6L7sCD6UHkU49gW94ADkOJtRXOiIWTg==";
System.out.println("message encrypted: " + ciphertextFromPhp);
decryptedtext = decryptMessageEnc(ciphertext, privateKeyBI);
System.out.println("message decrypted: " + decryptedtext);
}
private static String encryptMessageEnc(String message, PublicKey publicKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, BadPaddingException, IllegalBlockSizeException {
String msg = "";
//Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] ciphertextBytes = cipher.doFinal(message.getBytes("UTF8"));
msg = Base64.getEncoder().encodeToString(ciphertextBytes).replaceAll("\\r|\\n", "");
return msg;
}
private static String decryptMessageEnc(String msg, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
//Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] message = Base64.getDecoder().decode(msg);
byte[] messageDataBytes = cipher.doFinal(message);
return new String(messageDataBytes);
}
}
output of EncryptSo:
encrypt and decrypt with Java with key generation via modulus and exponent
java version: 11.0.6+8-b520.43
message Original : this is the message to send
message encrypted: WZs0jp6yMWR71I4g7Oxo54A28yDZRBs5usKYLz9NfoRkMPy7vpe+riLSZzr6mdC8XZFNGveH9HsG2maZWSxhsw==
message decrypted: this is the message to send
decryption of a encrypted message from PHP
message encrypted: B3a1v8oGVYqRpRwRwGP5KRaqaNiiXFRfTdWnz0LsI4Ek63BpXIrWsEXsVNaj1jSu4XIQNrvYHIpwdxwKQrBUUfXXwq6Pix0YfuOmz7mUJMyTerHMcVzcXIpEGAD/L0gGomfCbkahed/CimThPSO527ulazHVirOY173JjMTrWdqyFLS6L7sCD6UHkU49gW94ADkOJtRXOiIWTg==
message decrypted: this is the message to send
File 3 (EncryptSo.php) is simple PHP-application that builds the public key via modulus and exponent and need the external dependency "phpseclib". I included the library without any composer-help just manually. Paste the modulus and exponent to the variables modulusString and publicExponentString and let it run.
<?php
// https://stackoverflow.com/questions/61966418/converting-a-java-encryption-method-to-php
include('phpseclib\Math\BigInteger.php');
include('phpseclib\Crypt\RSA.php');
include('phpseclib\Crypt\HASH.php');
echo 'php version: ' . PHP_VERSION . ' openssl version: ' . OPENSSL_VERSION_TEXT . ' phpseclib 2.0.27' . PHP_EOL;
$message = "this is the message to send";
$modulusString = "7655411376708364139873444642436134423578239360576333940175884244078181837546293928220019721607335417517025652060442851820596480386882812189086919617782503";
$publicExponentString = "65537";
$rsa = new \phpseclib\Crypt\RSA();
//$rsa = new Crypt_RSA();
$exponent = new phpseclib\Math\BigInteger($publicExponentString, 256);
$modulus = new phpseclib\Math\BigInteger($modulusString, 256);
$PUBLICKEY = "";
$rsa->loadKey(['n' => $modulus, 'e'=>$exponent]);
$rsa->setPublicKey();
$publicKey = $rsa->getPublicKey();
openssl_public_encrypt($message, $encryptedData, $publicKey);
$encryptedData = base64_encode($encryptedData);
echo PHP_EOL ."encryptedData base64: " . $encryptedData . PHP_EOL;
// encryptedData base64: K4DCBvi2lWbyQJGiQbZ9cXiZy49sg+Q0KKPvj7+TMObTCyWKtoQce8pmUJlDZ48+K1Fy3vHtTTZFDQzr7fkWKoeYffl171IsxOgFLz2bmjQYhrNiLy5ZI03qUX4i9MI0mtSMlITXhiryDOajHB61Cgs5cfgH+yVCJItV7cM/qMBAGnQVqoMxRAKaSOBEz/zxp3If5X9Jb5zuhA==
?>
Result of PHP encryption:
php version: 7.4.6 openssl version: OpenSSL 1.1.1g 21 Apr 2020 phpseclib 2.0.27
encryptedData base64: M5ys/5JrlleQO5MJDVl6FvRcIUIcxXQhp00y/KLHfB1p0XRNaVaWRwV9t5NKoJmo4wKI1KQI1H9PBd71c6t3i7IWsWcS8QsebOk5iitacvgOTJBW71pjrzWkv4+M7Ge8KZ/jhCl6nQ+e9zNSkJf4HZE1NHmOzFan3pBN1gXDptj19AZPue/MxqdAIgDD538UElvhTzyWMpCJeA==

PowerShell ConvertFrom-SecureString in Java?

I'm trying to re-implement PowerShell's ConvertFrom-SecureString in Java. The documentation there is a bit sparse. All it says is "AES". Trying out various AES encryption examples on the Java side did not get me any further.
Would someone have some pointers for me?
Addendum 1
The pointers provided by the comments look helpful. Thanks!
This PowerShell script shows what I'm trying to "port" to Java, at least the encryption part (with key being just 32 random byte values):
$key = 202,144,73,88,228,1,7,104,95,212,137,87,125,201,80,75,53,18,39,108,60,218,212,151,239,241,34,117,106,184,212,179
$secret = "banana"
Write-Output "secret : $($secret)"
# encrypt
$secretSecured = ConvertTo-SecureString $secret -AsPlainText -Force
$encrypted = ConvertFrom-SecureString -secureString $secretSecured -key $key
Write-Output "encrypted: $($encrypted)"
# decrypt
$secure = $encrypted | ConvertTo-SecureString -key $key
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
$decrypted = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
Write-Output "decrypted: $($decrypted)"
Running it gives this:
secret : banana
encrypted: 76492d1116743f0423413b16050a5345MgB8AEkAdQBpAEIANQBaAHQAeQAvAE0AOQBpAE0ATwByAEEAcgBlAC8AOQB2AGcAPQA9AHwANwBkAGIANwBiADgAYgBhADIAZgA4ADAAZQBlADEAZQA0ADgAYQA1ADUAYgBiADYAZgAyADQAMQA5ADkAMwA5AA==
decrypted: banana
Addendum 2
Here's now a first draft port in Java (also in this Github repository):
import org.junit.Before;
import org.junit.Test;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
public class EncryptionTest{
SecretKeySpec key;
IvParameterSpec ivSpec;
Cipher cipher;
#Before
public void init() throws Exception{
int[] ints = {202,144,73,88,228,1,7,104,95,212,137,87,125,201,80,75,53,18,39,108,60,218,212,151,239,241,34,117,106,184,212,179};
byte[] bytes = new byte[ints.length];
for (int i=0; i<ints.length; i++){
bytes[i] = (byte)ints[i];
}
key = new SecretKeySpec(bytes, "AES");
byte[] iv = new byte[16];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
ivSpec = new IvParameterSpec(iv);
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}
#Test
public void testIt() throws Exception{
String secret = "banana";
System.out.println("secret : "+secret);
byte[] encrypted = encrypt(secret);
System.out.println("encrypted: "+Base64.getEncoder().encodeToString(encrypted));
String decrypted = decrypt(encrypted);
System.out.println("decrypted: "+decrypted);
}
byte[] encrypt(String secret) throws Exception{
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
return cipher.doFinal(secret.getBytes());
}
String decrypt(byte[] encrypted) throws Exception{
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
return new String(cipher.doFinal(encrypted));
}
}
Running it (in JUnit) gives this:
secret : banana
encrypted: P51DH0d0FRvUoetaujEyjA==
decrypted: banana
I wonder why the encrypted string here is only 24 characters long, but the PowerShell one has 192 characters?

decrypting aes-gcm encrypted with java using openssl

I have the following code in Java:
public static void deriveKeyAndIV(String password)
throws Exception
{
SecureRandom random = new SecureRandom();
if (salt == null)
{
salt = new byte[HASH_BYTE_SIZE / 8]; // use salt size at least as long as hash
random.nextBytes(salt);
}
if (ivBytes == null)
{
ivBytes = new byte[HASH_BYTE_SIZE / 8];
random.nextBytes(ivBytes);
}
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
keyBytes = skf.generateSecret(spec).getEncoded();
}
public static byte[] encrypt(byte[] message)
throws Exception
{
// wrap key data in Key/IV specs to pass to cipher
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
//IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
// create the cipher with the algorithm you choose
// see javadoc for Cipher class for more info, e.g.
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
GCMParameterSpec gps = new GCMParameterSpec(128, ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, gps);
byte[] encrypted = new byte[cipher.getOutputSize(message.length)];
int enc_len = cipher.update(message, 0, message.length, encrypted, 0);
enc_len += cipher.doFinal(encrypted, enc_len);
return encrypted;
}
public static byte[] decrypt(byte[] cipher_text)
throws Exception
{
// wrap key data in Key/IV specs to pass to cipher
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
// create the cipher with the algorithm you choose
// see javadoc for Cipher class for more info, e.g.
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
GCMParameterSpec gps = new GCMParameterSpec(128, ivBytes);
cipher.init(Cipher.DECRYPT_MODE, key, gps);
byte[] decrypted = new byte[cipher.getOutputSize(cipher_text.length)];
int dec_len = cipher.update(cipher_text, 0, cipher_text.length, decrypted, 0);
dec_len += cipher.doFinal(decrypted, dec_len);
return decrypted;
}
public static void main(String[] args) {
String pass = "hello";
try {
deriveKeyAndIV(pass);
byte[] tmp = encrypt("world!".getBytes());
System.out.println(new String(Base64.getEncoder().encode(tmp)));
System.out.println(new String(tmp));
System.out.println("encrypted:\t" + bytesToHex(tmp));
System.out.println("key:\t" + bytesToHex(keyBytes));
System.out.println("iv:\t" + bytesToHex(ivBytes));
tmp = decrypt(tmp);
System.out.println("decrypted:\t" + bytesToHex(tmp));
} catch (Exception e) {
e.printStackTrace();
}
}
Sample output:
5xwfm037nXfGS06V5OKgW/oo6WDuow==
��M��w�KN���[�(�`�
encrypted: E71C1F9B4DFB9D77C64B4E95E4E2A05BFA28E960EEA3
key: 6D525D38BFF7F70AD25205E97368C197
iv: 060374643557ED8E2F6A215F1B6DBD0E
decrypted: 776F726C6421
I copied the Base64 output into a file (test-in), and tried decrypting it using the following command:
openssl enc -d -base64 -id-aes128-GCM -K 6D525D38BFF7F70AD25205E97368C197 -in ~/Desktop/test-in -out ~/Desktop/test-out -iv 060374643557ED8E2F6A215F1B6DBD0E
I got a bad decrypt error message (exit code: 1). trying different modes (id-aes192-GCM and id-aes256-GCM) resulted the same.
What I'm doing wrong?
I copied the Base64 output into a file (test-in), and tried decrypting it using the following command ...
Authenticated encryption modes do not work from the command line tools. From the openssl enc man page:
The enc program does not support authenticated encryption modes like
CCM and GCM. The utility does not store or retrieve the authentication
tag.
I know the documentation was recently updated (circa May or June 2014) with the statement above. The mailing list message that triggered it was v1.0.1g command line gcm error.
I don't know if newer versions of the tools (like openssl enc in 1.0.2 or 1.1.0) provide a meaningful error message, or if you just get bad decrypt.
What I'm doing wrong?
Nothing.
it may be a bug, see: http://openssl.6102.n7.nabble.com/1-1-0-dev-AES-GCM-on-command-line-quot-bad-decrypt-quot-but-seems-to-work-td49979.html, even this does not entirely work:
KEY=6D525D38BFF7F70AD25205E97368C197
IV=060374643557ED8E2F6A215F1B6DBD0E
echo "world!" | openssl enc -id-aes128-GCM -K $KEY -iv $IV | openssl enc -d -id-aes128-GCM -K $KEY -iv $IV
world!
bad decrypt

How to fix the NoSuchAlgorithmException in Java when using Blowfish?

So I'm writing a program to encrypt and decrypt text files but I seem to be always getting this error when I use an encrypthion other than "Blowfish" (e.g. "Blowfish/CBC/PKCS5Padding"). The excepthiong I get is:
Exception in thread "main" java.security.NoSuchAlgorithmException: Blowfish/CBC/PKCS5Padding KeyGenerator not available
at javax.crypto.KeyGenerator.<init>(DashoA13*..)
at javax.crypto.KeyGenerator.getInstance(DashoA13*..)
at Encryptor.<init>(Encryptor.java:87)
at Encryptor.main(Encryptor.java:30)
A portion of my code:
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Encryptor2 {
private IvParameterSpec ivSpec;
private SecretKeySpec keySpec;
private Cipher cipher;
public static void main(String[] args) throws Exception {
Encryptor2 e = new Encryptor2(
"averylongtext!#$##$##$#*&(*&}{23432432432dsfsdf");
String enc = e.encrypt("john doe");
String dec = e.decrypt(enc);
}
public Encryptor2(String pass) throws Exception {
// setup AES cipher in CBC mode with PKCS #5 padding
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// setup an IV (initialization vector) that should be
// randomly generated for each input that's encrypted
byte[] iv = new byte[cipher.getBlockSize()];
new SecureRandom().nextBytes(iv);
ivSpec = new IvParameterSpec(iv);
// hash keyString with SHA-256 and crop the output to 128-bit for key
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(pass.getBytes());
byte[] key = new byte[16];
System.arraycopy(digest.digest(), 0, key, 0, key.length);
keySpec = new SecretKeySpec(key, "AES");
}
public String encrypt(String original) throws Exception {
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(original.getBytes("UTF-8"));
System.out.println("encrypted: `" + new String(encrypted) + "`");
return new String(encrypted);
}
public String decrypt(String encrypted) throws Exception {
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(encrypted.getBytes("UTF-8"));
System.out.println("decrypted: `" + new String(decrypted, "UTF-8")
+ "`");
return new String(decrypted, "UTF-8");
}
}
But now it fails with Input length must be multiple of 16 when decrypting with padded cipher
The additional parameters that you're specifying with the algorithm are meant for Cipher. For KeyGenerator and SecretKeySpec you only specify the algorithm. The other parameters are for the cipher mode of operation and padding to be used. For example, if you're using Blowfish in CBC mode with PKCS #5 padding you want:
KeyGenerator keyGen = KeyGenerator.getInstance("Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
See Encrypting and Decrypting Using Java: Unable to get same output for an example. It uses the same mode and padding as you have. The only difference is that uses AES instead of Blowfish, however it works exactly the same.

Categories