uint8_t sane_key(RSA *rsa) { // checks sanity of a RSA key (PKCS#1 v2.1) uint8_t sane = 1; BN_CTX *ctx = BN_CTX_new(); BN_CTX_start(ctx); BIGNUM *p1 = BN_CTX_get(ctx), // p - 1 *q1 = BN_CTX_get(ctx), // q - 1 *chk = BN_CTX_get(ctx), // storage to run checks with *gcd = BN_CTX_get(ctx), // GCD(p - 1, q - 1) *lambda = BN_CTX_get(ctx); // LCM(p - 1, q - 1) BN_sub(p1, rsa->p, BN_value_one()); // p - 1 BN_sub(q1, rsa->q, BN_value_one()); // q - 1 BN_gcd(gcd, p1, q1, ctx); // gcd(p - 1, q - 1) BN_lcm(lambda, p1, q1, gcd, ctx); // lambda(n) BN_gcd(chk, lambda, rsa->e, ctx); // check if e is coprime to lambda(n) if(!BN_is_one(chk)) sane = 0; // check if public exponent e is less than n - 1 BN_sub(chk, rsa->e, rsa->n); // subtract n from e to avoid checking BN_is_zero if(!chk->neg) sane = 0; BN_mod_inverse(rsa->d, rsa->e, lambda, ctx); // d BN_mod(rsa->dmp1, rsa->d, p1, ctx); // d mod (p - 1) BN_mod(rsa->dmq1, rsa->d, q1, ctx); // d mod (q - 1) BN_mod_inverse(rsa->iqmp, rsa->q, rsa->p, ctx); // q ^ -1 mod p BN_CTX_end(ctx); BN_CTX_free(ctx); // this is excessive but you're better off safe than (very) sorry // in theory this should never be true unless I made a mistake ;) if((RSA_check_key(rsa) != 1) && sane) { fprintf(stderr, "WARNING: Key looked okay, but OpenSSL says otherwise!\n"); sane = 0; } return sane; }
int generateRandomKeys(paillierKeys *keys, int *key_len, BN_CTX *ctx) { int ret = 1, final_key_l = 0; BIGNUM *p, *q, *tmp, *n, *n2, *g, *lamda, *mu; if (key_len != NULL && *key_len == 0) { *key_len = DEFAULT_KEY_LEN; final_key_l = *key_len; } else if (key_len != NULL) { final_key_l = *key_len; } else { final_key_l = DEFAULT_KEY_LEN; } if (final_key_l < 32) { fprintf(stderr, "Key lenght too short. Minimum lenght 32 bits"); goto end; } BN_CTX_start(ctx); // Temp BIGNUMs p = BN_CTX_get(ctx); q = BN_CTX_get(ctx); tmp = BN_CTX_get(ctx); // Part of the keys BIGNUMs n = BN_new(); n2 = BN_new(); g = BN_new(); lamda = BN_new(); mu = BN_new(); // 1. Choose two large prime numbers // This numbers have to hold gcd(pq, (p-1)(q-1)) = 1 unsigned char buffer; do { if (!RAND_bytes(&buffer, sizeof(buffer))) goto end; srandom((int)buffer); if (!BN_generate_prime_ex(p, final_key_l / 2, 0, NULL, NULL, NULL)) goto end; if (!BN_generate_prime_ex(q, final_key_l / 2, 0, NULL, NULL, NULL)) goto end; // 2. Compute n = pq if (!BN_mul(n, p, q, ctx)) goto end; // Test if primes are ok if (!BN_sub_word(p, 1)) goto end; if (!BN_sub_word(q, 1)) goto end; if (!BN_mul(tmp, p, q, ctx)) goto end; } while (BN_cmp(p, q) == 0 || BN_gcd(tmp, tmp, n, ctx) != 1); // and lamda = lcm(p-1,q-1) if (!BN_lcm(lamda, p, q, ctx)) goto end; if (!BN_mul(n2, n, n, ctx)) goto end; do { // 3. Select a random integer g moz n2 do { if (!BN_rand_range(g, n2)) goto end; } while (BN_is_zero(g)); // 4. Ensure n divides the order of g if (!BN_mod_exp(tmp, g, lamda, n2, ctx)) goto end; if (L(tmp, tmp, n, ctx) != 0) goto end; BN_mod_inverse(mu, tmp, n, ctx); } while (mu == NULL); keys->pub.n = n; keys->pub.n2 = n2; keys->pub.g = g; keys->priv.n = BN_dup(n); keys->priv.n2 = BN_dup(n2); keys->priv.lamda = lamda; keys->priv.mu = mu; keys->n = BN_dup(n); keys->n2 = BN_dup(n2); ret = 0; end: if (ret) { ERR_load_crypto_strings(); fprintf(stderr, "Error generating keys: %s", ERR_error_string(ERR_get_error(), NULL)); } BN_CTX_end(ctx); return ret; }