mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02:00
gpg: Support decryption of the new AEAD packet
* common/openpgpdefs.h (aead_algo_t): New.
(pkttype_t): Add PKT_ENCRYPTED_AEAD.
* g10/decrypt-data.c (struct decode_filter_context_s): Add fields for
AEAD.
(aead_set_nonce_and_ad): New.
(aead_checktag): New.
(decrypt_data): Support AEAD.
(aead_underflow): New.
(aead_decode_filter): New.
* g10/dek.h (DEK): Add field use_aead. Turn use_mdc,
algo_info_printed, and symmetric into bit flags.
* g10/mainproc.c (struct mainproc_context): Add field
seen_pkt_encrypted_aead.
(release_list): Clear it.
(have_seen_pkt_encrypted_aead): New.
(symkey_decrypt_seskey): Support AEAD.
(proc_symkey_enc): Ditto.
(proc_encrypted): Ditto.
(proc_plaintext): Ditto.
* g10/misc.c (MY_GCRY_CIPHER_MODE_EAX): New.
(openpgp_aead_test_algo): New.
(openpgp_aead_algo_name): New.
(openpgp_aead_algo_info): New.
* g10/packet.h (PKT_symkey_enc): Add field use_aead.
(PKT_user_id): Add field flags.aead
(PKT_public_key): Ditto.
(PKT_encrypted): Add fields for AEAD.
* g10/parse-packet.c (parse): Handle PKT_ENCRYPTED_AEAD.
(parse_symkeyenc): Support AEAD.
(parse_encrypted): Ditto.
(dump_sig_subpkt): Dump AEAD preference packet.
(parse_encrypted_aead): New.
--
This patch allows to decrypt data encrypted using the new AEAD
mechanism as specified in rfc4880bis. Although preferences are used
to enable this new mode, it is useful to have at least a decryption
option in case a user switches between GnuPG 2.2 and newer versions.
The new AEAD mechanism is much faster than the current CFB+MDC and
thus 2.2 will allow faster decryption of symmetric only decryption.
This patch is based on the current master (2.3) code base and includes
a few other patches. In particular
commit 44be675b75
(gpg: More check for symmetric key encryption.)
is included.
Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
144b95cc9d
commit
1dfe71c62b
10 changed files with 907 additions and 68 deletions
|
@ -81,6 +81,9 @@ static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||
PACKET * packet, int new_ctb);
|
||||
static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
PACKET * packet, int new_ctb, int partial);
|
||||
static gpg_error_t parse_encrypted_aead (IOBUF inp, int pkttype,
|
||||
unsigned long pktlen, PACKET *packet,
|
||||
int partial);
|
||||
static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
PACKET * packet, int new_ctb);
|
||||
static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
|
@ -665,6 +668,7 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
|
|||
case PKT_PLAINTEXT:
|
||||
case PKT_ENCRYPTED:
|
||||
case PKT_ENCRYPTED_MDC:
|
||||
case PKT_ENCRYPTED_AEAD:
|
||||
case PKT_COMPRESSED:
|
||||
iobuf_set_partial_body_length_mode (inp, c & 0xff);
|
||||
pktlen = 0; /* To indicate partial length. */
|
||||
|
@ -852,6 +856,9 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
|
|||
case PKT_MDC:
|
||||
rc = parse_mdc (inp, pkttype, pktlen, pkt, new_ctb);
|
||||
break;
|
||||
case PKT_ENCRYPTED_AEAD:
|
||||
rc = parse_encrypted_aead (inp, pkttype, pktlen, pkt, partial);
|
||||
break;
|
||||
case PKT_GPG_CONTROL:
|
||||
rc = parse_gpg_control (inp, pkttype, pktlen, pkt, partial);
|
||||
break;
|
||||
|
@ -1127,19 +1134,17 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||
{
|
||||
PKT_symkey_enc *k;
|
||||
int rc = 0;
|
||||
int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
|
||||
int i, version, s2kmode, cipher_algo, aead_algo, hash_algo, seskeylen, minlen;
|
||||
|
||||
if (pktlen < 4)
|
||||
{
|
||||
log_error ("packet(%d) too short\n", pkttype);
|
||||
if (list_mode)
|
||||
es_fprintf (listfp, ":symkey enc packet: [too short]\n");
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
goto leave;
|
||||
}
|
||||
goto too_short;
|
||||
version = iobuf_get_noeof (inp);
|
||||
pktlen--;
|
||||
if (version != 4)
|
||||
if (version == 4)
|
||||
;
|
||||
else if (version == 5)
|
||||
;
|
||||
else
|
||||
{
|
||||
log_error ("packet(%d) with unknown version %d\n", pkttype, version);
|
||||
if (list_mode)
|
||||
|
@ -1157,6 +1162,15 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||
}
|
||||
cipher_algo = iobuf_get_noeof (inp);
|
||||
pktlen--;
|
||||
if (version == 5)
|
||||
{
|
||||
aead_algo = iobuf_get_noeof (inp);
|
||||
pktlen--;
|
||||
}
|
||||
else
|
||||
aead_algo = 0;
|
||||
if (pktlen < 2)
|
||||
goto too_short;
|
||||
s2kmode = iobuf_get_noeof (inp);
|
||||
pktlen--;
|
||||
hash_algo = iobuf_get_noeof (inp);
|
||||
|
@ -1191,6 +1205,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||
+ seskeylen - 1);
|
||||
k->version = version;
|
||||
k->cipher_algo = cipher_algo;
|
||||
k->aead_algo = aead_algo;
|
||||
k->s2k.mode = s2kmode;
|
||||
k->s2k.hash_algo = hash_algo;
|
||||
if (s2kmode == 1 || s2kmode == 3)
|
||||
|
@ -1221,10 +1236,20 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp,
|
||||
":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
|
||||
version, cipher_algo, s2kmode, hash_algo);
|
||||
":symkey enc packet: version %d, cipher %d, aead %d,"
|
||||
"s2k %d, hash %d",
|
||||
version, cipher_algo, aead_algo, s2kmode, hash_algo);
|
||||
if (seskeylen)
|
||||
es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
|
||||
{
|
||||
/* To compute the size of the session key we need to know
|
||||
* the size of the AEAD nonce which we may not know. Thus
|
||||
* we show only the size of the entire encrypted session
|
||||
* key. */
|
||||
if (aead_algo)
|
||||
es_fprintf (listfp, ", encrypted seskey %d bytes", seskeylen);
|
||||
else
|
||||
es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
|
||||
}
|
||||
es_fprintf (listfp, "\n");
|
||||
if (s2kmode == 1 || s2kmode == 3)
|
||||
{
|
||||
|
@ -1241,6 +1266,13 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||
leave:
|
||||
iobuf_skip_rest (inp, pktlen, 0);
|
||||
return rc;
|
||||
|
||||
too_short:
|
||||
log_error ("packet(%d) too short\n", pkttype);
|
||||
if (list_mode)
|
||||
es_fprintf (listfp, ":symkey enc packet: [too short]\n");
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1421,6 +1453,11 @@ dump_sig_subpkt (int hashed, int type, int critical,
|
|||
for (i = 0; i < length; i++)
|
||||
es_fprintf (listfp, " %d", buffer[i]);
|
||||
break;
|
||||
case SIGSUBPKT_PREF_AEAD:
|
||||
es_fputs ("pref-aead-algos:", listfp);
|
||||
for (i = 0; i < length; i++)
|
||||
es_fprintf (listfp, " %d", buffer[i]);
|
||||
break;
|
||||
case SIGSUBPKT_REV_KEY:
|
||||
es_fputs ("revocation key: ", listfp);
|
||||
if (length < 22)
|
||||
|
@ -1601,6 +1638,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
|
|||
case SIGSUBPKT_KEY_FLAGS:
|
||||
case SIGSUBPKT_KS_FLAGS:
|
||||
case SIGSUBPKT_PREF_SYM:
|
||||
case SIGSUBPKT_PREF_AEAD:
|
||||
case SIGSUBPKT_PREF_HASH:
|
||||
case SIGSUBPKT_PREF_COMPR:
|
||||
case SIGSUBPKT_POLICY:
|
||||
|
@ -3253,6 +3291,9 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||
ed->buf = NULL;
|
||||
ed->new_ctb = new_ctb;
|
||||
ed->is_partial = partial;
|
||||
ed->aead_algo = 0;
|
||||
ed->cipher_algo = 0; /* Only used with AEAD. */
|
||||
ed->chunkbyte = 0; /* Only used with AEAD. */
|
||||
if (pkttype == PKT_ENCRYPTED_MDC)
|
||||
{
|
||||
/* Fixme: add some pktlen sanity checks. */
|
||||
|
@ -3344,6 +3385,81 @@ parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen,
|
||||
PACKET *pkt, int partial)
|
||||
{
|
||||
int rc = 0;
|
||||
PKT_encrypted *ed;
|
||||
unsigned long orig_pktlen = pktlen;
|
||||
int version;
|
||||
|
||||
ed = pkt->pkt.encrypted = xtrymalloc (sizeof *pkt->pkt.encrypted);
|
||||
if (!ed)
|
||||
return gpg_error_from_syserror ();
|
||||
ed->len = 0;
|
||||
ed->extralen = 0; /* (only used in build_packet.) */
|
||||
ed->buf = NULL;
|
||||
ed->new_ctb = 1; /* (packet number requires a new CTB anyway.) */
|
||||
ed->is_partial = partial;
|
||||
ed->mdc_method = 0;
|
||||
/* A basic sanity check. We need one version byte, one algo byte,
|
||||
* one aead algo byte, one chunkbyte, at least 15 byte IV. */
|
||||
if (orig_pktlen && pktlen < 19)
|
||||
{
|
||||
log_error ("packet(%d) too short\n", pkttype);
|
||||
if (list_mode)
|
||||
es_fputs (":aead encrypted packet: [too short]\n", listfp);
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
iobuf_skip_rest (inp, pktlen, partial);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
version = iobuf_get_noeof (inp);
|
||||
if (orig_pktlen)
|
||||
pktlen--;
|
||||
if (version != 1)
|
||||
{
|
||||
log_error ("aead encrypted packet with unknown version %d\n",
|
||||
version);
|
||||
if (list_mode)
|
||||
es_fputs (":aead encrypted packet: [unknown version]\n", listfp);
|
||||
/*skip_rest(inp, pktlen); should we really do this? */
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
ed->cipher_algo = iobuf_get_noeof (inp);
|
||||
if (orig_pktlen)
|
||||
pktlen--;
|
||||
ed->aead_algo = iobuf_get_noeof (inp);
|
||||
if (orig_pktlen)
|
||||
pktlen--;
|
||||
ed->chunkbyte = iobuf_get_noeof (inp);
|
||||
if (orig_pktlen)
|
||||
pktlen--;
|
||||
|
||||
/* Store the remaining length of the encrypted data. We read the
|
||||
* rest during decryption. */
|
||||
ed->len = pktlen;
|
||||
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, ":aead encrypted packet: cipher=%u aead=%u cb=%u\n",
|
||||
ed->cipher_algo, ed->aead_algo, ed->chunkbyte);
|
||||
if (orig_pktlen)
|
||||
es_fprintf (listfp, "\tlength: %lu\n", orig_pktlen);
|
||||
else
|
||||
es_fprintf (listfp, "\tlength: unknown\n");
|
||||
}
|
||||
|
||||
ed->buf = inp;
|
||||
|
||||
leave:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This packet is internally generated by us (in armor.c) to transfer
|
||||
* some information to the lower layer. To make sure that this packet
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue