У меня есть следующая функция шифрования в моем приложении:
public static String encrypt(String key, String value) {
try {
IvParameterSpec iv = new IvParameterSpec(key.substring(0, 16).getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes("UTF-8"));
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
И в PHP зашифрованное сообщение декодируется с использованием openssl_decrypt()
с AES-128-CBC
установить в качестве метода шифрования.
Однако дешифрование всегда терпит неудачу, ответ, который я получаю от сервера, заключается в том, что он не может распознать метод шифрования.
У меня нет контроля над сервером, поэтому я ничего не могу изменить только в моем приложении Java.
Я пробовал разные режимы, такие как AES/CBC/NoPadding
но я получаю исключение
Input Length Not Multiple of 16 bytes
Теперь я знаю, что нет ничего плохого в шифровании, потому что я могу зашифровать и расшифровать в своем приложении Java при использовании AES/CBC/PKCS5Padding
это просто не удается при публикации на сервер.
Ключ — это хэш MD5.
Это пример данных, которые мне нужно зашифровать:
{
"merchant_id": "EXX-00000001",
"user_id": "000000000001",
"code": "000200",
"details": {
"acc_no": "1234691007924321",
"exp": "07/19",
"name": "MICHAEL XXXXXX",
"type": "VIS"}
}
Предполагается, что только значение «details» должно быть зашифровано. Код должен быть хэшем md5. Полученный в результате хеш затем будет использоваться в качестве ключа для шифрования AES. Предполагается, что IV — это первые 16 символов хэша. Когда шифрование выполнено, результат должен быть закодирован в base64 и отправлен на сервер.
Пытаясь изменить это, я получил ошибку
java.security.InvalidKeyException: недопустимый размер ключа
на линии
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
Чтобы это работало, я изменил SecretKeySpec
байтовый массив из key.getBytes("UTF-8")
в key.substring(0, 16).getBytes("UTF-8")
и использовал это так:
String md5Key= "e510a13edeea112b57683d724d5d70a6";
String detailsData = "{\n" +
" \"acc_no\": \"1234691007924321\",\n" +
" \"exp\": \"07/19\",\n" +
" \"name\": \"MICHAEL XXXXXX\",\n" +
" \"type\": \"VIS\"\n" +
" }";
System.out.println(encrypt(md5Key, detailsData));
Я получил вывод, как это:
iufp4Rl+x/yTO7hSQBH7uU63sXAyzxgLequ3+JkFYZFz3PWwhxDC87TEC+bZ4rirgZVasrkLE1ehWWRGFV42Z29vAok+TMdwOvOettELUD3g8W2F40OyjMg4ItYkiZM+2W6Q2zf6t4sLzM6/AYqmAy1dKjPJcCQaFcnqK6mUFcM=
Чтобы расшифровать это в PHP, я использовал следующий код, который использует первые 16 символов key
использовать его как key
а также iv
инициализатор, как это:
$enc_data = 'iufp4Rl+x/yTO7hSQBH7uU63sXAyzxgLequ3+JkFYZFz3PWwhxDC87TEC+bZ4rirgZVasrkLE1ehWWRGFV42Z29vAok+TMdwOvOettELUD3g8W2F40OyjMg4ItYkiZM+2W6Q2zf6t4sLzM6/AYqmAy1dKjPJcCQaFcnqK6mUFcM=';
$key = 'e510a13edeea112b57683d724d5d70a6';
$key16 = substr($key, 0, 16);
$key16Hex = unpack('H*', $key16);
print openssl_decrypt($enc_data, "AES-128-CBC", $key16, 0, hex2bin($key16Hex[1]));
И, конечно, я получил нужные данные JSON, которые я зашифровал с помощью Java:
{
"acc_no": "1234691007924321",
"exp": "07/19",
"name": "MICHAEL XXXXXX",
"type": "VIS"}
Странно, что вы не получаете сообщение об ошибке в этой строке:
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
потому что я использую JDK 1.8 с:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
Других решений пока нет …