AES 256 совместимое с Java и .Net шифрование и дешифрование? - PullRequest
0 голосов
/ 07 января 2019

Я хочу сделать шифрование / дешифрование AES 256 с использованием Java и .Net. Что означает, что я должен быть в состоянии зашифровать с помощью Java и расшифровать с помощью .Net и Vice vesra. Ниже приводится шифрование Java AES 256.

byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(KEY.toCharArray(), SALT.getBytes(), 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
System.out.println(Cipher.getMaxAllowedKeyLength("AES"));
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
return new String(Base64.encodeBase64(cipher.doFinal(strToEncrypt.getBytes("UTF-8"))));

1 Ответ

0 голосов
/ 07 января 2019

1) Часть Java-дешифрования задается как

byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(KEY.toCharArray(), SALT.getBytes(), 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec);
return new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt.getBytes("UTF-8"))));

, где strToDecrypt - это зашифрованные данные в кодировке Base64 (заданные возвращаемым значением части шифрования), которые отклоняются от части шифрования только в двух последних строках.

Примечание: На практике IV следует генерировать случайным образом (например, Генерация случайного IV для AES в Java ). Но я предполагаю, что это понятно, и 0-последовательность предназначена только для тестирования.

2) Относительно получения ключа PBKDF2WithHmacSHA256 решение C # зависит от вашей версии .NET-фреймворка. Для V4.7.2 и выше ключ может быть получен с помощью:

// .NET Framework 4.7.2 +
byte[] secretKey = null;
using (Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(KEY, Encoding.UTF8.GetBytes(SALT), 65536, HashAlgorithmName.SHA256))   
{
    secretKey = rfc2898.GetBytes(32);                                                                                                                                                                                
}

Примечание: В предыдущих реализациях (до v4.7.2) Rfc2898DeriveBytes использовалось SHA1 (жестко запрограммировано) вместо SHA256, и, таким образом, нет ctor, ожидающего 4 параметра. Более того, класс Rfc2898DeriveBytes требует, чтобы длина соли составляла не менее 8 байтов, в противном случае выдается System.ArgumentException: Salt is not at least eight bytes.

Альтернатива:

// .NET Framework 4.5 + 
byte[] secretKey = null;
KeyDerivationPrf keyDerivationPrf = KeyDerivationPrf.HMACSHA256;
secretKey = KeyDerivation.Pbkdf2(KEY, Encoding.UTF8.GetBytes(SALT), keyDerivationPrf, 65536, 32);

Последний работает для V4.6.1 и выше, но вам нужен класс Microsoft.AspNetCore.Cryptography.KeyDerivation.KeyDerivation, который Вы можете найти, например, на https://www.nuget.org/packages/Microsoft.AspNetCore.Cryptography.KeyDerivation/. Для установки вы можете используйте, например, Консоль диспетчера пакетов (Инструменты - Диспетчер пакетов NuGet - Консоль диспетчера пакетов). Просто введите соответствующую команду, как описано в ссылке. Может быть, вы получите IDE-ошибку CS0012. В этом случае вы должны добавить <Reference Include="netstandard" /> к ссылочному разделу вашего csproj -файла (см. Также https://github.com/dotnet/standard/issues/542). KeyDerivationPrf -класс не ограничивает длину соли.

Есть и другие возможности (например, Bouncy Castle), которые я не пробовал, но, возможно, они являются лучшими альтернативами для вас. Эта тема также обсуждается в Rfc2898 / PBKDF2 с SHA256 в качестве дайджеста в c # .

3) Пример метода C # -encryption:

public string Encrypt(string plainText)
{
    // PBKDF2WithHmacSHA256 Key derivation
    // ...

    using (RijndaelManaged cipher = new RijndaelManaged())
    {
        cipher.Key = secretKey;
        cipher.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        cipher.Mode = CipherMode.CBC;
        cipher.Padding = PaddingMode.PKCS7;

        byte[] encryptedData;
        using (ICryptoTransform encryptor = cipher.CreateEncryptor())
        {
            using (System.IO.MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
                    {
                        streamWriter.Write(plainText);
                    }
                    encryptedData = memoryStream.ToArray();
                }
            }
        }

        return Convert.ToBase64String(encryptedData);
    }
}

где plainText - строка, содержащая ваш простой текст (соответствующий strToEncrypt). Зашифрованные данные кодируются в base64 и возвращаются в виде строки (аналог вашего Java-метода).

Контрольный пример:

String KEY = "The Password";
String SALT = "The Salt";
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

дает

Plain text:       This is a plain text that needs to be encrypted
Key (hex):        2D7664713D701C58FC506F93CEA3194671AD3B5C034255A4AC04AF46EADC89BC
Base64 encoded
encrypted data:   ksUYjmbP9ga39LXr3wXQ34Bp32UlloYPxg3WWuW0iovWbg/GxHJrIuF3jrDvjr/Q

4) Пример метода C # -decryption:

public string Decrypt(string encryptedText)
{
    // PBKDF2WithHmacSHA256 Key derivation
    // ...

    using (RijndaelManaged cipher = new RijndaelManaged())
    {
        cipher.Key = secretKey;
        cipher.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        cipher.Mode = CipherMode.CBC;
        cipher.Padding = PaddingMode.PKCS7;

        string decryptedText;
        using (ICryptoTransform decryptor = cipher.CreateDecryptor())
        {
            using (System.IO.MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(encryptedText)))
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader streamReader = new StreamReader(cryptoStream))
                    {
                        decryptedText = streamReader.ReadToEnd();
                    }
                }
            }
        }

        return decryptedText;
    }
}

где encryptedText - возвращаемое значение части шифрования (зашифрованные данные, которые закодированы в base64, соответствуют strToDecrypt). Метод возвращает расшифрованный текст (аналог Java-метода).

...