7

I'd like to generate a public/private keypair in javascript, and use the public key to encrypt message and the private key to decrypt the message.

I prefer native browser support over external libraries. How can I do this in JavaScript?

Modern browsers implement window.crypto.subtle.generateKey. I can use it to generate ECDSA private/public keys to sign/verify messages, this works. But I cannot find a way how to use it to generate pub/private keys to encrypt/decrypt. If I try the generateKey for the recommended AES-GCM Algorithm, it generates just one cryptoKey, which can be probably used to both encrypt and decrypt. But I prefer to get a keypair (publib/private keys), not just a single key. Any suggestions?

This table lists currently supported methods, but it seems none of the green algorithms is what I need: https://diafygi.github.io/webcrypto-examples/

asked Sep 18, 2017 at 19:23
4
  • 3
    Since JavaScript runs in the user's browser, how could this possibly be secure? Any debugger would be able to isolate your private key pretty easily, negating the entire purpose of encryption. My recommendation would be to host the private key side in a php or asp or other sever-side process , so the code can't be browsed by the user. Commented Sep 18, 2017 at 19:37
  • Sure, but my problem is that none of the green-marked algos generate a private key at all. Commented Sep 18, 2017 at 19:44
  • @Jim sometimes the goal is to isolate the key from the server (ie provide end-to-end encryption to the user). The practicalities of that is a can of worms. Commented Sep 18, 2017 at 19:48
  • Isn't AES a symmetric-key algorithm? I would only expect it to only produce one, private, key. You would need to use a different algorithm in order to produce a public/private pair. Commented Sep 18, 2017 at 20:06

3 Answers 3

2

Due to ProtonMail's efforts, there is now an open source Symmetric Key Encryption implementation in the browser at: https://openpgpjs.org/

This has had multiple security audits and is the basis of protonmail.com, so it has a fairly good records and maintainer in place. They also have a good summary of important security browser models.

answered Mar 15, 2018 at 11:27
Sign up to request clarification or add additional context in comments.

1 Comment

The question was about asymmetric key encryption, not symmetric key encryption
0

Fortunately the page you pointed at shows that ECDH - including ECDH key pair generation - is supported. This can be used to implement the ECIES encryption scheme. You can then use the raw bits as raw AES key and use that for AES-GCM mode.

The security would of course depend on the system, and Java Script crypto is notoriously hard to get right. This kind of scheme should only be used in addition to TLS, and even then only with extreme care.

answered Sep 19, 2017 at 0:55

2 Comments

I am not sure if I understand you right. I need a public key which will be sent to other person to encrypt a message, and I need a private key which will stay in the browser so it can decrypt the message later. With your proposal, I will have ECDH keypair (public and private keys) but those can be used only to deriveKeys. So, if I derive an AES key from this, can it be used as a public key to encrypt, and I will be able to use my private (ECDH) key to decrypt?
No, what ever you do, you need a trusted public key of the other person to send him an encrypted message. If you don't have that then anybody could create their own key pair and ask for you to encrypt. Or, if you send them a private key, then anybody could decrypt the message using that. Once you have received the public key then you can create a temporary key pair to derive a secret AES key. You then send the encrypted message & (untrusted) public key to the other person. That other person also derives the AES key and decrypts the message. Everything from "Once" is just a description of IES
-1

mdn example

const encode = (e => e.encode.bind(e))(new TextEncoder)
let { publicKey: pub, privateKey: key } = await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-521' }, true, ['deriveKey']) // generate key pairs
// get server ecdh public key
let jwk = await fetch('/others public key').then(res=>res.json())
let spub = await crypto.subtle.importKey('jwk', jwk, { name: 'ECDH', namedCurve: 'P-521' }, false, [])
// use spub and key derive a ase key
let gcm = crypto.subtle.deriveKey({ name: 'ECDH', namedCurve: 'P-521', public: spub }, key, { name: 'AES-GCM', length: 256 }, true, ["encrypt", "decrypt"])
// now use gcm to encrypt or decrypt
let text = crypto.subtle.encrypt({ name: 'AES', length: 256 }, gcm, encode('hello world'))
// same on the server

answered Mar 18, 2020 at 6:19

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.