首个8字节在Java中进行AES解密时被截断,而加密是在C#中完成的。

huangapple go评论68阅读模式
英文:

First 8 bytes is truncating in AES decryption in java where encryption is done in c#

问题

public static String encrypt(String clearText, String passphrase) {
    String encryptedText = null;
    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

        byte[] saltByte = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
        KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), saltByte, 1000, 256);
        SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
        IvParameterSpec iv = new IvParameterSpec(Arrays.copyOf(saltByte, 16));

        cipher.init(Cipher.ENCRYPT_MODE, key, iv);
        byte[] encryptedBytes = cipher.doFinal(clearText.getBytes());
        encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return encryptedText;
}
public static String decrypt(String cipherText, String passphrase) {
    String decryptedText = null;
    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

        byte[] saltByte = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
        KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), saltByte, 1000, 256);
        SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
        IvParameterSpec iv = new IvParameterSpec(Arrays.copyOf(saltByte, 16));

        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));
        decryptedText = new String(decryptedBytes);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return decryptedText;
}

Please note that the provided Java code snippets are equivalent to the C# encryption and decryption functions you provided. However, make sure to properly handle exceptions and consider security best practices when implementing encryption and decryption in your application.

英文:

I am trying to decrypt the string which is encrypted in c# with same key length and vector.

JAVA CODE

public static void main(String[] args) {
		// TODO Auto-generated method stub
		
	    String cum006333 = decrypt("h+VJ5or2yBFQYawNWXET11nekUzWYYVWk0/O2fHxoLNm60l3d3qQo2NJjGr3+zZP", "MYPRIVATE@KEY");
	    System.out.println(cum006333);

	}

	public static String decrypt(String cipherText, String passphrase) {
	    String s = null;
	    try {

	    	Cipher   cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
	    	SecretKeyFactory  factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
	        
	        byte[] bytes = Base64.getDecoder().decode(cipherText);
	        int keySize = 256;
	        int iterCount = 1000;

	        int ivLength = 16;
	        byte[] saltByte = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
	        byte[] ivB = Arrays.copyOf(bytes, ivLength);
	        byte[] data = Arrays.copyOfRange(bytes,ivLength, bytes.length);

	        KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), saltByte, iterCount, keySize);
	        SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
	        IvParameterSpec iv = new IvParameterSpec(ivB);
	        cipher.init(Cipher.DECRYPT_MODE, key, iv);
	        byte[] original = cipher.doFinal(data);
	        s = new String(original);
	        System.out.println(s);
	    } catch (Exception ex) {
	        ex.printStackTrace();
	    }
	    return s;
	}

	
}

expexted output is - Duplicate Request ID

output coming is - e Request Id

I need to encrypt the request in java and send to api where they will decrypt it and use it. So i want java equivalent of the below C# code..

please find C# code used for encrypting and decrypting below

public static string EncryptResponse(string clearText)
    {
        string EncryptionKey = System.Configuration.ConfigurationManager.AppSettings["SECRETMSG"].ToString();
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes rfcdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = rfcdb.GetBytes(32);
            encryptor.IV = rfcdb.GetBytes(16);
            using (MemoryStream mem = new MemoryStream())
            {
                using (CryptoStream cryp = new CryptoStream(mem, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cryp.Write(clearBytes, 0, clearBytes.Length);
                    cryp.Close();
                }
                clearText = Convert.ToBase64String(mem.ToArray());
            }
        }
        return clearText;
    }


    public static string DecryptResponse(string cipherText)
    {
        string EncryptionKey = System.Configuration.ConfigurationManager.AppSettings["SECRETMSG"].ToString();
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes rfcdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = rfcdb.GetBytes(32);
            encryptor.IV = rfcdb.GetBytes(16);

            using (MemoryStream mem = new MemoryStream())
            {
                using (CryptoStream cryp = new CryptoStream(mem, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cryp.Write(cipherBytes, 0, cipherBytes.Length);
                    cryp.Close();
                }
                cipherText = Encoding.Unicode.GetString(mem.ToArray());
            }
        }
        return cipherText;
    }

答案1

得分: 1

很遗憾,你没有展示C#中的加密代码,这会直接指向解决方案,而不是争论和搜索。

