Java DES解密代码转C#实现的密钥与填充问题咨询
DES解密:Java到C#的移植问题
问题描述
我有一段Java的DES解密代码:
try { byte[] key = new String(keyString).getBytes(); byte[] enc = Base64.getDecoder().decode(encryptedMessage); SecretKey generateSecret = SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(key)); Cipher cipher = Cipher.getInstance("DES"); cipher.init(2, generateSecret); String dec = new String(cipher.doFinal(enc)); } catch (Exception ex) { }
现在要移植到C#,但不清楚Java中SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(key))这部分的逻辑怎么处理。我当前的C#代码如下:
byte[] enc = Convert.FromBase64String(encryptedMessage); byte[] key = Encoding.UTF8.GetBytes(keyString); using (DESCryptoServiceProvider des = new DESCryptoServiceProvider()) { des.Key = key; ICryptoTransform desDecrypt = des.CreateDecryptor(); byte[] result = desDecrypt.TransformFinalBlock(enc, 0, enc.Length); return Encoding.UTF8.GetString(result); }
我的keyString长度超过30字节,而DES的Key只需要8字节。查DESKeySpec文档知道它会取前8字节作为密钥,但按这个处理后代码因填充错误崩溃,求正确的处理方式。
解决方案
问题核心是Java和C#默认的DES工作模式、填充模式不一致,加上密钥处理的细节差异,具体修复步骤如下:
对齐Java的密钥处理逻辑
Java的DESKeySpec会直接取密钥字节数组的前8个字节,但注意Java中new String(keyString).getBytes()默认使用平台默认编码(通常为UTF-8,旧环境可能是GBK),C#中需使用相同编码获取字节数组后截取前8字节:// 若Java端用的不是UTF-8,替换为对应编码,比如Encoding.GetEncoding("GBK") byte[] keyBytes = Encoding.UTF8.GetBytes(keyString); // 截取前8字节作为DES密钥 byte[] desKey = keyBytes.Take(8).ToArray();对齐DES的工作模式与填充模式
Java中Cipher.getInstance("DES")默认对应DES/ECB/PKCS5Padding,而C#的DESCryptoServiceProvider默认工作模式为CipherMode.CBC,这是导致填充错误的核心原因。需显式设置为ECB模式,填充模式用PKCS7(与Java的PKCS5Padding完全兼容):byte[] enc = Convert.FromBase64String(encryptedMessage); byte[] keyBytes = Encoding.UTF8.GetBytes(keyString); byte[] desKey = keyBytes.Take(8).ToArray(); using (DESCryptoServiceProvider des = new DESCryptoServiceProvider()) { des.Key = desKey; // 对齐Java默认工作模式:ECB des.Mode = CipherMode.ECB; // PKCS7与Java的PKCS5Padding兼容 des.Padding = PaddingMode.PKCS7; ICryptoTransform desDecrypt = des.CreateDecryptor(); byte[] result = desDecrypt.TransformFinalBlock(enc, 0, enc.Length); return Encoding.UTF8.GetString(result); }额外排查要点
- 确认Java端
getBytes()使用的编码,若不是UTF-8必须同步修改C#的编码类型,否则密钥会不匹配 - 若Java加密时使用了CBC模式,C#需同步设置
CipherMode.CBC并指定相同的IV向量(Java默认会生成随机IV,但如果是固定IV需手动传入) - 不要吞掉异常,打印具体错误信息(如填充错误、密钥不匹配),便于快速定位问题
- 确认Java端
内容的提问来源于stack exchange,提问作者Luka
相关产品推荐
相关产品推荐

