mirror of
https://github.com/stefanberger/libtpms
synced 2026-01-12 01:03:11 +00:00
tpm2: Use Carmichael function for RSA priv. exponent D (>= 2048 bits)
Like OpenSSL use the Carmichael function for the RSA private exponent D when an RSA key has >= 2048 bits and public exponent e uses more than 2 bytes. Otherwise use the Euler totient function. The main difference is that by TPM 2 using the Carmichael function OpenSSL now behaves the same way as when it is used by other programs that for example load keys from PEM files where the private exponent D was calculated with this function. The difference is seen when for example blobs cannot be decrypted where newer versions of OpenSSL (with implicit rejection enabled) returned results of 48 bytes every time rather than a deterministic (for same input blob) but varying number of bytes (Euler totient). Switching to the Carmichael function does not have any negative impact on interoperatibility with OpenSSL nor does it affect interoperability between versions of TPM 2 code that did not use it. This means that data encrypted or signed by OpenSSL or TPM 2 can be decrypted or verified by TPM 2 or OpenSSL and that data encrypted or signed with either new or old code in TPM 2 can be decrypted or verified with either old or new code in TPM 2. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
parent
6566330177
commit
920aa5e02b
@ -471,7 +471,7 @@ GetDigestNameByHashAlg(const TPM_ALG_ID hashAlg)
|
||||
}
|
||||
|
||||
static BOOL
|
||||
ComputePrivateExponentD(
|
||||
ComputePrivateExponentD_Euler(
|
||||
const BIGNUM *P, // IN: first prime (size is 1/2 of bnN)
|
||||
const BIGNUM *Q, // IN: second prime (size is 1/2 of bnN)
|
||||
const BIGNUM *E, // IN: the public exponent
|
||||
@ -500,6 +500,78 @@ ComputePrivateExponentD(
|
||||
return pOK;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
ComputePrivateExponentD_Carmichael(
|
||||
const BIGNUM *P, // IN: first prime (size is 1/2 of bnN)
|
||||
const BIGNUM *Q, // IN: second prime (size is 1/2 of bnN)
|
||||
const BIGNUM *E, // IN: the public exponent
|
||||
const BIGNUM *N, // IN: the public modulus
|
||||
BIGNUM **D // OUT:
|
||||
)
|
||||
{
|
||||
BOOL pOK = FALSE;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *pm1, *qm1, *pm1qm1, *gcd, *lcm;
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
if (!ctx)
|
||||
return FALSE;
|
||||
|
||||
BN_CTX_start(ctx);
|
||||
pm1 = BN_CTX_get(ctx);
|
||||
qm1 = BN_CTX_get(ctx);
|
||||
pm1qm1 = BN_CTX_get(ctx);
|
||||
gcd = BN_CTX_get(ctx);
|
||||
lcm = BN_CTX_get(ctx);
|
||||
if (pm1 && qm1 && pm1qm1 && gcd && lcm) {
|
||||
BN_set_flags(pm1, BN_FLG_CONSTTIME);
|
||||
BN_set_flags(qm1, BN_FLG_CONSTTIME);
|
||||
BN_set_flags(pm1qm1, BN_FLG_CONSTTIME);
|
||||
BN_set_flags(gcd, BN_FLG_CONSTTIME);
|
||||
BN_set_flags(lcm, BN_FLG_CONSTTIME);
|
||||
|
||||
/* Carmichael */
|
||||
pOK = BN_sub(pm1, P, BN_value_one());
|
||||
pOK = pOK && BN_sub(qm1, Q, BN_value_one());
|
||||
pOK = pOK && BN_mul(pm1qm1, pm1, qm1, ctx);
|
||||
pOK = pOK && BN_gcd(gcd, pm1, qm1, ctx);
|
||||
pOK = pOK && BN_div(lcm, NULL, pm1qm1, gcd, ctx);
|
||||
pOK = pOK && (*D = BN_mod_inverse(NULL, E, lcm, ctx)) != NULL;
|
||||
}
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
return pOK;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
ComputePrivateExponentD(
|
||||
const BIGNUM *P, // IN: first prime (size is 1/2 of bnN)
|
||||
const BIGNUM *Q, // IN: second prime (size is 1/2 of bnN)
|
||||
const BIGNUM *E, // IN: the public exponent
|
||||
const BIGNUM *N, // IN: the public modulus
|
||||
BIGNUM **D // OUT:
|
||||
)
|
||||
{
|
||||
int nbits = BN_num_bits(N);
|
||||
/* like OpenSSL:
|
||||
* < 2048 bits : Euler totient function
|
||||
* >= 2048 bits & e >= 0x10000: Carmichael function
|
||||
*/
|
||||
if (nbits >= 2048 && BN_num_bits(E) > 16) {
|
||||
if (ComputePrivateExponentD_Carmichael(P, Q, E, N, D) == FALSE)
|
||||
return FALSE;
|
||||
/* D too small? A key generated following SP800-56B rev 1
|
||||
* 6.3.1.1 step 3 should not exist -> fall back to Euler
|
||||
*/
|
||||
if (BN_num_bits(*D) <= (nbits >> 1))
|
||||
return ComputePrivateExponentD_Euler(P, Q, E, N, D);
|
||||
return TRUE;
|
||||
} else {
|
||||
return ComputePrivateExponentD_Euler(P, Q, E, N, D);
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
/* Build an RSA key from the given BIGUMs. The caller must always free
|
||||
|
||||
Loading…
Reference in New Issue
Block a user