mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
gpg: Accept SEIPDv2 packet.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
parent
07af232493
commit
51fe266705
@ -78,6 +78,9 @@ struct decode_filter_context_s
|
|||||||
/* The AEAD algo. */
|
/* The AEAD algo. */
|
||||||
byte aead_algo;
|
byte aead_algo;
|
||||||
|
|
||||||
|
/* The Packet Type. */
|
||||||
|
byte pkttype;
|
||||||
|
|
||||||
/* The encoded chunk byte for AEAD. */
|
/* The encoded chunk byte for AEAD. */
|
||||||
byte chunkbyte;
|
byte chunkbyte;
|
||||||
|
|
||||||
@ -161,33 +164,40 @@ aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final)
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD);
|
ad[0] = (0xc0 | dfx->pkttype);
|
||||||
ad[1] = 1;
|
ad[1] = dfx->pkttype == PKT_ENCRYPTED_AEAD? 1 : 2;
|
||||||
ad[2] = dfx->cipher_algo;
|
ad[2] = dfx->cipher_algo;
|
||||||
ad[3] = dfx->aead_algo;
|
ad[3] = dfx->aead_algo;
|
||||||
ad[4] = dfx->chunkbyte;
|
ad[4] = dfx->chunkbyte;
|
||||||
ad[5] = dfx->chunkindex >> 56;
|
if (dfx->pkttype == PKT_ENCRYPTED_AEAD)
|
||||||
ad[6] = dfx->chunkindex >> 48;
|
{
|
||||||
ad[7] = dfx->chunkindex >> 40;
|
ad[5] = dfx->chunkindex >> 56;
|
||||||
ad[8] = dfx->chunkindex >> 32;
|
ad[6] = dfx->chunkindex >> 48;
|
||||||
ad[9] = dfx->chunkindex >> 24;
|
ad[7] = dfx->chunkindex >> 40;
|
||||||
ad[10]= dfx->chunkindex >> 16;
|
ad[8] = dfx->chunkindex >> 32;
|
||||||
ad[11]= dfx->chunkindex >> 8;
|
ad[9] = dfx->chunkindex >> 24;
|
||||||
ad[12]= dfx->chunkindex;
|
ad[10]= dfx->chunkindex >> 16;
|
||||||
|
ad[11]= dfx->chunkindex >> 8;
|
||||||
|
ad[12]= dfx->chunkindex;
|
||||||
|
i = 13;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i = 5;
|
||||||
if (final)
|
if (final)
|
||||||
{
|
{
|
||||||
ad[13] = dfx->total >> 56;
|
ad[i++] = dfx->total >> 56;
|
||||||
ad[14] = dfx->total >> 48;
|
ad[i++] = dfx->total >> 48;
|
||||||
ad[15] = dfx->total >> 40;
|
ad[i++] = dfx->total >> 40;
|
||||||
ad[16] = dfx->total >> 32;
|
ad[i++] = dfx->total >> 32;
|
||||||
ad[17] = dfx->total >> 24;
|
ad[i++] = dfx->total >> 24;
|
||||||
ad[18] = dfx->total >> 16;
|
ad[i++] = dfx->total >> 16;
|
||||||
ad[19] = dfx->total >> 8;
|
ad[i++] = dfx->total >> 8;
|
||||||
ad[20] = dfx->total;
|
ad[i++] = dfx->total;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DBG_CRYPTO)
|
if (DBG_CRYPTO)
|
||||||
log_printhex (ad, final? 21 : 13, "authdata:");
|
log_printhex (ad, final? 21 : 13, "authdata:");
|
||||||
return gcry_cipher_authenticate (dfx->cipher_hd, ad, final? 21 : 13);
|
return gcry_cipher_authenticate (dfx->cipher_hd, ad, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -213,6 +223,84 @@ aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* HKDF Extract and expand. */
|
||||||
|
static gpg_error_t
|
||||||
|
hkdf_derive (const byte *salt, int saltlen, const byte *key, int keylen,
|
||||||
|
const byte *info, int infolen, int outlen, byte *out)
|
||||||
|
{
|
||||||
|
int algo = GCRY_MD_SHA256;
|
||||||
|
gcry_md_hd_t hd;
|
||||||
|
unsigned char *t;
|
||||||
|
unsigned char *p;
|
||||||
|
int mdlen;
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
int off = 0;
|
||||||
|
unsigned char n = 0;
|
||||||
|
|
||||||
|
mdlen = gcry_md_get_algo_dlen (algo);
|
||||||
|
if (salt && saltlen != mdlen)
|
||||||
|
return gpg_error (GPG_ERR_INV_LENGTH);
|
||||||
|
|
||||||
|
t = xtrymalloc (mdlen);
|
||||||
|
if (!t)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
err = gcry_md_open (&hd, algo, GCRY_MD_FLAG_HMAC);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (salt)
|
||||||
|
{
|
||||||
|
err = gcry_md_setkey (hd, salt, mdlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
xfree (t);
|
||||||
|
gcry_md_close (hd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keylen)
|
||||||
|
gcry_md_write (hd, key, keylen);
|
||||||
|
|
||||||
|
p = gcry_md_read (hd, 0);
|
||||||
|
memcpy (t, p, mdlen);
|
||||||
|
|
||||||
|
gcry_md_reset (hd);
|
||||||
|
err = gcry_md_setkey (hd, t, mdlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
xfree (t);
|
||||||
|
gcry_md_close (hd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
n++;
|
||||||
|
gcry_md_write (hd, info, infolen);
|
||||||
|
gcry_md_write (hd, &n, 1);
|
||||||
|
p = gcry_md_read (hd, 0);
|
||||||
|
memcpy (t, p, mdlen);
|
||||||
|
if ((outlen - off) / mdlen)
|
||||||
|
{
|
||||||
|
memcpy (out + off, t, mdlen);
|
||||||
|
off += mdlen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (out + off, t, (outlen - off));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gcry_md_reset (hd);
|
||||||
|
gcry_md_write (hd, t, mdlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (t);
|
||||||
|
gcry_md_close (hd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Decrypt the data, specified by ED with the key DEK.
|
* Decrypt the data, specified by ED with the key DEK.
|
||||||
*/
|
*/
|
||||||
@ -295,8 +383,10 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
|
|||||||
if ( !blocksize || blocksize > 16 )
|
if ( !blocksize || blocksize > 16 )
|
||||||
log_fatal ("unsupported blocksize %u\n", blocksize );
|
log_fatal ("unsupported blocksize %u\n", blocksize );
|
||||||
|
|
||||||
if (ed->aead_algo)
|
if (ed->aead_algo && ed->mdc_method == 0)
|
||||||
{
|
{
|
||||||
|
dfx->pkttype = PKT_ENCRYPTED_AEAD;
|
||||||
|
|
||||||
if (blocksize != 16)
|
if (blocksize != 16)
|
||||||
{
|
{
|
||||||
rc = gpg_error (GPG_ERR_CIPHER_ALGO);
|
rc = gpg_error (GPG_ERR_CIPHER_ALGO);
|
||||||
@ -375,6 +465,107 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (ed->aead_algo && ed->mdc_method)
|
||||||
|
{ /* SEIPDv2 */
|
||||||
|
unsigned char info[5];
|
||||||
|
int keylen;
|
||||||
|
int outlen;
|
||||||
|
unsigned char *out = NULL;
|
||||||
|
|
||||||
|
dfx->pkttype = PKT_ENCRYPTED_MDC;
|
||||||
|
|
||||||
|
info[0] = (0xc0 | dfx->pkttype);
|
||||||
|
info[1] = 0x02;
|
||||||
|
info[2] = ed->cipher_algo;
|
||||||
|
info[3] = ed->aead_algo;
|
||||||
|
info[4] = ed->chunkbyte;
|
||||||
|
|
||||||
|
if (blocksize != 16)
|
||||||
|
{
|
||||||
|
rc = gpg_error (GPG_ERR_CIPHER_ALGO);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ed->chunkbyte > 16)
|
||||||
|
{
|
||||||
|
log_error ("invalid AEAD chunkbyte %u\n", ed->chunkbyte);
|
||||||
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the salt. */
|
||||||
|
for (i=0; i < 32 && ed->len; i++, ed->len--)
|
||||||
|
if ((c=iobuf_get (ed->buf)) == -1)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
temp[i] = c;
|
||||||
|
if (i != 32)
|
||||||
|
{
|
||||||
|
log_error ("Salt in SEIPDv2 packet too short (%d/%u)\n",
|
||||||
|
i, 32);
|
||||||
|
rc = gpg_error (GPG_ERR_TOO_SHORT);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
keylen = openpgp_cipher_get_algo_keylen (ed->cipher_algo);
|
||||||
|
outlen = startivlen - 8 + keylen;
|
||||||
|
out = xtrymalloc (outlen);
|
||||||
|
if (!out)
|
||||||
|
{
|
||||||
|
rc = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_printhex (dek->key, dek->keylen, "the session key:");
|
||||||
|
|
||||||
|
hkdf_derive (temp, 32, dek->key, dek->keylen,
|
||||||
|
info, sizeof (info), outlen, out);
|
||||||
|
|
||||||
|
dfx->cipher_algo = ed->cipher_algo;
|
||||||
|
dfx->aead_algo = ed->aead_algo;
|
||||||
|
dfx->chunkbyte = ed->chunkbyte;
|
||||||
|
dfx->chunksize = (uint64_t)1 << (dfx->chunkbyte + 6);
|
||||||
|
memcpy (dfx->startiv, out+keylen, startivlen-8);
|
||||||
|
memset (dfx->startiv+startivlen-8, 0, 8);
|
||||||
|
|
||||||
|
if (dek->algo != dfx->cipher_algo)
|
||||||
|
log_info ("Note: different cipher algorithms used (%s/%s)\n",
|
||||||
|
openpgp_cipher_algo_name (dek->algo),
|
||||||
|
openpgp_cipher_algo_name (dfx->cipher_algo));
|
||||||
|
|
||||||
|
rc = openpgp_cipher_open (&dfx->cipher_hd,
|
||||||
|
dfx->cipher_algo,
|
||||||
|
ciphermode,
|
||||||
|
GCRY_CIPHER_SECURE);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
xfree (out);
|
||||||
|
goto leave; /* Should never happen. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_printhex (out, keylen, "thekey:");
|
||||||
|
rc = gcry_cipher_setkey (dfx->cipher_hd, out, keylen);
|
||||||
|
xfree (out);
|
||||||
|
if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
|
||||||
|
{
|
||||||
|
log_info (_("WARNING: message was encrypted with"
|
||||||
|
" a weak key in the symmetric cipher.\n"));
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
else if (rc)
|
||||||
|
{
|
||||||
|
log_error("key setup failed: %s\n", gpg_strerror (rc));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ed->buf)
|
||||||
|
{
|
||||||
|
log_error(_("problem handling encrypted packet\n"));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
else /* CFB encryption. */
|
else /* CFB encryption. */
|
||||||
{
|
{
|
||||||
nprefix = blocksize;
|
nprefix = blocksize;
|
||||||
@ -509,7 +700,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
|
|||||||
ed->buf = NULL;
|
ed->buf = NULL;
|
||||||
if (dfx->eof_seen > 1 )
|
if (dfx->eof_seen > 1 )
|
||||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||||
else if ( ed->mdc_method )
|
else if ( ed->mdc_method && ed->aead_algo == 0 )
|
||||||
{
|
{
|
||||||
/* We used to let parse-packet.c handle the MDC packet but this
|
/* We used to let parse-packet.c handle the MDC packet but this
|
||||||
turned out to be a problem with compressed packets: With old
|
turned out to be a problem with compressed packets: With old
|
||||||
|
@ -3525,7 +3525,22 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
version = iobuf_get_noeof (inp);
|
version = iobuf_get_noeof (inp);
|
||||||
if (orig_pktlen)
|
if (orig_pktlen)
|
||||||
pktlen--;
|
pktlen--;
|
||||||
if (version != 1)
|
if (version == 1)
|
||||||
|
ed->mdc_method = DIGEST_ALGO_SHA1;
|
||||||
|
else if (version == 2)
|
||||||
|
{
|
||||||
|
ed->mdc_method = 0xff; /* SEIPDv2 */
|
||||||
|
ed->cipher_algo = iobuf_get_noeof (inp);
|
||||||
|
if (orig_pktlen)
|
||||||
|
pktlen--;
|
||||||
|
ed->aead_algo = iobuf_get_noeof (inp);
|
||||||
|
if (orig_pktlen)
|
||||||
|
pktlen--;
|
||||||
|
ed->chunkbyte = iobuf_get_noeof (inp);
|
||||||
|
if (orig_pktlen)
|
||||||
|
pktlen--;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
log_error ("encrypted_mdc packet with unknown version %d\n",
|
log_error ("encrypted_mdc packet with unknown version %d\n",
|
||||||
version);
|
version);
|
||||||
@ -3535,7 +3550,6 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
ed->mdc_method = DIGEST_ALGO_SHA1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ed->mdc_method = 0;
|
ed->mdc_method = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user