Я пытаюсь реализовать симметричное шифрование с использованием AES, где я указываю ключ и IV. В рамках каждой экосистемы (Java → Java/.NET → .NET) шифрование и дешифрование работают так, как было разработано, но если я попытаюсь пройти между ними, я получаю множество ошибок в отношении заполнения и т.д. (Подробности ниже).
Я прочитал несколько сообщений, включая http://blogs.msdn.com/b/dotnetinterop/archive/2005/01/24/java-and-net-aes-crypto-interop.aspx, но ни один из них не имеет одного и того же варианта использования. Вот мой код:
JAVA
public class Main {
public static void main(String[] args) throws Exception {
String data = "Something to decrypt";
String encrypt = Encrypt(data);
System.out.println(encrypt);
String decrypt = Decrypt(encrypt);
System.out.println(decrypt);
}
private static String Encrypt(String raw) throws Exception {
Cipher c = getCipher(Cipher.ENCRYPT_MODE);
byte[] encryptedVal = c.doFinal(raw.getBytes("UTF-8"));
return new BASE64Encoder().encode(encryptedVal);
}
private static Cipher getCipher(int mode) throws Exception {
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", new SunJCE());
//a random Init. Vector. just for testing
byte[] iv = "e675f725e675f725".getBytes("UTF-8");
c.init(mode, generateKey(), new IvParameterSpec(iv));
return c;
}
private static String Decrypt(String encrypted) throws Exception {
byte[] decodedValue = new BASE64Decoder().decodeBuffer(encrypted);
Cipher c = getCipher(Cipher.DECRYPT_MODE);
byte[] decValue = c.doFinal(decodedValue);
return new String(decValue);
}
private static Key generateKey() throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
char[] password = "[email protected]".toCharArray();
byte[] salt = "[email protected]@1t".getBytes("UTF-8");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
byte[] encoded = tmp.getEncoded();
return new SecretKeySpec(encoded, "AES");
}
}
.NET
internal class Program
{
private static void Main(string[] args)
{
string encrypted = Encrypt("Something to decrypt");
Console.Out.WriteLine(encrypted);
string decrypted = Decrypt(encrypted);
Console.Out.WriteLine(decrypted);
Console.Out.WriteLine("Press any key to continue");
Console.ReadKey();
}
private static string Encrypt(string raw)
{
using (var csp = new AesCryptoServiceProvider())
{
ICryptoTransform e = GetCryptoTransform(csp, true);
byte[] inputBuffer = Encoding.UTF8.GetBytes(raw);
byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
string encrypted = Convert.ToBase64String(output);
return encrypted;
}
}
public static string Decrypt(string encrypted)
{
using (var csp = new AesCryptoServiceProvider())
{
var d = GetCryptoTransform(csp, false);
byte[] output = Convert.FromBase64String(encrypted);
byte[] decryptedOutput = d.TransformFinalBlock(output, 0, output.Length);
string decypted = Encoding.UTF8.GetString(decryptedOutput);
return decypted;
}
}
private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting)
{
csp.Mode = CipherMode.CBC;
csp.Padding = PaddingMode.PKCS7;
var passWord = "[email protected]";
var salt = "[email protected]@lt";
//a random Init. Vector. just for testing
String iv = "e675f725e675f725";
var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(passWord), Encoding.UTF8.GetBytes(salt), 65536);
byte[] key = spec.GetBytes(16);
csp.IV = Encoding.UTF8.GetBytes(iv);
csp.Key = key;
if (encrypting)
{
return csp.CreateEncryptor();
}
return csp.CreateDecryptor();
}
}
Выходы для приложений:
JAVA
EO88Y8EjPAbaiZGoQM47z5i3vvy8jgVoehCPJDQES/4=
Something to decrypt
.NET
T/m/GatOCvFEJ4frVIoY8CbuQ1av97HoKdhUhAZcXp0=
Something to decrypt
Когда я пытаюсь расшифровать строку .NET в Java, я получаю: Исключение в потоке "main" javax.crypto.BadPaddingException: данный окончательный блок неправильно заполнен.
В .NET я получаю аналогичное: System.Security.Cryptography.CryptographicException не было обработано HResult = -2146233296 Message = Padding недопустимо и не может быть удалено.
В .NET я использую Rfc2898DeriveBytes для генерации моего ключа на основе пароля, соли и количества итераций. Я предполагаю, что это первопричина, поскольку в Java я использую SecretKeyFactory, надеясь достичь того же результата. Однако, если это причина, я не уверен, как примирить два...?
Спасибо за любую помощь.
** ОБНОВЛЕНО - РЕШЕНО **
Мальчик, я чувствую себя глупее, чем обычно. Проблема заключалась в опечатке в моем коде. Значение соли .NET имеет значение "1" и "L", где значение значения соли Java имеет значение "1" и "1" . Исправление этой ошибки устранило проблему. Извините, что трачу любое время..NET
var salt = "[email protected]@lt";
Java
byte[] salt = "[email protected]@1t"