Я пытаюсь зашифровать короткую строку в JavaScript и расшифровать ее в Java. Расшифровка не удалась, и я думаю, что это из-за разницы в блочном режиме и/или дополнении между двумя платформами. Я попытался зашифровать одну и ту же строку как в Java, так и в JavaScript и получил разные результаты, что указывает на то, что разница действительно есть. Вот код Java, который создает ключ:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair keyPair = kpg.generateKeyPair();
А вот код Java, который я использовал для проверки шифрования:
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] bytes = cipher.doFinal("asdf".getBytes());
Я отправляю открытый ключ в процесс JavaScript и преобразовываю его в ArrayBuffer с именем переменной publicKey. Я проверил, что ключ на стороне JavaScript совпадает с ключом на стороне Java (путем экспорта с помощью crypto.subtle.exportKey и проверки байтов). Вот код JavaScript, который я использовал для проверки шифрования:
crypto.subtle.importKey('spki', publicKey,
{hash: 'SHA-256', name: 'RSA-OAEP'}, true,
['encrypt'])
.then((key) => {
crypto.subtle.encrypt({name: 'RSA-OAEP'}, key,
new TextEncoder().encode('asdf'))
.then((buffer) => {
});
});
Содержимое массива байтов в Java и буфера массива в JavaScript не совпадают. Настройки, в которых я не уверен, — это параметр Cipher#getInstance на стороне Java и параметры importKey и encrypt на стороне JavaScript. Существуют ли какие-либо настройки, которые будут работать между Java и JavaScript с использованием встроенных классов? Или мне стоит посмотреть на сторонние библиотеки (например, Bouncy Castle)?
@kelalaka Я не видел этого вопроса, спасибо! К сожалению, похоже, что единственным рабочим предложением из этого вопроса было использование пакета node-forge, и я действительно не хочу использовать сторонний пакет, если его можно избежать.
@AndyKing спасибо за вопрос. У меня была такая же проблема, и я мог найти решение без использования сторонних библиотек. Извините, если уже поздно :).



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Похоже, встроенное шифрование/дешифрование в JavaScript и Java не имеет совместимых настроек для шифрования RSA. Жизнеспособным решением является библиотека forge из github (кузница на гитхабе). Настройки ключа описаны на странице github следующим образом (Примеры RSA):
// encrypt data with a public key using RSAES-OAEP/SHA-256/MGF1-SHA-1
// compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding
var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha1.create()
}
});
Это старое, но вот альтернативное решение, если вы хотите использовать тонкое шифрование в javascript и контролировать расшифровку java.
Вот как вы расшифровываете в Java, предполагая, что вы использовали исходный код JS в вопросе для шифрования:
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
cipher.init(Cipher.DECRYPT_MODE, privKey, oaepParams);
byte[] decrypted = cipher.doFinal(encryptedBytes)
Проблема с шифром RSA/ECB/OAEPWithSHA-256AndMGF1Padding заключается в том, что он по умолчанию использует SHA-1 для заполнения MGF1. Javascript использует SHA-256, что приводит к несоответствию. Указав MGF1ParamterSpec, мы можем заставить Java использовать тот же алгоритм хэширования, что и Javascript по умолчанию.
В дополнение к ответу @Chip, который был действительно полезен, я хотел бы добавить следующий случай:
Предположим, вы хотите использовать следующее для расшифровки в Javascript (webcrypto):
window.crypto.subtle.decrypt(
{
name: "RSA-OAEP",
hash: { name: "SHA-512" }
//label: Uint8Array([...]) //optional
},
privateRsaKey, //CryptoKey object containing private RSA key
encdata //ArrayBuffer containing to be decrypted data
)
.catch(function(err){
console.error(err);
})
Затем вам нужно использовать следующий OAEPParameterSpec для шифрования в Java (и, вероятно, наоборот, но я этого не пробовал):
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-512", "MGF1",
new MGF1ParameterSpec("SHA-512"), PSource.PSpecified.DEFAULT);
Поскольку @Chip ссылался только на заполнение MGF1 I, я предположил, что нужно будет использовать
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-512", "MGF1",
new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
но, видимо, нужно изменить обе хэш-функции на SHA-512, как показано в моем первом блоке кода OAEPParameterSpec.
Вы видели это?