你声称“截断”的原因不在于Java端(解密),而在于你的C#加密函数。很可能你对明文使用了UTF-16编码,而在Java端使用了标准编码(UTF-8)。

以下是稍微修改过的代码版本,其中为了确保所有数据具有正确的长度,添加了专门的输出。

观察“.doFinal”输出,我们可以看到一个值为(十六进制)“650020005200650071007500650073007400200049004400” - 每个字符之间有很多“x00”值,这明显是UTF-16编码,因此最终的字符串值不是e Request Id”,而是“e R e q u e s t I D”。

将“new String”编码更改为“new String(original, StandardCharsets.UTF_16LE)”会得到“正确”的输出“e Request ID” - 但起始处的“Duplicat”在哪里?我相信你同样也是通过“Array-copying”获取密文的(base64编码)字符串,并且只复制密文的最后12个(或在UTF-16中为24个)字节,所以 - 我所相信的 - 你在C#端截断了密文。

以下是输出和修改后的代码行:

输出:

First 8 bytes is truncating in AES decryption in java where encryption is done in c#
cipherByte length: 48 data: 87e549e68af6c8115061ac0d597113d759de914cd6618556934fced9f1f1a0b366eb4977777a90a363498c6af7fb364f
ivB        length: 16 data: 87e549e68af6c8115061ac0d597113d7
data       length: 32 data:                                 59de914cd6618556934fced9f1f1a0b366eb4977777a90a363498c6af7fb364f
original   length: 24 data: 650020005200650071007500650073007400200049004400
e   R e q u e s t   I D
e   R e q u e s t   I D

修改代码行:

s = new String(original);
改为
s = new String(original, StandardCharsets.UTF_16LE);

代码:

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 java.security.spec.KeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;

public class mainSo {

    public static void main(String[] args) {
        System.out.println("First 8 bytes is truncating in AES decryption in java where encryption is done in c#");
        String cipherstring = "h+VJ5or2yBFQYawNWXET11nekUzWYYVWk0/O2fHxoLNm60l3d3qQo2NJjGr3+zZP";
        byte[] cipherByte = Base64.getDecoder().decode(cipherstring);
        System.out.println("cipherByte length: " + cipherByte.length + " data: " + bytesToHex(cipherByte));
        String cum006333 = decrypt(cipherstring, "KEY@CRISIL123");
        System.out.println(cum006333);
    }

    public static String decrypt(String cipherText, String passphrase) {
        String s = null;
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            byte[] bytes = Base64.getDecoder().decode(cipherText);
            int keySize = 256;
            int iterCount = 1000;
            int ivLength = 16;
            byte[] saltByte = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
            byte[] ivB = Arrays.copyOf(bytes, ivLength);
            byte[] data = Arrays.copyOfRange(bytes, ivLength, bytes.length);
            System.out.println("ivB        length: " + ivB.length + " data: " + bytesToHex(ivB));
            System.out.println("data       length: " + data.length + " data:                                 " + bytesToHex(data));
            KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), saltByte, iterCount, keySize);
            SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
            IvParameterSpec iv = new IvParameterSpec(ivB);
            cipher.init(Cipher.DECRYPT_MODE, key, iv);
            byte[] original = cipher.doFinal(data);
            System.out.println("original   length: " + original.length + " data: " + bytesToHex(original));
            s = new String(original);
            //s = new String(original, StandardCharsets.UTF_16LE);
            System.out.println(s);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return s;
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuffer result = new StringBuffer();
        for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
        return result.toString();
    }
}
英文:

What a shame that you don't show us the encryption code in C# as it would point us directly to the solution instead of arguing and searching.

The reason for your claiming of "truncating" is not on Java-side (decryption) but on your c# encryption function. Most probably you are using a UTF-16 encoding for your plaintext but on Java-side the standard encoding (UTF-8) takes place.

Below you find a slightly added version of your code with dedicated outputs for your data to be fore sure all data has the right length.

Having a look on the ".doFinal" output we see a value of (hex) "650020005200650071007500650073007400200049004400" - a lot of "x00" values between each character that is definitely a UTF-16 encoding, so in the end the string value is not "e Request Id" but "e R e q u e s t I D".

