mirror of
git://git.gnupg.org/gnupg.git
synced 2024-05-31 22:18:03 +02:00
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>
This commit is contained in:
parent
da3015e3c0
commit
9aab9167bc
|
@ -617,11 +617,8 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
|
||||||
IOBUF a = iobuf_temp();
|
IOBUF a = iobuf_temp();
|
||||||
|
|
||||||
log_assert (ctb_pkttype (ctb) == PKT_SYMKEY_ENC);
|
log_assert (ctb_pkttype (ctb) == PKT_SYMKEY_ENC);
|
||||||
|
log_assert (enc->version == 4 || enc->version == 5);
|
||||||
|
|
||||||
/* The only acceptable version. */
|
|
||||||
log_assert( enc->version == 4 );
|
|
||||||
|
|
||||||
/* RFC 4880, Section 3.7. */
|
|
||||||
switch (enc->s2k.mode)
|
switch (enc->s2k.mode)
|
||||||
{
|
{
|
||||||
case 0: /* Simple S2K. */
|
case 0: /* Simple S2K. */
|
||||||
|
@ -632,23 +629,26 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
|
||||||
default:
|
default:
|
||||||
log_bug ("do_symkey_enc: s2k=%d\n", enc->s2k.mode);
|
log_bug ("do_symkey_enc: s2k=%d\n", enc->s2k.mode);
|
||||||
}
|
}
|
||||||
iobuf_put( a, enc->version );
|
iobuf_put (a, enc->version);
|
||||||
iobuf_put( a, enc->cipher_algo );
|
iobuf_put (a, enc->cipher_algo);
|
||||||
iobuf_put( a, enc->s2k.mode );
|
if (enc->version == 5)
|
||||||
iobuf_put( a, enc->s2k.hash_algo );
|
iobuf_put (a, enc->aead_algo);
|
||||||
if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) {
|
iobuf_put (a, enc->s2k.mode);
|
||||||
iobuf_write(a, enc->s2k.salt, 8 );
|
iobuf_put (a, enc->s2k.hash_algo);
|
||||||
if( enc->s2k.mode == 3 )
|
if (enc->s2k.mode == 1 || enc->s2k.mode == 3)
|
||||||
iobuf_put(a, enc->s2k.count);
|
{
|
||||||
|
iobuf_write (a, enc->s2k.salt, 8);
|
||||||
|
if (enc->s2k.mode == 3)
|
||||||
|
iobuf_put (a, enc->s2k.count);
|
||||||
}
|
}
|
||||||
if( enc->seskeylen )
|
if (enc->seskeylen)
|
||||||
iobuf_write(a, enc->seskey, enc->seskeylen );
|
iobuf_write (a, enc->seskey, enc->seskeylen);
|
||||||
|
|
||||||
write_header(out, ctb, iobuf_get_temp_length(a) );
|
write_header (out, ctb, iobuf_get_temp_length(a));
|
||||||
rc = iobuf_write_temp( out, a );
|
rc = iobuf_write_temp (out, a);
|
||||||
|
|
||||||
iobuf_close(a);
|
iobuf_close (a);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -212,8 +212,10 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
|
||||||
if ( opt.verbose && !dek->algo_info_printed )
|
if ( opt.verbose && !dek->algo_info_printed )
|
||||||
{
|
{
|
||||||
if (!openpgp_cipher_test_algo (dek->algo))
|
if (!openpgp_cipher_test_algo (dek->algo))
|
||||||
log_info (_("%s encrypted data\n"),
|
log_info (_("%s.%s encrypted data\n"),
|
||||||
openpgp_cipher_algo_name (dek->algo));
|
openpgp_cipher_algo_name (dek->algo),
|
||||||
|
ed->aead_algo? openpgp_aead_algo_name (ed->aead_algo)
|
||||||
|
/**/ : "CFB");
|
||||||
else
|
else
|
||||||
log_info (_("encrypted with unknown algorithm %d\n"), dek->algo );
|
log_info (_("encrypted with unknown algorithm %d\n"), dek->algo );
|
||||||
dek->algo_info_printed = 1;
|
dek->algo_info_printed = 1;
|
||||||
|
|
151
g10/encrypt.c
151
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
|
* 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
|
int
|
||||||
encrypt_symmetric (const char *filename)
|
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
|
/* Encrypt a session key using DEK and store a pointer to the result
|
||||||
* at R_ENCKEY and its length at R_ENCKEYLEN.
|
* 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
|
* the algorithm that will be used to encrypt the contents of the
|
||||||
* SKESK packet (.ALGO). If R_SESKEY points to NULL, then a random
|
* SKESK packet (.ALGO). If R_SESKEY points to NULL, then a random
|
||||||
* session key that is appropriate for DEK->ALGO is generated and
|
* 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
|
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;
|
gpg_error_t err;
|
||||||
gcry_cipher_hd_t hd = NULL;
|
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 );*/
|
/*log_hexdump( "thekey", c->key, c->keylen );*/
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = xtrymalloc_secure (1 + seskey->keylen);
|
|
||||||
if (!buf)
|
if (aead_algo)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
unsigned int noncelen;
|
||||||
goto leave;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
*r_enckey = buf;
|
|
||||||
buf = NULL;
|
|
||||||
*r_enckeylen = seskey->keylen + 1;
|
|
||||||
/* Return the session key in case we allocated it. */
|
/* Return the session key in case we allocated it. */
|
||||||
*r_seskey = seskey;
|
*r_seskey = seskey;
|
||||||
seskey = NULL;
|
seskey = NULL;
|
||||||
|
@ -332,7 +388,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
|
||||||
{
|
{
|
||||||
DEK *dek = NULL;
|
DEK *dek = NULL;
|
||||||
|
|
||||||
rc = encrypt_seskey (cfx.dek, &dek, &enckey, &enckeylen);
|
rc = encrypt_seskey (cfx.dek, aead_algo, &dek, &enckey, &enckeylen);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
xfree (cfx.dek);
|
xfree (cfx.dek);
|
||||||
|
@ -346,14 +402,16 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
|
||||||
cfx.dek = dek;
|
cfx.dek = dek;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.verbose)
|
|
||||||
log_info(_("using cipher %s\n"),
|
|
||||||
openpgp_cipher_algo_name (cfx.dek->algo));
|
|
||||||
|
|
||||||
if (aead_algo)
|
if (aead_algo)
|
||||||
cfx.dek->use_aead = aead_algo;
|
cfx.dek->use_aead = aead_algo;
|
||||||
else
|
else
|
||||||
cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
|
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
|
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. */
|
/* Fixme: This is quite similar to write_symkey_enc. */
|
||||||
PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen);
|
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->cipher_algo = cfx.dek->algo;
|
||||||
|
enc->aead_algo = cfx.dek->use_aead;
|
||||||
enc->s2k = *s2k;
|
enc->s2k = *s2k;
|
||||||
if (enckeylen)
|
if (enckeylen)
|
||||||
{
|
{
|
||||||
|
@ -535,8 +594,8 @@ setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
|
write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo,
|
||||||
iobuf_t out)
|
DEK *symkey_dek, DEK *dek, iobuf_t out)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
void *enckey;
|
void *enckey;
|
||||||
|
@ -544,7 +603,7 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
|
||||||
PKT_symkey_enc *enc;
|
PKT_symkey_enc *enc;
|
||||||
PACKET pkt;
|
PACKET pkt;
|
||||||
|
|
||||||
rc = encrypt_seskey (symkey_dek, &dek, &enckey, &enckeylen);
|
rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
enc->version = 4;
|
enc->version = aead_algo? 5 : 4;
|
||||||
enc->cipher_algo = opt.s2k_cipher_algo;
|
enc->cipher_algo = opt.s2k_cipher_algo;
|
||||||
|
enc->aead_algo = aead_algo;
|
||||||
enc->s2k = *symkey_s2k;
|
enc->s2k = *symkey_s2k;
|
||||||
enc->seskeylen = enckeylen;
|
enc->seskeylen = enckeylen;
|
||||||
memcpy (enc->seskey, enckey, enckeylen);
|
memcpy (enc->seskey, enckey, enckeylen);
|
||||||
|
@ -813,10 +873,11 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
/* We put the passphrase (if any) after any public keys as this
|
/* 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
|
* 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
|
* point in prompting a user for a passphrase if they have the
|
||||||
secret key needed to decrypt. */
|
* secret key needed to decrypt. */
|
||||||
if(use_symkey && (rc = write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out)))
|
if (use_symkey && (rc = write_symkey_enc (symkey_s2k, cfx.dek->use_aead,
|
||||||
|
symkey_dek, cfx.dek, out)))
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (!opt.no_literal)
|
if (!opt.no_literal)
|
||||||
|
@ -1014,9 +1075,9 @@ encrypt_filter (void *opaque, int control,
|
||||||
|
|
||||||
if(efx->symkey_s2k && efx->symkey_dek)
|
if(efx->symkey_s2k && efx->symkey_dek)
|
||||||
{
|
{
|
||||||
rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek,
|
rc = write_symkey_enc (efx->symkey_s2k, efx->cfx.dek->use_aead,
|
||||||
efx->cfx.dek,a);
|
efx->symkey_dek, efx->cfx.dek, a);
|
||||||
if(rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1084,9 +1145,11 @@ write_pubkey_enc (ctrl_t ctrl,
|
||||||
if ( opt.verbose )
|
if ( opt.verbose )
|
||||||
{
|
{
|
||||||
char *ustr = get_user_id_string_native (ctrl, enc->keyid);
|
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_pk_algo_name (enc->pubkey_algo),
|
||||||
openpgp_cipher_algo_name (dek->algo),
|
openpgp_cipher_algo_name (dek->algo),
|
||||||
|
dek->use_aead? openpgp_aead_algo_name (dek->use_aead)
|
||||||
|
/**/ : "CFB",
|
||||||
ustr );
|
ustr );
|
||||||
xfree (ustr);
|
xfree (ustr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2284,7 +2284,7 @@ sk_esk (const char *option, int argc, char *argv[], void *cookie)
|
||||||
|
|
||||||
/* Now encrypt the session key (or rather, the algorithm used to
|
/* Now encrypt the session key (or rather, the algorithm used to
|
||||||
encrypt the SKESK plus the session key) using ENCKEY. */
|
encrypt the SKESK plus the session key) using ENCKEY. */
|
||||||
err = encrypt_seskey (&s2kdek, &sesdekp,
|
err = encrypt_seskey (&s2kdek, 0, &sesdekp,
|
||||||
(void**)&ske->seskey, (size_t *)&ske->seskeylen);
|
(void**)&ske->seskey, (size_t *)&ske->seskeylen);
|
||||||
if (err)
|
if (err)
|
||||||
log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err));
|
log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err));
|
||||||
|
|
19
g10/import.c
19
g10/import.c
|
@ -1113,6 +1113,24 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
|
||||||
problem=1;
|
problem=1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(prefs->type==PREFTYPE_AEAD)
|
||||||
|
{
|
||||||
|
if (openpgp_aead_test_algo (prefs->value))
|
||||||
|
{
|
||||||
|
/* FIXME: The test below is wrong. We should
|
||||||
|
* check if ...algo_name yields a "?" and
|
||||||
|
* only in that case use NUM. */
|
||||||
|
const char *algo =
|
||||||
|
(openpgp_aead_test_algo (prefs->value)
|
||||||
|
? num
|
||||||
|
: openpgp_aead_algo_name (prefs->value));
|
||||||
|
if(!problem)
|
||||||
|
check_prefs_warning(pk);
|
||||||
|
log_info(_(" \"%s\": preference for AEAD"
|
||||||
|
" algorithm %s\n"), user, algo);
|
||||||
|
problem=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if(prefs->type==PREFTYPE_HASH)
|
else if(prefs->type==PREFTYPE_HASH)
|
||||||
{
|
{
|
||||||
if(openpgp_md_test_algo(prefs->value))
|
if(openpgp_md_test_algo(prefs->value))
|
||||||
|
@ -2255,6 +2273,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
|
||||||
{
|
{
|
||||||
char countbuf[35];
|
char countbuf[35];
|
||||||
|
|
||||||
|
/* FIXME: Support AEAD */
|
||||||
/* Note that the IVLEN may be zero if we are working on a
|
/* Note that the IVLEN may be zero if we are working on a
|
||||||
dummy key. We can't express that in an S-expression and
|
dummy key. We can't express that in an S-expression and
|
||||||
thus we send dummy data for the IV. */
|
thus we send dummy data for the IV. */
|
||||||
|
|
|
@ -3064,6 +3064,23 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
|
||||||
tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
|
tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
|
||||||
}
|
}
|
||||||
tty_printf ("\n ");
|
tty_printf ("\n ");
|
||||||
|
tty_printf (_("AEAD: "));
|
||||||
|
for (i = any = 0; prefs[i].type; i++)
|
||||||
|
{
|
||||||
|
if (prefs[i].type == PREFTYPE_AEAD)
|
||||||
|
{
|
||||||
|
if (any)
|
||||||
|
tty_printf (", ");
|
||||||
|
any = 1;
|
||||||
|
/* We don't want to display strings for experimental algos */
|
||||||
|
if (!openpgp_aead_test_algo (prefs[i].value)
|
||||||
|
&& prefs[i].value < 100)
|
||||||
|
tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value));
|
||||||
|
else
|
||||||
|
tty_printf ("[%d]", prefs[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tty_printf ("\n ");
|
||||||
tty_printf (_("Digest: "));
|
tty_printf (_("Digest: "));
|
||||||
for (i = any = 0; prefs[i].type; i++)
|
for (i = any = 0; prefs[i].type; i++)
|
||||||
{
|
{
|
||||||
|
@ -3172,6 +3189,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
|
||||||
for (i = 0; prefs[i].type; i++)
|
for (i = 0; prefs[i].type; i++)
|
||||||
{
|
{
|
||||||
tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
|
tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
|
||||||
|
prefs[i].type == PREFTYPE_AEAD ? 'A' :
|
||||||
prefs[i].type == PREFTYPE_HASH ? 'H' :
|
prefs[i].type == PREFTYPE_HASH ? 'H' :
|
||||||
prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
|
prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
|
||||||
prefs[i].value);
|
prefs[i].value);
|
||||||
|
|
|
@ -235,7 +235,7 @@ void display_online_help( const char *keyword );
|
||||||
|
|
||||||
/*-- encode.c --*/
|
/*-- encode.c --*/
|
||||||
int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
|
int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
|
||||||
gpg_error_t encrypt_seskey (DEK *dek, DEK **r_seskey,
|
gpg_error_t encrypt_seskey (DEK *dek, aead_algo_t aead_algo, DEK **r_seskey,
|
||||||
void **r_enckey, size_t *r_enckeylen);
|
void **r_enckey, size_t *r_enckeylen);
|
||||||
aead_algo_t use_aead (pk_list_t pk_list, int algo);
|
aead_algo_t use_aead (pk_list_t pk_list, int algo);
|
||||||
int use_mdc (pk_list_t pk_list,int algo);
|
int use_mdc (pk_list_t pk_list,int algo);
|
||||||
|
|
116
g10/mainproc.c
116
g10/mainproc.c
|
@ -245,46 +245,102 @@ add_signature (CTX c, PACKET *pkt)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static gpg_error_t
|
||||||
symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
|
symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
gcry_cipher_hd_t hd;
|
gcry_cipher_hd_t hd;
|
||||||
|
unsigned int noncelen, keylen;
|
||||||
|
enum gcry_cipher_modes ciphermode;
|
||||||
|
byte ad[4];
|
||||||
|
|
||||||
if(slen < 17 || slen > 33)
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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"),
|
log_error ( _("weird size for an encrypted session key (%d)\n"),
|
||||||
(int)slen);
|
(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))
|
err = openpgp_cipher_open (&hd, dek->algo, ciphermode, GCRY_CIPHER_SECURE);
|
||||||
BUG ();
|
if (!err)
|
||||||
if (gcry_cipher_setkey ( hd, dek->key, dek->keylen ))
|
err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
|
||||||
BUG ();
|
if (!err)
|
||||||
gcry_cipher_setiv ( hd, NULL, 0 );
|
err = gcry_cipher_setiv (hd, noncelen? seskey : NULL, noncelen);
|
||||||
gcry_cipher_decrypt ( hd, seskey, slen, NULL, 0 );
|
if (err)
|
||||||
gcry_cipher_close ( hd );
|
goto leave;
|
||||||
|
|
||||||
/* Now we replace the dek components with the real session key to
|
if (dek->use_aead)
|
||||||
decrypt the contents of the sequencing packet. */
|
{
|
||||||
|
byte ad[4];
|
||||||
|
|
||||||
dek->keylen=slen-1;
|
ad[0] = (0xc0 | PKT_SYMKEY_ENC);
|
||||||
dek->algo=seskey[0];
|
ad[1] = 5;
|
||||||
|
ad[2] = dek->algo;
|
||||||
if(dek->keylen > DIM(dek->key))
|
ad[3] = dek->use_aead;
|
||||||
BUG ();
|
err = gcry_cipher_authenticate (hd, ad, 4);
|
||||||
|
if (err)
|
||||||
memcpy(dek->key, seskey + 1, dek->keylen);
|
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 );*/
|
/*log_hexdump( "thekey", dek->key, dek->keylen );*/
|
||||||
|
|
||||||
return 0;
|
leave:
|
||||||
|
gcry_cipher_close (hd);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
proc_symkey_enc (CTX c, PACKET *pkt)
|
proc_symkey_enc (CTX c, PACKET *pkt)
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
PKT_symkey_enc *enc;
|
PKT_symkey_enc *enc;
|
||||||
|
|
||||||
enc = pkt->pkt.symkey_enc;
|
enc = pkt->pkt.symkey_enc;
|
||||||
|
@ -294,19 +350,21 @@ proc_symkey_enc (CTX c, PACKET *pkt)
|
||||||
{
|
{
|
||||||
int algo = enc->cipher_algo;
|
int algo = enc->cipher_algo;
|
||||||
const char *s = openpgp_cipher_algo_name (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 (!openpgp_cipher_test_algo (algo))
|
||||||
{
|
{
|
||||||
if (!opt.quiet)
|
if (!opt.quiet)
|
||||||
{
|
{
|
||||||
if (enc->seskeylen)
|
if (enc->seskeylen)
|
||||||
log_info (_("%s encrypted session key\n"), s );
|
log_info (_("%s.%s encrypted session key\n"), s, a );
|
||||||
else
|
else
|
||||||
log_info (_("%s encrypted data\n"), s );
|
log_info (_("%s.%s encrypted data\n"), s, a );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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))
|
if (openpgp_md_test_algo (enc->s2k.hash_algo))
|
||||||
{
|
{
|
||||||
|
@ -334,6 +392,7 @@ proc_symkey_enc (CTX c, PACKET *pkt)
|
||||||
if (c->dek)
|
if (c->dek)
|
||||||
{
|
{
|
||||||
c->dek->symmetric = 1;
|
c->dek->symmetric = 1;
|
||||||
|
c->dek->use_aead = enc->aead_algo;
|
||||||
|
|
||||||
/* FIXME: This doesn't work perfectly if a symmetric key
|
/* FIXME: This doesn't work perfectly if a symmetric key
|
||||||
comes before a public key in the message - if the
|
comes before a public key in the message - if the
|
||||||
|
@ -344,9 +403,16 @@ proc_symkey_enc (CTX c, PACKET *pkt)
|
||||||
come later. */
|
come later. */
|
||||||
if (enc->seskeylen)
|
if (enc->seskeylen)
|
||||||
{
|
{
|
||||||
if (symkey_decrypt_seskey (c->dek,
|
err = symkey_decrypt_seskey (c->dek,
|
||||||
enc->seskey, enc->seskeylen))
|
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);
|
xfree (c->dek);
|
||||||
c->dek = NULL;
|
c->dek = NULL;
|
||||||
}
|
}
|
||||||
|
|
13
g10/packet.h
13
g10/packet.h
|
@ -94,12 +94,14 @@ typedef struct
|
||||||
/* A symmetric-key encrypted session key packet as defined in RFC
|
/* A symmetric-key encrypted session key packet as defined in RFC
|
||||||
4880, Section 5.3. All fields are serialized. */
|
4880, Section 5.3. All fields are serialized. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* RFC 4880: this must be 4. */
|
/* We support version 4 (rfc4880) and 5 (rfc4880bis). */
|
||||||
byte version;
|
byte version;
|
||||||
/* The cipher algorithm used to encrypt the session key. (This may
|
/* The cipher algorithm used to encrypt the session key. Note that
|
||||||
be different from the algorithm that is used to encrypt the SED
|
* this may be different from the algorithm that is used to encrypt
|
||||||
packet.) */
|
* bulk data. */
|
||||||
byte cipher_algo;
|
byte cipher_algo;
|
||||||
|
/* The AEAD algorithm or 0 for CFB encryption. */
|
||||||
|
byte aead_algo;
|
||||||
/* The string-to-key specifier. */
|
/* The string-to-key specifier. */
|
||||||
STRING2KEY s2k;
|
STRING2KEY s2k;
|
||||||
/* The length of SESKEY in bytes or 0 if this packet does not
|
/* The length of SESKEY in bytes or 0 if this packet does not
|
||||||
|
@ -107,7 +109,8 @@ typedef struct {
|
||||||
S2K function on the password is the session key. See RFC 4880,
|
S2K function on the password is the session key. See RFC 4880,
|
||||||
Section 5.3.) */
|
Section 5.3.) */
|
||||||
byte seskeylen;
|
byte seskeylen;
|
||||||
/* The session key as encrypted by the S2K specifier. */
|
/* The session key as encrypted by the S2K specifier. For AEAD this
|
||||||
|
* includes the nonce and the authentication tag. */
|
||||||
byte seskey[1];
|
byte seskey[1];
|
||||||
} PKT_symkey_enc;
|
} PKT_symkey_enc;
|
||||||
|
|
||||||
|
|
|
@ -1105,7 +1105,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||||
{
|
{
|
||||||
PKT_symkey_enc *k;
|
PKT_symkey_enc *k;
|
||||||
int rc = 0;
|
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)
|
if (pktlen < 4)
|
||||||
{
|
{
|
||||||
|
@ -1117,7 +1117,11 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||||
}
|
}
|
||||||
version = iobuf_get_noeof (inp);
|
version = iobuf_get_noeof (inp);
|
||||||
pktlen--;
|
pktlen--;
|
||||||
if (version != 4)
|
if (version == 4)
|
||||||
|
;
|
||||||
|
else if (version == 5)
|
||||||
|
;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
log_error ("packet(%d) with unknown version %d\n", pkttype, version);
|
log_error ("packet(%d) with unknown version %d\n", pkttype, version);
|
||||||
if (list_mode)
|
if (list_mode)
|
||||||
|
@ -1135,6 +1139,13 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||||
}
|
}
|
||||||
cipher_algo = iobuf_get_noeof (inp);
|
cipher_algo = iobuf_get_noeof (inp);
|
||||||
pktlen--;
|
pktlen--;
|
||||||
|
if (version == 5)
|
||||||
|
{
|
||||||
|
aead_algo = iobuf_get_noeof (inp);
|
||||||
|
pktlen--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aead_algo = 0;
|
||||||
s2kmode = iobuf_get_noeof (inp);
|
s2kmode = iobuf_get_noeof (inp);
|
||||||
pktlen--;
|
pktlen--;
|
||||||
hash_algo = iobuf_get_noeof (inp);
|
hash_algo = iobuf_get_noeof (inp);
|
||||||
|
@ -1169,6 +1180,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||||
+ seskeylen - 1);
|
+ seskeylen - 1);
|
||||||
k->version = version;
|
k->version = version;
|
||||||
k->cipher_algo = cipher_algo;
|
k->cipher_algo = cipher_algo;
|
||||||
|
k->aead_algo = aead_algo;
|
||||||
k->s2k.mode = s2kmode;
|
k->s2k.mode = s2kmode;
|
||||||
k->s2k.hash_algo = hash_algo;
|
k->s2k.hash_algo = hash_algo;
|
||||||
if (s2kmode == 1 || s2kmode == 3)
|
if (s2kmode == 1 || s2kmode == 3)
|
||||||
|
@ -1199,10 +1211,20 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||||
if (list_mode)
|
if (list_mode)
|
||||||
{
|
{
|
||||||
es_fprintf (listfp,
|
es_fprintf (listfp,
|
||||||
":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
|
":symkey enc packet: version %d, cipher %d, aead %d,"
|
||||||
version, cipher_algo, s2kmode, hash_algo);
|
" s2k %d, hash %d",
|
||||||
|
version, cipher_algo, aead_algo, s2kmode, hash_algo);
|
||||||
if (seskeylen)
|
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 seize 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");
|
es_fprintf (listfp, "\n");
|
||||||
if (s2kmode == 1 || s2kmode == 3)
|
if (s2kmode == 1 || s2kmode == 3)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1326,9 +1326,6 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
|
||||||
s2k->hash_algo = S2K_DIGEST_ALGO;
|
s2k->hash_algo = S2K_DIGEST_ALGO;
|
||||||
|
|
||||||
algo = default_cipher_algo();
|
algo = default_cipher_algo();
|
||||||
if (!opt.quiet || !opt.batch)
|
|
||||||
log_info (_("%s encryption will be used\n"),
|
|
||||||
openpgp_cipher_algo_name (algo) );
|
|
||||||
cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled);
|
cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled);
|
||||||
|
|
||||||
if (!cfx.dek || !cfx.dek->keylen) {
|
if (!cfx.dek || !cfx.dek->keylen) {
|
||||||
|
@ -1341,6 +1338,12 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
|
||||||
if (!cfx.dek->use_aead)
|
if (!cfx.dek->use_aead)
|
||||||
cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
|
cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
|
||||||
|
|
||||||
|
if (!opt.quiet || !opt.batch)
|
||||||
|
log_info (_("%s.%s encryption will be used\n"),
|
||||||
|
openpgp_cipher_algo_name (algo),
|
||||||
|
cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead)
|
||||||
|
/**/ : "CFB");
|
||||||
|
|
||||||
/* now create the outfile */
|
/* now create the outfile */
|
||||||
rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
|
rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user