]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added blinding in RSA. Correct broken private keys on import. Nettle
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 25 May 2010 21:53:25 +0000 (23:53 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 3 Jun 2010 17:54:55 +0000 (19:54 +0200)
uses more values than gcrypt does from RSA decryption and it seemed
that some values in our stored private keys were messy (generated by
very old gnutls).

lib/nettle/pk.c

index e028d9b49e02fd613af8183f840b82d4779670bc..9ce6c468cf8ca7f6bc860c212bb3ee8b471f6c49 100644 (file)
@@ -65,15 +65,13 @@ static void _dsa_params_to_privkey(const gnutls_pk_params_st * pk_params, struct
 
 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
@@ -119,6 +117,65 @@ cleanup:
        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,
@@ -131,24 +188,32 @@ _wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
        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();
@@ -224,8 +289,6 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
 
                ret = _gnutls_mpi_dprint(hash, signature);
                _gnutls_mpi_release(&hash);
-               mpz_clear(priv.a);
-               mpz_clear(priv.b);
 
                if (ret < 0) {
                        gnutls_assert();
@@ -446,6 +509,31 @@ wrap_nettle_pk_fixup(gnutls_pk_algorithm_t algo,
                     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;
 }