/*
* Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* For the prime check..
* FIPS 186-4 Section C.3 Table C.1
* Returns the minimum number of Miller Rabin iterations for a L,N pair
* (where L = len(p), N = len(q))
* L N Min
* 1024 160 40
* 2048 224 56
* 2048 256 56
* 3072 256 64
*
* BN_check_prime() uses:
* 64 iterations for L <= 2048 OR
* 128 iterations for L > 2048
* So this satisfies the requirement.
*/
#include <string.h> /* memset */
#include <openssl/sha.h> /* SHA_DIGEST_LENGTH */
#include <openssl/rand.h>
#include "crypto/bn.h"
#include "internal/ffc.h"
/*
* Verify that the passed in L, N pair for DH or DSA is valid.
* Returns 0 if invalid, otherwise it returns the security strength.
*/
static int ffc_validate_LN(size_t L, size_t N, int type)
{
if (type == FFC_PARAM_TYPE_DH) {
/* Valid DH L,N parameters from SP800-56Ar3 5.5.1 Table 1 */
if (L == 2048 && (N == 224 || N == 256))
return 112;
} else if (type == FFC_PARAM_TYPE_DSA) {
/* Valid DSA L,N parameters from FIPS 186-4 Section 4.2 */
if (L == 1024 && N == 160)
return 80;
if (L == 2048 && (N == 224 || N == 256))
return 112;
if (L == 3072 && N == 256)
return 128;
}
return 0;
}
/* FIPS186-4 A.2.1 Unverifiable Generation of Generator g */
static int generate_unverifiable_g(BN_CTX *ctx, BN_MONT_CTX *mont, BIGNUM *g,
BIGNUM *hbn, const BIGNUM *p,
const BIGNUM *e,const BIGNUM *pm1,
int *hret)
{
int h = 2;
/* Step (2): choose h (where 1 < h)*/
if (!BN_set_word(hbn, h))
return 0;
for (;;) {
/* Step (3): g = h^e % p */
if (!BN_mod_exp_mont(g, hbn, e, p, ctx, mont))
return 0;
/* Step (4): Finish if g > 1 */
if (BN_cmp(g, BN_value_one()) > 0)
break;
/* Step (2) Choose any h in the range 1 < h < (p-1) */
if (!BN_add_word(hbn, 1) || BN_cmp(hbn, pm1) >= 0)
return 0;
++h;
}
*hret = h;
return 1;
}
/*
* FIPS186-4 A.2 Generation of canonical generator g.
*
* It requires the following values as input:
* 'evpmd' digest, 'p' prime, 'e' cofactor, gindex and seed.
* tmp is a passed in temporary BIGNUM.
* mont is used in a BN_mod_exp_mont() with a modulus of p.
* Returns a value in g.
*/
static int generate_canonical_g(BN_CTX *ctx, BN_MONT_CTX *mont,
const EVP_MD *evpmd, BIGNUM *g, BIGNUM *tmp,
const BIGNUM *p, const BIGNUM *e,
int gindex, unsigned char *seed, size_t seedlen)
{
int ret = 0;
int counter = 1;
unsigned char md[EVP_MAX_MD_SIZE];
EVP_MD_CTX *mctx = NULL;
int mdsize;
mdsize = EVP_MD_size(evpmd);
if (mdsize <= 0)
return 0;
mctx = EVP_MD_CTX_new();
if (mctx == NULL)
return 0;
/*
* A.2.3 Step (4) & (5)
* A.2.4 Step (6) & (7)
* counter = 0; counter += 1
*/
for (counter = 1; counter <= 0xFFFF; ++counter) {
/*
* A.2.3 Step (7) & (8) & (9)
* A.2.4 Step (9) & (10) & (11)
* W = Hash(seed || "ggen" || index || counter)
* g = W^e % p
*/
static const unsigned char ggen[4] = { 0x67, 0x67, 0x65, 0x6e };
md[0] = (unsigned char)(gindex & 0xff);
md[1] = (unsigned char)((counter >> 8) & 0xff);
md[2] = (unsigned char)(counter & 0xff);
if (!EVP_DigestInit_ex(mctx, evpmd, NULL)
|| !