Changing the "new String" encoding to "new String(original, StandardCharsets.UTF_16LE)" get the "correct" output of "e Request ID" - but where is the missing
"Duplicat" in the beginning? I'm sure you are getting the (base64 encoded) string of ciphertext by "Array-copying" as well and you are just copy the last 12 (or 24 in UTF-16) bytes of the ciphertext so - what I am believing - you are truncating the ciphertext on C#-side.

output

First 8 bytes is truncating in AES decryption in java where encryption is done in c#
cipherByte length: 48 data: 87e549e68af6c8115061ac0d597113d759de914cd6618556934fced9f1f1a0b366eb4977777a90a363498c6af7fb364f
ivB        length: 16 data: 87e549e68af6c8115061ac0d597113d7
data       length: 32 data:                                 59de914cd6618556934fced9f1f1a0b366eb4977777a90a363498c6af7fb364f
original   length: 24 data: 650020005200650071007500650073007400200049004400
e   R e q u e s t   I D
e   R e q u e s t   I D

change code line

s = new String(original);
to
s = new String(original, StandardCharsets.UTF_16LE);

gives:

e Request ID

code:

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 java.security.spec.KeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
public class mainSo {
public static void main(String[] args) {
System.out.println("First 8 bytes is truncating in AES decryption in java where encryption is done in c#");
String cipherstring = "h+VJ5or2yBFQYawNWXET11nekUzWYYVWk0/O2fHxoLNm60l3d3qQo2NJjGr3+zZP";
byte[] cipherByte = Base64.getDecoder().decode(cipherstring);
System.out.println("cipherByte length: " + cipherByte.length + " data: " + bytesToHex(cipherByte));
String cum006333 = decrypt(cipherstring, "KEY@CRISIL123");
System.out.println(cum006333);
}
public static String decrypt(String cipherText, String passphrase) {
String s = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] bytes = Base64.getDecoder().decode(cipherText);
int keySize = 256;
int iterCount = 1000;
int ivLength = 16;
byte[] saltByte = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
byte[] ivB = Arrays.copyOf(bytes, ivLength);
byte[] data = Arrays.copyOfRange(bytes,ivLength, bytes.length);
System.out.println("ivB        length: " + ivB.length + " data: " + bytesToHex(ivB));
System.out.println("data       length: " + data.length + " data:                                 " + bytesToHex(data));
KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), saltByte, iterCount, keySize);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
IvParameterSpec iv = new IvParameterSpec(ivB);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] original = cipher.doFinal(data);
System.out.println("original   length: " + original.length + " data: " + bytesToHex(original));
s = new String(original);
//s = new String(original, StandardCharsets.UTF_16LE);
System.out.println(s);
} catch (Exception ex) {
ex.printStackTrace();
}
return s;
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}

答案2

得分: 1

由于您请求只返回翻译的代码部分,以下是您提供的代码的翻译版本:

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 java.nio.charset.StandardCharsets;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;

public class mainSo2 {

    public static void main(String[] args) {
        System.out.println("在 Java 中,AES 解密时会截断前 8 个字节,而在 C# 中进行加密");
        String cipherstring = "h+VJ5or2yBFQYawNWXET11nekUzWYYVWk0/O2fHxoLNm60l3d3qQo2NJjGr3+zZP";
        byte[] cipherByte = Base64.getDecoder().decode(cipherstring);
        System.out.println("cipherByte 长度:" + cipherByte.length + " 数据:" + bytesToHex(cipherByte));
        String decryptedText = decrypt(cipherstring, "KEY@CRISIL123");
        System.out.println(decryptedText);
    }

    public static String decrypt(String cipherText, String passphrase) {
        String s = null;
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            byte[] bytes = Base64.getDecoder().decode(cipherText);
            int keySize = 256;
            int iterCount = 1000;
            int ivLength = 16;
            byte[] saltByte = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
            KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), saltByte, iterCount, (keySize + (8 * ivLength))); // 32 + 16
            byte[] rawKey = factory.generateSecret(spec).getEncoded(); // 48 字节
            byte[] keyDerived = Arrays.copyOf(rawKey, (keySize / 8)); // 前 32 字节
            byte[] ivB = Arrays.copyOfRange(rawKey, (keySize / 8), rawKey.length); // 后 16 字节
            System.out.println("keyDerived 长度:" + keyDerived.length + " 数据:" + bytesToHex(keyDerived));
            System.out.println("ivB        长度:" + ivB.length + " 数据:" + bytesToHex(ivB));
            SecretKey key = new SecretKeySpec(keyDerived, "AES");
            IvParameterSpec iv = new IvParameterSpec(ivB);
            cipher.init(Cipher.DECRYPT_MODE, key, iv);
            byte[] original = cipher.doFinal(bytes);
            System.out.println("original   长度:" + original.length + " 数据:" + bytesToHex(original));
            s = new String(original, StandardCharsets.UTF_16LE);
            System.out.println(s);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return s;
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuffer result = new StringBuffer();
        for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
        return result.toString();
    }
}

