1

I'm trying to generate every time same RSA key with RSA_generate_key_ex(...) and then write in file, but I always get different keys. Is there any turnkey solution or I need to write my own function for this? (I know that this is unsecure solution)

char *passW = "password";
RSA *rsa = RSA_new();

BIGNUM *bn = BN_new();
BN_bn2bin(bn, (unsigned char *)passW);
BN_set_word(bn, RSA_3);

OpenSSL_add_all_algorithms();
RSA_generate_key_ex(rsa, 1024, bn, nullptr); 

/* Save private key */
FILE* fp = fopen("private.key", "w");
PEM_write_RSAPrivateKey(fp, rsa, EVP_aes_256_cbc(), nullptr, 0, nullptr, &passW);
fclose(fp);

I expect same RSA key, if password matches.

BrutalWizard
  • 495
  • 1
  • 9
  • 19
  • Read the documentation for `BN_bn2bin` it converts from a Big Number (`bn` initialised to 0 by `BN_new`) and stores it in the address provided (`passW`). See: https://www.openssl.org/docs/man1.0.2/man3/BN_bn2bin.html – Richard Critten Apr 30 '19 at 19:43
  • How do you seed random number generator before calling this? – SergeyA Apr 30 '19 at 19:47
  • @SergeyA, **RAND_seed(*char rand_buff[16]*, 16);** – BrutalWizard Apr 30 '19 at 19:51
  • 1
    Same seed could lead to same outcome. Try that. Preserve whatever seed you get the first time. If the password is salted you'll need to deal with that issue as well. – tadman Apr 30 '19 at 19:53
  • You need to make sure the seed is the same. If seed is the same, output would be identical. – SergeyA Apr 30 '19 at 19:55
  • I have tested and I get that **rand_buff = ""** *(nothing)* but **RAND_status** returns 1, it means *random generator has been seeded with enough data* – BrutalWizard Apr 30 '19 at 20:14

1 Answers1

2

Reading docs about RAND_seed I have found that, I have to write my one rand engine (I took it from this answer), I have modified this solution for my problem

// These don't need to do anything if you don't have anything for them to do.
static void stdlib_rand_cleanup() {}
static void stdlib_rand_add(const void *buf, int num, double add_entropy) {}
static int stdlib_rand_status() { return 1; }

// Seed the RNG. srand() takes an unsigned int, so we just use the first
// sizeof(unsigned int) bytes in the buffer to seed the RNG.
static void stdlib_rand_seed(const void *buf, int num)
{
    assert(num >= sizeof(unsigned int)); /// Use if statement, if u don't want to terminate ur app
    srand(*((unsigned int *)buf));
}

// Fill the buffer with random bytes.  For each byte in the buffer, we generate
// a random number and clamp it to the range of a byte, 0-255.
static int stdlib_rand_bytes(unsigned char *buf, int num)
{
    for(int index = 0; index < num; ++index)
    {
        buf[index] = rand() % 256;
    }
    return 1;
}

// Create the table that will link OpenSSL's rand API to our functions.
static RAND_METHOD stdlib_rand_meth = {
    stdlib_rand_seed,
    stdlib_rand_bytes,
    stdlib_rand_cleanup,
    stdlib_rand_add,
    stdlib_rand_bytes,
    stdlib_rand_status
};

// This is a public-scope accessor method for our table.
RAND_METHOD *RAND_stdlib() { return &stdlib_rand_meth; }

void createRSAKey() {
    // Intilize data
    int bits = 2048; // 512, 1024, 2048, 4096
    std::string passW = "password";    
    unsigned int randBuff = sizeof(passW);
    unsigned int randNum[4];

    // Create BIGNUM
    BIGNUM *bn = BN_new();
    BN_set_word(bn, RSA_3);

    // Create RSA
    RSA *rsa = RSA_new();

    // Connect algorithms, another way it crashes    
    OpenSSL_add_all_algorithms();

    // Randomize bytes
    RAND_set_rand_method(RAND_stdlib());
    RAND_seed(&randBuff, sizeof(randBuff));
    RAND_bytes(reinterpret_cast<unsigned char *>(&randNum[0]), sizeof(randNum));

    if(RSA_generate_key_ex(rsa, bits, bn, nullptr) != 1) { qDebug() << "error"; }

    // Save private key
    FILE *fp = fopen("private.key", "w");
    PEM_write_RSAPrivateKey(fp, rsa, nullptr, nullptr, 0, nullptr, &passW);
    fclose(fp);

    // Clear memory
    BN_free(bn);
    RSA_free(rsa);
}
BrutalWizard
  • 495
  • 1
  • 9
  • 19