gnupg/g10/pubkey-enc.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

562 lines
16 KiB
C
Raw Normal View History

2010-04-21 19:30:07 +02:00
/* pubkey-enc.c - Process a public key encoded packet.
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009,
* 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
2007-07-04 21:49:40 +02:00
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gpg.h"
#include "../common/util.h"
#include "packet.h"
#include "keydb.h"
#include "trustdb.h"
#include "../common/status.h"
#include "options.h"
#include "main.h"
#include "../common/i18n.h"
#include "pkglue.h"
#include "call-agent.h"
#include "../common/host2net.h"
#include "../common/compliance.h"
static gpg_error_t get_it (ctrl_t ctrl, struct pubkey_enc_list *k,
DEK *dek, PKT_public_key *sk, u32 *keyid);
2010-04-21 19:30:07 +02:00
/* Check that the given algo is mentioned in one of the valid user-ids. */
static int
2010-04-21 19:30:07 +02:00
is_algo_in_prefs (kbnode_t keyblock, preftype_t type, int algo)
{
2010-04-21 19:30:07 +02:00
kbnode_t k;
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
prefitem_t *prefs = uid->prefs;
if (uid->created && prefs && !uid->flags.revoked && !uid->flags.expired)
2010-04-21 19:30:07 +02:00
{
for (; prefs->type; prefs++)
if (prefs->type == type && prefs->value == algo)
return 1;
}
}
}
2010-04-21 19:30:07 +02:00
return 0;
}
2010-04-21 19:30:07 +02:00
/*
* Get the session key from a pubkey enc packet and return it in DEK,
* which should have been allocated in secure memory by the caller.
*/
2010-04-21 19:30:07 +02:00
gpg_error_t
get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
{
PKT_public_key *sk = NULL;
gpg_error_t err;
void *enum_context = NULL;
u32 keyid[2];
int search_for_secret_keys = 1;
struct pubkey_enc_list *k;
2010-04-21 19:30:07 +02:00
gpg: Cache keybox searches. * common/iobuf.c (iobuf_seek): Fix for temp streams. * g10/pubkey-enc.c (get_session_key, get_it): Add some log_clock calls. * g10/keydb.c (dump_search_desc): New. (enum_keyblock_states, struct keyblock_cache): New. (keyblock_cache_clear): New. (keydb_get_keyblock, keydb_search): Implement a keyblock cache. (keydb_update_keyblock, keydb_insert_keyblock, keydb_delete_keyblock) (keydb_rebuild_caches, keydb_search_reset): Clear the cache. -- Gpg uses the key database at several places without a central coordination. This leads to several scans of the keybox for the same key. To improve that we now use a simple cache to store a retrieved keyblock in certain cases. In theory this caching could also be done for old keyrings, but it is a bit more work and questionable whether it is needed; the keybox scheme is anyway much faster than keyrings. Using a keybox with 20000 384 bit ECDSA/ECHD keypairs and a 252 byte sample text we get these values for encrypt and decrypt operations on an Core i5 4*3.33Ghz system. The option --trust-model=always is used. Times are given in milliseconds wall time. | | enc | dec | dec,q | |-----------+-----+-----+-------| | key 1 | 48 | 96 | 70 | | key 10000 | 60 | 98 | 80 | | key 20000 | 69 | 106 | 88 | | 10 keys | 540 | 290 | 70 | The 10 keys test uses a mix of keys, the first one is used for decryption but all keys are looked up so that information about are printed. The last column gives decryption results w/o information printing (--quiet). The keybox is always scanned sequentially without using any index. By adding an index to the keybox it will be possible to further reduce the time required for keys stored to the end of the file.
2013-01-08 14:44:49 +01:00
if (DBG_CLOCK)
log_clock ("get_session_key enter");
while (search_for_secret_keys)
2010-04-21 19:30:07 +02:00
{
sk = xmalloc_clear (sizeof *sk);
err = enum_secret_keys (ctrl, &enum_context, sk);
if (err)
break;
2010-04-21 19:30:07 +02:00
/* Check compliance. */
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
sk->pubkey_algo, 0,
sk->pkey, nbits_from_pk (sk), NULL))
2010-04-21 19:30:07 +02:00
{
log_info (_("key %s is not suitable for decryption"
" in %s mode\n"),
keystr_from_pk (sk),
gnupg_compliance_option_string (opt.compliance));
continue;
}
/* FIXME: The list needs to be sorted so that we try the keys in
* an appropriate order. For example:
* - On-disk keys w/o protection
* - On-disk keys with a cached passphrase
* - On-card keys of an active card
* - On-disk keys with protection
* - On-card keys from cards which are not plugged it. Here a
* cancel-all button should stop asking for other cards.
* Without any anonymous keys the sorting can be skipped.
*/
for (k = list; k; k = k->next)
{
if (!(k->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E
|| k->pubkey_algo == PUBKEY_ALGO_ECDH
|| k->pubkey_algo == PUBKEY_ALGO_KYBER
|| k->pubkey_algo == PUBKEY_ALGO_RSA
|| k->pubkey_algo == PUBKEY_ALGO_RSA_E
|| k->pubkey_algo == PUBKEY_ALGO_ELGAMAL))
continue;
if (openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC))
2010-04-21 19:30:07 +02:00
continue;
if (sk->pubkey_algo != k->pubkey_algo)
2010-10-13 17:57:08 +02:00
continue;
keyid_from_pk (sk, keyid);
if (!k->keyid[0] && !k->keyid[1])
{
if (opt.skip_hidden_recipients)
continue;
if (!opt.quiet)
log_info (_("anonymous recipient; trying secret key %s ...\n"),
keystr (keyid));
}
else if (opt.try_all_secrets
|| (k->keyid[0] == keyid[0] && k->keyid[1] == keyid[1]))
{
if (!opt.quiet && !(sk->pubkey_usage & PUBKEY_USAGE_ENC))
log_info (_("used key is not marked for encryption use.\n"));
}
else
continue;
err = get_it (ctrl, k, dek, sk, keyid);
k->result = err;
if (!err)
2010-04-21 19:30:07 +02:00
{
if (!opt.quiet && !k->keyid[0] && !k->keyid[1])
{
log_info (_("okay, we are the anonymous recipient.\n"));
if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
log_info (_("used key is not marked for encryption use.\n")
);
}
search_for_secret_keys = 0;
2010-04-21 19:30:07 +02:00
break;
}
else if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
{
search_for_secret_keys = 0;
break; /* Don't try any more secret keys. */
}
2010-04-21 19:30:07 +02:00
}
}
enum_secret_keys (ctrl, &enum_context, NULL); /* free context */
if (gpg_err_code (err) == GPG_ERR_EOF)
{
err = gpg_error (GPG_ERR_NO_SECKEY);
/* Return the last specific error, if any. */
for (k = list; k; k = k->next)
if (k->result != -1)
err = k->result;
}
gpg: Cache keybox searches. * common/iobuf.c (iobuf_seek): Fix for temp streams. * g10/pubkey-enc.c (get_session_key, get_it): Add some log_clock calls. * g10/keydb.c (dump_search_desc): New. (enum_keyblock_states, struct keyblock_cache): New. (keyblock_cache_clear): New. (keydb_get_keyblock, keydb_search): Implement a keyblock cache. (keydb_update_keyblock, keydb_insert_keyblock, keydb_delete_keyblock) (keydb_rebuild_caches, keydb_search_reset): Clear the cache. -- Gpg uses the key database at several places without a central coordination. This leads to several scans of the keybox for the same key. To improve that we now use a simple cache to store a retrieved keyblock in certain cases. In theory this caching could also be done for old keyrings, but it is a bit more work and questionable whether it is needed; the keybox scheme is anyway much faster than keyrings. Using a keybox with 20000 384 bit ECDSA/ECHD keypairs and a 252 byte sample text we get these values for encrypt and decrypt operations on an Core i5 4*3.33Ghz system. The option --trust-model=always is used. Times are given in milliseconds wall time. | | enc | dec | dec,q | |-----------+-----+-----+-------| | key 1 | 48 | 96 | 70 | | key 10000 | 60 | 98 | 80 | | key 20000 | 69 | 106 | 88 | | 10 keys | 540 | 290 | 70 | The 10 keys test uses a mix of keys, the first one is used for decryption but all keys are looked up so that information about are printed. The last column gives decryption results w/o information printing (--quiet). The keybox is always scanned sequentially without using any index. By adding an index to the keybox it will be possible to further reduce the time required for keys stored to the end of the file.
2013-01-08 14:44:49 +01:00
if (DBG_CLOCK)
log_clock ("get_session_key leave");
return err;
}
2010-04-21 19:30:07 +02:00
static gpg_error_t
get_it (ctrl_t ctrl,
struct pubkey_enc_list *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
{
gpg_error_t err;
byte *frame = NULL;
unsigned int frameidx;
size_t nframe;
u16 csum, csum2;
int padding;
gcry_sexp_t s_data;
char *desc;
char *keygrip;
byte fp[MAX_FINGERPRINT_LEN];
gpg: Cache keybox searches. * common/iobuf.c (iobuf_seek): Fix for temp streams. * g10/pubkey-enc.c (get_session_key, get_it): Add some log_clock calls. * g10/keydb.c (dump_search_desc): New. (enum_keyblock_states, struct keyblock_cache): New. (keyblock_cache_clear): New. (keydb_get_keyblock, keydb_search): Implement a keyblock cache. (keydb_update_keyblock, keydb_insert_keyblock, keydb_delete_keyblock) (keydb_rebuild_caches, keydb_search_reset): Clear the cache. -- Gpg uses the key database at several places without a central coordination. This leads to several scans of the keybox for the same key. To improve that we now use a simple cache to store a retrieved keyblock in certain cases. In theory this caching could also be done for old keyrings, but it is a bit more work and questionable whether it is needed; the keybox scheme is anyway much faster than keyrings. Using a keybox with 20000 384 bit ECDSA/ECHD keypairs and a 252 byte sample text we get these values for encrypt and decrypt operations on an Core i5 4*3.33Ghz system. The option --trust-model=always is used. Times are given in milliseconds wall time. | | enc | dec | dec,q | |-----------+-----+-----+-------| | key 1 | 48 | 96 | 70 | | key 10000 | 60 | 98 | 80 | | key 20000 | 69 | 106 | 88 | | 10 keys | 540 | 290 | 70 | The 10 keys test uses a mix of keys, the first one is used for decryption but all keys are looked up so that information about are printed. The last column gives decryption results w/o information printing (--quiet). The keybox is always scanned sequentially without using any index. By adding an index to the keybox it will be possible to further reduce the time required for keys stored to the end of the file.
2013-01-08 14:44:49 +01:00
if (DBG_CLOCK)
log_clock ("decryption start");
/* Get the keygrip. */
err = hexkeygrip_from_pk (sk, &keygrip);
if (err)
goto leave;
/* Convert the data to an S-expression. */
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id. * common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a string. * g10/keygen.c (check_keygrip): Adjust for change. * sm/certreqgen-ui.c (check_keygrip): Likewise. * agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry. * g10/misc.c (map_pk_openpgp_to_gcry): Remove. (openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2. (openpgp_pk_test_algo2): Rewrite. (openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA. (openpgp_pk_algo_name): Rewrite to remove need for gcry calls. (pubkey_get_npkey, pubkey_get_nskey): Ditto. (pubkey_get_nsig, pubkey_get_nenc): Ditto. * g10/keygen.c(do_create_from_keygrip): Support EdDSA. (common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto. * g10/build-packet.c (do_key): Ditto. * g10/export.c (transfer_format_to_openpgp): Ditto. * g10/getkey.c (cache_public_key): Ditto. * g10/import.c (transfer_secret_keys): Ditto. * g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto. * g10/mainproc.c (proc_pubkey_enc): Ditto. * g10/parse-packet.c (parse_key): Ditto, * g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto. * g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name. * g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only OpenPGP algo ids and support EdDSA. * g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids. * g10/seskey.c (encode_md_value): Ditto. -- This patch separates Libgcrypt and OpenPGP public key algorithms ids and in most cases completely removes the Libgcrypt ones. This is useful because for Libgcrypt we specify the algorithm in the S-expressions and the public key ids are not anymore needed. This patch also adds some support for PUBKEY_ALGO_EDDSA which will eventually be used instead of merging EdDSA with ECDSA. As of now an experimental algorithm id is used but the plan is to write an I-D so that we can get a new id from the IETF. Note that EdDSA (Ed25519) does not yet work and that more changes are required. The ECC support is still broken right now. Needs to be fixed. Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
if (sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL
|| sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_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)))",
enc->data[0], enc->data[1]);
}
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id. * common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a string. * g10/keygen.c (check_keygrip): Adjust for change. * sm/certreqgen-ui.c (check_keygrip): Likewise. * agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry. * g10/misc.c (map_pk_openpgp_to_gcry): Remove. (openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2. (openpgp_pk_test_algo2): Rewrite. (openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA. (openpgp_pk_algo_name): Rewrite to remove need for gcry calls. (pubkey_get_npkey, pubkey_get_nskey): Ditto. (pubkey_get_nsig, pubkey_get_nenc): Ditto. * g10/keygen.c(do_create_from_keygrip): Support EdDSA. (common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto. * g10/build-packet.c (do_key): Ditto. * g10/export.c (transfer_format_to_openpgp): Ditto. * g10/getkey.c (cache_public_key): Ditto. * g10/import.c (transfer_secret_keys): Ditto. * g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto. * g10/mainproc.c (proc_pubkey_enc): Ditto. * g10/parse-packet.c (parse_key): Ditto, * g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto. * g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name. * g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only OpenPGP algo ids and support EdDSA. * g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids. * g10/seskey.c (encode_md_value): Ditto. -- This patch separates Libgcrypt and OpenPGP public key algorithms ids and in most cases completely removes the Libgcrypt ones. This is useful because for Libgcrypt we specify the algorithm in the S-expressions and the public key ids are not anymore needed. This patch also adds some support for PUBKEY_ALGO_EDDSA which will eventually be used instead of merging EdDSA with ECDSA. As of now an experimental algorithm id is used but the plan is to write an I-D so that we can get a new id from the IETF. Note that EdDSA (Ed25519) does not yet work and that more changes are required. The ECC support is still broken right now. Needs to be fixed. Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
else if (sk->pubkey_algo == PUBKEY_ALGO_RSA
|| sk->pubkey_algo == PUBKEY_ALGO_RSA_E)
{
if (!enc->data[0])
err = gpg_error (GPG_ERR_BAD_MPI);
else
err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))",
enc->data[0]);
}
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id. * common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a string. * g10/keygen.c (check_keygrip): Adjust for change. * sm/certreqgen-ui.c (check_keygrip): Likewise. * agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry. * g10/misc.c (map_pk_openpgp_to_gcry): Remove. (openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2. (openpgp_pk_test_algo2): Rewrite. (openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA. (openpgp_pk_algo_name): Rewrite to remove need for gcry calls. (pubkey_get_npkey, pubkey_get_nskey): Ditto. (pubkey_get_nsig, pubkey_get_nenc): Ditto. * g10/keygen.c(do_create_from_keygrip): Support EdDSA. (common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto. * g10/build-packet.c (do_key): Ditto. * g10/export.c (transfer_format_to_openpgp): Ditto. * g10/getkey.c (cache_public_key): Ditto. * g10/import.c (transfer_secret_keys): Ditto. * g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto. * g10/mainproc.c (proc_pubkey_enc): Ditto. * g10/parse-packet.c (parse_key): Ditto, * g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto. * g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name. * g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only OpenPGP algo ids and support EdDSA. * g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids. * g10/seskey.c (encode_md_value): Ditto. -- This patch separates Libgcrypt and OpenPGP public key algorithms ids and in most cases completely removes the Libgcrypt ones. This is useful because for Libgcrypt we specify the algorithm in the S-expressions and the public key ids are not anymore needed. This patch also adds some support for PUBKEY_ALGO_EDDSA which will eventually be used instead of merging EdDSA with ECDSA. As of now an experimental algorithm id is used but the plan is to write an I-D so that we can get a new id from the IETF. Note that EdDSA (Ed25519) does not yet work and that more changes are required. The ECC support is still broken right now. Needs to be fixed. Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
else if (sk->pubkey_algo == PUBKEY_ALGO_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[1], enc->data[0]);
}
else if (sk->pubkey_algo == PUBKEY_ALGO_KYBER)
{
char fixedinfo[1+MAX_FINGERPRINT_LEN];
int fixedlen;
if ((opt.compat_flags & COMPAT_T7014_OLD))
{
/* Temporary use for tests with original test vectors. */
fixedinfo[0] = 0x69;
fixedlen = 1;
}
else
{
fixedinfo[0] = enc->seskey_algo;
v5_fingerprint_from_pk (sk, fixedinfo+1, NULL);
fixedlen = 33;
}
if (!enc->data[0] || !enc->data[1] || !enc->data[2])
err = gpg_error (GPG_ERR_BAD_MPI);
else
err = gcry_sexp_build (&s_data, NULL,
"(enc-val(pqc(e%m)(k%m)(s%m)(c%d)(fixed-info%b)))",
enc->data[0], enc->data[1], enc->data[2],
enc->seskey_algo, fixedlen, fixedinfo);
}
else
err = gpg_error (GPG_ERR_BUG);
if (err)
goto leave;
if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
fingerprint_from_pk (sk, fp, NULL);
/* Decrypt. */
desc = gpg_format_keydesc (ctrl, sk, FORMAT_KEYDESC_NORMAL, 1);
gpg: Add pinentry-mode feature. * g10/gpg.c: Include shareddefs.h. (main): Add option --pinentry-mode. * g10/options.h (struct opt): Add field pinentry_mode. * g10/passphrase.c: Include shareddefs.h. (have_static_passphrase): Take care of loopback pinentry_mode. (read_passphrase_from_fd): Ditto. (get_static_passphrase): New. (passphrase_to_dek_ext): Factor some code out to ... (emit_status_need_passphrase): new. * g10/call-agent.c (start_agent): Send the pinentry mode. (default_inq_cb): Take care of the PASSPHRASE inquiry. Return a proper error code. (agent_pksign): Add args keyid, mainkeyid and pubkey_algo. (agent_pkdecrypt): Ditto. * g10/pubkey-enc.c (get_it): Pass new args. * g10/sign.c (do_sign): Pass new args. * g10/call-agent.c (struct default_inq_parm_s): New. Change all similar structs to reference this one. Change all users and inquire callback to use this struct, instead of NULL or some undefined but not used structs. This change will help to eventually get rid of global variables. -- This new features allows to use gpg without a Pinentry. As a prerequisite the agent must be configured to allow the loopback pinentry mode (option --allow-loopback-pinentry). For example gpg2 --pinentry-mode=loopback FILE.gpg may be used to decrypt FILE.gpg while entering the passphrase on the tty. If batch is used, --passphrase et al. may be used, if --command-fd is used, the passphrase may be provided by another process. Note that there are no try-again prompts in case of a bad passphrase.
2013-02-07 20:37:58 +01:00
err = agent_pkdecrypt (NULL, keygrip,
desc, sk->keyid, sk->main_keyid, sk->pubkey_algo,
s_data, &frame, &nframe, &padding);
xfree (desc);
gcry_sexp_release (s_data);
if (err)
goto leave;
2010-04-21 19:30:07 +02:00
/* Now get the DEK (data encryption key) from the frame
*
* Old versions encode the DEK in this format (msb is left):
2010-04-21 19:30:07 +02:00
*
* 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2
*
* Later versions encode the DEK like this:
*
* 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
*
* (mpi_get_buffer already removed the leading zero).
*
* RND are non-zero randow bytes.
* A is the cipher algorithm
* DEK is the encryption key (session key) with length k
* CSUM
*/
if (DBG_CRYPTO)
log_printhex (frame, nframe, "DEK frame:");
frameidx = 0;
if (sk->pubkey_algo == PUBKEY_ALGO_KYBER)
{
/* We expect a 32 byte session key. We should not see this
* error here because due to the KEM mode the agent_pkdecrypt
* should have already failed. */
if (nframe != 32)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
dek->keylen = nframe;
dek->algo = enc->seskey_algo;
}
else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
gcry_mpi_t decoded;
/* At the beginning the frame are the bytes of shared point MPI. */
err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/,
frame, nframe, sk->pkey);
if(err)
goto leave;
xfree (frame);
err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, decoded);
mpi_release (decoded);
if (err)
goto leave;
/* Now the frame are the bytes decrypted but padded session key. */
if (!nframe || nframe <= 8
|| frame[nframe-1] > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
nframe -= frame[nframe-1]; /* Remove padding. */
if (4 > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
dek->keylen = nframe - 3;
dek->algo = frame[0];
frameidx = 1;
}
else
{
if (padding)
{
if (7 > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
/* FIXME: Actually the leading zero is required but due to
* the way we encode the output in libgcrypt as an MPI we
* are not able to encode that leading zero. However, when
* using a Smartcard we are doing it the right way and
* therefore we have to skip the zero. This should be fixed
* in gpg-agent of course. */
frameidx = 0;
if (!frame[frameidx])
frameidx++;
if (frame[frameidx] == 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[frameidx] != 2) /* Something went wrong. */
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
/* Skip the random bytes. */
for (frameidx++; frameidx < nframe && frame[frameidx]; frameidx++)
;
frameidx++; /* Skip the zero byte. */
}
2010-04-21 19:30:07 +02:00
if (frameidx + 4 > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
dek->keylen = nframe - (frameidx + 1) - 2;
dek->algo = frame[frameidx++];
}
/* Check whether we support the ago. */
err = openpgp_cipher_test_algo (dek->algo);
if (err)
2010-04-21 19:30:07 +02:00
{
if (!opt.quiet && gpg_err_code (err) == GPG_ERR_CIPHER_ALGO)
2010-04-21 19:30:07 +02:00
{
log_info (_("cipher algorithm %d%s is unknown or disabled\n"),
dek->algo,
dek->algo == CIPHER_ALGO_IDEA ? " (IDEA)" : "");
}
dek->algo = 0;
goto leave;
}
2010-04-21 19:30:07 +02:00
if (dek->keylen != openpgp_cipher_get_algo_keylen (dek->algo))
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
2010-04-21 19:30:07 +02:00
goto leave;
}
/* Copy the key to DEK and compare the checksum if needed. */
/* We use the frameidx as flag for the need of a checksum. */
memcpy (dek->key, frame + frameidx, dek->keylen);
if (frameidx)
2010-04-21 19:30:07 +02:00
{
csum = buf16_to_u16 (frame+nframe-2);
for (csum2 = 0, frameidx = 0; frameidx < dek->keylen; frameidx++)
csum2 += dek->key[frameidx];
if (csum != csum2)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
2010-04-21 19:30:07 +02:00
}
gpg: Cache keybox searches. * common/iobuf.c (iobuf_seek): Fix for temp streams. * g10/pubkey-enc.c (get_session_key, get_it): Add some log_clock calls. * g10/keydb.c (dump_search_desc): New. (enum_keyblock_states, struct keyblock_cache): New. (keyblock_cache_clear): New. (keydb_get_keyblock, keydb_search): Implement a keyblock cache. (keydb_update_keyblock, keydb_insert_keyblock, keydb_delete_keyblock) (keydb_rebuild_caches, keydb_search_reset): Clear the cache. -- Gpg uses the key database at several places without a central coordination. This leads to several scans of the keybox for the same key. To improve that we now use a simple cache to store a retrieved keyblock in certain cases. In theory this caching could also be done for old keyrings, but it is a bit more work and questionable whether it is needed; the keybox scheme is anyway much faster than keyrings. Using a keybox with 20000 384 bit ECDSA/ECHD keypairs and a 252 byte sample text we get these values for encrypt and decrypt operations on an Core i5 4*3.33Ghz system. The option --trust-model=always is used. Times are given in milliseconds wall time. | | enc | dec | dec,q | |-----------+-----+-----+-------| | key 1 | 48 | 96 | 70 | | key 10000 | 60 | 98 | 80 | | key 20000 | 69 | 106 | 88 | | 10 keys | 540 | 290 | 70 | The 10 keys test uses a mix of keys, the first one is used for decryption but all keys are looked up so that information about are printed. The last column gives decryption results w/o information printing (--quiet). The keybox is always scanned sequentially without using any index. By adding an index to the keybox it will be possible to further reduce the time required for keys stored to the end of the file.
2013-01-08 14:44:49 +01:00
if (DBG_CLOCK)
log_clock ("decryption ready");
if (DBG_CRYPTO)
log_printhex (dek->key, dek->keylen, "DEK is:");
/* Check that the algo is in the preferences and whether it has
* expired. Also print a status line with the key's fingerprint. */
2010-04-21 19:30:07 +02:00
{
PKT_public_key *pk = NULL;
PKT_public_key *mainpk = NULL;
KBNODE pkb = get_pubkeyblock (ctrl, keyid);
2010-04-21 19:30:07 +02:00
if (!pkb)
{
err = -1;
2010-04-21 19:30:07 +02:00
log_error ("oops: public key not found for preference check\n");
}
else if (pkb->pkt->pkt.public_key->selfsigversion > 3
&& dek->algo != CIPHER_ALGO_3DES
&& !opt.quiet
&& !is_algo_in_prefs (pkb, PREFTYPE_SYM, dek->algo))
log_info (_("WARNING: cipher algorithm %s not found in recipient"
" preferences\n"), openpgp_cipher_algo_name (dek->algo));
if (!err)
2010-04-21 19:30:07 +02:00
{
kbnode_t k;
int first = 1;
2010-04-21 19:30:07 +02:00
for (k = pkb; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
u32 aki[2];
if (first)
{
first = 0;
mainpk = k->pkt->pkt.public_key;
}
keyid_from_pk (k->pkt->pkt.public_key, aki);
2010-04-21 19:30:07 +02:00
if (aki[0] == keyid[0] && aki[1] == keyid[1])
{
pk = k->pkt->pkt.public_key;
break;
}
}
}
if (!pk)
BUG ();
if (pk->expiredate && pk->expiredate <= make_timestamp ())
{
log_info (_("Note: secret key %s expired at %s\n"),
2010-04-21 19:30:07 +02:00
keystr (keyid), asctimestamp (pk->expiredate));
}
}
if (pk && pk->flags.revoked)
2010-04-21 19:30:07 +02:00
{
log_info (_("Note: key has been revoked"));
2010-04-21 19:30:07 +02:00
log_printf ("\n");
show_revocation_reason (ctrl, pk, 1);
2010-04-21 19:30:07 +02:00
}
if (is_status_enabled () && pk && mainpk)
{
char pkhex[MAX_FINGERPRINT_LEN*2+1];
char mainpkhex[MAX_FINGERPRINT_LEN*2+1];
hexfingerprint (pk, pkhex, sizeof pkhex);
hexfingerprint (mainpk, mainpkhex, sizeof mainpkhex);
/* Note that we do not want to create a trustdb just for
* getting the ownertrust: If there is no trustdb there can't
* be ulitmately trusted key anyway and thus the ownertrust
* value is irrelevant. */
write_status_printf (STATUS_DECRYPTION_KEY, "%s %s %c",
pkhex, mainpkhex,
get_ownertrust_info (ctrl, mainpk, 1));
}
2010-04-21 19:30:07 +02:00
release_kbnode (pkb);
err = 0;
2010-04-21 19:30:07 +02:00
}
leave:
2010-04-21 19:30:07 +02:00
xfree (frame);
xfree (keygrip);
return err;
}
2010-04-21 19:30:07 +02:00
/*
* Get the session key from the given string.
* String is supposed to be formatted as this:
* <algo-id>:<even-number-of-hex-digits>
*/
2010-04-21 19:30:07 +02:00
gpg_error_t
get_override_session_key (DEK *dek, const char *string)
{
2010-04-21 19:30:07 +02:00
const char *s;
int i;
if (!string)
return GPG_ERR_BAD_KEY;
2010-04-21 19:30:07 +02:00
dek->algo = atoi (string);
if (dek->algo < 1)
return GPG_ERR_BAD_KEY;
2010-04-21 19:30:07 +02:00
if (!(s = strchr (string, ':')))
return GPG_ERR_BAD_KEY;
2010-04-21 19:30:07 +02:00
s++;
for (i = 0; i < DIM (dek->key) && *s; i++, s += 2)
{
int c = hextobyte (s);
if (c == -1)
return GPG_ERR_BAD_KEY;
2010-04-21 19:30:07 +02:00
dek->key[i] = c;
}
2010-04-21 19:30:07 +02:00
if (*s)
return GPG_ERR_BAD_KEY;
2010-04-21 19:30:07 +02:00
dek->keylen = i;
return 0;
}