aboutsummaryrefslogtreecommitdiffstats
path: root/g10/decrypt-data.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/decrypt-data.c')
-rw-r--r--g10/decrypt-data.c197
1 files changed, 157 insertions, 40 deletions
diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c
index 55e078e56..df56fbc1a 100644
--- a/g10/decrypt-data.c
+++ b/g10/decrypt-data.c
@@ -54,7 +54,7 @@ struct decode_filter_context_s
/* The hash handle for use in MDC mode. */
gcry_md_hd_t mdc_hash;
- /* The start IV for AEAD encryption. */
+ /* The start IV for AEAD encryption. For OCB this is the nonce. */
byte startiv[16];
/* The holdback buffer and its used length. For AEAD we need 32+1
@@ -75,6 +75,9 @@ struct decode_filter_context_s
/* Flag to convey an error from aead_checktag. */
unsigned int checktag_failed : 1;
+ /* Set if the RFC-9850 SEIPD version 2 packet is used. */
+ unsigned int seipdv2 : 1;
+
/* The actually used cipher algo for AEAD. */
byte cipher_algo;
@@ -132,6 +135,7 @@ aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final)
gpg_error_t err;
unsigned char ad[21];
unsigned char nonce[16];
+ unsigned int adlen;
int i;
switch (dfx->aead_algo)
@@ -146,6 +150,11 @@ aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final)
i = 8;
break;
+ case AEAD_ALGO_GCM:
+ memcpy (nonce, dfx->startiv, 12);
+ i = 4;
+ break;
+
default:
BUG ();
}
@@ -164,8 +173,8 @@ aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final)
if (err)
return err;
- ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD);
- ad[1] = 1;
+ ad[0] = (0xc0 | (dfx->seipdv2? PKT_ENCRYPTED_MDC:PKT_ENCRYPTED_OCB));
+ ad[1] = dfx->seipdv2? 2:1;
ad[2] = dfx->cipher_algo;
ad[3] = dfx->aead_algo;
ad[4] = dfx->chunkbyte;
@@ -188,9 +197,22 @@ aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final)
ad[19] = dfx->total >> 8;
ad[20] = dfx->total;
}
+
+ if (dfx->seipdv2)
+ {
+ adlen = 5;
+ if (final)
+ {
+ adlen += 8;
+ memmove (ad+5, ad+13, 8);
+ }
+ }
+ else
+ adlen = final? 21 : 13;
+
if (DBG_CRYPTO)
- log_printhex (ad, final? 21 : 13, "authdata:");
- return gcry_cipher_authenticate (dfx->cipher_hd, ad, final? 21 : 13);
+ log_printhex (ad, adlen, "authdata:");
+ return gcry_cipher_authenticate (dfx->cipher_hd, ad, adlen);
}
@@ -201,19 +223,19 @@ aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf)
{
gpg_error_t err;
- if (DBG_FILTER)
- log_printhex (tagbuf, 16, "tag:");
err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16);
if (err)
{
+ if (DBG_CRYPTO)
+ log_printhex (tagbuf, 16, "invalid %stag:", final?"final ":"");
log_error ("gcry_cipher_checktag%s failed: %s\n",
final? " (final)":"", gpg_strerror (err));
write_status_error ("aead_checktag", err);
dfx->checktag_failed = 1;
return err;
}
- if (DBG_FILTER)
- log_debug ("%stag is valid\n", final?"final ":"");
+ if (DBG_CRYPTO)
+ log_printhex (tagbuf, 16, "valid %stag:", final?"final ":"");
return 0;
}
@@ -236,6 +258,11 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek,
byte temp[32];
unsigned int blocksize;
unsigned int nprefix;
+ unsigned char *thekeybuffer = NULL; /* Used by seipdv2 */
+ size_t thekeybufferlen; /* Malloced length of thekeybuffer. */
+ const void *thekey; /* Points either to thekeybuffer or dek->key. */
+ size_t thekeylen; /* Same as dek->keylen */
+
*compliance_error = 0;
@@ -243,9 +270,12 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek,
if (!dfx)
return gpg_error_from_syserror ();
dfx->refcount = 1;
+ dfx->seipdv2 = (ed->seipd && ed->version == 2);
if ( opt.verbose && !dek->algo_info_printed )
{
+ if (dfx->seipdv2)
+ log_info (_("Note: Using the %s encryption packet\n"), "RFC-9580");
if (!openpgp_cipher_test_algo (dek->algo))
log_info (_("%s encrypted data\n"),
openpgp_cipher_algo_mode_name (dek->algo, ed->aead_algo));
@@ -345,32 +375,6 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek,
goto leave;
}
- /* Read the Start-IV. */
- if (ed->len)
- {
- for (i=0; i < startivlen && ed->len; i++, ed->len--)
- {
- if ((c=iobuf_get (ed->buf)) == -1)
- break;
- dfx->startiv[i] = c;
- }
- }
- else
- {
- for (i=0; i < startivlen; i++ )
- if ( (c=iobuf_get (ed->buf)) == -1 )
- break;
- else
- dfx->startiv[i] = c;
- }
- if (i != startivlen)
- {
- log_error ("Start-IV in AEAD packet too short (%d/%u)\n",
- i, startivlen);
- rc = gpg_error (GPG_ERR_TOO_SHORT);
- goto leave;
- }
-
dfx->cipher_algo = ed->cipher_algo;
dfx->aead_algo = ed->aead_algo;
dfx->chunkbyte = ed->chunkbyte;
@@ -381,6 +385,115 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek,
openpgp_cipher_algo_name (dek->algo),
openpgp_cipher_algo_name (dfx->cipher_algo));
+ if (dfx->seipdv2) /* RFC-9580 mode */
+ {
+ gcry_kdf_hd_t kdfhd;
+ unsigned long kdfparam[1];
+ unsigned char kdfinfo[5];
+ unsigned char salt[32];
+
+ /* Read the salt. */
+ if (ed->len)
+ {
+ for (i=0; i < sizeof salt && ed->len; i++, ed->len--)
+ {
+ if ((c=iobuf_get (ed->buf)) == -1)
+ break;
+ salt[i] = c;
+ }
+ }
+ else
+ {
+ for (i=0; i < sizeof salt; i++ )
+ if ( (c=iobuf_get (ed->buf)) == -1 )
+ break;
+ else
+ salt[i] = c;
+ }
+ if (i != sizeof salt)
+ {
+ log_error ("SALT in SEIPDv2 packet too short (%d/%u)\n", i, 32);
+ rc = gpg_error (GPG_ERR_TOO_SHORT);
+ goto leave;
+ }
+
+ /* Expand key to M + N - 8. */
+ kdfparam[0] = dek->keylen + startivlen - 8;
+
+ kdfinfo[0] = 0xd2;
+ kdfinfo[1] = 2;
+ kdfinfo[2] = dek->algo;
+ kdfinfo[3] = ed->aead_algo;
+ kdfinfo[4] = ed->chunkbyte;
+
+ if (DBG_CRYPTO)
+ {
+ log_printhex (salt, sizeof salt, "salt:");
+ log_printhex (kdfinfo, sizeof kdfinfo, "info:");
+ }
+ rc = gcry_kdf_open (&kdfhd, GCRY_KDF_HKDF, GCRY_MAC_HMAC_SHA256,
+ kdfparam, 1,
+ dek->key, dek->keylen,
+ NULL, 0,
+ salt, sizeof salt,
+ kdfinfo, sizeof kdfinfo);
+ if (!rc)
+ {
+ rc = gcry_kdf_compute (kdfhd, NULL);
+ if (!rc)
+ {
+ /* Allocate M + N */
+ thekeybufferlen = dek->keylen + startivlen;
+ thekeybuffer = xtrymalloc_secure (thekeybufferlen);
+ if (!thekeybuffer)
+ rc = gpg_error_from_syserror ();
+ else /* Get M + N - 8 */
+ rc = gcry_kdf_final (kdfhd, kdfparam[0], thekeybuffer);
+ }
+ gcry_kdf_close (kdfhd);
+ }
+ if (rc)
+ {
+ log_error ("HKDF for session key failed: %s\n", gpg_strerror(rc));
+ goto leave;
+ }
+ log_assert (sizeof dfx->startiv >= startivlen);
+ memcpy (dfx->startiv, thekeybuffer + dek->keylen, startivlen - 8);
+ memset (dfx->startiv + dek->keylen + startivlen - 8, 0, 8);
+ thekey = thekeybuffer;
+ thekeylen = dek->keylen;
+ }
+ else /* Standard RFC-4880bis (aka LibrePGP) mode. */
+ {
+ /* Read the Start-IV (aka nonce). */
+ if (ed->len)
+ {
+ for (i=0; i < startivlen && ed->len; i++, ed->len--)
+ {
+ if ((c=iobuf_get (ed->buf)) == -1)
+ break;
+ dfx->startiv[i] = c;
+ }
+ }
+ else
+ {
+ for (i=0; i < startivlen; i++ )
+ if ( (c=iobuf_get (ed->buf)) == -1 )
+ break;
+ else
+ dfx->startiv[i] = c;
+ }
+ if (i != startivlen)
+ {
+ log_error ("Start-IV in OCB packet too short (%d/%u)\n",
+ i, startivlen);
+ rc = gpg_error (GPG_ERR_TOO_SHORT);
+ goto leave;
+ }
+ thekey = dek->key;
+ thekeylen = dek->keylen;
+ }
+
rc = openpgp_cipher_open (&dfx->cipher_hd,
dfx->cipher_algo,
ciphermode,
@@ -389,8 +502,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek,
goto leave; /* Should never happen. */
if (DBG_CRYPTO)
- log_printhex (dek->key, dek->keylen, "thekey:");
- rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
+ log_printhex (thekey, thekeylen, "thekey:");
+ rc = gcry_cipher_setkey (dfx->cipher_hd, thekey, thekeylen);
if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
{
log_info (_("WARNING: message was encrypted with"
@@ -408,7 +521,6 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek,
log_error(_("problem handling encrypted packet\n"));
goto leave;
}
-
}
else /* CFB encryption. */
{
@@ -441,8 +553,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek,
BUG();
}
-
- /* log_hexdump( "thekey", dek->key, dek->keylen );*/
+ if (DBG_CRYPTO)
+ log_printhex (dek->key, dek->keylen, "thekey:");
rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY )
{
@@ -588,6 +700,11 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek,
}
leave:
+ if (thekeybuffer)
+ {
+ wipememory (thekeybuffer, thekeybufferlen);
+ xfree (thekeybuffer);
+ }
release_dfx_context (dfx);
return rc;
}