C# AES加密至Java 8解密

huangapple go评论88阅读模式
英文:

C# AES encrypt to java 8 decrypt

问题

我正在尝试在C#中模拟一个Java加密例程,因为端点是基于Java的,并且将解密C#生成的值。

我尝试过使用`AesCryptoServiceProvider`和`AesManaged`来实现不同的方法,这些方法来自于Stack Overflow和网络中找到的几个示例,但我仍然无法使Java端点成功解密该值,它会出现错误:`{"message":"AUTHENTICATION_ERROR: Error while decrypting the cipher.","status":"Error"}`。

使用Postman,我能够调用Java端点并使用Java代码下面生成的加密文本来检索文档,所以这部分已经得到了积极的验证。

端点使用标头值来解密文本并验证内容,以下是相关的代码片段:


### Java加密

      private static Cipher generateCipher(int mode, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
        byte[] saltBytes = salt.getBytes("UTF-8"); byte[]ivBytes = iv.getBytes("UTF-8");
        // 密钥派生
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, iterations, keySize);

        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
        // 加密消息
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(mode, secret, new IvParameterSpec(ivBytes));
        return cipher;
      }

      public static String AES_encrypt(String plainText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
        Cipher cipher = generateCipher(Cipher.ENCRYPT_MODE, password, salt, iv, iterations, keySize);
        byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
        Base64.Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(encryptedTextBytes);
      }


### 标头

      interface_name: interfaceName  
      strength: 256  
      salt: salt_sixteen1234  
      iterate: 100  
      iv: sixteen_value_12  
      ciphertext: ECtKO7VluxCPFS/D8LVsb2bOQjhViIZm+O3zfMqSwJOLLTpDL4xdgwmIWr+41n5j  


### C#加密

      ...
       using (var csp = new AesCryptoServiceProvider())
       {
              ICryptoTransform e = GetCryptoTransform(csp, true, key, salt, iv);
              byte[] inputBuffer = Encoding.UTF8.GetBytes(plainText);
              byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
             string encrypted = Convert.ToBase64String(output);

            return encrypted;
       }
      ...

       private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting, string password, string salt, string iv, int iterations)
       {
            csp.Mode = CipherMode.CBC;
            csp.Padding = PaddingMode.PKCS7;
            var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), iterations);
            byte[] key = spec.GetBytes(16);

            csp.IV = Encoding.UTF8.GetBytes(iv);
            csp.Key = key;
            if (encrypting)
            {
                return csp.CreateEncryptor();
            }
            return csp.CreateDecryptor();
       }
英文:

I'm trying to mimic a java encryption routine in C# because the endpoint is java based and will be decrypting the value generated by C#.

I've tried different implementations using AesCryptoServiceProvider and AesManaged from several examples found in SO and around the web but I still can't get the java endpoint to successfully decrypt the value, it errors with {"message":"AUTHENTICATION_ERROR: Error while decrypting the cipher.","status":"Error"}.

Using postman I was able to call the java endpoint and retrieve a document using the
encrypted text generated by the java code posted below, so that part is positively verified.

The endpoint uses the header values to decrypt the text and verify the contents, here are the pertinent code pieces:

java encryption

  private static Cipher generateCipher(int mode, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
    byte[] saltBytes = salt.getBytes("UTF-8"); byte[]ivBytes = iv.getBytes("UTF-8");
    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, iterations, keySize);

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
    //encrypt the message
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(mode, secret, new IvParameterSpec(ivBytes));
    return cipher;
  }

  public static String AES_encrypt(String plainText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
    Cipher cipher = generateCipher(Cipher.ENCRYPT_MODE, password, salt, iv, iterations, keySize);
    byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
    Base64.Encoder encoder = Base64.getEncoder();
    return encoder.encodeToString(encryptedTextBytes);
  }

headers

  interface_name: interfaceName  
  strength: 256  
  salt: salt_sixteen1234  
  iterate: 100  
  iv: sixteen_value_12  
  ciphertext: ECtKO7VluxCPFS/D8LVsb2bOQjhViIZm+O3zfMqSwJOLLTpDL4xdgwmIWr+41n5j  

