Generate RSA key pair in javascript, based on a password
Asked Answered
B

5

20

As far as I understand, RSA keys are usually generated based on a (strong) random generator.

Instead, I want to create them based on a password.

Or rather on its hash, for example sha512(sha512(password+salt)+password+pepper)

This needs to be done client side, in JavaScript.

Would anyone know how to do this? Is there an easy JavaScript library that creates RSA key pairs deterministically, based on a given input?

(Actually, I'm mentioning RSA but any secure asymmetrical encryption would suffice, I just need public-private encryption)


Addition: I need this because I'm building some secure communication solution, that doesn't need to rely on the connection or even the server to be secure.

I'm encrypting all content with AES using random keys, and the keys are RSA-encrypted. The idea is Alice can RSA-encrypt her content (or actually, the AES-key for her content) with Bob's public key (therefore Bob's public key must be stored online).

Later, when Bob enters his password again, his browser can deterministically calculate his RSA private & public key on the spot, download the content from Alice, and decrypt it locally using his private key.

Bathos answered 22/6, 2012 at 12:35 Comment(5)
Creating RSA keys using JavaScript? I remember trying it myself. It ate up all my memory and took forever to calculate. I switched to Java then.Tabber
An asymmetrical encryption scheme other than RSA would be fine as well. But I need to generate the keys client side, and encrypt data (with private key) before sending it. Public key will be stored server side. I don't know if ECC approaches are any faster?Bathos
@SheldonPinkman encryption is done using public key, not private. Consquently your idea is flawed.Slack
@Eugene: sorry you're right, I meant encrypting with public keys, and I'm storing public keys + the encrypted content online. Users will actually encrypt stuff with eachother's public keys.Bathos
Note this warning about doing crypto in javascript -> https://mcmap.net/q/663805/-how-to-make-a-digital-signature-in-a-web-application-javascript-using-a-smartcardSykes
S
11

Looks like Cryptico can help you, when you feed your password as a seed for RNG.

Spandrel answered 23/6, 2012 at 12:3 Comment(0)
R
5

2020's year answer for browser/client-side:

If you want to use RSA encryption on client side with TypeScript (in browser or hybrid app with Ionic for example) do next:

  • npm i cryptico-js --save
  • in your TypeScript (v3.4+) code use next import: import * as cryptico from 'cryptico-js/dist/cryptico.browser.js';
  • after that you can use all cryptico methods as described there: https://www.npmjs.com/package/cryptico
Roberto answered 23/6, 2020 at 13:16 Comment(1)
It was actually not clear anywhere on the internet that I looked, on how to use it in Angular application. Thanks!Headcheese
M
4

I can not comment on my punctuationbut, but additional to what he said +Eugene_Mayevski_'EldoS

for javascript pure: https://www.npmjs.com/package/cryptico

for nodejs: https://www.npmjs.com/package/cryptico you need:

npm install cryptico

And add this line:

var cryptico = require("cryptico");

to create objects:

function cryptoObj(passPhrase)
{
   this.bits = 1024; //2048;
   this.passPhrase = passPhrase;
   this.rsaKey = cryptico.generateRSAKey(this.passPhrase,this.bits);
   this.rsaPublicKey = cryptico.publicKeyString(this.rsaKey);

   this.encrypt = function(message){
     var result = cryptico.encrypt(message,this.rsaPublicKey);
     return result.cipher;
   };

   this.decrypt = function(message){
     var result = cryptico.decrypt(message, this.rsaKey);
     return result.plaintext;
   };
}

console.log('---------------------------------------------------------');
var localEncryptor = new cryptoObj("XXyour secret txt or number hereXX");

var encryptedMessage = localEncryptor.encrypt('new message or json code here');
var decryptedMessage = localEncryptor.decrypt(encryptedMessage);

console.log('');
console.log('>>> Encrypted Message: '+encryptedMessage);
console.log('');
console.log('>>> Decrypted Message: '+decryptedMessage);
Maiden answered 8/2, 2015 at 0:45 Comment(1)
when i use var cryptico = require("cryptico"); in my component.ts i got an error -----"(SystemJS) XHR error (404 Not Found) loading localhost:5555/node_modules/crypto.js".Quod
C
2

RSA keys are not just random bits like most symmetric algorithms, they are exponents and modulouses derived from large prime numbers. Therefore I do not see any reasonable way you could generate them from a password. See this wikipedia article.

What are you using these key pairs for? Why must they be derived from a password? If you want to use a password to encrypt something, you could use a SHA256(password) to derive an AES256 key. (make sure to read up on key strengthening if you are going to do this).

Chirpy answered 22/6, 2012 at 15:6 Comment(3)
you can initialize the randomizer with the password, and get the key which "depends" on the password this way. But there's usually no practical reason to do this (I know one case when it is reasonable though :).Slack
Well, I suppose the lack of a RNG would be a good cause. But I've got the feeling this whole scheme has some serious design flaws.Gath
@Petey: I know RSA keys are not just random bits, but I could simply replace the random generator (wherever it occurs in an existing RSA key generator) with something that is derived from the password. It could even be a random generator that is simply seeded with the password's hash. That way, the same password will result in exactly the same RSA key.Bathos
S
2

2022 Updated - Deterministic RSA using node-forge

As I pointed out in another answer, you can use node-forge to create a "rigged" prng that consistently returns an appropriately formatted seed rather than a pseudo-random value.

Code could look like the following, grabbing user's input and generating a long hash from it:

import forge from "node-forge"

const userInput = 'The quick brown fox jumps over the lazy dog'

const md = forge.md.sha256.create();
md.update(userInput);
const seed = md.digest().toHex());

console.log(seed) // output: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592

Then creating the PRNG and generating the keys deterministically:

// "Rigged" PRNG
const prng = forge.random.createInstance()
prng.seedFileSync = () => seed

// Deterministic key generation
const { privateKey, publicKey } = forge.pki.rsa.generateKeyPair({ bits: 4096, prng })
Sequestered answered 29/4, 2022 at 11:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.