gpg: Cache keybox searches.
[gnupg.git] / g10 / pubkey-enc.c
index a5224e2..a69536e 100644 (file)
@@ -77,6 +77,9 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
   PKT_public_key *sk = NULL;
   int rc;
 
+  if (DBG_CLOCK)
+    log_clock ("get_session_key enter");
+
   rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC);
   if (rc)
     goto leave;
@@ -97,8 +100,7 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
 
       for (;;)
         {
-          if (sk)
-            free_public_key (sk);
+          free_public_key (sk);
           sk = xmalloc_clear (sizeof *sk);
           rc = enum_secret_keys (&enum_context, sk);
           if (rc)
@@ -111,13 +113,15 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
           if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
             continue;
           keyid_from_pk (sk, keyid);
-          log_info (_("anonymous recipient; trying secret key %s ...\n"),
-                    keystr (keyid));
+          if (!opt.quiet)
+            log_info (_("anonymous recipient; trying secret key %s ...\n"),
+                      keystr (keyid));
 
           rc = get_it (k, dek, sk, keyid);
           if (!rc)
             {
-              log_info (_("okay, we are the anonymous recipient.\n"));
+              if (!opt.quiet)
+                log_info (_("okay, we are the anonymous recipient.\n"));
               break;
             }
           else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
@@ -127,8 +131,9 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
     }
 
 leave:
-  if (sk)
-    free_public_key (sk);
+  free_public_key (sk);
+  if (DBG_CLOCK)
+    log_clock ("get_session_key leave");
   return rc;
 }
 
@@ -145,8 +150,12 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
   gcry_sexp_t s_data;
   char *desc;
   char *keygrip;
-  byte fp[MAX_FINGERPRINT_LEN]; 
+  byte fp[MAX_FINGERPRINT_LEN];
   size_t fpn;
+  const int pkalgo = map_pk_openpgp_to_gcry (sk->pubkey_algo);
+
+  if (DBG_CLOCK)
+    log_clock ("decryption start");
 
   /* Get the keygrip.  */
   err = hexkeygrip_from_pk (sk, &keygrip);
@@ -154,15 +163,15 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
     goto leave;
 
   /* Convert the data to an S-expression.  */
-  if (sk->pubkey_algo == GCRY_PK_ELG || sk->pubkey_algo == GCRY_PK_ELG_E)
+  if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
     {
       if (!enc->data[0] || !enc->data[1])
         err = gpg_error (GPG_ERR_BAD_MPI);
       else
-        err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))", 
+        err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))",
                                enc->data[0], enc->data[1]);
     }
-  else if (sk->pubkey_algo == GCRY_PK_RSA || sk->pubkey_algo == GCRY_PK_RSA_E)
+  else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_E)
     {
       if (!enc->data[0])
         err = gpg_error (GPG_ERR_BAD_MPI);
@@ -170,18 +179,29 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
         err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))",
                                enc->data[0]);
     }
+  else if (pkalgo == GCRY_PK_ECDH)
+    {
+      if (!enc->data[0] || !enc->data[1])
+        err = gpg_error (GPG_ERR_BAD_MPI);
+      else
+        err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))",
+                               enc->data[0], enc->data[1]);
+    }
   else
     err = gpg_error (GPG_ERR_BUG);
 
   if (err)
     goto leave;
 
-  fingerprint_from_pk( sk, fp, &fpn );
-  assert( fpn == 20 );
+  if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
+    {
+      fingerprint_from_pk (sk, fp, &fpn);
+      assert (fpn == 20);
+    }
 
   /* Decrypt. */
   desc = gpg_format_keydesc (sk, 0, 1);
-  err = agent_pkdecrypt (NULL, keygrip, desc, s_data, fp, &frame, &nframe);
+  err = agent_pkdecrypt (NULL, keygrip, desc, s_data, &frame, &nframe);
   xfree (desc);
   gcry_sexp_release (s_data);
   if (err)
@@ -208,51 +228,78 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
     log_printhex ("DEK frame:", frame, nframe);
   n = 0;
 
