我正在开发一个 需要 Java中3DES加密的项目。问题是我已经(并将继续)提供128位十六进制密钥,如“0123456789ABCDEF0123456789ABCDEF”。转换为字节是没有问题的。然而, 的问题是Java Cryptographic Extensions API会阻塞此密钥,说它无效。我认为每个字节的MSB只是一个奇偶校验位,所以JCE希望我删除它们(或者我认为)。但是,在.NET中,我可以指定所提供的密钥,并且它可以安静地处理加密/解密而无需投诉。
有没有什么方法可以根据我提供的密钥生成JCE所期望的那种密钥?
我发现JCE允许你为DES加密指定一个8字节的密钥,所以我尝试使用提供的密钥的一半来实现3DES作为DES EDE。但是,我仍然在使用.NET获得不一致的结果。
这是Java代码:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
public class Main{
public static void main(String[] args) throws Exception {
byte [] plain = "I eat fish every day".getBytes("utf-8");
byte [] keyBytes = new byte [] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
};
byte [] key2Bytes = new byte [] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0 }; // actual keys replaced with dummies.
SecretKey keySpec = new SecretKeySpec(keyBytes, "DES");
SecretKey keySpec2 = new SecretKeySpec(key2Bytes, "DES");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher e_cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
e_cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
cipher.init(Cipher.DECRYPT_MODE, keySpec2, iv);
byte [] cipherText = e_cipher.doFinal(plain);
cipherText = cipher.doFinal(cipherText);
cipherText = e_cipher.doFinal(cipherText);
System.out.println("Ciphertext: " + new sun.misc.BASE64Encoder().encode(cipherText));
}
}
这是.NET代码:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace EncryptionDemo
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
// TODO: Implement Functionality Here
var plainBytes = Encoding.UTF8.GetBytes("I eat fish every day");
var keyBytes = new byte [] { 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
var tripleDES = TripleDESCryptoServiceProvider.Create();
var transform = tripleDES.CreateEncryptor(keyBytes, new byte [8]);
var memStream = new MemoryStream();
var cStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write);
cStream.Write(plainBytes, 0, plainBytes.Length);
cStream.FlushFinalBlock();
//memStream.Position = 0;
var cipherBytes = memStream.ToArray();
Console.WriteLine("Ciphertext: " + Convert.ToBase64String(cipherBytes));
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
两者都产生不同的输出(Base64字符串中的某些字符是相同的)
答案 0 :(得分:4)
3DES键长192位。
您是如何创建SecretKey
实例的?你得到什么错误信息?
问题中的Java代码使用的是DES,而不是“Triple DES”。算法名称应为"DESede/CBC/PKCS5Padding"
。您的答案中的代码可能有效,因为您获得了正确的算法,而不是因为您切换了提供商。 Java 6中的SunJCE提供程序将接受128位密钥(并使用密钥选项2)。我不确定旧版本。
答案 1 :(得分:1)
Sun提供商不接受16字节的3DES密钥,但BouncyCastle提供商会这样做。我只是尝试了它,它就像一个魅力 - 它产生与.NET代码相同的输出!
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class Main{
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
byte [] plain = "I eat fish every day".getBytes("utf-8");
byte [] keyBytes = new byte [] { (byte) 0xC1, (byte) 0x57, (byte) 0x45, (byte) 0x08,
(byte) 0x85, (byte) 0x02, (byte) 0xB0, (byte) 0xD3,
(byte) 0xA2, (byte) 0xEF, (byte) 0x68, (byte) 0x43,
(byte) 0x5E, (byte) 0xE6, (byte) 0xD0, (byte) 0x75 };
SecretKey keySpec = new SecretKeySpec(keyBytes, "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher e_cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding", "BC");
e_cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte [] cipherText = e_cipher.doFinal(plain);
System.out.println("Ciphertext: " + new sun.misc.BASE64Encoder().encode(cipherText));
}
}
答案 2 :(得分:1)
在jPOS项目中,总是使用单长度(8字节)或三长度(24字节)密钥来解决问题。假设你的双倍长度密钥(以字节为单位)是AAAAAAAA BBBBBBBB。到目前为止,我见过的jPOS项目中的所有代码都使用JCE将前8个字节再次附加到clear键,因此它成为三倍长度的密钥:AAAAAAAA BBBBBBBB AAAAAAAA。似乎Sun提供商确实接受这种材料来创建一个SecreKeySpec,因为它是192位长,正如@erickson所提到的那样。