下面我将提供一个完整、可运行的 C# 加密和 Java 解密的示例,并详细解释关键步骤和注意事项,以确保它们能够正确配合工作。
核心原则
要实现 C# 和 Java 之间的 DES 加密解密,必须确保以下四个方面在两端完全一致:
- 算法:
DES(在 Java 中通常写作DES/CBC/PKCS5Padding)。 - 密钥: 必须是 8 字节(64 位)的原始字节数组,两端需要使用完全相同的密钥。
- 初始化向量: 必须是 8 字节的原始字节数组,两端需要使用完全相同的 IV。IV 不需要保密,但必须与加密时使用的 IV 完全一致。
- 加密模式与填充: 通常使用
CBC模式和PKCS5Padding或PKCS7Padding(对于 DES,两者效果相同)。
第一步:C# 加密代码
我们将创建一个 C# 控制台应用程序来执行加密。
创建 C# 项目
使用 Visual Studio 或 dotnet new console 创建一个新的 C# 控制台项目。
编写 C# 加密代码
在 Program.cs 文件中,粘贴以下代码。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class CSharpEncryptor
{
// 必须是8字节 (64位) 的密钥
private static readonly byte[] Key = Encoding.UTF8.GetBytes("12345678"); // 示例密钥,请替换为你自己的密钥
// IV 也必须是8字节,对于CBC模式,它和密钥同样重要
private static readonly byte[] IV = Encoding.UTF8.GetBytes("abcdefgh"); // 示例IV,请替换为你自己的IV
public static byte[] Encrypt(string plainText)
{
// 使用 DES 算法,CBC 模式,PKCS7 填充
using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
{
des.Key = Key;
des.IV = IV;
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;
// 创建加密器
ICryptoTransform encryptor = des.CreateEncryptor(des.Key, des.IV);
// 将明文转换为字节数组
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
// 使用 MemoryStream 和 CryptoStream 进行加密
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(plainBytes, 0, plainBytes.Length);
cs.FlushFinalBlock();
}
// 返回加密后的字节数组
return ms.ToArray();
}
}
}
public static void Main(string[] args)
{
string originalText = "这是一段需要加密的秘密信息,Hello, World!";
Console.WriteLine("原始文本: " + originalText);
// 加密
byte[] encryptedBytes = Encrypt(originalText);
// 为了方便传输,通常将字节数组转换为 Base64 字符串
string encryptedBase64 = Convert.ToBase64String(encryptedBytes);
Console.WriteLine("加密后的 Base64 字符串: " + encryptedBase64);
// 将这个 Base64 字符串传递给 Java 程序进行解密
// 你可以将它保存到文件或通过网络发送
File.WriteAllText("encrypted_data.txt", encryptedBase64);
Console.WriteLine("加密数据已保存到 encrypted_data.txt");
}
}
C# 代码要点:
DESCryptoServiceProvider是 C# 中实现 DES 算法的标准类。- 我们显式设置了
Mode = CipherMode.CBC和Padding = PaddingMode.PKCS7。 - 加密结果是一个
byte[],我们使用Convert.ToBase64String将其转换为字符串,这样可以方便地在文本文件或网络中传输。
第二步:Java 解密代码
我们创建一个 Java 程序来读取 C# 生成的加密文件并解密它。
创建 Java 项目
使用你喜欢的 IDE(如 IntelliJ IDEA, Eclipse)或命令行创建一个新的 Java 项目。
编写 Java 解密代码
在主类中,粘贴以下代码。
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
public class JavaDecryptor {
// C# 端使用的密钥和 IV,必须完全一致
private static final String KEY = "12345678"; // 8 bytes
private static final String IV = "abcdefgh"; // 8 bytes
public static String decrypt(String encryptedBase64) throws Exception {
// 1. 准备密钥和 IV
// SecretKeySpec 需要 key 的字节数组
SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "DES");
// IvParameterSpec 需要 IV 的字节数组
IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
// 2. 创建 Cipher 实例
// "DES/CBC/PKCS5Padding" 是 Java 中描述算法的标准格式
// DES: 算法
// CBC: 加密模式
// PKCS5Padding: 填充方式
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
// 3. 初始化 Cipher 为解密模式
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
// 4. 解密
// Base64 解码
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedBase64);
// 执行解密
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
// 5. 将解密后的字节数组转换回字符串
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
public static void main(String[] args) {
try {
// 从 C# 生成的文件中读取加密数据
String encryptedBase64 = new String(Files.readAllBytes(Paths.get("encrypted_data.txt")));
System.out.println("从文件读取的加密 Base64 字符串: " + encryptedBase64);
// 解密
String decryptedText = decrypt(encryptedBase64);
System.out.println("解密后的文本: " + decryptedText);
} catch (Exception e) {
e.printStackTrace();
System.err.println("解密过程中发生错误: " + e.getMessage());
}
}
}
Java 代码要点:
Cipher.getInstance("DES/CBC/PKCS5Padding")是关键,这个字符串明确指定了算法、模式和填充,必须与 C# 端的逻辑完全对应。SecretKeySpec和IvParameterSpec分别用于包装密钥和 IV。- Java 8+ 使用
java.util.Base64进行 Base64 编码/解码,这与 C# 的Convert.ToBase64String兼容。 cipher.init(Cipher.DECRYPT_MODE, ...)将Cipher对象设置为解密模式。
第三步:运行和验证
-
运行 C# 程序:
- 执行
CSharpEncryptor。 - 它会在控制台打印出加密后的 Base64 字符串,并在项目根目录下创建一个名为
encrypted_data.txt的文件,内容就是这个 Base64 字符串。
- 执行
-
运行 Java 程序:
- 确保你的 Java 项目可以访问到
encrypted_data.txt文件(通常将它放在与 Java 源代码相同的目录下,或者指定正确的路径)。 - 执行
JavaDecryptor。 - 它会读取
encrypted_data.txt,解密其中的内容,并在控制台打印出原始的明文。
- 确保你的 Java 项目可以访问到
如果一切配置正确,你将在 Java 的控制台看到与 C# 程序原始文本完全相同的内容。
常见问题与排查
如果解密失败(抛出 BadPaddingException 或 IllegalBlockSizeException),请按以下顺序检查:
- 密钥: 确保 C# 和 Java 中的
KEY字符串完全相同,并且长度为 8 个字符。 - IV: 确保 C# 和 Java 中的
IV字符串完全相同,并且长度为 8 个字符。 - 填充: 确保 C# 的
PaddingMode.PKCS7和 Java 的PKCS5Padding匹配,对于 DES,它们是等价的。 - 模式: 确保 C# 的
CipherMode.CBC和 Java 的CBC匹配。 - Base64: 确保 Java 正确读取了 C# 写入的 Base64 字符串,没有多余的空格或换行符。
File.WriteAllText通常是安全的,但如果手动处理,请小心。 - 编码: 明文和密钥/IV 的编码(C# 和 Java 都使用 UTF-8)必须一致。
安全性警告
- DES 算法已经过时:它的密钥长度(56位)太短,很容易被暴力破解。绝对不要在新的、对安全性有要求的系统中使用 DES。
- 此示例仅用于演示跨语言加密解密的原理。
- 在实际应用中,请考虑使用更安全的算法,如 AES(高级加密标准),AES 的实现原理与 DES 类似,只需将算法名称、密钥长度等参数更换即可。