C# encrypt

  ...
   using (var csp = new AesCryptoServiceProvider())
   {
          ICryptoTransform e = GetCryptoTransform(csp, true, key, salt, iv);
          byte[] inputBuffer = Encoding.UTF8.GetBytes(plainText);
          byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
         string encrypted = Convert.ToBase64String(output);

        return encrypted;
   }
  ...

   private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting, string password, string salt, string iv, int iterations)
   {
        csp.Mode = CipherMode.CBC;
        csp.Padding = PaddingMode.PKCS7;
        var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), iterations);
        byte[] key = spec.GetBytes(16);

        csp.IV = Encoding.UTF8.GetBytes(iv);
        csp.Key = key;
        if (encrypting)
        {
            return csp.CreateEncryptor();
        }
        return csp.CreateDecryptor();
   }

答案1

得分: 2

以下是你要翻译的内容:

测试任何 C# 加密,我在你的 Java 代码中添加了一个解密方法,并成功运行了一个完整的循环(加密和解密)。

对于 C# 部分,我懒得检查你的代码(就像 @Topaco 做的那样),而是使用了我自己的代码和你的凭据来获得一个输出,你可以将其呈现给 Java 解密方法。

让我们从一个更长的 安全警告开始:这些代码使用了静态初始化向量和静态盐,并且 PBKDF2 密钥派生的迭代次数要远远低于标准(应该使用至少 10,000 次)。这些代码没有任何异常处理,仅供教育目的。

运行 C# 代码会得到一个简短的输出:

AES CBC 256 通过 PBKDF2 SHA1 密钥派生进行字符串加密
明文:      The quick brown fox jumps over the lazy dog
密文:     5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4

将密文呈现给 Java 解密方法会得到以下输出:

C# AES 加密到 Java 8 解密
明文: The quick brown fox jumps over the lazy dog
密文: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
解密后的文本: The quick brown fox jumps over the lazy dog

来自 C# 的密文解密
来自 C# 的密文: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
来自 C# 的解密后文本: The quick brown fox jumps over the lazy dog

