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

3DES加密实现报告与C#实现不同的输出,c#,java,encryption,bouncycastle,3des,C#,Java,Encryption,Bouncycastle,3des,我一直试图使用BouncyCastle套件在java中使用3DES对明文进行加密,但没有成功。这个结果应该与现有C#实现产生的结果相匹配,因为我计划稍后对其进行解密 我不断得到不同的结果,尽管我确信我已经用Java生成了C#algo的“等价物”。有人能帮我看完这两个片段并提出建议吗?我将不胜感激 C#加密: public static byte[] encryptStringToBytes_3DES(string plainText, string passKey) {

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

我不断得到不同的结果,尽管我确信我已经用Java生成了C#algo的“等价物”。有人能帮我看完这两个片段并提出建议吗?我将不胜感激

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

}
应该执行“等效”加密的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();
}
}
这是它对应的十六进制。。作用

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();
 }
公共静态字符串asHex(字节buf[]{
StringBuffer strbuf=新的StringBuffer(buf.length*2);
int i;
对于(i=0;i

请帮助。

您正在使用不同的填充模式。在C#中,您编写了
tdes.Padding=PaddingMode.Zeros

在Java中,您在CBC模式下使用了PKCS5P。这是不一样的事情

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

一些评论:

  • .NET TripleDESCryptoServiceProvider的默认模式实际上是CBC,这是您在JAVA代码中显式指定的模式,但如果您在C#代码中也显式指定它,则不会有任何影响

  • 在原始代码中,在C#代码中使用PaddingMode.zero,但在JAVA代码中添加pkcs5p。Java中没有提供PaddingMode.zero等价物的内置密码提供程序。如果您仍然可以更改C#代码,则应改用PaddingMode.Pkcs7。否则,您必须为Java搜索第三方密码提供商来完成这项工作

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

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

  • 一些评论:

  • .NET TripleDESCryptoServiceProvider的默认模式实际上是CBC,这是您在JAVA代码中显式指定的模式,但如果您在C#代码中也显式指定它,则不会有任何影响

  • 在原始代码中,在C#代码中使用PaddingMode.zero,但在JAVA代码中添加pkcs5p。Java中没有提供PaddingMode.zero等价物的内置密码提供程序。如果您仍然可以更改C#代码,则应改用PaddingMode.Pkcs7。否则,您必须为Java搜索第三方密码提供商来完成这项工作

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

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


  • 我会仔细检查字符集(UTF等)。字符串的默认值有时会使您在执行此类操作时出错,尤其是调用getBytes()时。确保阅读所有的javadoc。我会仔细检查字符集(UTF等)。字符串的默认值有时会使您在执行此类操作时出错,尤其是调用getBytes()时。确保阅读所有的javadoc。你是对的!我几分钟前就注意到了。。。。我不得不将Java中的填充方案更新为DESede/CBC/ZeroBytePadding。非常感谢!!ZeroBytePadding并不总是最佳填充方案。在解密过程中,您可能会在和处丢失消息的
    0x00
    字节。我建议使用PKCS7、ISO 10126或ANSI x.923填充模式。这些填充模式将确保解密后消息长度保持不变。你是对的!我几分钟前就注意到了。。。。我不得不将Java中的填充方案更新为DESede/CBC/ZeroBytePadding。非常感谢!!ZeroBytePadding并不总是最佳填充方案。在解密过程中,您可能会在和处丢失消息的
    0x00
    字节。我建议使用PKCS7、ISO 10126或ANSI x.923填充模式。这些填充模式将确保解密后消息长度保持不变。
    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();
     }