1

我一直在尝试使用 BouncyCastle 套件在 java 中使用 3DES 加密明文,但没有成功。该结果应该与现有 C# 实现产生的结果相匹配,因为我计划稍后对其进行解密。

尽管我确信我已经在 J​​ava 中产生了 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();

}

我在将结果转换为十六进制时使用了这个辅助函数......

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();
 }

请帮忙。

4

2 回答 2

3

您正在使用不同的填充模式。在 C# 中您编写tdes.Padding = PaddingMode.Zeros; 并在 Java 中您在 CBC 模式下使用 PKCS5Padding。这不是一回事。

于 2012-02-09T16:10:20.577 回答
3

一些评论:

  1. .NET TripleDESCryptoServiceProvider 的默认模式确实是 CBC,这是您在 JAVA 代码中明确指定的模式,但如果您也在 C# 代码中明确指定它也不会受到影响。

  2. 在您的原始代码中,您在 C# 代码中使用 PaddingMode.Zeros,但在您的 JAVA 代码中使用 PKCS5Padding。AFAIK 没有在 Java 中提供等效于 PaddingMode.Zeros 的内置密码提供程序。如果您仍然可以更改 C# 代码,则应使用 PaddingMode.Pkcs7 代替。否则,您必须为 Java 搜索可以完成这项工作的第 3 方密码提供程序。

  3. 避免使用 ASCII 编码,除非您能够保证输入实际上包含 7 位 ascii。如果传入带有其他字符的字符串,则输出未定义。

  4. 传递给 3DES 构造函数的密钥数据的长度应为 8、16 或 24,并且通常设置 DES 奇偶校验位。AFAIK .NET 和 Java 都会忽略奇偶校验位,但如果密钥长度不属于任何一个正确的值,它们的行为可能会有所不同。因此,如果您希望您的加密适用于任何可能的密钥输入,您应该使用 .NET 和 Java 都支持的密钥派生函数。在 Java 中尝试 PBEWithHmacSHA1AndDESede,并在 C# 中添加使用 System.Security.Cryptography.Rfc2898DeriveBytes 转换密码的代码。

于 2012-02-09T16:38:37.340 回答