
rc4加密输出的是任意字节序列,不能直接用new string(byte[])解释为字符串;否则会导致乱码、字符截断或解密错误,尤其在处理非ascii文本(如法语)时更为明显。正确做法是将密文以十六进制(hex)或base64编码表示。
rc4加密输出的是任意字节序列,不能直接用new string(byte[])解释为字符串;否则会导致乱码、字符截断或解密错误,尤其在处理非ascii文本(如法语)时更为明显。正确做法是将密文以十六进制(hex)或base64编码表示。
RC4是一种流密码算法,其核心操作基于字节异或(XOR),加密结果是任意取值的字节数组(0–255),其中大量字节对应不可见控制字符(如\u0000–\u001F)、无效Unicode代理对或无意义符号(如¯, ô, Î)。当你调用 new String(cipher) 时,Java 默认使用平台默认字符集(如UTF-8)尝试将这些原始字节“解释”为字符——但绝大多数密文字节根本不是合法的UTF-8/ISO-8859-1编码单元,因此会触发替换字符()、截断或静默损坏,导致后续解密失败(例如 "saisir" 变成 "saiÎir")。
✅ 正确做法:始终用无损二进制编码表示密文
不要将密文字节数组转为 String,而应使用标准无损编码格式进行显示和传输:
1. 推荐方案:十六进制(Hex)编码(最直观,适合教学演示)
// 工具方法:字节数组 → 十六进制字符串(小写,两位一组)
public static String toHex(byte[] bytes) {
StringBuilder hex = new StringBuilder();
for (byte b : bytes) {
hex.append(String.format("%02x", b & 0xFF));
}
return hex.toString();
}
// 使用示例(修改 main 中的加密输出部分):
String cipherText = toHex(rc.chiffrer(plain)); // ✅ 安全、可逆、可读
System.out.println("Le cryptogramme (hex) : " + cipherText);
2. 替代方案:Base64 编码(更紧凑,适合网络传输)
import java.util.Base64;
// 加密后:
String cipherText = Base64.getEncoder().encodeToString(rc.chiffrer(plain));
System.out.println("Le cryptogramme (base64) : " + cipherText);
// 解密前(需先解码):
byte[] cipherBytes = Base64.getDecoder().decode(cipherText);
byte[] plainBytes = rc.dechiffrer(cipherBytes);
String plainText = new String(plainBytes, StandardCharsets.UTF_8); // ✅ 指定UTF-8解码明文
⚠️ 关键注意事项
-
明文编码必须显式指定:plainText.getBytes() 使用平台默认编码(可能不是UTF-8),应在所有 getBytes() 和 new String() 处强制指定 StandardCharsets.UTF_8:
byte[] plain = plainText.getBytes(StandardCharsets.UTF_8); // ✅ 明确编码 String plainText = new String(plain, StandardCharsets.UTF_8); // ✅ 明确解码
-
密钥编码同样重要:keyText.getBytes() 也应指定编码,避免法语字符(如 é, ç)因平台差异被错误转换:
byte[] key = keyText.getBytes(StandardCharsets.UTF_8);
- RC4状态不可重用:当前实现中,chiffrer() 方法会修改内部 S 数组状态。若对同一 RC4 实例连续加密多段数据,会导致密钥流错位。教学演示中建议每次加密/解密都新建 RC4 实例(或重置状态),确保确定性。
✅ 完整修复后的 main 片段(含 Hex 输出与 UTF-8 显式编码)
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Saisir la clé secrète:");
String keyText = scanner.nextLine();
byte[] key = keyText.getBytes(StandardCharsets.UTF_8); // ✅ 强制UTF-8
System.out.println("Entrer a pour chiffrer et b pour déchiffrer:");
String choice = scanner.nextLine();
if ("a".equals(choice)) {
System.out.println("Saisir le mot à chiffrer:");
String plainText = scanner.nextLine();
byte[] plain = plainText.getBytes(StandardCharsets.UTF_8);
RC4 rc = new RC4(key); // ✅ 每次新建实例
byte[] cipher = rc.chiffrer(plain);
System.out.println("Le cryptogramme (hex) : " + toHex(cipher)); // ✅ Hex输出
}
else if ("b".equals(choice)) {
System.out.println("Saisir le cryptogramme en hex:");
String hexCipher = scanner.nextLine().trim();
byte[] cipher = hexStringToByteArray(hexCipher); // ✅ 自定义Hex解码
RC4 rc = new RC4(key);
byte[] plain = rc.dechiffrer(cipher);
System.out.println("Le texte en clair : " + new String(plain, StandardCharsets.UTF_8));
}
}
总结:RC4 的输入/输出本质是字节,而非字符串。将密文转为 String 是根本性误用。采用 Hex 或 Base64 编码,配合显式的 UTF-8 文本编解码,即可彻底解决法语等多语言环境下的乱码与解密异常问题,让您的演示清晰、可靠且专业。











