diff options
author | Werner Koch <[email protected]> | 2018-01-23 11:07:25 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2018-01-23 11:07:57 +0000 |
commit | 9aab9167bca38323973e853845ca95ae8e9b6871 (patch) | |
tree | f06594e52ed3722b0cc37979c7d6d3829dcb0d96 /g10/mainproc.c | |
parent | gpg: Unify AEAD parameter retrieval. (diff) | |
download | gnupg-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.c | 118 |
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; } |