У нас есть вариант использования, когда мы хотим расшифровать данные в java, которые ранее были зашифрованы с использованием .NET.
Вот класс Crypt, используемый для шифрования и расшифровки данных в .NET:
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, в ее счетчик String и использовал ее как соль в моем коде Java.
Также благодаря классу PasswordDerivedBytes, найденному здесь:
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;
}