Я уже пару дней борюсь с этим. Мне необходимо использовать API, который принимает зашифрованный параметр. API был написан на C#. Запрошенное шифрование следующее:
Алгоритм: AES
Режим шифрования: CBC
Режим заполнения: PKCS7
Размер блока: 128
Размер ключа: 256
Ключ: String -> Ключ создается путем преобразования предоставленной строки в массив байтов размером 32: Encoding.ASCII.GetBytes (…). API заявляет, что строка создается ими с использованием хеш-функции строки MD5.
Массив IV: IV создается путем преобразования предоставленной строки в массив байтов размером 16: Encoding.ASCII.GetBytes (…).
Представление зашифрованной строки: Base64
После поиска и опробования стольких вещей, которые были предложены в Интернете, я все еще не могу получить такое же зашифрованное значение (особенно, что PKCS7 не поддерживается по умолчанию, а PKCS5 должен работать так же, но это не так). Вот некоторые вещи, которые я пробовал:
1) Использование bouncy castle jar для использования PKCS7
2) Добавление соответствия JCE, чтобы можно было снять ограничение на размеры ключей и блоков.
После того, как они связались с ними, они отправили мне работающий фрагмент Android (который, если я запустил простой java 8, жалуется на поставщика (NoSuchAlgorithmException: не удается найти ни одного поставщика, поддерживающего AES / CBC / PKCS7Padding)):
public static String encrypt(String value) {
String plainText = value;
String escapedString;
try {
byte[] key = ENCRYPT_KEY.getBytes("UTF-8");
byte[] ivs = ENCRYPT_IV.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
AlgorithmParameterSpec paramSpec = new IvParameterSpec(ivs);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, paramSpec);
escapedString = Base64.encodeToString(cipher.doFinal(plainText.getBytes("UTF-8")), Base64.DEFAULT).trim();
return escapedString;
} catch (Exception e) {
e.printStackTrace();
return value;
}
}
Пожалуйста, любая помощь будет очень признательна.
Вот фрагмент кода из того, что я пробовал:
package com.melhem.TestJava;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class StringFunc {
final static String key = "API_KEY_32_CHARs";
final static String iv = "API_IV_16_CHARs";
final static String algorithm = "AES/CBC/PKCS7Padding";
private static Cipher cipher = null;
private static SecretKeySpec skeySpec = null;
private static IvParameterSpec ivSpec = null;
public static void main(String[] args) {
System.out.println(encrypt("STRING_TO_ENCODE"));
}
private static void setUp(){
try{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
skeySpec = new SecretKeySpec(key.getBytes("ASCII"), "AES");
ivSpec = new IvParameterSpec(iv.getBytes("ASCII"));
cipher = Cipher.getInstance(algorithm);
}catch(NoSuchAlgorithmException | NoSuchPaddingException ex){
ex.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String encrypt(String str){
try{
// Integer strL = (int) Math.ceil(str.length() / 8.0);
// Integer strB = strL*8;
// str = padRight(str, ' ', strB);
setUp();
try {
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
System.out.println("Block size: " + cipher.getBlockSize() * 8);
System.out.println("Algorithm name: " + cipher.getAlgorithm());
System.out.println("Key size: " + skeySpec.getEncoded().length * 8);
} catch (InvalidAlgorithmParameterException ex) {
ex.printStackTrace();
return "";
}
byte[] enc = cipher.doFinal(str.getBytes("ASCII"));
String s = new String(Base64.getEncoder().encode(enc));
s = s.replace("+", "__plus__");
s = s.replace("/", "__slash__");
return s;
}catch(InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex){
ex.printStackTrace();
return "";
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "";
}
}
public static String padRight(String msg, char x, int l) {
String result = "";
if (!msg.isEmpty()) {
for (int i=0; i<(l-msg.length()); i++) {
result = result + x;
}
result = msg + result;
}
return result;
}
}
Что ж, этот код не приведет к исключению, которое, как вы утверждаете, получают в другом месте. Пожалуйста, прочтите Как создать минимальный, полный и проверяемый пример. MCVE - это способ решить ваши проблемы с помощью stackoverflow.
Ваша проблема не в заполнении. В Java заполнение PKCS7 называется PKCS5 (обратите внимание, что AES с заполнением PKCS5 невозможно). Проблема, скорее всего, связана с "хешированием MD5" и кодировкой строк. Если вы предоставите образец ввода и ожидаемый результат, возможно, мы сможем перепроектировать его для вас. Да, и укажите свой точный номер версии Java (например, 1.8.161).




Java Пакет шифров поддерживает только заполнение PKCS # 7 с помощью AES/CBC/PKCS5Padding. Это неправильное именование, поскольку заполнение PKCS # 5 поддерживает размеры блоков 8 байтов, поскольку DES и PKCS # 7 поддерживают до 255 байтов. Для Java используйте это;
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
# 5 и # 7 не взаимозаменяемы для большинства современных блочных шифров, поскольку AES - это 128-битный блочный шифр. См. Вопрос по Crypto.StackExchange.
и, для использования AES с размером ключа 256 бит;
Стандартная библиотека шифров Java ограничена размером ключа 128 бит. Вы должны пойти и скачать Java Файлы политики юрисдикции с неограниченной надежностью Cryptography Extension (JCE) 6
Спасибо, kelalaka .. Я пробовал, но он выдает исключение InvalidAlgorithmParameterException: Неверная длина IV: должна быть 8 байтов .. Кроме того, API запрашивает размер IV 16 байтов, а алгоритм - AES
Да, я пробовал использовать это раньше, так как они взаимозаменяемы, но это дает другое значение, которое API не может расшифровать. Как вы думаете, это означает, что владелец API выполняет дополнительные действия после шифрования, или проблема заключается в использовании PKCS5Padding?
Я уже добавил обе банки из JCE, но проблема все еще остается .. Дело не в том, что он жалуется на размер ключа после добавления JCE-банок, но дает неправильное значение
ты забыл сделать финал?
Если вы используете последнюю версию Java 8 или выше, вам больше не нужны файлы политики юрисдикции с неограниченной надежностью, они уже включены.
Обратите внимание, что Oracle 8u161 и более поздние версии (с конца 2017 года) больше не нуждаются в загрузке «неограниченной политики» - OOTB позволяет использовать 256-битную симметричность. @ M.R.M: Политика FYI никогда не ограничивает размер блока (только ключ). «IV должен быть 8 байтов» для AES / CBC - безумие. И это плохая практика, поэтому подозрительно рассматривать ключ или IV как символы - а также очень плохая практика, чтобы IV был известен заранее. или повторяется, как указывает Саптарши. Есть ли у них какие-либо тестовые примеры или тестовая среда, о которых вы могли бы подробно рассказать, не вызывая проблем с безопасностью?
@ dave_thompson_085 К сожалению, у них нет ... и я согласен, но они реализовали это именно так, но они сказали, что мы должны приспособиться, и они не могут изменить API, поскольку он используется другими и работает (хотя я сказал им их путь небезопасно) .. но что касается IV, это 16 байт, а не 8
Вот чего не хватает в вашем вопросе: кода Java, который, как вы утверждаете, вы пробовали, но не сработали.