javascript - 从 Web 应用程序导出/导入 RSA key 对

标签 javascript encryption rsa service-worker

我想对聊天室(网络应用程序)中的消息进行加密,除了接收者之外,任何人都无法解密它们。看来RSA加密是一个好方法。每个用户(实际上是每个设备)都会有一个公钥-私钥对,每条消息都将使用接收者公钥进行加密,并使用接收者私钥进行解密,因此每条消息都应该发送与接收者相同的次数。 我找到了tutorial其中解释了如何实现该目标。加密/解密是在 Service Worker 中计算的,私钥不会暴露,只是存储在同一个 Worker 中。

但是,我想知道是否有一种安全的方法可以从设备导出 key 对,以便能够从另一台设备查看您的消息。 我可以添加一个名为 "exportKeys"messageType 并检索两个 key ,如下例所示:

从上面的教程中添加“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
  }
}

然后,我可以向用户显示二维码或其他内容,将其 key 导出到另一台设备,并让他使用 "importKeys" 之类的内容执行与新设备相反的操作。

尽管这可能有效,但我也会在客户端使用 "exportKeys" 公开私钥。但如果你不真正通过互联网发送私钥,会出现安全问题吗?

还有其他相关提示吗?

最佳答案

如果是私有(private)加密消息,也许您可​​以在javascript中使用libsodium实现,例如js-nacl ,或libsodium用于使用 crypto_box 实现公钥验证加密。大多数功能与您已经使用的功能相似。为了更好地解释:

发送者和接收者必须拥有一组 key (公共(public)私有(private))才能加密/解密消息。

发件人需要 sender-PrivateKeyrecipient-PublicKey 以及 nonce 来加密消息。

收件人需要 recipient-PrivateKeysender-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加密是不是一个好方法。根据被认为是最好的策略Cryptographic Best Practices - Asymmetric Encryption使用libsodium(NaCL)函数进行加密比RSA更好。

最后一件事是如何导出 key 而不泄露它们?

您可以使用 nacl.crypto_box_seed_keypair(Uint8Array) 导出 key 和用户提供的输入(要转换为 Uint8Array 使用 nacl.encode_utf8(String) )。

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.

关于javascript - 从 Web 应用程序导出/导入 RSA key 对,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51767414/

相关文章:

c# - .NET 中的 RSA 加密 - JAVA 中的解密 -> Java 抛出 "modulus not positive"错误

javascript - FullCalendar:更改事件开始日期和时间格式

javascript - Chart.js 仅在按下 f12 后显示

javascript - 如何字符串替换数组中的符号并拆分?

c# - .NET 的等效 "openssl_seal"?

iphone - 如何从iPhone程序中的证书获取公钥?

erlang - 使用 Erlang 生成 RSA key 对?

用于检查 Gmail 未读计数的 Javascript

c# - Azure 网站上的数据保护/加密?

java - Java RSA 中来自字符串的键