Java Android加密数据无法在C# Unity中解密的问题求助
Alright, let's dig into why your Unity C# code can't decrypt data encrypted by Java—even with matching keys. The issue almost always boils down to misaligned implementation details between the two languages, not the key itself. Let's walk through the most common culprits and how to fix them step by step:
1. Ensure Matching Encryption Mode & Padding Scheme
This is the #1 cause of cross-language encryption failures. Java and C# might default to different modes/padding if you don't explicitly specify them. For AES (the most common choice), you need to align on:
- Mode: CBC (recommended for security, avoid ECB)
- Padding: PKCS5Padding (Java) / PKCS7 (C#—these are functionally identical for AES, since AES uses 128-bit blocks)
Java Example (Explicit Parameters)
import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; public class Encryptor { public static byte[] encrypt(String plainText, byte[] key) throws Exception { // Explicitly define mode and padding Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // Generate and use a random IV (critical for security) byte[] iv = new byte[16]; // AES block size is 128 bits = 16 bytes new SecureRandom().nextBytes(iv); SecretKeySpec secretKey = new SecretKeySpec(key, "AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); byte[] encryptedData = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); // Prepend IV to encrypted data (we need it for decryption) byte[] result = new byte[iv.length + encryptedData.length]; System.arraycopy(iv, 0, result, 0, iv.length); System.arraycopy(encryptedData, 0, result, iv.length, encryptedData.length); return result; } }
Unity C# Example (Matching Parameters)
using System; using System.IO; using System.Security.Cryptography; using System.Text; using UnityEngine; public class Decryptor : MonoBehaviour { public static string Decrypt(byte[] encryptedWithIv, byte[] key) { using Aes aes = Aes.Create(); // Match Java's mode and padding aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.Key = key; // Extract IV from the start of the data byte[] iv = new byte[16]; Array.Copy(encryptedWithIv, 0, iv, 0, iv.Length); aes.IV = iv; // Extract encrypted data (after the IV) byte[] encryptedData = new byte[encryptedWithIv.Length - iv.Length]; Array.Copy(encryptedWithIv, iv.Length, encryptedData, 0, encryptedData.Length); // Decrypt using ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); using MemoryStream ms = new MemoryStream(encryptedData); using CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read); using StreamReader sr = new StreamReader(cs, Encoding.UTF8); return sr.ReadToEnd(); } }
2. Handle Initialization Vector (IV) Correctly
Many developers forget that IVs are required for modes like CBC, and they must be identical during encryption and decryption. Never hardcode an IV (bad for security)—instead:
- Generate a random IV in Java during encryption
- Prepend the IV to the encrypted data before writing to the file
- In C#, extract the IV from the start of the file before decrypting the remaining data
3. Verify Key Byte Consistency
Even if your key string is the same, Java and C# might convert it to bytes differently if you use the wrong encoding. Always use UTF-8 explicitly for key conversion:
Java Key Conversion
// Convert key string to bytes with UTF-8 byte[] keyBytes = "Your16ByteOr32ByteKey".getBytes(StandardCharsets.UTF_8);
C# Key Conversion
// Match Java's UTF-8 encoding byte[] keyBytes = Encoding.UTF8.GetBytes("Your16ByteOr32ByteKey");
Pro Tip: Print the byte array values in both languages to confirm they're identical (e.g.,
Arrays.toString(keyBytes)in Java,BitConverter.ToString(keyBytes)in C#).
4. Align Data Encoding & Storage Format
- Plaintext to Bytes: Always convert your plaintext string to bytes using UTF-8 in both languages (never rely on default encodings, which vary by system).
- Encrypted Data Storage: Choose a consistent format:
- Option 1: Write raw bytes (IV + encrypted data) directly to the file (used in the examples above).
- Option 2: Encode the encrypted data to Base64 before writing (easier for text files), then decode it in C# before decrypting.
Java Base64 Example
// After generating the IV + encrypted data byte array String base64Data = Base64.getEncoder().encodeToString(result); // Write base64Data to file as text
C# Base64 Example
// Read base64 string from file string base64Data = File.ReadAllText("encrypted.txt"); byte[] encryptedWithIv = Convert.FromBase64String(base64Data); // Proceed with decryption as before
5. Debugging Checklist
If you're still stuck, go through these checks:
- Print the IV used in Java and the IV extracted in C#—they must be identical.
- Compare the raw encrypted bytes (before any Base64 encoding) from Java with what C# reads from the file.
- Ensure both languages are using the same key length (128, 192, or 256 bits—your key string must be 16, 24, or 32 bytes long respectively when converted to UTF-8).
内容的提问来源于stack exchange,提问作者Alexandre Blanchet




