We use window.crypto.subtle.generateKey to generate an RSA key pair.
How can we use the Web Crypto API to add a passphrase to the private key?
Keys generated with WebCrypto are not password-protected.
You could export the key and build a format that supports encryption, like pkcs8 in a PEM file, but to do this it would be needed to use an additional library.
I'm a bit late to the party, but isn't wrapKey() what you're looking for? It's on the same API and allows you to wrap the key up in a password-protected form, e.g. pkcs8.
#pedrofb is right. If you wanted to do this for better or worse PKCS8 is the right format, here is a link to code that can be used to create such a bag - https://github.com/PeculiarVentures/PKI.js/blob/5b9c35c154c48b232b45cc2a908c88e2f56a8447/src/PKCS8ShroudedKeyBag.js
You should probably also read this: http://unmitigatedrisk.com/?p=543 which describes some concepts related to key bags that are material.
You may also want to look into using webcrypto in a service worker and exposing an interface over PostMessage to get the operation to take place. This, combined with a non-exportable key, provides some protection from arbitrary use of the key, e.g the attacker can only do what the interface allows.
Related
I am developing and web based end to end encrypted chat website. For that I am generating private keys using the window.crypto.subtle.generateKey function provided in the web crypto api.
I want the user to remember or store a mnemonic phrase like we use in ethereum wallets instead of an encryption key.
Is there a way to generate the mnemonic phrase from the private key that is generated by the window.crypto.subtle.generateKey function or is there any other way I should go to implement this?
Thanks in advance
Is there a way to generate the mnemonic phrase from the private key
It's the other way around. A set of private keys can be determined from each mnemonic phrase - but you can't determine a mnemonic from a private key.
A widely-used standard is BIP-39. Even though it was first introduced as a Bitcoin Improvement Protocol, many Ethereum wallets use it too. You can find its JS implementation in this package for example.
Note: You're looking for functions mnemonicToSeed() and mnemonicToSeedSync(). Even though it might seem at the first look that entropyToMnemonic() translates private key to the phrase, it's not true - the entropy numbers are just positions of the words in the wordlist, not the private key bytes.
What you want, as you describe it, is to encode your private key into mnemonic words. Which you totally can, with the simplest example being: split up the key into chunks of n-bits, and match each chunk to a word list consisting of 2^n words.
Whether you actually want this for your overall purposes is a different question.
I'd also like to expand on Petr Hejda's answer, which at first confused me, but I now understand.
Petr is using the definition of "private key" in a different context than in the question. Petr is referring to "private keys" in terms of the bitcoin protocol, where the mnemonic is not used as an encoding for private keys, but to generate a seed which may then be used to generate any number of keys deterministically (BIP-0032), so that such generated keys can be re-generated when using the same seed, which in turn can be re-generated from the mnemonic. In this protocol, the mnemonic-to-seed is defined, but seed-to-mnemonic is not, because the protocol never does that. It only generates mnemonics from entropy, and then generate the seed from the mnemonic.
But in your case, you can simply feed it your "private key" (as you've defined it) as the "entropy" input in the entropyToMnemonic() function, and it will give you the mnemonic encoding of the "private key" that you wanted. You'll still have to decode it yourself though, as the BIP39 package doesn't have that functionality.
Im using the JavaScript library forge.js (https://github.com/digitalbazaar/forge)
rsa publicKey if 896 bits in length lets me encrypt a fare bit of text but, the length of the publicKey it's self is too long for my needs.
If I shorten it to a key of 460 bits then the length of the key is almost ok but, I then am limited to only encrypting a short amount.
I like the features of RSA (encrypt/decrypt & sign/verify) but I don't like the length of the key it's self and the limit on size.
Is there another form of encryption that would be better suited for my use?
needs:
A public key about 20 characters long
to be able to encrypt around 140 characters
same or similar features as RSA
I have been playing around with forge AES but it looks like the encryption is sort of a shared thing - You have your one key (that is shared?). then you can create a cypher and decypher. But I don't see how this would work similar to rsa as; with rsa I can share my publicKey and be safe to sign and decrypt but I don't see how I can do the same with my current understanding of aes.
How I currently would opperate:
//make sure that what user has said both hasn't been tampered with and is for you
var kp=forge.pki.rsa.generateKeyPair({bits: 896,e:0x10001});
var m=['Hi!'];
m[1]=kp.privateKey.sign(forge.md.sha1.create().update(m[0],'utf8'));
console.log(m);
console.log(kp.publicKey.verify(forge.md.sha1.create().update(m[0],'utf8').digest().bytes(),m[1]));
var asked='did you read this?';
var ask=kp.publicKey.encrypt(asked);
var read=kp.privateKey.decrypt(ask);
var r=['yes!'];
console.log('yes?');
r[1]=kp.privateKey.sign(forge.md.sha1.create().update(r[0],'utf8'));
r[2]=kp.privateKey.sign(forge.md.sha1.create().update(read,'utf8'));
console.log(kp.publicKey.verify(forge.md.sha1.create().update(asked,'utf8').digest().bytes(),r[2]));
Note: You would need do the decrypt and verify with try{}catch(e){} in production just incase the messages we're for a different users publicKey.
So far I can encrypt and decrypt REALLY basicly but I don't understand how to turn this form of cyrptography into what I am used to
//encypher the letter i then decypher it
var aes=forge.pkcs5.pbkdf2('k9','kr',1000,32);
var ci=forge.cipher.createCipher('AES-CBC',aes);
ci.start({'iv':'k5'});
ci.update(forge.util.createBuffer('i','utf8'));
ci.finish();
console.log(ci.output.toHex());
var ci=forge.cipher.createDecipher('AES-CBC',aes);
ci.start({'iv':'k5'});
ci.update(forge.util.createBuffer(forge.util.hexToBytes('7276131d61a323c37b5e451c3acc983e')));
ci.finish();
ci.output.toString('utf8')
//7276131d61a323c37b5e451c3acc983e
//"i"
// k9 kr k5 might as well just be me mashing the keyboard with my head btw
No, you can't use AES as a replacement of RSA, because as you already noted, then AES key must be shared.
A 460 bit RSA key doesn't provide (any) security nowadays. It can be brute-forced with a little bit of EC2 time. The recommendation would be to use at least 2048 bit RSA keys.
Since you want to sign stuff, you can use ECDSA which is based on Elliptic Curve Cryptography (ECC) and enables you to use much smaller keys for similar security (Some numbers). Forge doesn't provide ECC support yet.
SJCL provides an implementation of ECDSA
Add sjcl.js, core/bn.js, core/ecc.js
Generate keys var ecdsaKeys = sjcl.ecc.ecdsa.generateKeys(256);
ecdsaKeys.pub provides the verify() function
ecdsaKeys.sec provides the sign() function
If you need to send the public or secret key, then you need to serialize it yourself.
If you need encryption instead of signature, use ElGamal instead of ECDSA. SJCL also provides that. Since it is impossible to encrypt 140 characters with any size of ElGamal keys, you would need to opt in for a hybrid encryption with AES. SJCL also provides that with some authenticated modes like GCM or CCM.
I'm a complete beginner in crypto. What I know about Diffie Hellman Key exchange is:
One Public key is generated and is world readable.
Sender and Reciever generate their own Private keys independent of each other or the public key
They mix their pvt keys with public key and send to each other
They mix the recieve d key with their respective pvt key and end up getting same key which is known by no one else.
They can now use any symmetric key crypto to encrypt and decrypt.
The question is: Is this computationally possible in javascript?
Yes, it is computationally possible (most algorithms are, given enough time and memory). However, I think you should read more into DH, because the above scheme isn't it. And if you have read into it, continue with ECDH because it will perform much better on Java Script.
Also note that implementing cryptography in Java Script has many pitfalls, especially if run within the browser, and even more so if it is run within the browser without TLS.
I'd like to encrypt and decrypt data with private and public keys, respectively.
The data is between 1 and 32 bytes.
I do not want to use a symmetric cipher for the data - I want to use the keys on the data directly. (This is not normally done for performance reasons, but my data is very small.)
Is this possible and Where should I start?
I'd like to encrypt and decrypt data with private and public keys
Pretty much anyone who's worked with crypto will tell you that you write crypto at your own risk. Use the standard libraries, they're made with all the things that (if you are not aware of these techniques) leave your traffic unsecured.
That said, here's some Python libraries (but you can get this in most languages from PHP to Java or whatever floats your boat):
https://pypi.python.org/pypi/pycrypto
https://www.dlitz.net/software/pycrypto/
Crypto RSA in Python
https://pypi.python.org/pypi/PyECC
You'll see pycrypto because it's popular if you're looking to use RSA. Another package is PyECC which includes functionality for elliptic curve crypto. This is important if you're looking to reduce your key size or have less resources to devote to crypto, usually in mobile systems or something small. The difference in key sizes (link) can get ridiculous as the keys grow (for increased security)
Maybe keyczar is what you're looking for:
http://www.keyczar.org/
Is there any library available (or well-written algorithm reference I could implement) that would allow me to sign a piece of text with a private key, preferably my existing SSH (RSA) or PGP key?
My goal is to write a bookmarklet to sign my blog posts, and provide another bookmarklet to allow others to verify them. I'm not trying to do any kind of secure communication. I just thought it might be neat to be able to store the public keys of others and use them to verify authorship automatically.
Maybe this one? PGP / GnuPG / OpenPGP Message Encryption in JavaScript
You may want to look into jCryption: http://www.jcryption.org/
It's made to encrypt forms using ajax, but it may be somewhere to get started.