aboutsummaryrefslogtreecommitdiffstats
path: root/g10/mainproc.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2018-01-23 11:07:25 +0000
committerWerner Koch <[email protected]>2018-01-23 11:07:57 +0000
commit9aab9167bca38323973e853845ca95ae8e9b6871 (patch)
treef06594e52ed3722b0cc37979c7d6d3829dcb0d96 /g10/mainproc.c
parentgpg: Unify AEAD parameter retrieval. (diff)
downloadgnupg-9aab9167bca38323973e853845ca95ae8e9b6871.tar.gz
gnupg-9aab9167bca38323973e853845ca95ae8e9b6871.zip
gpg: Implement AEAD for SKESK packets.
* g10/packet.h (PKT_symkey_enc): Add field aead_algo. * g10/build-packet.c (do_symkey_enc): Support version 5 packets. * g10/parse-packet.c (parse_symkeyenc): Ditto. * g10/encrypt.c (encrypt_symmetric): Force using a random session key in AEAD mode. (encrypt_seskey): Add and support arg aead_algo. (write_symkey_enc): Ditto. (encrypt_simple): Adjust accordingly. (encrypt_filter): Ditto. * g10/gpgcompose.c (sk_esk): For now call encrypt_seskey without AEAD support. * g10/mainproc.c (symkey_decrypt_seskey): Support AEAD. Nver call BUG but return an error. (proc_symkey_enc): Call symkey_decrypt_seskey in a bug compatible way. * g10/import.c (check_prefs): Check AEAD preferences. * g10/keyedit.c (show_prefs): Print AEAD preferences. -- For easier debugging this patch also changes some diagnostics to also print the encryption mode with the cipher algorithm. Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'g10/mainproc.c')
-rw-r--r--g10/mainproc.c118
1 files changed, 92 insertions, 26 deletions
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 92da98242..d1d44d774 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -245,46 +245,102 @@ add_signature (CTX c, PACKET *pkt)
return 1;
}
-static int
+static gpg_error_t
symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
{
+ gpg_error_t err;
gcry_cipher_hd_t hd;
+ unsigned int noncelen, keylen;
+ enum gcry_cipher_modes ciphermode;
+ byte ad[4];
+
+ if (dek->use_aead)
+ {
+ err = openpgp_aead_algo_info (dek->use_aead, &ciphermode, &noncelen);
+ if (err)
+ return err;
+ }
+ else
+ {
+ ciphermode = GCRY_CIPHER_MODE_CFB;
+ noncelen = 0;
+ }
- if(slen < 17 || slen > 33)
+ /* Check that the session key has a size of 16 to 32 bytes. */
+ if ((dek->use_aead && (slen < (noncelen + 16 + 16)
+ || slen > (noncelen + 32 + 16)))
+ || (!dek->use_aead && (slen < 17 || slen > 33)))
{
log_error ( _("weird size for an encrypted session key (%d)\n"),
(int)slen);
- return GPG_ERR_BAD_KEY;
+ return gpg_error (GPG_ERR_BAD_KEY);
}
- if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1))
- BUG ();
- if (gcry_cipher_setkey ( hd, dek->key, dek->keylen ))
- BUG ();
- gcry_cipher_setiv ( hd, NULL, 0 );
- gcry_cipher_decrypt ( hd, seskey, slen, NULL, 0 );
- gcry_cipher_close ( hd );
-
- /* Now we replace the dek components with the real session key to
- decrypt the contents of the sequencing packet. */
-
- dek->keylen=slen-1;
- dek->algo=seskey[0];
+ err = openpgp_cipher_open (&hd, dek->algo, ciphermode, GCRY_CIPHER_SECURE);
+ if (!err)
+ err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
+ if (!err)
+ err = gcry_cipher_setiv (hd, noncelen? seskey : NULL, noncelen);
+ if (err)
+ goto leave;
- if(dek->keylen > DIM(dek->key))
- BUG ();
-
- memcpy(dek->key, seskey + 1, dek->keylen);
+ if (dek->use_aead)
+ {
+ byte ad[4];
+
+ ad[0] = (0xc0 | PKT_SYMKEY_ENC);
+ ad[1] = 5;
+ ad[2] = dek->algo;
+ ad[3] = dek->use_aead;
+ err = gcry_cipher_authenticate (hd, ad, 4);
+ if (err)
+ goto leave;
+ gcry_cipher_final (hd);
+ keylen = slen - noncelen - 16;
+ err = gcry_cipher_decrypt (hd, seskey+noncelen, keylen, NULL, 0);
+ if (err)
+ goto leave;
+ err = gcry_cipher_checktag (hd, seskey+noncelen+keylen, 16);
+ if (err)
+ goto leave;
+ /* Now we replace the dek components with the real session key to
+ * decrypt the contents of the sequencing packet. */
+ if (keylen > DIM(dek->key))
+ {
+ err = gpg_error (GPG_ERR_TOO_LARGE);
+ goto leave;
+ }
+ dek->keylen = keylen;
+ memcpy (dek->key, seskey + noncelen, dek->keylen);
+ }
+ else
+ {
+ gcry_cipher_decrypt (hd, seskey, slen, NULL, 0 );
+ /* Now we replace the dek components with the real session key to
+ * decrypt the contents of the sequencing packet. */
+ keylen = slen-1;
+ if (keylen > DIM(dek->key))
+ {
+ err = gpg_error (GPG_ERR_TOO_LARGE);
+ goto leave;
+ }
+ dek->algo = seskey[0];
+ dek->keylen = keylen;
+ memcpy (dek->key, seskey + 1, dek->keylen);
+ }
/*log_hexdump( "thekey", dek->key, dek->keylen );*/
- return 0;
+ leave:
+ gcry_cipher_close (hd);
+ return err;
}
static void
proc_symkey_enc (CTX c, PACKET *pkt)
{
+ gpg_error_t err;
PKT_symkey_enc *enc;
enc = pkt->pkt.symkey_enc;
@@ -294,19 +350,21 @@ proc_symkey_enc (CTX c, PACKET *pkt)
{
int algo = enc->cipher_algo;
const char *s = openpgp_cipher_algo_name (algo);
+ const char *a = (enc->aead_algo ? openpgp_aead_algo_name (enc->aead_algo)
+ /**/ : "CFB");
if (!openpgp_cipher_test_algo (algo))
{
if (!opt.quiet)
{
if (enc->seskeylen)
- log_info (_("%s encrypted session key\n"), s );
+ log_info (_("%s.%s encrypted session key\n"), s, a );
else
- log_info (_("%s encrypted data\n"), s );
+ log_info (_("%s.%s encrypted data\n"), s, a );
}
}
else
- log_error (_("encrypted with unknown algorithm %d\n"), algo);
+ log_error (_("encrypted with unknown algorithm %d.%s\n"), algo, a);
if (openpgp_md_test_algo (enc->s2k.hash_algo))
{
@@ -334,6 +392,7 @@ proc_symkey_enc (CTX c, PACKET *pkt)
if (c->dek)
{
c->dek->symmetric = 1;
+ c->dek->use_aead = enc->aead_algo;
/* FIXME: This doesn't work perfectly if a symmetric key
comes before a public key in the message - if the
@@ -344,9 +403,16 @@ proc_symkey_enc (CTX c, PACKET *pkt)
come later. */
if (enc->seskeylen)
{
- if (symkey_decrypt_seskey (c->dek,
- enc->seskey, enc->seskeylen))
+ err = symkey_decrypt_seskey (c->dek,
+ enc->seskey, enc->seskeylen);
+ if (err)
{
+ log_info ("decryption of the symmetrically encrypted"
+ " session key failed: %s\n",
+ gpg_strerror (err));
+ if (gpg_err_code (err) != GPG_ERR_BAD_KEY)
+ log_fatal ("process terminated to be bug compatible"
+ " with GnuPG <= 2.2\n");
xfree (c->dek);
c->dek = NULL;
}