我一直试图通过使用BouncyCastle套件在java中使用3DES加密明文而不成功。该结果应该与现有C#实现产生的结果相匹配,因为我计划稍后对其进行解密。
虽然我确信我已经在Java中生成了“等效”的C#算法,但我仍然得到了不同的结果。有人可以仔细查看两个片段并提出建议吗?我将非常感激。
C#加密:
public static byte[] encryptStringToBytes_3DES(string plainText, string passKey)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
// Declare the streams used
// to encrypt to an in memory
// array of bytes.
MemoryStream msEncrypt = null;
CryptoStream csEncrypt = null;
StreamWriter swEncrypt = null;
ASCIIEncoding ascii = new System.Text.ASCIIEncoding();
// used to encrypt the data.
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
string passphrase = passKey;
byte[] iv = ascii.GetBytes("AVREWASH");
byte[] key = ascii.GetBytes(passphrase);
try
{
// Create a TripleDES object
// with the specified key and IV.
//Console.WriteLine("Key size is " + tdes.KeySize+" and IV is "+tdes.IV+" and that of key is "+key.Length);
tdes.Key = key;
tdes.IV = iv;
tdes.Padding = PaddingMode.Zeros;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = tdes.CreateEncryptor(tdes.Key, tdes.IV);
// Create the streams used for encryption.
msEncrypt = new MemoryStream();
csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
swEncrypt = new StreamWriter(csEncrypt);
//Write all data to the stream.
swEncrypt.Write(plainText);
}
catch (Exception ex)
{
Console.WriteLine("Error is " + ex.Message);
while (true)
{
}
}
finally
{
// Clean things up.
// Close the streams.
if (swEncrypt != null)
swEncrypt.Close();
if (csEncrypt != null)
csEncrypt.Close();
if (msEncrypt != null)
msEncrypt.Close();
// Clear the TripleDES object.
if (tdes != null)
tdes.Clear();
}
// Return the encrypted bytes from the memory stream.
return msEncrypt.ToArray();
}
我将这个辅助函数用于将结果转换为Hex ...
public static string ByteArrayToString(byte[] ba)
{
string hex = BitConverter.ToString(ba);
return hex.Replace("-", "");
}
Java片段应该进行“等效”加密:
public void encrypt(String plaintext, String IV, String tripleDesKey){
try{
SecretKey keySpec = new SecretKeySpec(tripleDesKey.getBytes("US-ASCII"),"DESede");
IvParameterSpec iv = new IvParameterSpec(IV.getBytes("US-ASCII"));
Cipher e_cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
e_cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte [] cipherText = e_cipher.doFinal(plaintext.trim().getBytes("US-ASCII"));
System.out.println("Ciphertext: " + asHex(cipherText));
}
catch(Exception exc){
ex.printStackTrace();
}
}
这是相应的Hex ..函数
public static String asHex (byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10)
strbuf.append("0");
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
请帮助。
答案 0 :(得分:3)
您正在使用不同的填充模式。在C#中你写了tdes.Padding = PaddingMode.Zeros;
在Java中,您在CBC模式下使用了PKCS5Padding。这不是一回事。
答案 1 :(得分:3)
一些意见:
.NET TripleDESCryptoServiceProvider的默认模式确实是CBC,这是您在JAVA代码中明确指定的,但如果您在C#代码中明确指定它也不会受到影响。
在原始代码中,您在C#代码中使用PaddingMode.Zeros,但在JAVA代码中使用PKCS5Padding。 Java中没有内置的密码提供程序,它提供了相当于PaddingMode.Zeros的AFAIK。如果您仍然可以更改C#代码,则应使用PaddingMode.Pkcs7。否则,您必须搜索将执行此任务的Java的第三方密码提供程序。
避免使用ASCII编码,除非您能够保证输入实际上包含7位ascii。如果传入包含其他字符的字符串,则输出未定义。
传递给3DES构造函数的关键数据长度应为8,16或24,并且 - 通常 - 设置DES奇偶校验位。 AFAIK .NET和Java都将忽略奇偶校验位,但如果密钥长度不属于任何一个正确的值,它们的行为可能会有所不同。因此,如果您希望加密适用于任何可能的键输入,则应使用.NET和Java都支持的键派生函数。在Java中尝试PBEWithHmacSHA1AndDESede,在C#中添加使用System.Security.Cryptography.Rfc2898DeriveBytes转换passKey的代码。