I am trying to use PBKDF2WithHmacSHA512 in PHP with OpenSSL.
But I am not able to create same string as Java created encrypted string. Data which I am trying to encrypt is Atom Insta Pay. With the below mentioned java code I am getting vneGN6vnDJ3Z4wj4u3+z1g== but in PHP I am getting JQubY9xCf+g9yASdNkq7cQ== which is totally different.
// Java code
import java.util.logging.Logger;
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;
public class myEncryption {
static Logger log = Logger.getLogger(myEncryption.class.getName());
private static int pswdIterations = 65536;
private static int keySize = 256;
private static final byte[] ivBytes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
public static String encrypt(String plainText, String key) {
try {
byte[] saltBytes = key.getBytes("UTF-8");
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, pswdIterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(1, secret, localIvParameterSpec);
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return byteToHex(encryptedTextBytes);
}catch (Exception e) {
log.info("Exception while encrypting data:" + e.toString());
}
return null;
}
public static String decrypt(String encryptedText, String key) {
try {
byte[] saltBytes = key.getBytes("UTF-8");
byte[] encryptedTextBytes = hex2ByteArray(encryptedText);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, pswdIterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secret, localIvParameterSpec);
byte[] decryptedTextBytes = (byte[]) null;
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
}catch (Exception e) {
log.info("Exception while decrypting data:" + e.toString());
}
return null;
}
private static String byteToHex(byte[] byData) {
StringBuffer sb = new StringBuffer(byData.length * 2);
for (int i = 0; i < byData.length; ++i) {
int v = byData[i] & 0xFF;
if (v < 16)
sb.append('0');
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase();
}
private static byte[] hex2ByteArray(String sHexData) {
byte[] rawData = new byte[sHexData.length() / 2];
for (int i = 0; i < rawData.length; ++i) {
int index = i * 2;
int v = Integer.parseInt(sHexData.substring(index, index + 2), 16);
rawData[i] = (byte) v;
}
return rawData;
}
}
//PHP code
$method = "AES-256-CBC";
$salt = 'A4476C2062FFA58980DC8F79EB6A799E';
$key = 'A4476C2062FFA58980DC8F79EB6A799E';
$data = 'Demo String';
//Converting Array to bytes
$iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
$chars = array_map("chr", $iv);
$IVbytes = join($chars);
$salt1 = mb_convert_encoding($salt, "UTF-8"); //Encoding to UTF-8
$key1 = mb_convert_encoding($key, "UTF-8"); //Encoding to UTF-8
//SecretKeyFactory Instance of PBKDF2WithHmacSHA512 Java Equivalent
$hash = openssl_pbkdf2($key1,$salt1,'256','65536', 'sha512');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
echo base64_encode($encrypted);
The PHP-solution is much "easier" as the Java-side and can consume the key and salt as direct input (without converting them).
As you like to compare base64-encoded ciphertexts the sample code returns the base64-encoded ciphertext and not the hex string
as the Java-prog is giving out.
This is the output with equal results:
expected: JQubY9xCf+g9yASdNkq7cQ==
encrypted: JQubY9xCf+g9yASdNkq7cQ==
Security warning: your code is using static salt and iv that makes the encryption unsecure (I hope it's just for demonstration).
This is the code:
<?php
//PHP code
$method = "AES-256-CBC";
$salt = 'A4476C2062FFA58980DC8F79EB6A799E';
$key = 'A4476C2062FFA58980DC8F79EB6A799E';
$data = 'Atom Insta Pay';
//Converting Array to bytes
$iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
$chars = array_map("chr", $iv);
$IVbytes = join($chars);
$hash = openssl_pbkdf2($key,$salt,32,65536, 'sha512');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
echo 'expected: JQubY9xCf+g9yASdNkq7cQ==' . PHP_EOL;
echo 'encrypted: ' . base64_encode($encrypted);
?>
Related
I am using a C# "encrypt" and need a Java "decrypt" method. I need help in java that i can't replicate C# decryption on java and it is not explicit Padding on C# , i don't know what use in java and my key size I think is different but I am not sure. I'm very confused.
know that i need change Java Policy , and did it ! and Change Key size JAVA to 32 bytes.
C#
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Voa.Cross.Util.Extensions;
namespace Voa.Core.Safeties
{
public class Security
{
private readonly string _defaultKey = "sjkdhfjksdhf3444KDFK4nFLFGKdsnjcnj2cmkeKDIK484dmd999sksksksUUddUZ83k030394m49jdjPuWzRk8Zq2PfnpR3YrYWSq2AaUT6meeC3tr36nTVkuudKWbDyPjhUwbwXBzkUhSPKPpSRheR49em4qJWa6YHSCjKX3K93FEMnqXhYauXwjJwbHXfPWTSdxy6ebCBPyAfqk7Uz5nrRddVjZrxWNCMZYG3PbcvPWA34ekdkd454ldnvJKl";
private readonly int _divisionKey = 4;
private readonly byte[] _iv = new byte[16] {0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c};
private byte[] _key;
public Security() => _key = SHA256.Create().ComputeHash(Encoding.ASCII.GetBytes(_defaultKey));
public string Encrypt(string data, string key)
{
if (!string.IsNullOrEmpty(key))
{
CustomKey(key);
}
var encryptor = Aes.Create();
encryptor.Mode = CipherMode.CBC;
// Set key and IV
var aesKey = new byte[32];
Array.Copy(_key, 0, aesKey, 0, 32);
encryptor.Key = aesKey;
encryptor.IV = _iv;
var memoryStream = new MemoryStream();
var aesEncryptor = encryptor.CreateEncryptor();
var cryptoStream = new CryptoStream(memoryStream, aesEncryptor, CryptoStreamMode.Write);
var plainBytes = Encoding.ASCII.GetBytes(data);
cryptoStream.Write(plainBytes, 0, plainBytes.Length);
cryptoStream.FlushFinalBlock();
var cipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
var cipherText = Convert.ToBase64String(cipherBytes, 0, cipherBytes.Length);
return cipherText;
}
public string Decrypt(string data, string key)
{
if (!string.IsNullOrEmpty(key))
{
CustomKey(key);
}
var encryptor = Aes.Create();
encryptor.Mode = CipherMode.CBC;
var aesKey = new byte[32];
Array.Copy(_key, 0, aesKey, 0, 32);
encryptor.Key = aesKey;
encryptor.IV = _iv;
var memoryStream = new MemoryStream();
var aesDecryptor = encryptor.CreateDecryptor();
var cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write);
var plainText = string.Empty;
try
{
var cipherBytes = Convert.FromBase64String(data);
cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
cryptoStream.FlushFinalBlock();
var plainBytes = memoryStream.ToArray();
plainText = Encoding.ASCII.GetString(plainBytes, 0, plainBytes.Length);
}
finally
{
memoryStream.Close();
cryptoStream.Close();
}
return plainText;
}
private void CustomKey(string key)
{
var blockSize = key.Length / _divisionKey;
var splitKey = key.CutString(blockSize).ToList();
var splitDefaultKey = _defaultKey.CutString(blockSize).ToList();
var newKey = string.Concat(splitDefaultKey.Intertwine(splitKey).ToList());
_key = SHA256.Create().ComputeHash(Encoding.ASCII.GetBytes(newKey));
}
}
}
JAVA test...
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SecurityAESEncryption {
private static final String _key = "sjkdhfjksdhf3444KDFK4nFLFGKdsnjcnj2cmkeKDIK484dmd999sksksksUUddUZ83k030394m49jdjPuWzRk8Zq2PfnpR3YrYWSq2AaUT6meeC3tr36nTVkuudKWbDyPjhUwbwXBzkUhSPKPpSRheR49em4qJWa6YHSCjKX3K93FEMnqXhYauXwjJwbHXfPWTSdxy6ebCBPyAfqk7Uz5nrRddVjZrxWNCMZYG3PbcvPWA34ekdkd454ldnvJKl";
private static final char[] initCharArray = new char[] {0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c};
private static final byte[] initVector = SecurityAESEncryption.charToByteArray(initCharArray);
//private static final String initArray = "26dcff00aded7aeec5fe07af4d08223c";
//private static final byte[] ivValue = SecurityAESEncryption.hexStringToByteArray(initArray);
//private static final byte[] key = DigestUtils.sha256(_key.getBytes(StandardCharsets.US_ASCII)).;
private static final byte[] key = SecurityAESEncryption.computeHash(_key);
public static String encrypt(String value) {
try {
System.out.println(key.length);
System.out.println(Base64.decodeBase64(key).length);
byte[] aesKey = new byte[32];
System.arraycopy(key, 0, aesKey, 0, 32);
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(initVector);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String encrypted) {
try {
byte[] encryptedBytes = Base64.decodeBase64(encrypted);
System.out.println(key.length);
System.out.println(Base64.decodeBase64(key).length);
byte[] aesKey = new byte[32];
System.arraycopy(key, 0, aesKey, 0, 32);
IvParameterSpec iv = new IvParameterSpec(initVector);
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
//byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
byte[] original = cipher.doFinal(encryptedBytes);
return new String(original,StandardCharsets.US_ASCII);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static byte[] charToByteArray(char[] x)
{
final byte[] res = new byte[x.length];
for (int i = 0; i < x.length; i++)
{
res[i] = (byte) x[i];
}
return res;
}
public static byte[] computeHash(String input) {
try {
// Static getInstance method is called with hashing SHA
MessageDigest md = MessageDigest.getInstance("SHA-256");
return md.digest(input.getBytes(StandardCharsets.US_ASCII));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static void main(String[] args) {
String originalString = "123456!##";
System.out.println("Original String to encrypt - " + originalString);
String encryptedString = encrypt(originalString);
System.out.println("Encrypted String - " + encryptedString);
String decryptedString = decrypt("Ci10C7ZjUPoEnitdh7QkEw==");
System.out.println("After decryption - " + decryptedString);
}
Your edited Java prog now successfully encrypts the string "123456!##" to this (Base64 encoded) string "LnZV0Vph+eUeJLT2Gst0kw==" using a String as input to a SHA-256 digest, so the real key used for en-/decryption is
(hex) "07c3491eaa6a6289ca91b7b0f290d60688538860b44753f1cf9617977985d2db".
Using this encoded string as input for your decrypt method returns the original string but when using the encoded/encrypted
string "Ci10C7ZjUPoEnitdh7QkEw==" I'm running into this exception:
javax.crypto.BadPaddingException: Given final block not properly padded.
Such issues can arise if a bad key is used during decryption.
Imho this indicates that the key your're using on Java-side is not the same as on C#-side (we don't see the real input
to Encrypt and I don't know what "CustomKey" is doing :-).
Could you please print out
the aeskey and -iv from your C#-Encrypt method directly after you setup them in encryptor-inits and share them here,
that might be usefull for us to help.
public string Encrypt(string data, string key)
...
// Set key and IV
var aesKey = new byte[32];
Array.Copy(_key, 0, aesKey, 0, 32);
encryptor.Key = aesKey;
encryptor.IV = _iv;
==> print aesKey & _iv
...
I have to decrypt text in JAVA, encrypted in C# (AES, RijndaelManaged).
After several days of reading and searching solutions, and a lot of stackoverflow solutions tested, i still have a problem unsolved.
I apply C# code here (which is working) and the java code (which not fully working).
Here is the exception from the java code:
Exception in thread "main" javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at test.Decrypt.main(Decrypt.java:39)
JAVA code
import java.nio.charset.StandardCharsets;
import java.security.spec.KeySpec;
import java.util.Base64;
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;
public class Decrypt {
public static void main(String[] args) throws Exception {
String encText = "EAAAADE2ODA2NjQya2JNN2M1ISShgi+Oi5tbsPgOz5KsCHj0";
final String password = "KJH#$#kds32#!kjhdkftt";
final String iv = "16806642kbM7c5!$";
byte[] salt = new byte[] { 34, (byte) 134, (byte) 145, 12, 7, 6, (byte) 243, 63, 43, 54, 75, 65, 53, 2, 34, 54,
45, 67, 64, 64, 32, (byte) 213 };
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1000, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(tmp.getEncoded(), "AES");
IvParameterSpec ivs = new IvParameterSpec(iv.getBytes(StandardCharsets.US_ASCII));
System.out.println("Key:" + Base64.getEncoder().encodeToString(secret.getEncoded()));
System.out.println("IV:" + Base64.getEncoder().encodeToString(ivs.getIV()));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, ivs);
byte [] decodedText = Base64.getDecoder().decode(encText);
String plaintext = new String(cipher.doFinal(decodedText), "UTF-8");
System.out.println(plaintext);
}
}
C# code
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Test
{
public class EncriptionHelper
{
public static void Main()
{
var cleanTxt = "8212093345";
var encTxt = "EAAAADE2ODA2NjQya2JNN2M1ISShgi+Oi5tbsPgOz5KsCHj0";
var secret = "KJH#$#kds32#!kjhdkftt";
var xtxt = EncryptStringAES(cleanTxt, secret);
var txt = DecryptStringAES(encTxt, secret);
Console.WriteLine(txt);
Console.WriteLine(xtxt);
}
private static byte[] vector = Encoding.ASCII.GetBytes("16806642kbM7c5!$");
private static byte[] salt = new byte[] { 34, 134, 145, 12, 7, 6, 243, 63, 43, 54, 75, 65, 53, 2, 34, 54, 45, 67, 64, 64, 32, 213 };
/// <summary>
/// Encrypt the given string using AES. The string can be decrypted using
/// DecryptStringAES(). The sharedSecret parameters must match.
public static string EncryptStringAES(string text, string sharedSecret)
{
if (string.IsNullOrEmpty(text))
{
throw new ArgumentNullException("Text is null or empty");
}
if (string.IsNullOrEmpty(sharedSecret))
{
throw new ArgumentNullException("Secret is null or empty");
}
if (salt == null || salt.Length == 0)
{
throw new ArgumentNullException("Salt is null or empty");
}
string outStr = null;
RijndaelManaged aesAlg = null;
try
{
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, salt);
aesAlg = new RijndaelManaged();
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
aesAlg.IV = vector;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(text);
}
}
outStr = Convert.ToBase64String(msEncrypt.ToArray());
}
}
finally
{
// Clear the RijndaelManaged object.
if (aesAlg != null)
aesAlg.Clear();
}
// Return the encrypted bytes from the memory stream.
return outStr;
}
/// <summary>
/// Decrypt the given string. Assumes the string was encrypted using
/// EncryptStringAES(), using an identical sharedSecret.
/// </summary>
public static string DecryptStringAES(string cipherText, string sharedSecret)
{
if (string.IsNullOrEmpty(cipherText))
{
throw new ArgumentNullException("Text is null or empty");
}
if (string.IsNullOrEmpty(sharedSecret))
{
throw new ArgumentNullException("Secret is null or empty");
}
if (salt == null || salt.Length == 0)
{
throw new ArgumentNullException("Salt is null or empty");
}
RijndaelManaged aesAlg = null;
string result = null;
try
{
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, salt);
byte[] bytes = Convert.FromBase64String(cipherText);
using (MemoryStream msDecrypt = new MemoryStream(bytes))
{
aesAlg = new RijndaelManaged();
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
aesAlg.IV = ReadByteArray(msDecrypt);
Console.WriteLine("KEY: "+ Convert.ToBase64String(aesAlg.Key));
Console.WriteLine("IV: "+ Convert.ToBase64String(aesAlg.IV));
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
result = srDecrypt.ReadToEnd();
}
}
}
}
finally
{
// Clear the RijndaelManaged object.
if (aesAlg != null)
aesAlg.Clear();
}
return result;
}
private static byte[] ReadByteArray(Stream s)
{
byte[] rawLength = new byte[sizeof(int)];
if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
{
throw new SystemException("Stream did not contain properly formatted byte array");
}
byte[] buffer = new byte[BitConverter.ToInt32(rawLength, 0)];
if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
{
throw new SystemException("Did not read byte array properly");
}
return buffer;
}
}
}
Here is Java code to decode encoded data from C#:
public static void main(String[] args) throws Exception {
String encText = "EAAAADE2ODA2NjQya2JNN2M1ISShgi+Oi5tbsPgOz5KsCHj0";
final String password = "KJH#$#kds32#!kjhdkftt";
byte[] salt = new byte[] { 34, (byte) 134, (byte) 145, 12, 7, 6, (byte) 243, 63, 43, 54, 75, 65, 53, 2, 34, 54,
45, 67, 64, 64, 32, (byte) 213 };
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1000, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(tmp.getEncoded(), "AES");
byte[] data = Base64.getDecoder().decode("EAAAADE2ODA2NjQya2JNN2M1ISShgi+Oi5tbsPgOz5KsCHj0");
// skip first 4 bytes (the length of IV) and get IV byte array
byte[] iv = Arrays.copyOfRange(data, 4, 20);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
// skip IV length (4 bytes) and IV (16 bytes)
cipher.update(data, 20, data.length - 20);
String plaintext = new String(cipher.doFinal(), "UTF-8");
System.out.println(plaintext);
}
Below is simplified example, just in case if someone has access to both sources:
C#:
private static byte[] salt = new byte[] { 34, 134, 145, 12, 7, 6, 243, 63, 43, 54, 75, 65, 53, 2, 34, 54, 45, 67, 64, 64, 32, 213 };
private static byte[] vector = Encoding.ASCII.GetBytes("16806642kbM7c5!$");
private static string cleartext = "8212093345";
static void Main(string[] args)
{
var kdf = new Rfc2898DeriveBytes("KJH#$#kds32#!kjhdkftt", salt);
using (var aes = new RijndaelManaged())
{
aes.Key = kdf.GetBytes(aes.KeySize / 8);
aes.IV = vector;
using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
// don't use StreamWriter, it just makes things more complicated
var bytes = Encoding.ASCII.GetBytes(cleartext);
cs.Write(bytes, 0, bytes.Length);
}
Console.WriteLine(Convert.ToBase64String(ms.ToArray()));
// outputs: oYIvjoubW7D4Ds+SrAh49A==
}
}
}
Java:
public static void main(String[] args) throws Exception {
String encText = "EAAAADE2ODA2NjQya2JNN2M1ISShgi+Oi5tbsPgOz5KsCHj0";
final String password = "KJH#$#kds32#!kjhdkftt";
final String iv = "16806642kbM7c5!$";
byte[] salt = new byte[] { 34, (byte) 134, (byte) 145, 12, 7, 6, (byte) 243, 63, 43, 54, 75, 65, 53, 2, 34, 54,
45, 67, 64, 64, 32, (byte) 213 };
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1000, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(tmp.getEncoded(), "AES");
IvParameterSpec ivs = new IvParameterSpec(iv.getBytes(StandardCharsets.US_ASCII));
// your code use PKCS7, but I use PKCS5 because it shows exception in my case
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, ivs);
// base64 string from C# output
String plaintext = new String(cipher.doFinal(Base64.getDecoder().decode("oYIvjoubW7D4Ds+SrAh49A==")), "UTF-8");
System.out.println(plaintext);
}
I want to replicate the encryption in PHP to JAVA but it's not same result.
I tried searching, no luck.
PHP
function encryptData($input, $key_seed = "1234567890123") {
$key = substr(md5($key_seed), 0, 24);
$iv_size = mcrypt_get_iv_size(MCRYPT_TRIPLEDES, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
// encrypt
$encrypted_data = mcrypt_encrypt(MCRYPT_TRIPLEDES, $key, $input, MCRYPT_MODE_ECB, $iv);
// clean up output and return base64 encoded
$encrypted_data = base64_encode($encrypted_data);
return $encrypted_data;
}
echo "Encrypted: ".encryptData("abcdefgh");
Encrypted: l\/ExrqsHBZg=
JAVA
public String encrypt(String message) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest("1234567890123".getBytes());
final byte[] keyBytes = Arrays.copyOf(Arrays.copyOf(digestOfPassword, 12), 24);
DESedeKeySpec spec = new DESedeKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey theKey = keyFactory.generateSecret(spec);
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, theKey);
byte[] plaintext = message.getBytes();
byte[] encrypted = cipher.doFinal(plaintext);
final String encodedCipherText = Base64.getEncoder().encodeToString(encrypted);
return encodedCipherText;
}
System.out.println("Encrypted: "+encrypt("abcdefgh"));
Encrypted: 27Zx94xwikE=
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have an encrypted AES-256 string from CryptoJS with a passphrase. I need to decrypt it in Java but can't figure out how to do it. It seems that you need IV, key and salt to decrypt, and as in CryptoJS mainpage, the encrypted data already contains all of them, and CryptoJS can somehow parse them out of encrypted input.
Anyone know how to do that? I've seen so much example about CryptoJS - Java encrypt/decrypt but most of them use hardcoded IV/key, or just send IV/key from cryptoJS side to Java side. All I have is a passphrase, just like what this site do!
When a message is encrypted in this way:
CryptoJS.AES.encrypt("message", "passphrase")
a password-based approach is used. For that CryptoJS generates a new salt and uses this salt in conjunction with the passphrase to derive the key and IV (I've recreated a derivation function for this question).
After the ciphertext is produced a special OpenSSL formatter is used to encode the ciphertext including the used salt:
var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
You need to decode the Base64 encoded string to get the byte array out if it. Then you can check if the header matches:
byte[] ctBytes = Base64.getDecoder().decode(ciphertext.getBytes("UTF-8"));
System.out.println("Is salted: " + new String(Arrays.copyOf(ctBytes, 8)).equals("Salted__"));
After that you can recover the salt and ciphertext from it:
byte[] saltBytes = Arrays.copyOfRange(ctBytes, 8, 16);
byte[] ciphertextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.length);
Derive the key+IV:
byte[] key = new byte[keySize/8];
byte[] iv = new byte[ivSize/8];
EvpKDF(password.getBytes("UTF-8"), keySize, ivSize, saltBytes, key, iv);
And decrypt the ciphertext:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),
new IvParameterSpec(iv));
byte[] recoveredPlaintextBytes = cipher.doFinal(ciphertextBytes);
String recoveredPlaintext = new String(recoveredPlaintextBytes);
Complete code:
public static void main(String[] args) throws UnsupportedEncodingException, GeneralSecurityException {
String ciphertext = "U2FsdGVkX1+0m/gle/XQX1shjnpveUrl1fO3oOlurPMlTks6+oQlEPfOrucihzEz";
String plaintext = "This is some example plaintext";
String password = "This is a very strong password";
int keySize = 256;
int ivSize = 128;
// var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
byte[] ctBytes = Base64.getDecoder().decode(ciphertext.getBytes("UTF-8"));
System.out.println("Is salted: " + Arrays.equals(Arrays.copyOf(ctBytes, 8), new byte[]{0x53, 0x61, 0x6c, 0x74, 0x65, 0x64, 0x5f, 0x5f}));
System.out.println("Is salted: " + new String(Arrays.copyOf(ctBytes, 8)).equals("Salted__"));
byte[] saltBytes = Arrays.copyOfRange(ctBytes, 8, 16);
System.out.println("Salt matches: " + Arrays.equals(saltBytes, hexStringToByteArray("b49bf8257bf5d05f")));
byte[] ciphertextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.length);
System.out.println("CT matches: " + Arrays.equals(ciphertextBytes, hexStringToByteArray("5b218e7a6f794ae5d5f3b7a0e96eacf3254e4b3afa842510f7ceaee722873133")));
byte[] key = new byte[keySize/8];
byte[] iv = new byte[ivSize/8];
EvpKDF(password.getBytes("UTF-8"), keySize, ivSize, saltBytes, key, iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
byte[] recoveredPlaintextBytes = cipher.doFinal(ciphertextBytes);
String recoveredPlaintext = new String(recoveredPlaintextBytes);
System.out.println("Recovered Plaintext: " + recoveredPlaintext);
System.out.println("Expected Plaintext: " + plaintext);
}
public static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
return EvpKDF(password, keySize, ivSize, salt, 1, "MD5", resultKey, resultIv);
}
public static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
keySize = keySize / 32;
ivSize = ivSize / 32;
int targetKeySize = keySize + ivSize;
byte[] derivedBytes = new byte[targetKeySize * 4];
int numberOfDerivedWords = 0;
byte[] block = null;
MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm);
while (numberOfDerivedWords < targetKeySize) {
if (block != null) {
hasher.update(block);
}
hasher.update(password);
block = hasher.digest(salt);
hasher.reset();
// Iterations
for (int i = 1; i < iterations; i++) {
block = hasher.digest(block);
hasher.reset();
}
System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4,
Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4));
numberOfDerivedWords += block.length/4;
}
System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4);
System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4);
return derivedBytes; // key + iv
}
/**
* Copied from https://stackoverflow.com/a/140861
* */
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
JavaScript code:
var pw = "This is a very strong password";
var pt = "This is some example plaintext";
var encrypted = CryptoJS.AES.encrypt(pt, pw);
encrypted.toString(); // U2FsdGVkX1+0m/gle/XQX1shjnpveUrl1fO3oOlurPMlTks6+oQlEPfOrucihzEz
encrypted.salt.toString(); // b49bf8257bf5d05f
encrypted.ciphertext.toString(); // 5b218e7a6f794ae5d5f3b7a0e96eacf3254e4b3afa842510f7ceaee722873133
We're trying to figure out how to do this in Java/scala:
use Crypt::CBC;
$aesKey = "some key"
$cipher = new Crypt::CBC($aesKey, "DES");
$encrypted = $cipher->encrypt("hello world");
print $encrypted // prints: Salted__�,%�8XL�/1�&�n;����쀍c
print encode_base64($encrypted); // prints: U2FsdGVkX19JwL/Dc4gwehTfZ1ahNlO6Jf41vALcshg=
$decrypted = $cipher->decrypt($encrypted);
print $decrypted // prints: hello world
The problem is that the perl code is something we can not chanage.
I tried a few things in scala but didn't really get it right, for example something like this:
val secretKey = new SecretKeySpec("some key".getBytes("UTF-8"), "DES")
val encipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
encipher.init(Cipher.ENCRYPT_MODE, secretKey)
val encrypted = encipher.doFinal("hello world".getBytes)
println(encrypted) // prints: [B#4896ceb3
println(java.util.Arrays.toString(encrypted)) // [-45, -126, -90, 36, 8, -73, 6, 85, -94, 108, 100, -120, 15, -8, 126, 76]
println(Hex.encodeHexString(encrypted)) //prints: 822c90f1116686e75160ff06c8faf4a4
What we eventually need to do is to be able to decrypt cookies in Java set by Perl.
Any help or direction in Java/scala would very much be appreciated
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
final class CrapEncryption
{
private static final byte[] MAGIC = "Salted__".getBytes(StandardCharsets.US_ASCII);
private static final int KEY_LEN = 8;
private static final int SALT_LEN = 8;
private static final SecureRandom random = new SecureRandom();
static byte[] pretendToEncrypt(byte[] password, byte[] msg)
throws GeneralSecurityException
{
byte[] salt = new byte[SALT_LEN];
random.nextBytes(salt);
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password);
md5.update(salt);
byte[] dk = md5.digest();
Cipher des;
try {
SecretKey key = new SecretKeySpec(dk, 0, KEY_LEN, "DES");
AlgorithmParameterSpec iv = new IvParameterSpec(dk, KEY_LEN, SALT_LEN);
des = Cipher.getInstance("DES/CBC/PKCS5Padding");
des.init(Cipher.ENCRYPT_MODE, key, iv);
}
finally {
Arrays.fill(dk, (byte) 0);
}
byte[] pkg = new byte[des.getOutputSize(msg.length) + MAGIC.length + SALT_LEN];
System.arraycopy(MAGIC, 0, pkg, 0, MAGIC.length);
System.arraycopy(salt, 0, pkg, MAGIC.length, SALT_LEN);
des.doFinal(msg, 0, msg.length, pkg, MAGIC.length + SALT_LEN);
return pkg;
}
static byte[] decrypt(byte[] password, byte[] pkg)
throws GeneralSecurityException
{
if ((pkg.length < MAGIC.length) || !Arrays.equals(Arrays.copyOfRange(pkg, 0, MAGIC.length), MAGIC))
throw new IllegalArgumentException("Expected magic number \"Salted__\"");
if (pkg.length < MAGIC.length + SALT_LEN)
throw new IllegalArgumentException("Missing salt");
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password); /* password */
md5.update(pkg, MAGIC.length, SALT_LEN); /* salt */
byte[] dk = md5.digest();
Cipher des;
try {
SecretKey secret = new SecretKeySpec(dk, 0, KEY_LEN, "DES");
des = Cipher.getInstance("DES/CBC/PKCS5Padding");
des.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(dk, KEY_LEN, SALT_LEN));
}
finally {
Arrays.fill(dk, (byte) 0);
}
return des.doFinal(pkg, MAGIC.length + SALT_LEN, pkg.length - MAGIC.length - SALT_LEN);
}
public static void main(String... argv)
throws Exception
{
byte[] password = "some key".getBytes(StandardCharsets.UTF_8);
byte[] message = "hello world".getBytes(StandardCharsets.UTF_8);
byte[] encrypted = pretendToEncrypt(password, message);
byte[] recovered = decrypt(password, encrypted);
System.out.println(new String(recovered, StandardCharsets.UTF_8));
}
}
Why "CrapEncryption" and "pretendToEncrypt"? Because the algorithms used here are the worst! DES is not secure. MD5 is not secure. The key derivation function uses only one iteration. This is all garbage. Use AES with PBKDF2 instead.