简体   繁体   English

用Java解密Rijndael,使用.NET加密

[英]Decrypting Rijndael in Java , Encrypted using .NET

We have a use case where we are looking to decrypt data in java which was previously encrypted using .NET 我们有一个用例,我们希望解密以前使用.NET加密的java中的数据

Here is the Crypt class used to Encrypt and Decrypt Data in .NET : 这是用于在.NET中加密和解密数据的Crypt类:

https://gist.github.com/epinapala/9400064 https://gist.github.com/epinapala/9400064

I separated the Decrypt method and executed, and It works fine in .NET, I am looking to port the code below: 我分离了Decrypt方法并执行了,它在.NET中工作正常,我希望移植以下代码:

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

class Program
{
    static void Main()
    {
        {
            string line = "f5EBWYipPKG1FpyTEP7pyPLLJNpqrvwYJFs8iMw9mOY$";

            line = line.Replace('-', '+').Replace('_', '/').Replace('$', '=');

            while (line.Length % 4 != 0){
                    line = line.PadRight(line.Length + (4 - line.Length % 4), '=');
            }
             Console.WriteLine(line);


            byte[] inputBuffer = Convert.FromBase64String(line);
             Console.WriteLine(inputBuffer.Length);
            byte[] numArray = new byte[16];
            byte[] key = new PasswordDeriveBytes("ThisIsMyKey", new byte[13]
      {
        (byte) 73,
        (byte) 118,
        (byte) 97,
        (byte) 110,
        (byte) 32,
        (byte) 77,
        (byte) 101,
        (byte) 100,
        (byte) 118,
        (byte) 101,
        (byte) 100,
        (byte) 101,
        (byte) 118
      }).GetBytes(16);

      Rijndael rijndael = GetRijndael(key);

      for (int index = 0; index < 16; ++index){
          numArray[index] = inputBuffer[index];
      }
           rijndael.IV = numArray;

            string decodedString = Encoding.UTF8.GetString(rijndael.CreateDecryptor().TransformFinalBlock(inputBuffer, 16, inputBuffer.Length - 16));
            Console.WriteLine(decodedString);
        }
    }


    private static Rijndael GetRijndael(byte[] key)
    {
      Rijndael rijndael = Rijndael.Create();
      rijndael.Mode = CipherMode.CBC;
      rijndael.KeySize = key.Length * 8;
      rijndael.Key = key;
      rijndael.Padding = PaddingMode.PKCS7;
      return rijndael;
    }
}

Here is what I tried so far: 这是我到目前为止尝试过的:

   public static void main() {
     ecnryptedData = "f5EBWYipPKG1FpyTEP7pyPLLJNpqrvwYJFs8iMw9mOY$";
     ecnryptedData = ecnryptedData.replace('-', '+')
         .replace('_', '/').replace('$', '=');

     while (ecnryptedData.length() % 4 != 0) {
         ecnryptedData = StringUtils.rightPad(ecnryptedData, ecnryptedData.length() + (4 - ecnryptedData.length() % 4),
             "=");
     }
     System.out.println(Decrypt(ecnryptedData, "ThisIsMyKey"));
 }

 public static String Decrypt(String text, String key) throws Exception {
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
     byte[] keyBytes = new byte[16];
     byte[] b = key.getBytes("UTF-8");
     int len = b.length;
     if (len > keyBytes.length) len = keyBytes.length;
     System.arraycopy(b, 0, keyBytes, 0, len);
     SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
     AlgorithmParameterSpec spec = new IvParameterSpec(keyBytes);
     cipher.init(Cipher.DECRYPT_MODE, keySpec, spec);

     BASE64Decoder decoder = new BASE64Decoder();
     byte[] results = cipher.doFinal(decoder.decodeBuffer(text));
     return new String(results, "UTF-8");
 }

I am getting the exception : "Given final block not properly padded". 我遇到了一个例外:“给出的最终块未正确填充”。 Not sure what I did wrong. 不知道我做错了什么。 I appreciate any help on this issue. 感谢您在此问题上的任何帮助。

[[EDIT]]: [[编辑]]:

I figured it out. 我想到了。 The thing I was missing was that I was using a wrong salt. 我所缺少的是我使用了错误的盐。 I decoded the constant salt used(as bytes) in the .NET code into its String counter part, and used it as Salt in my Java code. 我将.NET代码中使用的常量salt(以字节为单位)解码为其String计数器部分,并在Java代码中将其用作Salt。

Also Thanks to the PasswordDerivedBytes class found here : 也要感谢在这里找到的PasswordDerivedBytes类:

https://github.com/getkksingh/TimesSSO/blob/fc78e4b30d5fd347341757c02eea6c9271575515/src/java/com/timesgroup/sso/hibernate/apis/PasswordDeriveBytes.java https://github.com/getkksingh/TimesSSO/blob/fc78e4b30d5fd347341757c02eea6c9271575515/src/java/com/timesgroup/sso/hibernate/apis/PasswordDeriveBytes.java

private static byte[] decryptData(byte[] data, String password,
            String paddingMode, String salt) throws Exception {
        if (data == null || data.length == 0)
            throw new IllegalArgumentException("data is empty");
        if (password == null || password == "")
            throw new IllegalArgumentException("password is empty");
        if (salt == null || salt == "")
            salt = ".";
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        byte[] saltBytes = salt.getBytes("UTF8");
        byte[] passBytes = password.getBytes("UTF8");

        PKCS5S1ParametersGenerator generator = new PasswordDeriveBytes(
                new SHA1Digest());
        generator.init(passBytes, saltBytes, 100);

        byte[] key = ((KeyParameter) generator.generateDerivedParameters(256))
                .getKey();
        passBytes = new byte[16];
        saltBytes = new byte[16];
        System.arraycopy(key, 0, passBytes, 0, 16);
        System.arraycopy(key, 16, saltBytes, 0, 16);

        Cipher cipher = Cipher.getInstance("AES/CBC/" + paddingMode, "BC");
        SecretKeySpec keySpec = new SecretKeySpec(passBytes, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec,
                new IvParameterSpec(saltBytes));

        byte[] original = cipher.doFinal(data);
        return original;
    }

You are using a custom Base64 variant in the C# code: _ and - as characters 62 and 63 and $ as padding. 您正在C#代码中使用自定义Base64变体: _-作为字符62和63,而$作为填充。 The C# code converts these to normal Base64 before attempting decoding. 在尝试解码之前,C#代码会将它们转换为正常的Base64。

Your java code passes invalid data to the Base64 decoder. 您的Java代码将无效数据传递给Base64解码器。 This should throw an IllegalArgumentException before the code even reaches the crypto. 这应该在代码到达加密IllegalArgumentException之前抛出IllegalArgumentException

Another issue is that your C# code uses PBKDF1 to derive the key from the password, the java code directly uses the password as key bytes. 另一个问题是您的C#代码使用PBKDF1从密码中获取密钥,而Java代码直接将密码用作密钥字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM