From 3be31bf21b500722d2faa2571a600bddfec2011b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 18 Nov 2025 11:19:10 +0100 Subject: [PATCH 01/10] rsa: extract helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Will gain a new implementation using the CRT, so we want to hide the upcoming complexity in a dedicated function. Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 08267dbfce..8de6e9129f 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1268,6 +1268,35 @@ cleanup: return 0; } +/* Generate random A and B such that A^-1 = B mod N */ +static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx, + mbedtls_mpi *A, + mbedtls_mpi *B, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret, count = 0; + mbedtls_mpi G; + + mbedtls_mpi_init(&G); + + mbedtls_mpi_lset(&G, 0); + do { + if (count++ > 10) { + ret = MBEDTLS_ERR_RSA_RNG_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_random(A, 1, &ctx->N, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, B, A, &ctx->N)); + } while (mbedtls_mpi_cmp_int(&G, 1) != 0); + +cleanup: + mbedtls_mpi_free(&G); + + return ret; +} + /* * Generate or update blinding values, see section 10 of: * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, @@ -1277,10 +1306,7 @@ cleanup: static int rsa_prepare_blinding(mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { - int ret, count = 0; - mbedtls_mpi R; - - mbedtls_mpi_init(&R); + int ret; if (ctx->Vf.p != NULL) { /* We already have blinding values, just update them by squaring */ @@ -1288,30 +1314,17 @@ static int rsa_prepare_blinding(mbedtls_rsa_context *ctx, MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vi, &ctx->Vi, &ctx->N)); MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &ctx->Vf)); MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->N)); - goto cleanup; } /* Unblinding value: Vf = random number, invertible mod N */ - mbedtls_mpi_lset(&R, 0); - do { - if (count++ > 10) { - ret = MBEDTLS_ERR_RSA_RNG_FAILED; - goto cleanup; - } - - MBEDTLS_MPI_CHK(mbedtls_mpi_random(&ctx->Vf, 1, &ctx->N, f_rng, p_rng)); - MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&R, &ctx->Vi, &ctx->Vf, &ctx->N)); - } while (mbedtls_mpi_cmp_int(&R, 1) != 0); + MBEDTLS_MPI_CHK(rsa_gen_rand_with_inverse(ctx, &ctx->Vf, &ctx->Vi, f_rng, p_rng)); /* Blinding value: Vi = Vf^(-e) mod N * (Vi already contains Vf^-1 at this point) */ MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN)); - cleanup: - mbedtls_mpi_free(&R); - return ret; } From b13033dd3e4cf6c7568189868e83a07a2eb0a815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 18 Nov 2025 11:39:40 +0100 Subject: [PATCH 02/10] rsa: extract helper function for CRT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was only used in one place so far, but will be used in rsa_gen_rand_with_inverse()'s upcoming CRT-based implementation. Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 8de6e9129f..0c3973b8d5 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1268,6 +1268,38 @@ cleanup: return 0; } +#if !defined(MBEDTLS_RSA_NO_CRT) +/* + * Compute T such that T = TP mod P and T = TP mod Q. + * (This is the Chinese Remainder Theorem - CRT.) + * + * WARNING: uses TP as a temporary, so its value is lost! + */ +static int rsa_apply_crt(mbedtls_mpi *T, + mbedtls_mpi *TP, + const mbedtls_mpi *TQ, + const mbedtls_rsa_context *ctx) +{ + int ret; + + /* + * T = (TP - TQ) * (Q^-1 mod P) mod P + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(T, TP, TQ)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(TP, T, &ctx->QP)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(T, TP, &ctx->P)); + + /* + * T = TQ + T * Q + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(TP, T, &ctx->Q)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(T, TQ, TP)); + +cleanup: + return ret; +} +#endif + /* Generate random A and B such that A^-1 = B mod N */ static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx, mbedtls_mpi *A, @@ -1524,19 +1556,7 @@ int mbedtls_rsa_private(mbedtls_rsa_context *ctx, MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&TP, &T, &DP_blind, &ctx->P, &ctx->RP)); MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&TQ, &T, &DQ_blind, &ctx->Q, &ctx->RQ)); - - /* - * T = (TP - TQ) * (Q^-1 mod P) mod P - */ - MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&T, &TP, &TQ)); - MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&TP, &T, &ctx->QP)); - MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&T, &TP, &ctx->P)); - - /* - * T = TQ + T * Q - */ - MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&TP, &T, &ctx->Q)); - MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&T, &TQ, &TP)); + MBEDTLS_MPI_CHK(rsa_apply_crt(&T, &TP, &TQ, ctx)); #endif /* MBEDTLS_RSA_NO_CRT */ /* Verify the result to prevent glitching attacks. */ From 8b0ee342fac4d7c3cd3c910af2ee9c5e9622f982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 18 Nov 2025 12:00:07 +0100 Subject: [PATCH 03/10] rsa: use the CRT to generate blinding values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/rsa.c b/library/rsa.c index 0c3973b8d5..b0194cefe6 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1307,6 +1307,7 @@ static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { +#if defined(MBEDTLS_RSA_NO_CRT) int ret, count = 0; mbedtls_mpi G; @@ -1327,6 +1328,31 @@ cleanup: mbedtls_mpi_free(&G); return ret; +#else + int ret; + mbedtls_mpi Ap, Aq, Bp, Bq; + + mbedtls_mpi_init(&Ap); mbedtls_mpi_init(&Aq); + mbedtls_mpi_init(&Bp); mbedtls_mpi_init(&Bq); + + /* Generate Ap in [1, P) and compute Bp = Ap^-1 mod P */ + MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Ap, 1, &ctx->P, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(NULL, &Bp, &Ap, &ctx->P)); + + /* Generate Ap in [1, Q) and compute Bq = Aq^-1 mod P */ + MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Aq, 1, &ctx->Q, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(NULL, &Bq, &Aq, &ctx->Q)); + + /* Reconstruct A and B */ + MBEDTLS_MPI_CHK(rsa_apply_crt(A, &Ap, &Aq, ctx)); + MBEDTLS_MPI_CHK(rsa_apply_crt(B, &Bp, &Bq, ctx)); + +cleanup: + mbedtls_mpi_free(&Ap); mbedtls_mpi_free(&Aq); + mbedtls_mpi_free(&Bp); mbedtls_mpi_free(&Bq); + + return ret; +#endif } /* From fbd73884829416df55f3cd7531db42d7e89f4568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 3 Dec 2025 11:26:09 +0100 Subject: [PATCH 04/10] RSA: handle low-probability events in a uniform way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we were looping in one case but not even checking the other. Let's check both cases and error out immediately. The error path should never be taken in pratice anyway. Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index b0194cefe6..41a437ba3f 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1313,16 +1313,15 @@ static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx, mbedtls_mpi_init(&G); - mbedtls_mpi_lset(&G, 0); - do { - if (count++ > 10) { - ret = MBEDTLS_ERR_RSA_RNG_FAILED; - goto cleanup; - } + MBEDTLS_MPI_CHK(mbedtls_mpi_random(A, 1, &ctx->N, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, B, A, &ctx->N)); - MBEDTLS_MPI_CHK(mbedtls_mpi_random(A, 1, &ctx->N, f_rng, p_rng)); - MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, B, A, &ctx->N)); - } while (mbedtls_mpi_cmp_int(&G, 1) != 0); + if (mbedtls_mpi_cmp_int(&G, 1) != 0) { + /* This happens if we're unlucky enough to draw a multiple of P or Q, + * of it one of them is not a prime and G is one of its factors. */ + ret = MBEDTLS_ERR_RSA_RNG_FAILED; + goto cleanup; + } cleanup: mbedtls_mpi_free(&G); @@ -1330,18 +1329,29 @@ cleanup: return ret; #else int ret; - mbedtls_mpi Ap, Aq, Bp, Bq; + mbedtls_mpi Ap, Aq, Bp, Bq, G; mbedtls_mpi_init(&Ap); mbedtls_mpi_init(&Aq); mbedtls_mpi_init(&Bp); mbedtls_mpi_init(&Bq); + mbedtls_mpi_init(&G); /* Generate Ap in [1, P) and compute Bp = Ap^-1 mod P */ MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Ap, 1, &ctx->P, f_rng, p_rng)); - MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(NULL, &Bp, &Ap, &ctx->P)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &Bp, &Ap, &ctx->P)); + if (mbedtls_mpi_cmp_int(&G, 1) != 0) { + /* This can only happen if P was not a prime. */ + ret = MBEDTLS_ERR_RSA_RNG_FAILED; + goto cleanup; + } /* Generate Ap in [1, Q) and compute Bq = Aq^-1 mod P */ MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Aq, 1, &ctx->Q, f_rng, p_rng)); - MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(NULL, &Bq, &Aq, &ctx->Q)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &Bq, &Aq, &ctx->Q)); + if (mbedtls_mpi_cmp_int(&G, 1) != 0) { + /* This can only happen if Q was not a prime. */ + ret = MBEDTLS_ERR_RSA_RNG_FAILED; + goto cleanup; + } /* Reconstruct A and B */ MBEDTLS_MPI_CHK(rsa_apply_crt(A, &Ap, &Aq, ctx)); @@ -1350,6 +1360,7 @@ cleanup: cleanup: mbedtls_mpi_free(&Ap); mbedtls_mpi_free(&Aq); mbedtls_mpi_free(&Bp); mbedtls_mpi_free(&Bq); + mbedtls_mpi_free(&G); return ret; #endif From 30c2fa00af055e051f9f85e60e587c7424c4eca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 3 Dec 2025 11:32:45 +0100 Subject: [PATCH 05/10] Add ChangeLog for RSA private performance regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- ChangeLog.d/rsa-private-perf.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ChangeLog.d/rsa-private-perf.txt diff --git a/ChangeLog.d/rsa-private-perf.txt b/ChangeLog.d/rsa-private-perf.txt new file mode 100644 index 0000000000..c7893032c6 --- /dev/null +++ b/ChangeLog.d/rsa-private-perf.txt @@ -0,0 +1,4 @@ +Bugfix + * Partially fix a performance regression in RSA operations introduced by a + security fix in 3.6.5, by improving the performance of RSA private key + operations when MBEDTLS_RSA_NO_CRT is disabled, which is the default. From f90c04d6465d1ad6b4c7e36d831acb526d010a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 3 Dec 2025 11:35:28 +0100 Subject: [PATCH 06/10] RSA: remove undocumented check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This only made the function harder to use. Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 1 - library/rsa_alt_helpers.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 41a437ba3f..93b47d52ed 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1101,7 +1101,6 @@ int mbedtls_rsa_gen_key(mbedtls_rsa_context *ctx, * if it exists (FIPS 186-4 §B.3.1 criterion 2(a)) */ ret = mbedtls_rsa_deduce_private_exponent(&ctx->P, &ctx->Q, &ctx->E, &ctx->D); if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { - mbedtls_mpi_lset(&ctx->D, 0); /* needed for the next call */ continue; } if (ret != 0) { diff --git a/library/rsa_alt_helpers.c b/library/rsa_alt_helpers.c index 50a5c4e0d7..8a09f93a3e 100644 --- a/library/rsa_alt_helpers.c +++ b/library/rsa_alt_helpers.c @@ -188,7 +188,7 @@ int mbedtls_rsa_deduce_private_exponent(mbedtls_mpi const *P, int ret = 0; mbedtls_mpi K, L; - if (D == NULL || mbedtls_mpi_cmp_int(D, 0) != 0) { + if (D == NULL) { return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; } From 83e3b37e9de1d2e6b904e8bf8259021d03c9abca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 3 Dec 2025 13:27:19 +0100 Subject: [PATCH 07/10] rsa: rm unused variable + fix typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 93b47d52ed..a706d90c83 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1307,7 +1307,7 @@ static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx, void *p_rng) { #if defined(MBEDTLS_RSA_NO_CRT) - int ret, count = 0; + int ret; mbedtls_mpi G; mbedtls_mpi_init(&G); @@ -1317,7 +1317,7 @@ static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx, if (mbedtls_mpi_cmp_int(&G, 1) != 0) { /* This happens if we're unlucky enough to draw a multiple of P or Q, - * of it one of them is not a prime and G is one of its factors. */ + * or if one of them is not a prime and G is one of its factors. */ ret = MBEDTLS_ERR_RSA_RNG_FAILED; goto cleanup; } From ec5bc199962f5a8326ac405f524336e907e02efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 9 Dec 2025 09:16:25 +0100 Subject: [PATCH 08/10] Fix some typos in comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index a706d90c83..2f3e3d93e3 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1269,7 +1269,7 @@ cleanup: #if !defined(MBEDTLS_RSA_NO_CRT) /* - * Compute T such that T = TP mod P and T = TP mod Q. + * Compute T such that T = TP mod P and T = TQ mod Q. * (This is the Chinese Remainder Theorem - CRT.) * * WARNING: uses TP as a temporary, so its value is lost! @@ -1343,7 +1343,7 @@ cleanup: goto cleanup; } - /* Generate Ap in [1, Q) and compute Bq = Aq^-1 mod P */ + /* Generate Aq in [1, Q) and compute Bq = Aq^-1 mod Q */ MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Aq, 1, &ctx->Q, f_rng, p_rng)); MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &Bq, &Aq, &ctx->Q)); if (mbedtls_mpi_cmp_int(&G, 1) != 0) { From d251d73d06ec9359e922e6f08feddfc2c9ed9de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 9 Dec 2025 09:26:20 +0100 Subject: [PATCH 09/10] rsa: clarify CRT computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 2f3e3d93e3..c21f102c32 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1271,28 +1271,26 @@ cleanup: /* * Compute T such that T = TP mod P and T = TQ mod Q. * (This is the Chinese Remainder Theorem - CRT.) - * - * WARNING: uses TP as a temporary, so its value is lost! */ static int rsa_apply_crt(mbedtls_mpi *T, - mbedtls_mpi *TP, + const mbedtls_mpi *TP, const mbedtls_mpi *TQ, const mbedtls_rsa_context *ctx) { int ret; /* - * T = (TP - TQ) * (Q^-1 mod P) mod P + * Set T = ((TP - TQ) * (Q^-1 mod P) mod P) * Q + TQ + * + * That way we have both: + * mod P: T = (TP - TQ) * (Q^-1 * Q) + TQ = (TP - TQ) * 1 + TQ = TP + * mod Q: T = (...) * Q + TQ = TQ */ - MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(T, TP, TQ)); - MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(TP, T, &ctx->QP)); - MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(T, TP, &ctx->P)); - - /* - * T = TQ + T * Q - */ - MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(TP, T, &ctx->Q)); - MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(T, TQ, TP)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(T, TP, TQ)); // T = TP - TQ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(T, T, &ctx->QP)); // T *= Q^-1 mod P + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(T, T, &ctx->P)); // T %= P + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(T, T, &ctx->Q)); // T *= Q + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(T, T, TQ)); // T += TQ cleanup: return ret; From f6f837aec5bc1dd618a7287f5948f35c2a1b2f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 9 Dec 2025 09:39:07 +0100 Subject: [PATCH 10/10] rsa: clarify drawing at random with the CRT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/library/rsa.c b/library/rsa.c index c21f102c32..2eb042ff5a 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1315,7 +1315,8 @@ static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx, if (mbedtls_mpi_cmp_int(&G, 1) != 0) { /* This happens if we're unlucky enough to draw a multiple of P or Q, - * or if one of them is not a prime and G is one of its factors. */ + * or if (at least) one of them is not a prime, and we drew a multiple + * of one of its factors. */ ret = MBEDTLS_ERR_RSA_RNG_FAILED; goto cleanup; } @@ -1332,6 +1333,20 @@ cleanup: mbedtls_mpi_init(&Bp); mbedtls_mpi_init(&Bq); mbedtls_mpi_init(&G); + /* + * Instead of generating A, B = A^-1 (mod N) directly, generate one Ap, Bp + * pair (mod P) and one pair (mod Q) and use Chinese Remainder Theorem to + * construct an A and B from those. + * + * This works because the CRT correspondence is a ring isomorphism between + * Z/NZ (integers mod N) and Z/PZ x Z/QZ (pairs of integers mod P and Q): + * - it is a bijection (one-to-one correspondence); + * - doing a ring operation (modular +, -, *, ^-1 when possible) on one side is + * the same as doing it on the other side. + * So, drawing uniformly at random an invertible A mod N is the same as + * drawing uniformly at random pairs of invertible Ap mod P, Aq mod Q. + */ + /* Generate Ap in [1, P) and compute Bp = Ap^-1 mod P */ MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Ap, 1, &ctx->P, f_rng, p_rng)); MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &Bp, &Ap, &ctx->P));