注意:由于您的代码涉及一些具体的技术内容,本翻译可能无法完全反映原始代码的含义和功能。如果您有任何关于翻译结果的疑问,欢迎随时提问。

英文:

As I don't like to mix answers I'm writing a second answer with the final solution for your question.

Thanks for providing the C#-code as it answered 2 questions - what is the encoding of the plaintext and what data is included in the ciphertext.

Using this line on C# shows us that the encoding is UNICODE (=UTF 16) as I argued in my first answer:

byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);

To get identical results in Java you need to decode any decryption result with

s = new String(original, StandardCharsets.UTF_16LE);

The second question - what is included in the ciphertext is answered very simple - just the ciphertext itself (no IV). The neccessary IV is derived by the

Rfc2898DeriveBytes...
encryptor.Key = rfcdb.GetBytes(32);
encryptor.IV = rfcdb.GetBytes(16);

Putting both information together I can decrypt the ciphertext with the given key as follows:

First 8 bytes is truncating in AES decryption in java where encryption is done in c#
cipherByte length: 48 data: 87e549e68af6c8115061ac0d597113d759de914cd6618556934fced9f1f1a0b366eb4977777a90a363498c6af7fb364f
keyDerived length: 32 data: e35b88684a86fe06ae80eab429b2c9c242ab64f225649aa484ced8f53e5de146
ivB        length: 16 data: 19b9e11cb1e6c6aa69060fbdfe10484c
original   length: 40 data: 4400750070006c006900630061007400650020005200650071007500650073007400200049004400
Duplicate Request ID
Duplicate Request ID

Here is the complete code:

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 java.nio.charset.StandardCharsets;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;
public class mainSo2 {
public static void main(String[] args) {
System.out.println("First 8 bytes is truncating in AES decryption in java where encryption is done in c#");
String cipherstring = "h+VJ5or2yBFQYawNWXET11nekUzWYYVWk0/O2fHxoLNm60l3d3qQo2NJjGr3+zZP";
byte[] cipherByte = Base64.getDecoder().decode(cipherstring);
System.out.println("cipherByte length: " + cipherByte.length + " data: " + bytesToHex(cipherByte));
String cum006333 = decrypt(cipherstring, "KEY@CRISIL123");
System.out.println(cum006333);
}
public static String decrypt(String cipherText, String passphrase) {
String s = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] bytes = Base64.getDecoder().decode(cipherText);
int keySize = 256;
int iterCount = 1000;
int ivLength = 16;
byte[] saltByte = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), saltByte, iterCount, (keySize + (8 * ivLength))); // 32 + 16
byte[] rawKey = factory.generateSecret(spec).getEncoded(); // 48 bytes
byte[] keyDerived = Arrays.copyOf(rawKey, (keySize / 8)); // first 32 bytes
byte[] ivB = Arrays.copyOfRange(rawKey, (keySize / 8), rawKey.length); // last 16 bytes
System.out.println("keyDerived length: " + keyDerived.length + " data: " + bytesToHex(keyDerived));
System.out.println("ivB        length: " + ivB.length + " data: " + bytesToHex(ivB));
SecretKey key = new SecretKeySpec(keyDerived, "AES");
IvParameterSpec iv = new IvParameterSpec(ivB);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
//byte[] original = cipher.doFinal(data);
byte[] original = cipher.doFinal(bytes);
System.out.println("original   length: " + original.length + " data: " + bytesToHex(original));
s = new String(original, StandardCharsets.UTF_16LE);
System.out.println(s);
} catch (Exception ex) {
ex.printStackTrace();
}
return s;
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}

huangapple
  • 本文由 发表于 2020年9月28日 19:59:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/64101756.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定