我在解密使用DES算法在Java中加密的加密字符串时遇到问题。我认为我的主要问题是,我在java代码中没有看到任何盐或IV规范。
我有以下信息: 这个HexSequence是我必须解密的加密数据:9465E19A6B9060D75C3F7256ED1F4D21EDC18BB185304B92061308A32725BE760F1847E3B19C1D3548F61165EA2E785E48F61165EA2E78
算法:DES,填充:DES / ECB / NoPadding,密钥:TESTKEY123
解密后我应该得到:550000000018h000000273Al2011112214340600000000000000000000000000
用于加密数据的java代码如下所示:
public class Encryptor {
private SecretKey secretKey;
private Cipher cipher;
public Encryptor(String algorithmName, String paddingName, String key) {
String keyHexCode = StringUtils.convertUnicodeToHexCode(key.getBytes());
try {
byte[] desKeyData = StringUtils.convertHexStringToByteArray(keyHexCode);
DESKeySpec desKeySpec = null;
try {
desKeySpec = new DESKeySpec(desKeyData);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithmName);
try {
secretKey = keyFactory.generateSecret(desKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
try {
cipher = Cipher.getInstance(paddingName);
} catch (NoSuchPaddingException e) {
// TODO: handle exception
}
} catch (NoSuchAlgorithmException e) {
// TODO: handle exception
}
}
private void initEncryptor(int mode) {
try {
cipher.init(mode, secretKey);
} catch (InvalidKeyException e) {
// TODO: handle exception
}
}
public String encrypt(String clearText) {
initEncryptor(Cipher.ENCRYPT_MODE);
try {
// Encrypt the cleartext
byte[] encryptedBytes = cipher.doFinal(clearText.getBytes());
return StringUtils.convertUnicodeToHexCode(encryptedBytes).toUpperCase();
} catch (IllegalBlockSizeException e) {
// TODO: handle exception
} catch (BadPaddingException e) {
// TODO: handle exception
}
return "";
}
public String decrypt(String encryptedTextHex) {
byte[] encryptedText = StringUtils.convertHexCodeSequenceToUnicode(encryptedTextHex);
initEncryptor(Cipher.DECRYPT_MODE);
try {
// Decrypt the encryptedTextHex
return new String(cipher.doFinal(encryptedText));
} catch (IllegalBlockSizeException e) {
// TODO: handle exception
} catch (BadPaddingException e) {
// TODO: handle exception
}
return "";
}
}
我尝试使用以下.net代码来解密数据:
public class URLDecryptor
{
public static string GetValue(string Data)
{
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
byte[] bytes = System.Text.UnicodeEncoding.Unicode.GetBytes("TESTKEY123");
byte[] salt = new byte[8];
byte[] iv = new byte[8];
Rfc2898DeriveBytes password = new Rfc2898DeriveBytes("TESTKEY123", salt);
cryptoProvider.Key = password.GetBytes(8);
cryptoProvider.IV = iv;
cryptoProvider.Padding = PaddingMode.None;
cryptoProvider.Mode = CipherMode.ECB;
MemoryStream memStream = new MemoryStream(convertHexCodeSequenceToUnicode(Data));
CryptoStream cryptoStream = new CryptoStream(memStream, cryptoProvider.CreateDecryptor(cryptoProvider.Key, cryptoProvider.IV), CryptoStreamMode.Read);
StreamReader reader = new StreamReader(cryptoStream);
string value = reader.ReadToEnd;
reader.Close();
cryptoStream.Close();
return value;
}
private static byte[] convertHexCodeSequenceToUnicode(string hexCodeSequence)
{
byte[] bytes = new byte[(hexCodeSequence.Length / 2) + 1]; //This is strange
int index = 0;
int count = 0;
while (count < hexCodeSequence.Length) {
string hexCode = hexCodeSequence.Substring(count, 2);
bytes[index] = getHexValue(hexCode);
count += 2;
index += 1;
}
return bytes;
}
public static byte getHexValue(string hexCode)
{
return byte.Parse(hexCode, System.Globalization.NumberStyles.HexNumber);
}
}
奇怪的是那条线:
byte[] bytes = new byte[(hexCodeSequence.Length / 2) + 1];
数据长度为55个字节,但我必须将其放在56个字节中。它向数组和数组添加一个0字节,但是如果我不这样做,那么cryptostream会抛出一个错误,即要解密的数据太短。
如果我这样尝试,我只会输出垃圾。我使用空盐和IV,因为我无法看到java代码使用的是哪种盐和IV。有没有我不知道的默认值?
编辑: 用于从hexCode中获取字节的Java代码:
private static byte getNegativeValueForHexConversion(String hexCode) {
int i = Integer.parseInt(hexCode, 16);
return (byte) (i > 127 ? i - 256 : i);
}
看起来Java使用带符号的字节,而.Net使用无符号字节来表示其所有功能。这可能是问题吗?
答案 0 :(得分:2)
DES是具有64位块大小的分组密码。因此(至少在ECB模式下)您必须解密的密文必须是64位(8字节)长的倍数。你的是55字节,所以你没有完整的密文 - 这就是你必须添加一个零字节的原因。您是否自己运行Java代码并看到输出长度为55个字节?这是复制和粘贴错误吗?
对此的例外是DES在一种有效创建密钥流的模式中使用,然后与明文进行异或运算以生成密文。这将包括CFB,OFB和CTR模式。所以有一种可能性就是使用其中一种解密就行了(我不记得.NET加密库是否支持CTR)。您确定在Java代码中指定了ECB吗?
但是,你也遇到了这样的问题:Java代码看起来像是在从密钥文本转换到密钥字节的十六进制文本,而.NET代码正在进行RFC-2898兼容转换,这将是没有给你相同的关键字节。