Преобразование. Net расшифровка в Java - PullRequest
1 голос
/ 25 февраля 2020

В настоящее время я работаю над проектом, в котором используется шифрование AES с производными байтами RFC2898. Это метод расшифровки, который я предоставил. Теперь мне нужно реализовать это в java.

private string Decrypt(string cipherText)
    {
        string EncryptionKey = "MAKV2SPBNI657328B";
        cipherText = cipherText.Replace(" ", "+");
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] {
                0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 
                });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }
                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }
        return cipherText;
    }

Это то, что я go пока:

   String EncryptionKey = "MAKV2SPBNI657328B";
   String userName="5L9p7pXPxc1N7ey6tpJOla8n10dfCNaSJFs%2bp5U0srs0GdH3OcMWs%2fDxMW69BQb7"; 
   byte[] salt =  new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
   try {
        userName = java.net.URLDecoder.decode(userName, StandardCharsets.UTF_8.name());
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec pbeKeySpec = new PBEKeySpec(EncryptionKey.toCharArray(), salt, 1000);
        Key secretKey = factory.generateSecret(pbeKeySpec);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] result = cipher.doFinal(userName.getBytes("UTF-8"));
        System.out.println(result.toString());
   } catch (Exception e) {
        System.out.println(e.getMessage());
   }

Но я получаю ошибки, как показано ниже:

Длина ключа не найдена java .security.spe c .InvalidKeySpecException: Длина ключа не найдена

1 Ответ

0 голосов
/ 25 февраля 2020

В коде Java есть некоторые проблемы: должно быть указано число генерируемых битов, кроме ключа, который должен быть получен IV, IV должен быть применен для дешифрования, зашифрованный текст должен быть декодирован Base64 и Utf. -16LE должен использоваться при декодировании открытого текста. Подробно:

  • При создании экземпляра PBEKeySpec количество генерируемых битов должно быть указано в 4-м параметре. Поскольку оба ключа (256 бит) и IV (128 бит) получены в коде C#, необходимо применить 384 (= 256 + 128):

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec pbeKeySpec = new PBEKeySpec(encryptionKey.toCharArray(), salt, 1000, 384);   
    
  • первые 256 битов являются ключом, следующие 128 битов IV:

    byte[] derivedData = factory.generateSecret(pbeKeySpec).getEncoded();
    byte[] key = new byte[32];
    byte[] iv = new byte[16];
    System.arraycopy(derivedData, 0, key, 0, key.length);
    System.arraycopy(derivedData, key.length, iv, 0, iv.length);
    
  • IV должен быть передан в 3-м параметре Cipher#init - вызов с использованием IvParameterSpec экземпляр:

    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(iv);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
    
  • Зашифрованный текст должен быть декодирован Base64, прежде чем его можно будет расшифровать:

    byte[] result = cipher.doFinal(Base64.getDecoder().decode(userName));
    
  • Из расшифрованного массива байтов должна быть создана строка с использованием кодировки Utf-16LE (что соответствует Encoding.Unicode в C#):

    System.out.println(new String(result, StandardCharsets.UTF_16LE)); // Output: Mohammad Al Mamun
    

Обратите внимание, что для режима CB C важно, чтобы комбинация ключ / IV использовалась только один раз по соображениям безопасности. Для кода C# (или Java) здесь это означает, что для одного и того же пароля разные соли должны использоваться для каждого шифрования, см. здесь .

...