У меня есть внешний интерфейс JavaScript, предназначенный для шифрования данных с использованием AES/CBC/PKCS7Padding и отправки на серверную часть Java для расшифровки.
Это выдержка из моего кода JavaScript:
export const encryptPaymentData = (data) => {
var encrypt = new JSEncrypt()
encrypt.setPublicKey(publicKey)
// convert the JSON object to a string
const jsonDataString = JSON.stringify(data)
// Create iv and secret_key
let iv = crypto.randomBytes(16)
let secret_key = crypto.randomBytes(32)
// iv = Buffer.from(iv).toString("base64")
// secret_key = Buffer.from(secret_key).toString("base64")
iv = CryptoJS.enc.Base64.stringify(CryptoJS.lib.WordArray.create(iv))
secret_key = CryptoJS.enc.Base64.stringify(
CryptoJS.lib.WordArray.create(secret_key)
)
// Encrypt the plaintext using AES/CBC/PKCS5Padding
console.info("iv", iv)
console.info("Secret", secret_key)
const ciphertext = CryptoJS.AES.encrypt(jsonDataString, secret_key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC,
})
console.info("cipherText", ciphertext)
// Print the ciphertext
console.info(ciphertext.toString())
}
И это выдержка из моего кода Java:
private static final String ALGORITHM = "AES/CBC/PKCS7Padding";
public String decryptAES(String ciphertext, String secretKey, String iv) throws Exception {
IvParameterSpec ivSpec = new IvParameterSpec(Base64.getDecoder().decode(iv));
SecretKeySpec keySpec = new SecretKeySpec(Base64.getDecoder().decode(secretKey), "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM, "BC");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
return new String(decrypted);
}
Когда я копирую секретный ключ, iv и зашифрованное значение и пытаюсь расшифровать в своей программе Java, я продолжаю получать сообщение об ошибке: javax.crypto.BadPaddingException: pad block corrupted
Пожалуйста, в чем может быть проблема?
Не устраивает шифрование, предоставляемое https?
Также IV следует передавать как WordArray. Кодировка Base64 ключа и IV должна использоваться только для вывода. Кроме того, в начале импортируется открытый ключ RSA, который не используется в остальной части кода. О чем это?
meant to encrypt data and send to backend for decryption
- Я лучше оспорю этот дизайн как ненужную сложность. от каких атак этот дизайн защитит ваших пользователей? экономьте свое время и не занимайтесь бесполезными вещами...
Привет, Урса, дизайн предназначен для имитации отправки данных карты из интерфейса javascript в бэкэнд java (вероятно, весенняя загрузка). Регулирующие органы, с которыми мы работаем, настаивают на использовании какой-либо формы шифрования для сокрытия информации о карте при отправке.
Привет Топако, ты был прав! Спасибо! Я следовал вашим инструкциям, и теперь все работает. Спасибо!
Следуя объяснению Topaco, я передал secret_key и iv как WordArray, а не Base64, и это решило проблему.
function encrypt(data) {
// convert the JSON object to a string
const jsonDataString = JSON.stringify(data);
// Create iv and secret_key
let iv = crypto.randomBytes(16);
let secret_key = crypto.randomBytes(32);
iv = CryptoJS.lib.WordArray.create(iv);
secret_key = CryptoJS.lib.WordArray.create(secret_key);
// Encrypt the plaintext using AES/CBC/PKCS5Padding
const ciphertext = CryptoJS.AES.encrypt(jsonDataString, secret_key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC,
});
console.info("cipherText", ciphertext);
// Print the ciphertext
console.info(ciphertext.toString());
}
Код CryptoJS несовместим. Вы генерируете случайный 32-байтовый ключ, но затем передаете его как строку в кодировке Base64. Поэтому CryptoJS использует функцию получения ключа. Вероятно, это не предусмотрено, так как такой ключ можно использовать напрямую. Для этого он должен быть передан как WordArray. Поэтому вам следует сначала исправить код CryptoJS. Кстати, в CryptoJS есть свой PRNG:
CryptoJS.lib.WordArray.random()
т.е. криптомодуль NodeJS вообще не нужен. Сочетание того и другого, вероятно, тоже не работает.