I'm trying to make openssl generate deterministic private and public RSA key-pair. The idea is that I fill my seedbuf with a HASH of some device dependent data, and use that as a seed. But seeding the RAND does not seem to work, the keys are still randomized.
For various reasons I don't want to just generate the key once, and then store it, I only want the private key to exist in memory.
RAND_seed(seedbuf, sizeof(seedbuf));
bne = BN_new();
if (1 != BN_set_word(bne,e)) {
goto free_stuff;
}
keypair = RSA_new();
if(1 != RSA_generate_key_ex(keypair, KEY_LENGTH, bne, NULL)) {
goto free_stuff;
}
So basically I want the "RSA_generate_key_ex" function to return same key-pair, each time it is seeded with same input.
You cannot generate private key from public key but you can generate public key from the private key using puttygen. As @alfasin mentioned if you could generate the private key from public key then RSA would be useless and this would make you vulnerable to attack.
Making openssl generate deterministic key...
I don't believe you can do it out of the box. By default, OpenSSL uses md_rand
, and that auto seeds itself. Calling rand_seed
internally calls rand_add
, which adds to the state (rather than discarding/replacing state). You can find the source for md_rand
in crypto/rand/md_rand.c
.
If you build with FIPS
enabled, then there are deterministic random bit generators from NIST's SP 800-90. However, I seem to recall they operate in similar fashion to md_rand
. That is, you can add to internal state, but you can't really control it. You can find the source in crypto/rand/rand_lib.c
.
I think you have one option. You can create you own my_rand
. Base it on a block cipher or hash. On startup, seed it with device dependent data, and then return the deterministic bytes.
Now, to get functions like RSA_generate_key_ex
to use your PRNG, you have to package it in an OpenSSL ENGINE
. Richard Levitte of OpenSSL has a nice two-series blog at Engine Building Lesson 1: A Minimum Useless Engine and Engine Building Lesson 2: An Example MD5 Engine on the OpenSSL blog.
Once you package it with an engine, you can use it like so. After you set the random method with ENGINE_METHOD_RAND
, you will be using your algorithm.
ENGINE* eng = ENGINE_by_id("my_rand");
unsigned long err = ERR_get_error();
if(NULL == eng) {
fprintf(stderr, "ENGINE_by_id failed, err = 0x%lx\n", err);
abort(); /* failed */
}
int rc = ENGINE_init(eng);
err = ERR_get_error();
if(0 == rc) {
fprintf(stderr, "ENGINE_init failed, err = 0x%lx\n", err);
abort(); /* failed */
}
rc = ENGINE_set_default(eng, ENGINE_METHOD_RAND);
err = ERR_get_error();
if(0 == rc) {
fprintf(stderr, "ENGINE_set_default failed, err = 0x%lx\n", err);
abort(); /* failed */
}
If you want to look at a ENGINE
implementation, take a look at the rdrand
engine in crypto/engine/eng_rdrand.c
. There's not much to the engine, and it will be easy to copy/paste. Be sure to add your new engine to the Makefile
in crypto/engine/Makefile
.
If you're looking for a way to generate deterministic keys not necessarily using OpenSSL, GnuTLS may be able to help:
certtool --generate-privkey --outfile privkey.pem --key-type=rsa --sec-param=high --seed=0000000000000000000000000000000000000000000000000000000000000000
Using --seed
, at least in the current version, implies using --provable
algorithm generation (FIPS PUB186-4).
The generated privkey.pem
will be in RSA-PSS format, you can use the following command to convert it to raw RSA format:
certtool --to-rsa --load-privkey privkey.pem --outfile privkey.key
Then from a key in either format you can generate a self-signed certificate, if needed:
certtool --generate-self-signed --load-privkey privkey.key --outfile signed.crt --template cert.cfg
If you'd like to make this step deterministic too or avoid answering the questions each time you run the command, add --template cert.cfg
parameter to the last command. The minimum content of cert.cfg
file to make the generation deterministic would be:
serial = 1
activation_date = "2019-01-01 00:00:00 UTC"
expiration_date = "2029-01-01 00:00:00 UTC"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With