将 DES 加密数据从 Java 解密到 .Net
我在解密使用 DES 算法在 Java 中加密的加密字符串时遇到问题。我认为我的主要问题是,我在 java 代码中没有看到任何 salt 或 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 字节,但如果我不这样做,加密流会抛出一个错误,指出要解密的数据太短。
如果我尝试这种方式,我只会得到垃圾作为输出。我使用空的盐和 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 使用无符号字节来执行其所有功能。这可能是问题所在吗?
I have a problem decrypting an encrypted string that was encrypted in Java using the DES algorithm. I think my main problem is, that I don't see any salt or IV specifications in the java code.
I have following information:
This HexSequence is the encrypted data I have to decrypt: 9465E19A6B9060D75C3F7256ED1F4D21EDC18BB185304B92061308A32725BE760F1847E3B19C1D3548F61165EA2E785E48F61165EA2E78
Algorithm: DES, Padding: DES/ECB/NoPadding, Key: TESTKEY123
After decryption I should get: 550000000018h000000273Al2011112214340600000000000000000000000000
The java-code used to encrypt the data looks like this:
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 "";
}
}
I tried to use following .net-code to decrypt the data:
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);
}
}
What's strange is that line:
byte[] bytes = new byte[(hexCodeSequence.Length / 2) + 1];
The data is 55 bytes long but I have to put it in 56 bytes. It appends a 0-byte to the and of the array, but if I don't do this the cryptostream throws an error that the data to decrypt is too short.
If I try it this way I only get garbage as output. I'm using a empty salt and IV because I can't see which salt and IV the java code is using. Are there any default values I don't know?
EDIT:
Java code to get the byte out of the hexCode:
private static byte getNegativeValueForHexConversion(String hexCode) {
int i = Integer.parseInt(hexCode, 16);
return (byte) (i > 127 ? i - 256 : i);
}
Looks like Java uses a signed byte and .Net uses an unsigned byte for all its functions. Is this maybe the problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
DES 是一种块大小为 64 位的块密码。因此(至少在 ECB 模式下)您必须解密的密文必须是 64 位(8 字节)长的倍数。你的是 55 个字节,所以你没有完整的密文 - 这就是为什么你必须添加一个零字节。您自己运行 Java 代码并看到输出有 55 个字节长吗?这是复制粘贴错误吗?
例外情况是 DES 在有效创建密钥流的模式中使用,然后与明文进行异或以生成密文。这包括 CFB、OFB 和 CTR 模式。因此,一种可能性是使用其中之一进行解密(我突然想起来,我不记得 .NET 加密库是否支持 CTR)。您确定 Java 代码中指定了 ECB 吗?
而且,您还遇到一个问题,Java 代码看起来像是从关键文本进行简单的文本到十六进制转换以获取关键字节,而 .NET 代码正在执行 RFC-2898 兼容转换,这不会为您提供相同的密钥字节。
DES is a block cipher with a 64-bit block size. Thus (in ECB mode at least) the ciphertext you have to decrypt must be a multiple of 64 bits (8 bytes) long. Yours is 55 bytes, so you do not have the full ciphertext - this is why you're having to add a zero byte. Have you run the Java code yourself and seen that the output is 55 bytes long? Is this a copy and paste error?
The exception to this would be DES used in a mode which effectively creates a key stream, that is then XORed with the plaintext to produce the ciphertext. This would include CFB, OFB and CTR modes. So one possibility is that decrypting with one of these would work (off the top of my head, I can't remember whether the .NET crypto libraries support CTR). Are you sure that ECB was specified in the Java code?
But also, you have the problem that the Java code looks like it's doing a straightforward text to hex conversion from the key text to get the key bytes, whereas the .NET code is doing an RFC-2898 compatible conversion, which will not give you the same key bytes.