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

时间:2014-03-06 21:18:23

标签: java .net rijndael

我们有一个用例,我们希望解密以前使用.NET加密的java中的数据

以下是用于在.NET中加密和解密数据的Crypt类:

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

我将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;
    }
}

这是我到目前为止所尝试的内容:

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

我得到了例外情况:“给定最后一个块没有正确填充”。不知道我做错了什么。我对此问题表示感谢。

[[编辑]]:

我明白了。我失踪的是我使用了错误的盐。我将.NET代码中使用的常量salt(作为字节)解码为其String计数器部分,并在我的Java代码中将其用作Salt。

还要感谢此处的PasswordDerivedBytes类:

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

1 个答案:

答案 0 :(得分:1)

您在C#代码中使用自定义Base64变体:_-作为字符62和63以及$作为填充。在尝试解码之前,C#代码将这些转换为普通的Base64。

您的java代码将无效数据传递给Base64解码器。这应该在代码甚至到达加密之前抛出IllegalArgumentException

另一个问题是你的C#代码使用PBKDF1从密码派生密钥,java代码直接使用密码作为密钥字节。