-  if( sk->pubkey_algo != PUBKEY_ALGO_ECDH )  {
-    if (!card)
-      {
-        if (n + 7 > nframe)
-          {
-            err = gpg_error (G10ERR_WRONG_SECKEY);
-            goto leave;
-          }
-        if (frame[n] == 1 && frame[nframe - 1] == 2)
-          {
-            log_info (_("old encoding of the DEK is not supported\n"));
-            err = gpg_error (G10ERR_CIPHER_ALGO);
-            goto leave;
-          }
-        if (frame[n] != 2) /* Something went wrong.  */
-          {
-            err = gpg_error (G10ERR_WRONG_SECKEY);
-            goto leave;
-          }
-        for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes.  */
-          ;
-        n++; /* Skip the zero byte.  */
-      }
-  }
-  else  {
-    /* Allow double padding for the benefit of DEK size concealment.
-     * Higher than this is wasteful.  
-     */
-    if( frame[nframe-1] > 8*2 || nframe <= 8 )  {
-      err = G10ERR_WRONG_SECKEY; goto leave; 
+  if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
+    {
+      gcry_mpi_t shared_mpi;
+      gcry_mpi_t decoded;
+
+      /* At the beginning the frame are the bytes of shared point MPI.  */
+      err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL);
+      if (err)
+        {
+          err = gpg_error (GPG_ERR_WRONG_SECKEY);
+          goto leave;
+        }
+
+      err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/,
+                             shared_mpi, sk->pkey);
+      mpi_release (shared_mpi);
+      if(err)
+        goto leave;
+
+      /* Reuse NFRAME, which size is sufficient to include the session key.  */
+      err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded);
+      mpi_release (decoded);
+      if (err)
+        goto leave;
+
+      /* Now the frame are the bytes decrypted but padded session key.  */
+
+      /* Allow double padding for the benefit of DEK size concealment.
+         Higher than this is wasteful. */
+      if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8
+          || frame[nframe-1] > nframe)
+        {
+          err = gpg_error (GPG_ERR_WRONG_SECKEY);
+          goto leave;
+        }
+      nframe -= frame[nframe-1]; /* Remove padding.  */
+      assert (!n); /* (used just below) */
+    }
+  else
+    {
+      if (!card)
+        {
+          if (n + 7 > nframe)
+            {
+              err = gpg_error (GPG_ERR_WRONG_SECKEY);
+              goto leave;
+            }
+          if (frame[n] == 1 && frame[nframe - 1] == 2)
+            {
+              log_info (_("old encoding of the DEK is not supported\n"));
+              err = gpg_error (GPG_ERR_CIPHER_ALGO);
+              goto leave;
+            }
+          if (frame[n] != 2) /* Something went wrong.  */
+            {
+              err = gpg_error (GPG_ERR_WRONG_SECKEY);
+              goto leave;
+            }
+          for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes.  */
+            ;
+          n++; /* Skip the zero byte.  */
+        }
     }
-    nframe -= frame[nframe-1]; /* remove padding */
-    assert( n==0 );    /* used just bellow */
-  }
 
   if (n + 4 > nframe)
     {
-      err = gpg_error (G10ERR_WRONG_SECKEY);
+      err = gpg_error (GPG_ERR_WRONG_SECKEY);
       goto leave;
     }
 
   dek->keylen = nframe - (n + 1) - 2;
   dek->algo = frame[n++];
-  if (dek->algo == CIPHER_ALGO_IDEA)
-    write_status (STATUS_RSA_OR_IDEA);
   err = openpgp_cipher_test_algo (dek->algo);
   if (err)
     {
@@ -261,8 +308,6 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
           log_info (_("cipher algorithm %d%s is unknown or disabled\n"),
                     dek->algo,
                     dek->algo == CIPHER_ALGO_IDEA ? " (IDEA)" : "");
-          if (dek->algo == CIPHER_ALGO_IDEA)
-            idea_cipher_warn (0);
         }
       dek->algo = 0;
       goto leave;
@@ -284,6 +329,8 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
       err = gpg_error (GPG_ERR_WRONG_SECKEY);
       goto leave;
     }
+  if (DBG_CLOCK)
+    log_clock ("decryption ready");
   if (DBG_CIPHER)
     log_printhex ("DEK is:", dek->key, dek->keylen);