static void _rsa_params_to_privkey(const gnutls_pk_params_st * pk_params, struct rsa_private_key *priv)
{
-mpz_t q_1;
-
memcpy(&priv->d, pk_params->params[2], sizeof(mpz_t));
memcpy(&priv->p, pk_params->params[3], sizeof(mpz_t));
memcpy(&priv->q, pk_params->params[4], sizeof(mpz_t));
memcpy(&priv->c, pk_params->params[5], sizeof(mpz_t));
-
memcpy(&priv->a, pk_params->params[6], sizeof(mpz_t));
memcpy(&priv->b, pk_params->params[7], sizeof(mpz_t));
+
}
static int
return ret;
}
+/* returns the blinded c and the inverse of a random
+ * number r;
+ */
+static bigint_t rsa_blind(bigint_t c, bigint_t e, bigint_t n, bigint_t *_ri)
+{
+bigint_t nc = NULL, r = NULL, ri = NULL;
+
+ /* nc = c*(r^e)
+ * ri = r^(-1)
+ */
+ nc = _gnutls_mpi_alloc_like(n);
+ if (nc == NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ ri = _gnutls_mpi_alloc_like(n);
+ if (nc == NULL) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ r = _gnutls_mpi_randomize (NULL, _gnutls_mpi_get_nbits(n),
+ GNUTLS_RND_NONCE);
+ if (r == NULL) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ /* invert r */
+ if (mpz_invert(ri, r, n)==0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ /* r = r^e */
+
+ _gnutls_mpi_powm(r, r, e, n);
+
+ _gnutls_mpi_mulm(nc, c, r, n);
+
+ *_ri = ri;
+
+ _gnutls_mpi_release(&r);
+
+ return nc;
+fail:
+ _gnutls_mpi_release(&nc);
+ _gnutls_mpi_release(&r);
+ return NULL;
+}
+
+/* c = c*ri mod n
+ */
+static inline void rsa_unblind(bigint_t c, bigint_t ri, bigint_t n)
+{
+ _gnutls_mpi_mulm(c, c, ri, n);
+}
+
static int
_wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
gnutls_datum_t * plaintext,
switch (algo) {
case GNUTLS_PK_RSA: {
struct rsa_private_key priv;
- bigint_t c;
+ bigint_t c, ri, nc;
if (_gnutls_mpi_scan_nz(&c, ciphertext->data, ciphertext->size) != 0) {
gnutls_assert();
return GNUTLS_E_MPI_SCAN_FAILED;
}
- /* FIXME: implement blinding */
+ nc = rsa_blind(c, pk_params->params[1]/*e*/,
+ pk_params->params[0]/*m*/, &ri);
+ _gnutls_mpi_release(&c);
+ if (nc == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
rsa_private_key_init(&priv);
_rsa_params_to_privkey(pk_params, &priv);
- rsa_compute_root(&priv, TOMPZ(c), TOMPZ(c));
+ rsa_compute_root(&priv, TOMPZ(nc), TOMPZ(nc));
- ret = _gnutls_mpi_dprint(c, plaintext);
- _gnutls_mpi_release(&c);
- mpz_clear(priv.a);
- mpz_clear(priv.b);
+ rsa_unblind(nc, ri, pk_params->params[0]/*m*/);
+
+ ret = _gnutls_mpi_dprint_size(nc, plaintext, ciphertext->size);
+
+ _gnutls_mpi_release(&nc);
+ _gnutls_mpi_release(&ri);
if (ret < 0) {
gnutls_assert();
ret = _gnutls_mpi_dprint(hash, signature);
_gnutls_mpi_release(&hash);
- mpz_clear(priv.a);
- mpz_clear(priv.b);
if (ret < 0) {
gnutls_assert();
gnutls_direction_t direction,
gnutls_pk_params_st * params)
{
+
+ if (direction == GNUTLS_IMPORT) {
+ /* do not trust the generated values. Some old private keys
+ * generated by us have mess on the values. Those were very
+ * old but it seemed some of the shipped example private
+ * keys were as old.
+ */
+ mpz_t q_1;
+
+ mpz_invert(TOMPZ(params->params[5]), TOMPZ(params->params[4]), TOMPZ(params->params[3]));
+
+ mpz_init(q_1);
+
+ /* a = d % p-1 */
+ mpz_sub_ui(q_1, TOMPZ(params->params[3])/*p*/, 1);
+ mpz_fdiv_r(TOMPZ(params->params[6]), TOMPZ(params->params[2])/*d*/, q_1);
+
+ /* b = d % q-1 */
+ mpz_sub_ui(q_1, TOMPZ(params->params[4])/*p*/, 1);
+
+ mpz_fdiv_r(TOMPZ(params->params[7]), TOMPZ(params->params[2])/*d*/, q_1);
+
+ mpz_clear(q_1);
+ }
+
return 0;
}