/** * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. * * @param ctx [in] The bigint session context. * @param bi [in] The bigint to perform the exp/mod. * @param dP [in] CRT's dP bigint * @param dQ [in] CRT's dQ bigint * @param p [in] CRT's p bigint * @param q [in] CRT's q bigint * @param qInv [in] CRT's qInv bigint * @return The result of the CRT operation */ bigint * ICACHE_FLASH_ATTR bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, bigint *p, bigint *q, bigint *qInv) { bigint *m1, *m2, *h; /* Montgomery has a condition the 0 < x, y < m and these products violate * that condition. So disable Montgomery when using CRT */ #if defined(CONFIG_BIGINT_MONTGOMERY) ctx->use_classical = 1; #endif ctx->mod_offset = BIGINT_P_OFFSET; m1 = bi_mod_power(ctx, bi_copy(bi), dP); ctx->mod_offset = BIGINT_Q_OFFSET; m2 = bi_mod_power(ctx, bi, dQ); h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); h = bi_multiply(ctx, h, qInv); ctx->mod_offset = BIGINT_P_OFFSET; h = bi_residue(ctx, h); #if defined(CONFIG_BIGINT_MONTGOMERY) ctx->use_classical = 0; /* reset for any further operation */ #endif return bi_add(ctx, m2, bi_multiply(ctx, q, h)); }
/** * Use the Chinese Remainder Theorem to quickly perform RSA decrypts. * This should really be in bigint.c (and was at one stage), but needs * access to the RSA_CTX context... */ static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi) { BI_CTX *ctx = rsa->bi_ctx; bigint *m1, *m2, *h; /* Montgomery has a condition the 0 < x, y < m and these products violate * that condition. So disable Montgomery when using CRT */ #if defined(CONFIG_BIGINT_MONTGOMERY) ctx->use_classical = 1; #endif ctx->mod_offset = BIGINT_P_OFFSET; m1 = bi_mod_power(ctx, bi_copy(bi), rsa->dP); ctx->mod_offset = BIGINT_Q_OFFSET; m2 = bi_mod_power(ctx, bi, rsa->dQ); h = bi_subtract(ctx, bi_add(ctx, m1, rsa->p), bi_copy(m2), NULL); h = bi_multiply(ctx, h, rsa->qInv); ctx->mod_offset = BIGINT_P_OFFSET; h = bi_residue(ctx, h); #if defined(CONFIG_BIGINT_MONTGOMERY) ctx->use_classical = 0; /* reset for any further operation */ #endif return bi_add(ctx, m2, bi_multiply(ctx, rsa->q, h)); }
/* * Work out g1, g3, g5, g7... etc for the sliding-window algorithm */ static void ICACHE_FLASH_ATTR precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) { int k = 1, i; bigint *g2; for (i = 0; i < window - 1; i++) { /* compute 2^(window-1) */ k <<= 1; } ctx->g = (bigint **)os_malloc(k * sizeof(bigint *)); ctx->g[0] = bi_clone(ctx, g1); bi_permanent(ctx->g[0]); g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */ for (i = 1; i < k; i++) { ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i - 1], bi_copy(g2))); bi_permanent(ctx->g[i]); } bi_free(ctx, g2); ctx->window = k; }
/** * @brief Perform a modular exponentiation. * * This function requires bi_set_mod() to have been called previously. This is * one of the optimisations used for performance. * @param ctx [in] The bigint session context. * @param bi [in] The bigint on which to perform the mod power operation. * @param biexp [in] The bigint exponent. * @return The result of the mod exponentiation operation * @see bi_set_mod(). */ bigint * ICACHE_FLASH_ATTR bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) { int i = find_max_exp_index(biexp), j, window_size = 1; bigint *biR = int_to_bi(ctx, 1); #if defined(CONFIG_BIGINT_MONTGOMERY) uint8_t mod_offset = ctx->mod_offset; if (!ctx->use_classical) { /* preconvert */ bi = bi_mont(ctx, bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */ bi_free(ctx, biR); biR = ctx->bi_R_mod_m[mod_offset]; /* A */ } #endif check(bi); check(biexp); #ifdef CONFIG_BIGINT_SLIDING_WINDOW for (j = i; j > 32; j /= 5) /* work out an optimum size */ window_size++; /* work out the slide constants */ precompute_slide_window(ctx, window_size, bi); #else /* just one constant */ ctx->g = (bigint **)SSL_MALLOC(sizeof(bigint *)); ctx->g[0] = bi_clone(ctx, bi); ctx->window = 1; bi_permanent(ctx->g[0]); #endif /* if sliding-window is off, then only one bit will be done at a time and * will reduce to standard left-to-right exponentiation */ do { if (exp_bit_is_one(biexp, i)) { int l = i-window_size+1; int part_exp = 0; if (l < 0) /* LSB of exponent will always be 1 */ l = 0; else { while (exp_bit_is_one(biexp, l) == 0) l++; /* go back up */ } /* build up the section of the exponent */ for (j = i; j >= l; j--) { biR = bi_residue(ctx, bi_square(ctx, biR)); if (exp_bit_is_one(biexp, j)) part_exp++; if (j != l) part_exp <<= 1; } part_exp = (part_exp-1)/2; /* adjust for array */ biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); i = l-1; } else /* square it */ { biR = bi_residue(ctx, bi_square(ctx, biR)); i--; } } while (i >= 0); /* cleanup */ for (i = 0; i < ctx->window; i++) { bi_depermanent(ctx->g[i]); bi_free(ctx, ctx->g[i]); } SSL_FREE(ctx->g); bi_free(ctx, bi); bi_free(ctx, biexp); #if defined CONFIG_BIGINT_MONTGOMERY return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */ #else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */ return biR; #endif }