Экспорт / импорт пары ключей RSA из веб-приложения

Я хочу зашифровать сообщения в чатах (веб-приложение) таким образом, чтобы никто, кроме получателей, не мог их расшифровать. Кажется, что шифрование RSA - хороший способ. Каждый пользователь (фактически, каждое устройство) будет иметь пару открытого и закрытого ключей, и каждое сообщение будет зашифровано открытым ключом получателя и расшифровано закрытым ключом получателя, поэтому каждое сообщение должно быть отправлено столько раз, сколько получатели того же самого. Я нашел руководство, который объясняет, как достичь этой цели. Шифрование / дешифрование рассчитывается в Service Worker, а закрытый ключ не отображается, а просто хранится в том же Worker.

Однако мне интересно, существует ли безопасный способ экспорта пары ключей с устройства, чтобы иметь возможность видеть ваши сообщения с другого устройства. Я мог бы добавить messageType под названием "exportKeys" и получить оба ключа, как в приведенном ниже примере:

Из приведенного выше руководства добавление типа сообщения и функции "exportKeys":

self.window = self // This is required for the jsencrypt library to work within the web worker

// Import the jsencrypt library
self.importScripts('https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/2.3.1/jsencrypt.min.js');

let crypt = null
let privateKey = null

/** Webworker onmessage listener */
onmessage = function(e) {
  const [ messageType, messageId, text, key ] = e.data
  let result
  switch (messageType) {
    case 'generate-keys':
      result = generateKeypair()
      break
    case 'encrypt':
      result = encrypt(text, key)
      break
    case 'decrypt':
      result = decrypt(text)
      break
    case 'exportKeys':
      result = exportKeys(key)
      break
  }

  // Return result to the UI thread
  postMessage([ messageId, result ])
}

/** Generate and store keypair */
function generateKeypair () {
  crypt = new JSEncrypt({default_key_size: 2056})
  privateKey = crypt.getPrivateKey()

  // Only return the public key, keep the private key hidden
  return crypt.getPublicKey()
}

/** Encrypt the provided string with the destination public key */
function encrypt (content, publicKey) {
  crypt.setKey(publicKey)
  return crypt.encrypt(content)
}

/** Decrypt the provided string with the local private key */
function decrypt (content) {
  crypt.setKey(privateKey)
  return crypt.decrypt(content)
}
/** Export keys */
function exportKeys (publicKey) {
  return {
    publicKey: publicKey, 
    privateKey: privateKey
  }
}

Затем я мог бы показать пользователю QR-код или что-то еще, чтобы экспортировать его ключи на другое устройство, и позволить ему сделать противоположное от нового с чем-то вроде "importKeys".

Хотя это может сработать, я бы раскрыл закрытый ключ с помощью "exportKeys" также на стороне клиента. Но будет ли это проблемой для безопасности, если вы на самом деле не отправляете закрытый ключ через Интернет?

Есть еще какой совет по этому поводу?

Может быть, использовать одноразовый токен / ключ доступа для (шифрования и) синхронизации реального ключа? так что, по крайней мере, настоящий ключ не будет отображаться напрямую (устройством записи экрана или чем-то еще)

apple apple 09.08.2018 14:48

Какую версию PHP вы используете? Если PHP 7.2, то я бы посоветовал вам использовать функции sodium, а точнее sodium_crypto_boxphp.net/manual/en/function.sodium-crypto-box.php

user2560539 09.08.2018 14:50

@PeterDarmis Здесь задействован только Javascript.

Manolo 09.08.2018 14:53

@Manolo, извините, тогда плохо ... В этом случае вы можете использовать NaCl.js github.com/tonyg/js-nacl для тех же функций или использовать любую реализацию libsodium в javascript в github, с которой вам удобно.

user2560539 09.08.2018 14:56

@PeterDarmis Вы имеете в виду, как и appleapple, зашифровать закрытый ключ перед его экспортом и требовать ключ для его импорта?

Manolo 09.08.2018 15:51

@Manolo нет, я имел в виду библиотеку libsodium, я думаю, что она имеет ту же функциональность, что и та, которую вы используете. Использование Service Worker - это здорово, но зачем вообще экспортировать ключи? Предложите пользователю зашифровать оба ключа, используя фразу по своему выбору. Когда на другом устройстве расшифруйте, используя эту фразу.

user2560539 09.08.2018 16:01

@Manolo В случае, если вы можете взаимодействовать с Service Worker с этой страницы, передайте фразу пользователя вашему Service Worker и получите ключи, зашифрованные с помощью парольной фразы. Также, пожалуйста, прочтите этот gist.github.com/atoponce/… и используйте что-то отличное от RSA

user2560539 09.08.2018 16:14
Поведение ключевого слова "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) для оценки ваших знаний,...
0
7
543
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

В случае сообщений private и encrypted, возможно, вы могли бы использовать реализацию libsodium в javascript, такую ​​как js-nacl или libsodium для реализации Public-key authenticated encryption using crypto_box. Большая часть функций аналогична той, которую вы уже используете. Чтобы лучше объяснить:

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

Отправителю нужны sender-PrivateKey, recipient-PublicKey и nonce для шифрования сообщения.

Получателю нужны recipient-PrivateKey, sender-PublicKey и nonce для расшифровки сообщения.

Пример кода взят со страницы js-nacl на Github.

senderKeypair = nacl.crypto_box_keypair();
recipientKeypair = nacl.crypto_box_keypair();
message = nacl.encode_utf8("Hello!");

nonce = nacl.crypto_box_random_nonce();
packet = nacl.crypto_box(message, nonce, recipientKeypair.boxPk, senderKeypair.boxSk);

decoded = nacl.crypto_box_open(packet, nonce, senderKeypair.boxPk, recipientKeypair.boxSk);

"Hello!" === nacl.decode_utf8(decoded); // always true

I want to encrypt messages in chat rooms (web app) in a way that it wouldn't be possible for anyone to decrypt them except for the receivers. It seems that RSA encryption is a good way.

Я не знаю, подходит ли шифрование RSA. Согласно тому, что считается лучшей тактикой Лучшие практики криптографии - асимметричное шифрование, для шифрования лучше использовать функции libsodium (NaCL), чем RSA.

Последний вопрос: как экспортировать ключи, не раскрывая их?

Вы можете экспортировать ключи, используя nacl.crypto_box_seed_keypair(Uint8Array) и вводимые пользователем данные (для преобразования в Uint8Array используйте nacl.encode_utf8 (строка)).

nacl.crypto_box_seed_keypair(Uint8Array)

  • Produces an encrypted authenticated box keypair from its argument. A given binary input will always produce the same keypair as output.

  • The input may be of any length. The input is hashed once with sha512, and the first 32 bytes of the result are taken as the 32-byte secret key, which is then passed to nacl.crypto_box_keypair_from_raw_sk.

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