3DES加密实现报告来自C#实现的不同输出

时间:2012-02-09 14:34:08

标签: c# java encryption bouncycastle 3des

我一直试图通过使用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();
 }

请帮助。

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:3)

一些意见:

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

  2. 在原始代码中,您在C#代码中使用PaddingMode.Zeros,但在JAVA代码中使用PKCS5Padding。 Java中没有内置的密码提供程序,它提供了相当于PaddingMode.Zeros的AFAIK。如果您仍然可以更改C#代码,则应使用PaddingMode.Pkcs7。否则,您必须搜索将执行此任务的Java的第三方密码提供程序。

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

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