Window Crypto Subtle: как мы можем использовать метод шифрования/дешифрования, если мы сгенерируем открытый закрытый ключ с помощью алгоритма «RSASSA-PKCS1-v1_5»?

Я хочу использовать один и тот же открытый и закрытый ключ для некоторого шифрования/дешифрования на уровне кода и хочу отправить зашифрованные данные в серверную часть вместе с моим открытым ключом, который я добавляю в свой токен JWT AUTH. Поэтому, пожалуйста, помогите мне зашифровать / расшифровать этот подход, если это возможно, так как я не могу изменить этот код из-за возможности повторного использования.

      const keyDetails = await window.crypto.subtle.generateKey(
          {
              name: 'RSASSA-PKCS1-v1_5',
              modulusLength: 2048, 
              publicExponent: new Uint8Array([1, 0, 1]),
              hash: { name: 'SHA-256' }, 
          },
          true, 
          ['verify', 'sign'] 
      );
      

Я пробовал так, но получил ошибку.

Кроме того, я хочу использовать свои экспортированные открытые и закрытые ключи, которые я делаю с таким подходом.

const publicKey: any = await window.crypto.subtle.exportKey('jwk', keyDetails.publicKey);
const privateKey: any = await window.crypto.subtle.exportKey('jwk', keyDetails.privateKey);
      const enc = new TextEncoder();
      const encodedText = enc.encode("testing 1234");
    
      const encryptedText = await window.crypto.subtle.encrypt({
        name: "RSASSA-PKCS1-v1_5"
      },
      publicKey,
      encodedText
    )
    console.info(encryptedText);
    const decryptedText = await window.crypto.subtle.decrypt({
        name: "RSASSA-PKCS1-v1_5"
      },
      privateKey,
      encryptedText
    )
TypeError: Failed to execute 'encrypt' on 'SubtleCrypto': parameter 2 is not of type 'CryptoKey'.
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

RSASSA-PKCS1-v1_5 — это заполнение, которое применяется во время подписания/проверки. Его нельзя использовать для шифрования/дешифрования. Заполнение для шифрования/дешифрования — RSAES-PKCS1-v1_5, но оно не поддерживается WebCrypto API. WebCrypto поддерживает только RSAES-OAEP для шифрования/дешифрования. См. RFC8017 и WebCrypto API для более подробной информации.
Кроме того, экспортированные ключи JWK должны быть предварительно адаптированы для шифрования/дешифрования. Затем ключи должны быть импортированы, прежде чем их можно будет использовать в шифровании/дешифровании.

Следующий пример демонстрирует это: Сначала создается пара ключей для подписи/проверки с помощью RSASSA-PKCS1-v1_5. Оба ключа экспортируются как JWK. Затем настраиваются параметры key_ops и alg. После этого измененные ключи повторно импортируются и используются для шифрования/дешифрования с помощью RSAES-OAEP:

(async () => {

// Generate
const keyDetails = await window.crypto.subtle.generateKey(
    {
        name: 'RSASSA-PKCS1-v1_5',
        modulusLength: 2048, 
        publicExponent: new Uint8Array([1, 0, 1]),
        hash: { name: 'SHA-256' }, 
    },
    true, 
    ['verify', 'sign'] 
);
console.info(keyDetails)

// Export
const publicKey = await window.crypto.subtle.exportKey('jwk', keyDetails.publicKey);
const privateKey = await window.crypto.subtle.exportKey('jwk', keyDetails.privateKey);
console.info(publicKey)
console.info(privateKey)

// Adapt parameters and import
publicKey.key_ops = ['encrypt'];
privateKey.key_ops = ['decrypt'];
publicKey.alg = 'RSA-OAEP-256';
privateKey.alg = 'RSA-OAEP-256';
const publicKeyReloaded = await window.crypto.subtle.importKey("jwk", publicKey, {name: "RSA-OAEP", hash: {name: "SHA-256"}}, true, ["encrypt"]);    
const privateKeyReloaded = await window.crypto.subtle.importKey("jwk", privateKey,{name: "RSA-OAEP", hash: {name: "SHA-256"}}, true, ["decrypt"]);    
console.info(publicKeyReloaded)
console.info(privateKeyReloaded)

// Encrypt/Decrypt
const enc = new TextEncoder();
const encodedText = enc.encode("testing 1234");
const encryptedText = await window.crypto.subtle.encrypt({name: "RSA-OAEP"}, publicKeyReloaded, encodedText)
console.info(ab2b64(encryptedText));
const dec = new TextDecoder();
const decryptedText = await window.crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKeyReloaded, encryptedText)
console.info(dec.decode(decryptedText));

// Helper
function ab2b64(arrayBuffer) {
    return window.btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
}

})();

Обратите внимание, что, как правило, одна и та же пара ключей должна фактически использоваться либо для подписи/проверки, либо для шифрования/дешифрования, а не для того и другого вместе, см. здесь.
WebCrypto API обеспечивает некоторую защиту от такого неправильного использования, привязывая к нему назначение ключа (однако эту защиту можно легко обойти, как показано выше).

Спасибо @topaco за то, что поделились своим подробным решением с ценной статьей. Теперь у меня есть лучшее понимание.

nks 30.01.2023 14:18

Что ж, ответ уже дал @topaco. теперь я просто хочу добавить еще один подход. Если кто-то хочет зашифровать и расшифровать конфиденциальные данные с помощью [JSON Web Encryption — Ciphertext] JOSE npm lib. с тем открытым/закрытым ключом, который генерируется только для подписи/проверки!

const jose = require('jose'); // npm i jose
async encryptDecryptLogic(data: string): Promise<any>{

    const keyDetails = await window.crypto.subtle.generateKey(
          {
              name: 'RSASSA-PKCS1-v1_5',
              modulusLength: 2048, 
              publicExponent: new Uint8Array([1, 0, 1]),
              hash: { name: 'SHA-256' }, 
          },
          true, 
          ['verify', 'sign'] 
      );

       // updating operation from sign-varify to encrypt-decrypt.
       // As that private/ public key is generated for sign and verification purposes only but here we extended its purpose. So we need to update a few properties to do encryption/decryption

        publicKey.key_ops = ['encrypt'];
        privateKey.key_ops = ['decrypt'];

        // updating algo from sign-varify[RS256] to encrypt-decrypt[RSA-OAEP]
        // Defines the algorithm used to encrypt the Content Encryption Key (CEK). This MUST be set to “RSA-OAEP”.

        publicKey.alg = 'RSA-OAEP';
        privateKey.alg = 'RSA-OAEP';

 const encodedText =  await this.jose.jwe.encrypt(publicKey, "lets encrypt me!!")
        console.info('encodedText', encodedText);

 const decodedText =  await this.jose.jwe.decrypt(privateKey, encodedText)
        console.info('decodedText', decodedText);
}

Другие вопросы по теме