summaryrefslogtreecommitdiffstats
path: root/g10/encrypt.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2018-01-23 12:07:25 +0100
committerWerner Koch <wk@gnupg.org>2018-01-23 12:07:57 +0100
commit9aab9167bca38323973e853845ca95ae8e9b6871 (patch)
treef06594e52ed3722b0cc37979c7d6d3829dcb0d96 /g10/encrypt.c
parentgpg: Unify AEAD parameter retrieval. (diff)
downloadgnupg2-9aab9167bca38323973e853845ca95ae8e9b6871.tar.xz
gnupg2-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 <wk@gnupg.org>
Diffstat (limited to 'g10/encrypt.c')
-rw-r--r--g10/encrypt.c151
1 files changed, 107 insertions, 44 deletions
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 4cc4b1a29..c6c9e3a03 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -47,12 +47,12 @@ static int write_pubkey_enc_from_list (ctrl_t ctrl,
/****************
* Encrypt FILENAME with only the symmetric cipher. Take input from
- * stdin if FILENAME is NULL.
+ * stdin if FILENAME is NULL. If --force-aead is used we use an SKESK.
*/
int
encrypt_symmetric (const char *filename)
{
- return encrypt_simple( filename, 1, 0 );
+ return encrypt_simple( filename, 1, opt.force_aead);
}
@@ -70,14 +70,16 @@ encrypt_store (const char *filename)
/* Encrypt a session key using DEK and store a pointer to the result
* at R_ENCKEY and its length at R_ENCKEYLEN.
*
- * R_SESKEY points to the unencrypted session key (.KEY, >KEYLEN) and
+ * R_SESKEY points to the unencrypted session key (.KEY, .KEYLEN) and
* the algorithm that will be used to encrypt the contents of the
* SKESK packet (.ALGO). If R_SESKEY points to NULL, then a random
* session key that is appropriate for DEK->ALGO is generated and
- * stored at R_SESKEY.
+ * stored at R_SESKEY. If AEAD_ALGO is not 0 the given AEAD algorithm
+ * is used for encryption.
*/
gpg_error_t
-encrypt_seskey (DEK *dek, DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
+encrypt_seskey (DEK *dek, aead_algo_t aead_algo,
+ DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
{
gpg_error_t err;
gcry_cipher_hd_t hd = NULL;
@@ -102,30 +104,84 @@ encrypt_seskey (DEK *dek, DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
/*log_hexdump( "thekey", c->key, c->keylen );*/
}
- buf = xtrymalloc_secure (1 + seskey->keylen);
- if (!buf)
+
+ if (aead_algo)
{
- err = gpg_error_from_syserror ();
- goto leave;
- }
+ unsigned int noncelen;
+ enum gcry_cipher_modes ciphermode;
+ byte ad[4];
+
+ err = openpgp_aead_algo_info (aead_algo, &ciphermode, &noncelen);
+ if (err)
+ goto leave;
+
+ /* Allocate space for the nonce, the key, and the authentication
+ * tag (16). */
+ buf = xtrymalloc_secure (noncelen + seskey->keylen + 16);
+ if (!buf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
- /* The encrypted session key is prefixed with a one-octet algorithm id. */
- buf[0] = seskey->algo;
- memcpy (buf + 1, seskey->key, seskey->keylen);
-
- err = openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1);
- if (!err)
- err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
- if (!err)
- err = gcry_cipher_setiv (hd, NULL, 0);
- if (!err)
- err = gcry_cipher_encrypt (hd, buf, seskey->keylen + 1, NULL, 0);
- if (err)
- goto leave;
+ gcry_randomize (buf, noncelen, GCRY_STRONG_RANDOM);
+
+ 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, buf, noncelen);
+ if (err)
+ goto leave;
+
+ ad[0] = (0xc0 | PKT_SYMKEY_ENC);
+ ad[1] = 5;
+ ad[2] = dek->algo;
+ ad[3] = aead_algo;
+ err = gcry_cipher_authenticate (hd, ad, 4);
+ if (err)
+ goto leave;
+
+ memcpy (buf + noncelen, seskey->key, seskey->keylen);
+ gcry_cipher_final (hd);
+ err = gcry_cipher_encrypt (hd, buf + noncelen, seskey->keylen, NULL,0);
+ if (err)
+ goto leave;
+ err = gcry_cipher_gettag (hd, buf + noncelen + seskey->keylen, 16);
+ if (err)
+ goto leave;
+ *r_enckeylen = noncelen + seskey->keylen + 16;
+ *r_enckey = buf;
+ buf = NULL;
+ }
+ else
+ {
+ /* In the old version 4 SKESK the encrypted session key is
+ * prefixed with a one-octet algorithm id. */
+ buf = xtrymalloc_secure (1 + seskey->keylen);
+ if (!buf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ buf[0] = seskey->algo;
+ memcpy (buf + 1, seskey->key, seskey->keylen);
+
+ err = openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1);
+ if (!err)
+ err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
+ if (!err)
+ err = gcry_cipher_setiv (hd, NULL, 0);
+ if (!err)
+ err = gcry_cipher_encrypt (hd, buf, seskey->keylen + 1, NULL, 0);
+ if (err)
+ goto leave;
+ *r_enckeylen = seskey->keylen + 1;
+ *r_enckey = buf;
+ buf = NULL;
+ }
- *r_enckey = buf;
- buf = NULL;
- *r_enckeylen = seskey->keylen + 1;
/* Return the session key in case we allocated it. */
*r_seskey = seskey;
seskey = NULL;
@@ -332,7 +388,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
{
DEK *dek = NULL;
- rc = encrypt_seskey (cfx.dek, &dek, &enckey, &enckeylen);
+ rc = encrypt_seskey (cfx.dek, aead_algo, &dek, &enckey, &enckeylen);
if (rc)
{
xfree (cfx.dek);
@@ -346,14 +402,16 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
cfx.dek = dek;
}
- if (opt.verbose)
- log_info(_("using cipher %s\n"),
- openpgp_cipher_algo_name (cfx.dek->algo));
-
if (aead_algo)
cfx.dek->use_aead = aead_algo;
else
cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
+
+ if (opt.verbose)
+ log_info(_("using cipher %s.%s\n"),
+ openpgp_cipher_algo_name (cfx.dek->algo),
+ cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead)
+ /**/ : "CFB");
}
if (do_compress
@@ -385,8 +443,9 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
{
/* Fixme: This is quite similar to write_symkey_enc. */
PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen);
- enc->version = 4;
+ enc->version = cfx.dek->use_aead ? 5 : 4;
enc->cipher_algo = cfx.dek->algo;
+ enc->aead_algo = cfx.dek->use_aead;
enc->s2k = *s2k;
if (enckeylen)
{
@@ -535,8 +594,8 @@ setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
static int
-write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
- iobuf_t out)
+write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo,
+ DEK *symkey_dek, DEK *dek, iobuf_t out)
{
int rc;
void *enckey;
@@ -544,7 +603,7 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
PKT_symkey_enc *enc;
PACKET pkt;
- rc = encrypt_seskey (symkey_dek, &dek, &enckey, &enckeylen);
+ rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen);
if (rc)
return rc;
enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen);
@@ -555,8 +614,9 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
return rc;
}
- enc->version = 4;
+ enc->version = aead_algo? 5 : 4;
enc->cipher_algo = opt.s2k_cipher_algo;
+ enc->aead_algo = aead_algo;
enc->s2k = *symkey_s2k;
enc->seskeylen = enckeylen;
memcpy (enc->seskey, enckey, enckeylen);
@@ -813,10 +873,11 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
goto leave;
/* We put the passphrase (if any) after any public keys as this
- seems to be the most useful on the recipient side - there is no
- point in prompting a user for a passphrase if they have the
- secret key needed to decrypt. */
- if(use_symkey && (rc = write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out)))
+ * seems to be the most useful on the recipient side - there is no
+ * point in prompting a user for a passphrase if they have the
+ * secret key needed to decrypt. */
+ if (use_symkey && (rc = write_symkey_enc (symkey_s2k, cfx.dek->use_aead,
+ symkey_dek, cfx.dek, out)))
goto leave;
if (!opt.no_literal)
@@ -1014,9 +1075,9 @@ encrypt_filter (void *opaque, int control,
if(efx->symkey_s2k && efx->symkey_dek)
{
- rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek,
- efx->cfx.dek,a);
- if(rc)
+ rc = write_symkey_enc (efx->symkey_s2k, efx->cfx.dek->use_aead,
+ efx->symkey_dek, efx->cfx.dek, a);
+ if (rc)
return rc;
}
@@ -1084,9 +1145,11 @@ write_pubkey_enc (ctrl_t ctrl,
if ( opt.verbose )
{
char *ustr = get_user_id_string_native (ctrl, enc->keyid);
- log_info (_("%s/%s encrypted for: \"%s\"\n"),
+ log_info (_("%s/%s.%s encrypted for: \"%s\"\n"),
openpgp_pk_algo_name (enc->pubkey_algo),
openpgp_cipher_algo_name (dek->algo),
+ dek->use_aead? openpgp_aead_algo_name (dek->use_aead)
+ /**/ : "CFB",
ustr );
xfree (ustr);
}