Шифрование в Nodejs и дешифрование на клиенте с использованием API WebCrypto
Я пытаюсь создать следующий поток:
- Создать пару ключей на клиенте
- Отправьте открытый ключ на сервер (nodejs)
- Зашифруйте строку на сервере с помощью полизаполнения WebCryptoAPI https://github.com/PeculiarVentures/node-webcrypto-ossl
- Отправьте зашифрованные данные обратно клиенту для расшифровки
Я борюсь (в течение длительного времени) с типами данных.
Ниже приведен код, первый для генерации ключей (клиент):
// some reusable settings objects
const crypto = window.crypto.subtle;
let publicKeyToExport = {};
let privateKeyToStore = {};
// function called to create a keypair
const generateKeypair = () => {
crypto.generateKey({
name : 'RSA-OAEP',
modulusLength : 2048, //can be 1024, 2048, or 4096
publicExponent : new Uint8Array([0x01, 0x00, 0x01]),
hash : {name: 'SHA-256'}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
}, true, ['encrypt', 'decrypt']
).then((key) => {
publicKeyToExport = key.publicKey;
privateKeyToStore = key.privateKey;
console.log(key);
}).catch((err) => {
console.error(err);
});
};
Затем на экспорт:
// function to export the generate publicKey
const exportPublicKey = (publicKey) => {
crypto.exportKey('jwk', publicKey)
.then((keydata) => {
fetch('/key2', {
method : 'POST',
mode : 'cors',
body : JSON.stringify(keydata),
headers : new Headers({
'Content-Type' : 'application/json'
})
}).then(res => res.json())
.catch(err => console.error(err))
.then(res => console.log(res));
console.log(keydata);
})
.catch((err) => {
console.log(err);
});
};
Сохранить ключ:
app.post('/key2', (req, res) => {
webcrypto.subtle.importKey(
'jwk', req.body,
{
name : 'RSA-OAEP',
hash : {name : 'SHA-256'},
},
false,
['encrypt']
).then((publicKey) => {
keyStorage.setItem('alicePubKey', publicKey);
if(publicKey == keyStorage.getItem('alicePubKey'));
res.json({ 'success' : 'key received and saved' });
console.log('saved key from client: ' + publicKey);
return;
})
.catch((err) => {
console.error(err);
});
});
Зашифровать на сервере:
app.get('/challenge', (req, res) => {
let challengeFromServer = null;
let key = keyStorage.getItem('alicePubKey');
let buf = new Buffer.from('decryptthis!');
webcrypto.subtle.encrypt(
{
name : 'RSA-OAEP'
}, key, buf
)
.then((encrypted) => {
console.log('challenge created: ' + encrypted);
res.json({'challenge' : new Uint8Array(encrypted) })
})
.catch((err) => {
console.error(err);
})
Получить зашифрованные данные и расшифровать - не работает:)
const requestChallenge = () => {
fetch('/challenge')
.then((res) => {
return res.json();
})
.then((data) => {
console.log(data);
console.log(ArrayBuffer.isView(data.challenge))
console.log(new ArrayBuffer(data.challenge))
crypto.decrypt({
name : 'RSA-OAEP'
}, privateKeyToStore, new ArrayBuffer(data.challenge))
.then((decrypted)=>{
console.log(decrypted)
})
.catch(err => console.error(err));
})
.catch(err => console.error(err));
};
Следующие строки - проблема, я думаю!
console.log(ArrayBuffer.isView(data.challenge)) // false
console.log(new ArrayBuffer(data.challenge)) // empty
Небольшое обновление:
res.json(
{'challenge' : encrypted , // {} empty
'uint' : new Uint8Array(encrypted), // {0: 162, 1: 252, 2: 113, 3: 38, .......
'stringify' : JSON.stringify(encrypted), // "{}" empty
'toString' : encrypted.toString() // "[object ArrayBuffer]"
});
2 ответа
РЕШИТЬ!
Проблема была с типами данных.
Чтобы решить эту проблему, если у кого-то возникнет проблема, убедитесь, что на ваш сервер вы отправляете свой зашифрованный текст в виде буфера, мое экспресс-приложение:
res.write(new Buffer(encrypted), 'binary')
res.end(null, 'binary')
А на клиенте его получают и декодируют, как показано ниже:
const decryptedReadable = new TextDecoder().decode(decrypted)
Удачного кодирования.
Подумайте о том, чтобы взглянуть на библиотеку более высокого уровня, которая занимается проблемами обмена для вас; например, js-jose https://github.com/square/js-jose/tree/master/examples или PKIjs https://pkijs.org/examples/CMSEnvelopedExample.html.