这两份代码都可以在此链接进行实时自测(Java: https://repl.it/@javacrypto/JavaAes256EncryptionWithPBKDF2SHA1keyderivation,C#: https://repl.it/@javacrypto/CsharpAes256Pbkdf2Encryption#main.cs)。

C# 代码:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Program {
    public static void Main() {
        Console.WriteLine("AES CBC 256 通过 PBKDF2 SHA1 密钥派生进行字符串加密");
        // 凭据
        string plaintext = "The quick brown fox jumps over the lazy dog";
        string password = "myPassword";
        string saltString = "salt_sixteen1234";
        var iterationsCount = 100;
        string ivString = "sixteen_value_12";

        Encoding enc = Encoding.UTF8;
        byte[] saltBytes = enc.GetBytes(saltString);
        byte[] iv = enc.GetBytes(ivString);
        byte[] key;

        try {
            // PBKDF2 SHA1 密钥派生
            using (var pbkdf2 = new Rfc2898DeriveBytes(
                password,
                saltBytes,
                iterationsCount,
                HashAlgorithmName.SHA1))
            {
                key = pbkdf2.GetBytes(32);
            }
            Console.WriteLine("明文:      {0}", plaintext);
            string ciphertext = encrypt(key, iv, plaintext);
            Console.WriteLine("密文:     {0}", ciphertext);
        }
        catch(Exception e) {
            Console.WriteLine("错误: {0}", e.Message);
        }
    }

    static string encrypt(byte[] key, byte[] IV, string data) {
        byte[] encrypted;
        using(Aes aesAlg = Aes.Create()) {
            aesAlg.Key = key;
            aesAlg.IV = IV;
            aesAlg.Mode = CipherMode.CBC;
            var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
            // 创建用于加密的流。
            using(var msEncrypt = new MemoryStream()) {
                using(var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
                    using(var swEncrypt = new StreamWriter(csEncrypt)) {
                        // 将所有数据写入流中。
                        swEncrypt.Write(data);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }
        return Convert.ToBase64String(encrypted);
    }
}

Java 代码:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("C# AES 加密到 Java 8 解密");

        String plaintext = "The quick brown fox jumps over the lazy dog";
        String password = "myPassword";
        String iv = "sixteen_value_12";
        String salt = "salt_sixteen1234";
        int iterations = 100;
        int keySize = 256;
        System.out.println("明文: " + plaintext);
        String ciphertext = AES_encrypt(plaintext, password, salt, iv, iterations, keySize);
        System.out.println("密文: " + ciphertext);
        String decryptedtext = AES_decrypt(ciphertext, password, salt, iv, iterations, keySize);
        System.out.println("解密后的文本: " + decryptedtext);
        System.out.println("\n来自 C# 的密文解密");
        String ciphertextFromCsharp = "5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4";
        System.out.println("来自 C# 的密文: " + ciphertextFromCsharp);
        String decryptedtextFromCsharp = AES_decrypt(ciphertextFromCsharp, password, salt, iv, iterations, keySize);
        System.out.println("来自 C# 的解密后文本: " + decryptedtextFromCsharp);
   }

    private static Cipher generateCipher(int mode, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
        byte[] saltBytes = salt.getBytes("UTF-8"); 
        byte[] ivBytes = iv.getBytes("UTF-8");
        // 派生密钥
        SecretKeyFactory

<details>
<summary>英文:</summary>

To test any C# encryption I added a decryption method to your Java code and run successfully a full round (encryption and decryption).

For the C# part I was too lazy to check your code (as @Topaco did it) and used my own code with your credentials to get an output that you can present to the Java decryption method.

Let&#39;s start with a longer **Security warning: the codes are using a static initialization vector and a static salt and the iteration count
for PBKDF2 key derivation is much too low (a minimum of 10.000 should be used)**. The codes do not have any exception handling and are for educational purpose only.

Running the C#-code gives a short output:

    AES CBC 256 string encryption with PBKDF2 SHA1 key derivation
    plaintext:      The quick brown fox jumps over the lazy dog
    ciphertext:     5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4

Presenting the ciphertext to the Java decryption will give this output:

    C# AES encrypt to java 8 decrypt
    plaintext: The quick brown fox jumps over the lazy dog
    ciphertext: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
    decryptedtext: The quick brown fox jumps over the lazy dog
    
    decryption of a ciphertext from C#
    ciphertextFromCsharp: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
    decryptedtextFromCsharp: The quick brown fox jumps over the lazy dog

Both codes are available for a live self test here (Java: https://repl.it/@javacrypto/JavaAes256EncryptionWithPBKDF2SHA1keyderivation, C#: https://repl.it/@javacrypto/CsharpAes256Pbkdf2Encryption#main.cs).

C#-code:

    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    
    public class Program {
    	public static void Main() {
    		Console.WriteLine(&quot;AES CBC 256 string encryption with PBKDF2 SHA1 key derivation&quot;);
    		// credentials
        string plaintext = &quot;The quick brown fox jumps over the lazy dog&quot;;
    		string password = &quot;myPassword&quot;;
        string saltString = &quot;salt_sixteen1234&quot;;
        var iterationsCount = 100;
        string ivString = &quot;sixteen_value_12&quot;;
    
        Encoding enc = Encoding.UTF8;
    		byte[] saltBytes = enc.GetBytes(saltString);
        byte[] iv = enc.GetBytes(ivString);
        byte[] key;
    
    		try {
          // pbkdf2 sha1 key derivation
          using (var pbkdf2 = new Rfc2898DeriveBytes(
        		password,
        		saltBytes,
       			iterationsCount,
        		HashAlgorithmName.SHA1))
    		  {
        		key = pbkdf2.GetBytes(32);
    		  }
    			Console.WriteLine(&quot;plaintext:      {0}&quot;, plaintext);
    			string ciphertext = encrypt(key, iv, plaintext);
    			Console.WriteLine(&quot;ciphertext:     {0}&quot;, ciphertext);
    		}
    		catch(Exception e) {
    			Console.WriteLine(&quot;Error: {0}&quot;, e.Message);
    		}
    	}
    
    	static string encrypt(byte[] key, byte[] IV, string data) {
    		byte[] encrypted;
    		using(Aes aesAlg = Aes.Create()) {
    			aesAlg.Key = key;
    			aesAlg.IV = IV;
    			aesAlg.Mode = CipherMode.CBC;
    			var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
    			// create the streams used for encryption.
    			using(var msEncrypt = new MemoryStream()) {
    				using(var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
    					using(var swEncrypt = new StreamWriter(csEncrypt)) {
    						//Write all data to the stream.
    						swEncrypt.Write(data);
    					}
    					encrypted = msEncrypt.ToArray();
    				}
    			}
    		}
    		return Convert.ToBase64String(encrypted);
    	}
    }

Java-code:

    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.nio.charset.StandardCharsets;
    import java.util.Base64;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            System.out.println(&quot;C# AES encrypt to java 8 decrypt&quot;);
    
            String plaintext = &quot;The quick brown fox jumps over the lazy dog&quot;;
            String password = &quot;myPassword&quot;;
            String iv = &quot;sixteen_value_12&quot;;
            String salt = &quot;salt_sixteen1234&quot;;
            int iterations = 100;
            int keySize = 256;
            System.out.println(&quot;plaintext: &quot; + plaintext);
            String ciphertext = AES_encrypt(plaintext, password, salt, iv, iterations, keySize);
            System.out.println(&quot;ciphertext: &quot; + ciphertext);
            String decryptedtext = AES_decrypt(ciphertext, password, salt, iv, iterations, keySize);
            System.out.println(&quot;decryptedtext: &quot; + decryptedtext);
            System.out.println(&quot;\ndecryption of a ciphertext from C#&quot;);
            String ciphertextFromCsharp = &quot;5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4&quot;;
            System.out.println(&quot;ciphertextFromCsharp: &quot; + ciphertextFromCsharp);
            String decryptedtextFromCsharp = AES_decrypt(ciphertextFromCsharp, password, salt, iv, iterations, keySize);
            System.out.println(&quot;decryptedtextFromCsharp: &quot; + decryptedtextFromCsharp);
       }
    
        private static Cipher generateCipher(int mode, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
            byte[] saltBytes = salt.getBytes(&quot;UTF-8&quot;); byte[]ivBytes = iv.getBytes(&quot;UTF-8&quot;);
            // Derive the key
            SecretKeyFactory factory = SecretKeyFactory.getInstance(&quot;PBKDF2WithHmacSHA1&quot;);
            PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, iterations, keySize);
            SecretKey secretKey = factory.generateSecret(spec);
            SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), &quot;AES&quot;);
            //encrypt the message
            Cipher cipher = Cipher.getInstance(&quot;AES/CBC/PKCS5Padding&quot;); cipher.init(mode, secret, new IvParameterSpec(ivBytes));
            return cipher;
        }
    
        public static String AES_encrypt(String plainText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
            Cipher cipher = generateCipher(Cipher.ENCRYPT_MODE, password, salt, iv, iterations, keySize);
            byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes(&quot;UTF-8&quot;));
            Base64.Encoder encoder = Base64.getEncoder();
            return encoder.encodeToString(encryptedTextBytes);
        }
    
        public static String AES_decrypt(String cipherText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
            Base64.Decoder decoder = Base64.getDecoder();
            Cipher cipher = generateCipher(Cipher.DECRYPT_MODE, password, salt, iv, iterations, keySize);
            return new String(cipher.doFinal(decoder.decode(cipherText)), StandardCharsets.UTF_8);
        }
    }




</details>



huangapple
  • 本文由 发表于 2020年10月23日 11:19:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/64493398.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定