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);
}
Related
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);
?>
Please help me :(, I am trying this answer in this post Converting string to SecretKey
But it doesn't seem to be working for RC4, please tell me what I am doing wrong.
This is my RC4 class in a separate file:
public class RC4 {
SecretKey k;
public RC4() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
KeyGenerator kg = KeyGenerator.getInstance("RC4");
k = kg.generateKey();
}
public byte[] encrypt(final byte[] plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RC4"); // Transformation of the algorithm
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] cipherBytes = cipher.doFinal(plaintext);
return cipherBytes;
}
public byte[] decrypt(final byte[] ciphertext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(Cipher.DECRYPT_MODE, k);
byte[] plainBytes = cipher.doFinal(ciphertext);
return plainBytes;
}
public SecretKey getK() {
return k;
}
public void setK(SecretKey k) {
this.k = k;
}
}
This code below is also from another file in a main method
RC4 rc4Client = new RC4();
SecretKey k = rc4Client.getK();
String encodedK = Base64.getEncoder().encodeToString(k.getEncoded());
//print
System.out.println("Random k: " + k.toString());
byte[] decodedKey = Base64.getDecoder().decode(encodedK);
k = new SecretKeySpec(decodedKey, 0, decodedKey.length, "RC4");
//print
System.out.println("Random k: " + k.toString());
The printed output is:
Random k: javax.crypto.spec.SecretKeySpec#2c97f72b
Random k: javax.crypto.spec.SecretKeySpec#fffe4170
They should be the same, why are they different??
Convert the k to a byte array and then to String:
byte[] kByte = k.getEncoded();
String encodedK = Base64.getEncoder().encodeToString(kByte)
As per comments. Running...
public static void main( String[] args ) throws NoSuchAlgorithmException {
KeyGenerator kg = KeyGenerator.getInstance("RC4");
SecretKey k1 = kg.generateKey();
String b64k1 = Base64.encode(k1.getEncoded());
byte[] bk1 = Base64.decode(b64k1);
SecretKey k2 = new SecretKeySpec( bk1, 0, bk1.length, "RC4");
String b64k2 = Base64.encode(k2.getEncoded());
byte[] bk2 = Base64.decode(b64k2);
System.out.println(k1);
System.out.println(k2);
System.out.println(Arrays.toString(bk1));
System.out.println(Arrays.toString(bk2));
System.out.println(b64k1);
System.out.println(b64k2);
}
Gives the following output:
javax.crypto.spec.SecretKeySpec#d36802be
javax.crypto.spec.SecretKeySpec#1b4e5
[107, -27, -118, -72, 46, -37, -57, -67, -84, 94, 20, 79, 123, 79, -50, 101]
[107, -27, -118, -72, 46, -37, -57, -67, -84, 94, 20, 79, 123, 79, -50, 101]
a+WKuC7bx72sXhRPe0/OZQ==
a+WKuC7bx72sXhRPe0/OZQ==
To clarify, k1.toString() and k2.toString() are only dependent on object instance in Object.toString() default implementation and since k1 and k2 are distinct objects, the output is different. The actual key material is shown in next 4 lines as byte[] and then as base64 encoded String of that byte array and is equal as expected.
As an additional note, RC4 is not considered safe and should not be used in real production code.
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 a project where i need to convert c# codes to java. I faced a problem in adopting the TripleDESCryptoServiceProvider functionality in java. Good news is I found a solution for this but unfortunately it's not working perfectly
c# code
using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.IO;
namespace HelloWorldApplication {
class HelloWorld {
private TripleDESCryptoServiceProvider TripleDes;
private byte[] key;
private byte[] iv;
static void Main(string[] args) {
new HelloWorld();
}
public HelloWorld(){
this.TripleDes = new TripleDESCryptoServiceProvider();
this.key = new byte[]
{
14,
4,
5,
12,
13,
6,
18,
19,
20,
1,
15,
16,
17,
2,
3,
23,
24,
7,
8,
9,
10,
11,
21,
22
};
this.iv = new byte[]
{
6,
5,
8,
3,
2,
7,
4,
1
};
string data="this is string data";
string enc=EncryptData(data);
Console.WriteLine(enc);
}
public string EncryptData(string plaintext)
{
byte[] bytes = Encoding.Unicode.GetBytes(plaintext);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream,
this.TripleDes.CreateEncryptor(this.key, this.iv),
CryptoStreamMode.Write);
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(memoryStream.ToArray());
}
public string DecryptData(string encryptedtext)
{
byte[] arr_ = Convert.FromBase64String(encryptedtext);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream,
this.TripleDes.CreateDecryptor(this.key, this.iv),
CryptoStreamMode.Write);
cryptoStream.Write(arr_, 0, arr_.Length);
cryptoStream.FlushFinalBlock();
return Encoding.Unicode.GetString(memoryStream.ToArray());
}
}
}
Output: "I6rXj2YRY6WN9iOoHbrHJcbPkAPDEeFWfBJr0dYxWNXwYAhcjJZX7w=="
And the following is corresponding java code:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import sun.misc.BASE64Encoder;
public class HelloWorld
{
private static byte[] sharedkey = new byte[]
{
14,
4,
5,
12,
13,
6,
18,
19,
20,
1,
15,
16,
17,
2,
3,
23,
24,
7,
8,
9,
10,
11,
21,
22
};
private static byte[] sharedvector = new byte[]
{
6,
5,
8,
3,
2,
7,
4,
1
};
public static void main(String[] argv)
throws Exception
{
String enctext ="I6rXj2YRY6WN9iOoHbrHJcbPkAPDEeFWfBJr0dYxWNXwYAhcjJZX7w==";
String text = decrypt(enctext);
System.out.println(text);
}
public static String encrypt(String plaintext)
throws Exception
{
Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sharedkey, "DESede"), new
IvParameterSpec(sharedvector));
byte[] encrypted = c.doFinal(plaintext.getBytes("UTF-8"));
return Base64.encode(encrypted);
}
public static String decrypt(String ciphertext)
throws Exception
{
Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sharedkey, "DESede"), new
IvParameterSpec(sharedvector));
byte[] decrypted = c.doFinal(Base64.decode(ciphertext));
return new String(decrypted, "UTF-8");
}
}
output:
How to get rid of this problem?
You solution is correct, you need to enable UTF-8 in your eclipse run configuration. I am able to get the plain text after decryption from the same code.
You should set Project->Properties->Resource->Text Fie encoding: UTF-8
public static void main(String[] argv) throws Exception {
String enctext = "I6rXj2YRY6WN9iOoHbrHJcbPkAPDEeFWfBJr0dYxWNXwYAhcjJZX7w==";
String text = decrypt(enctext);
System.out.println("decrypt:" + text);
String text2 = encrypt(text);
System.out.println("entcrypt:" + text2);
}
output:
decrypt:t
entcrypt:I6rXj2YRY6WN9iOoHbrHJcbPkAPDEeFWfBJr0dYxWNXwYAhcjJZX7w==
Your code works!
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.