.NET TripleDESCryptoServiceProvider 在 Java 中等效
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1400830/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
.NET TripleDESCryptoServiceProvider equivalent in Java
提问by David Hofmann
Please, just don't ask me why. I just have this code in .NET that encrypt/decrypt strings of data. I need now to make 'exactly' the same funcionality in java. I have tried several examples for DESede crypt, but none of them gives the same results as this class in .net.
拜托了,别问我为什么。我在 .NET 中只有这段代码,用于加密/解密数据字符串。我现在需要在 Java 中“完全”实现相同的功能。我已经为 DESede crypt 尝试了几个示例,但没有一个给出与 .net 中的此类相同的结果。
I even though on making a .net webserbvice behind ssl to serve this two methods writen in .net but it is just too stupid to do without exhausting all the posibilities.
我虽然在 ssl 后面制作了一个 .net webserbvice 来为这两种用 .net 编写的方法提供服务,但如果不穷尽所有的可能性就去做太愚蠢了。
Maybe some of you java people which are more related in the area will have on top of your heads how to make it.
也许你们中一些在该领域更相关的 Java 人将如何制作它。
Thanks !!!
谢谢 !!!
public class Encryption
{
private static byte[] sharedkey = {...};
private static byte[] sharedvector = {...};
public static String Decrypt(String val)
{
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
byte[] toDecrypt = Convert.FromBase64String(val);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, tdes.CreateDecryptor( sharedkey, sharedvector ), CryptoStreamMode.Write);
cs.Write(toDecrypt, 0, toDecrypt.Length);
cs.FlushFinalBlock();
return Encoding.UTF8.GetString(ms.ToArray());
}
public static String Encrypt(String val)
{
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
byte[] toEncrypt = Encoding.UTF8.GetBytes(val);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, tdes.CreateEncryptor( sharedkey, sharedvector ), CryptoStreamMode.Write);
cs.Write(toEncrypt, 0, toEncrypt.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
}
Samle input/output
示例输入/输出
String plain = "userNameHere:passwordHere";
Console.WriteLine("plain: " + plain);
String encrypted = Encrypt(plain);
Console.WriteLine("encrypted: " + encrypted);
// "zQPZgQHpjxR+41Bc6+2Bvqo7+pQAxBBVN+0V1tRXcOc="
String decripted = Decrypt(encrypted);
Console.WriteLine("decripted: " + decripted);
// "userNameHere:passwordHere"
回答by erickson
Code follows, but first a few notes.
代码如下,但首先要注意几点。
- A different initialization vector must be chosen for every message. Hard-coding the initialization vector does not make sense. The IV should be sent along with the cipher text to the message recipient (it's not secret).
- I used my own utility class for base-64 encoding. You can use
sun.misc.BASE64Encoderandsun.misc.BASE64Decoderinstead, use a third-party library like BouncyCastle, or write your own. - You are using 2-key triple DES, where the first key and the third key is the same. I modified
sharedkeyto reflect this, since the Java DESede cipher always requires a 192-bit key; it's up to the key generator to handle the keying option. - A CBC IV is only 64 bits. I've used only the first 64 bits of
sharedvector.
- 必须为每条消息选择不同的初始化向量。对初始化向量进行硬编码没有意义。IV 应该与密文一起发送给消息接收者(这不是秘密)。
- 我使用自己的实用程序类进行 base-64 编码。您可以使用
sun.misc.BASE64Encoder和sun.misc.BASE64Decoder替代,使用第三方库像BouncyCastle的,或自己编写。 - 您正在使用 2 键三重 DES,其中第一个密钥和第三个密钥相同。我进行了修改
sharedkey以反映这一点,因为 Java DESede 密码总是需要一个 192 位的密钥;由密钥生成器来处理键控选项。 - CBC IV 只有 64 位。我只使用了前 64 位的
sharedvector.
This class should inter-operate with the C# version.
此类应与 C# 版本互操作。
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Encryption
{
private static byte[] sharedkey = {
0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11,
0x12, 0x11, 0x0D, 0x0B, 0x07, 0x02, 0x04, 0x08,
0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11
};
private static byte[] sharedvector = {
0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11
};
public static void main(String... argv)
throws Exception
{
String plaintext = "userNameHere:passwordHere";
String ciphertext = encrypt(plaintext);
System.out.println(ciphertext);
System.out.println(decrypt(ciphertext));
}
public static String encrypt(String plaintext)
throws Exception
{
Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sharedkey, "DESede"), new IvParameterSpec(sharedvector));
byte[] encrypted = c.doFinal(plaintext.getBytes("UTF-8"));
return Base64.encode(encrypted);
}
public static String decrypt(String ciphertext)
throws Exception
{
Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sharedkey, "DESede"), new IvParameterSpec(sharedvector));
byte[] decrypted = c.doFinal(Base64.decode(ciphertext));
return new String(decrypted, "UTF-8");
}
}
Output:
输出:
zQPZgQHpjxR+41Bc6+2Bvqo7+pQAxBBVN+0V1tRXcOc=
userNameHere:passwordHere
zQPZgQHpjxR+41Bc6+2Bvqo7+pQAxBBVN+0V1tRXcOc=
此处为用户名:此处为密码
回答by ZZ Coder
You got a few problems,
你遇到了一些问题,
- Your key must be 24 bytes if you want generate the same key materials on both .NET and Java.
- The IV must be block size, which is 8 bytes for Triple DES.
- In Java, you need to specify the default mode and padding, which is "DESede/CBC/NoPadding".
- 如果您想在 .NET 和 Java 上生成相同的密钥材料,您的密钥必须是 24 个字节。
- IV 必须是块大小,对于三重 DES 是 8 个字节。
- 在Java中,需要指定默认模式和填充,即“DESede/CBC/NoPadding”。
Once you make these changes, you should be able to decrypt it on Java side.
进行这些更改后,您应该能够在 Java 端解密它。
回答by Kyle Rozendo
Have you made sure the .NET code uses the same padding as the Java code? I see no padding specified in the .NET code, that's why I ask.
您确定 .NET 代码使用与 Java 代码相同的填充吗?我看不到 .NET 代码中指定的填充,这就是我问的原因。
Do you happen to have the source for the Java code, it will help find mistakes.
您是否有 Java 代码的源代码,这将有助于查找错误。
回答by Kevin
Try the following. For actual usage, I would get a base64 library like commons codec or use the codec that comes with BouncyCastle
请尝试以下操作。对于实际使用,我会得到一个类似 commons 编解码器的 base64 库或使用 BouncyCastle 附带的编解码器
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class Encryption {
private static SecretKey sharedkey;
private static byte [] sharedvector;
static {
int keySize = 168;
int ivSize = 8;
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
keyGenerator.init(keySize);
sharedkey = keyGenerator.generateKey();
sharedvector = new byte [ivSize];
byte [] data = sharedkey.getEncoded();
int half = ivSize / 2;
System.arraycopy(data, data.length-half, sharedvector, 0, half);
System.arraycopy(sharedvector, 0, sharedvector, half, half);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static void main(String [] args) throws Exception {
System.out.println(Decrypt(Encrypt("Hello World")));
}
public static String Encrypt(String val) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, sharedkey, new IvParameterSpec(sharedvector));
return new sun.misc.BASE64Encoder().encode(cipher.doFinal(val.getBytes()));
}
public static String Decrypt(String val) throws GeneralSecurityException, IOException {
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, sharedkey, new IvParameterSpec(sharedvector));
return new String(cipher.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(val)));
}
}

