summaryrefslogtreecommitdiffstats
path: root/g10/pubkey-enc.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/pubkey-enc.c')
-rw-r--r--g10/pubkey-enc.c91
1 files changed, 75 insertions, 16 deletions
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 312b591e9..1b94af54f 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -145,6 +145,9 @@ 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];
+ size_t fpn;
+ const int pkalgo = map_pk_openpgp_to_gcry (sk->pubkey_algo);
/* Get the keygrip. */
err = hexkeygrip_from_pk (sk, &keygrip);
@@ -152,15 +155,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);
@@ -168,12 +171,26 @@ 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;
+ 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, &frame, &nframe);
@@ -202,32 +219,74 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
if (DBG_CIPHER)
log_printhex ("DEK frame:", frame, nframe);
n = 0;
- if (!card)
+
+ if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
- if (n + 7 > nframe)
+ 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 (G10ERR_WRONG_SECKEY);
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
- if (frame[n] == 1 && frame[nframe - 1] == 2)
+
+ 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)
{
- log_info (_("old encoding of the DEK is not supported\n"));
- err = gpg_error (G10ERR_CIPHER_ALGO);
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
- if (frame[n] != 2) /* Something went wrong. */
+ nframe -= frame[nframe-1]; /* Remove padding. */
+ assert (!n); /* (used just below) */
+ }
+ else
+ {
+ if (!card)
{
- err = gpg_error (G10ERR_WRONG_SECKEY);
- goto leave;
+ 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. */
}
- for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
- ;
- n++; /* Skip the zero byte. */
}
if (n + 4 > nframe)
{
- err = gpg_error (G10ERR_WRONG_SECKEY);
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}