Decryption does now work

This commit is contained in:
Werner Koch 2001-12-06 20:48:10 +00:00
parent e4a72423ff
commit ce32f6b6c8
4 changed files with 295 additions and 34 deletions

View File

@ -553,8 +553,3 @@ gpgsm_destroy_writer (Base64Context ctx)
{
xfree (ctx);
}

View File

@ -190,10 +190,12 @@ start_agent (void)
log_debug ("connection to agent established\n");
log_debug ("waiting for debugger .....\n");
getchar ();
log_debug ("okay\n");
if (DBG_AGENT)
{
log_debug ("waiting for debugger [hit RETURN when ready] .....\n");
getchar ();
log_debug ("... okay\n");
}
return 0;
}
@ -288,8 +290,9 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
char line[LINELENGTH];
struct membuf data;
struct cipher_parm_s cipher_parm;
size_t len;
size_t n, len;
char *buf, *endp;
if (!keygrip || strlen(keygrip) != 40 || !ciphertext || !r_buf || !r_buflen)
return GNUPG_Invalid_Value;
*r_buf = NULL;
@ -321,7 +324,28 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
xfree (get_membuf (&data, &len));
return map_assuan_err (rc);
}
*r_buf = get_membuf (&data, r_buflen);
return *r_buf? 0 : GNUPG_Out_Of_Core;
put_membuf (&data, "", 1); /* make sure it is 0 terminated */
buf = get_membuf (&data, &len);
if (!buf)
return seterr (Out_Of_Core);
assert (len);
len--; /* remove the terminating 0 */
n = strtoul (buf, &endp, 10);
if (!n || *endp != ':')
return seterr (Invalid_Sexp);
endp++;
if (endp-buf+n > len)
return seterr (Invalid_Sexp); /* oops len does not match internal len*/
memmove (buf, endp, n);
*r_buflen = n;
*r_buf = buf;
return 0;
}

View File

@ -34,6 +34,21 @@
#include "keydb.h"
#include "i18n.h"
struct decrypt_filter_parm_s {
int algo;
int blklen;
GCRY_CIPHER_HD hd;
char iv[16];
size_t ivlen;
int any_data; /* dod we push anything through the filter at all? */
unsigned char lastblock[16]; /* to strip the padding we have to
keep this one */
char helpblock[16]; /* needed because there is no block bufferin in
libgcrypt (yet) */
int helpblocklen;
};
static void
print_integer (unsigned char *p)
{
@ -49,6 +64,174 @@ print_integer (unsigned char *p)
}
}
/* decrypt the session key and fill in the parm structure. The
algo and the IV is expected to be already in PARM. */
static int
prepare_decryption (const char *hexkeygrip, const char *enc_val,
struct decrypt_filter_parm_s *parm)
{
char *seskey = NULL;
size_t n, seskeylen;
int rc;
rc = gpgsm_agent_pkdecrypt (hexkeygrip, enc_val, strlen (enc_val),
&seskey, &seskeylen);
if (rc)
{
log_error ("error decrypting session key: %s\n", gnupg_strerror (rc));
goto leave;
}
if (DBG_CRYPTO)
log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
n=0;
if (n + 7 > seskeylen )
{
rc = seterr (Invalid_Session_Key);
goto leave;
}
if (seskey[n] != 2 ) /* wrong block type version */
{
rc = seterr (Invalid_Session_Key);
goto leave;
}
for (n++; n < seskeylen && seskey[n]; n++) /* skip the random bytes */
;
n++; /* and the zero byte */
if (n >= seskeylen )
{
rc = seterr (Invalid_Session_Key);
goto leave;
}
if (DBG_CRYPTO)
log_printhex ("session key:", seskey+n, seskeylen-n);
parm->hd = gcry_cipher_open (parm->algo, GCRY_CIPHER_MODE_CBC, 0);
if (!parm->hd)
{
rc = gcry_errno ();
log_error ("error creating decryptor: %s\n", gcry_strerror (rc));
rc = map_gcry_err (rc);
goto leave;
}
rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
if (rc == GCRYERR_WEAK_KEY)
{
log_info (_("WARNING: message was encrypted with "
"a weak key in the symmetric cipher.\n"));
rc = 0;
}
if (rc)
{
log_error("key setup failed: %s\n", gcry_strerror(rc) );
rc = map_gcry_err (rc);
goto leave;
}
gcry_cipher_setiv (parm->hd, parm->iv, parm->ivlen);
leave:
xfree (seskey);
return rc;
}
/* This function is called by the KSab writer just before the actual
write is done. The function must take INLEN bytes from INBUF,
decrypt it and store it inoutbuf which has a maximum size of
maxoutlen. The valid bytes in outbuf should be return in outlen.
Due to different buffer sizes or different length of input and
output, it may happen that fewer bytes are process or fewer bytes
are written. */
static KsbaError
decrypt_filter (void *arg,
const void *inbuf, size_t inlen, size_t *inused,
void *outbuf, size_t maxoutlen, size_t *outlen)
{
struct decrypt_filter_parm_s *parm = arg;
int blklen = parm->blklen;
size_t orig_inlen = inlen;
/* fixme: Should we issue an error when we have not seen one full block? */
if (!inlen)
return KSBA_Bug;
if (maxoutlen < 2*parm->blklen)
return KSBA_Bug;
/* make some space becuase we will later need an extra block at the end */
maxoutlen -= blklen;
if (parm->helpblocklen)
{
int i, j;
for (i=parm->helpblocklen,j=0; i < blklen && j < inlen; i++, j++)
parm->helpblock[i] = ((const char*)inbuf)[j];
inlen -= j;
if (blklen > maxoutlen)
return KSBA_Bug;
if (i < blklen)
{
parm->helpblocklen = i;
*outlen = 0;
}
else
{
parm->helpblocklen = 0;
if (parm->any_data)
{
memcpy (outbuf, parm->lastblock, blklen);
*outlen =blklen;
}
else
*outlen = 0;
gcry_cipher_decrypt (parm->hd, parm->lastblock, blklen,
parm->helpblock, blklen);
parm->any_data = 1;
}
*inused = orig_inlen - inlen;
return 0;
}
if (inlen > maxoutlen)
inlen = maxoutlen;
if (inlen % blklen)
{ /* store the remainder away */
parm->helpblocklen = inlen%blklen;
inlen = inlen/blklen*blklen;
memcpy (parm->helpblock, (const char*)inbuf+inlen, parm->helpblocklen);
}
*inused = inlen + parm->helpblocklen;
if (inlen)
{
assert (inlen >= blklen);
if (parm->any_data)
{
gcry_cipher_decrypt (parm->hd, (char*)outbuf+blklen, inlen,
inbuf, inlen);
memcpy (outbuf, parm->lastblock, blklen);
memcpy (parm->lastblock,(char*)outbuf+inlen, blklen);
*outlen = inlen;
}
else
{
gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen);
memcpy (parm->lastblock, (char*)outbuf+inlen-blklen, blklen);
*outlen = inlen - blklen;
parm->any_data = 1;
}
}
else
*outlen = 0;
return 0;
}
@ -67,6 +250,9 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
KEYDB_HANDLE kh;
int recp;
FILE *in_fp = NULL;
struct decrypt_filter_parm_s dfparm;
memset (&dfparm, 0, sizeof dfparm);
kh = keydb_new (0);
if (!kh)
@ -130,6 +316,33 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
if (stopreason == KSBA_SR_BEGIN_DATA
|| stopreason == KSBA_SR_DETACHED_DATA)
{
int algo;
const char *algoid;
algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
algo = gcry_cipher_map_name (algoid);
if (!algo)
{
log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
rc = GNUPG_Unsupported_Algorithm;
goto leave;
}
dfparm.algo = algo;
dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
if (dfparm.blklen > sizeof (dfparm.helpblock))
return GNUPG_Bug;
rc = ksba_cms_get_content_enc_iv (cms,
dfparm.iv,
sizeof (dfparm.iv),
&dfparm.ivlen);
if (rc)
{
log_error ("error getting IV: %s\n", ksba_strerror (err));
rc = map_ksba_err (err);
goto leave;
}
for (recp=0; recp < 1; recp++)
{
char *issuer;
@ -164,8 +377,7 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
if (rc)
{
log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
goto oops;
}
goto oops; }
hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
@ -181,31 +393,54 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
recp);
else
{
char *seskey;
size_t seskeylen;
log_debug ("recp %d - enc-val: `%s'\n",
recp, enc_val);
rc = gpgsm_agent_pkdecrypt (hexkeygrip,
enc_val, strlen (enc_val),
&seskey, &seskeylen);
if (rc)
log_debug ("problem: %s\n", gnupg_strerror (rc));
else
{
unsigned char *p;
log_debug ("plaintext=");
for (p=seskey; seskeylen; seskeylen--, p++)
log_printf (" %02X", *p);
log_printf ("\n");
}
rc = prepare_decryption (hexkeygrip, enc_val,
&dfparm);
xfree (enc_val);
if (rc)
log_error ("decrypting session key failed: %s\n",
gnupg_strerror (rc));
else
{ /* setup the bulk decrypter */
ksba_writer_set_filter (writer,
decrypt_filter,
&dfparm);
}
}
}
}
else if (stopreason == KSBA_SR_END_DATA)
{
ksba_writer_set_filter (writer, NULL, NULL);
if (dfparm.any_data)
{ /* write the last block with padding removed */
int i, npadding = dfparm.lastblock[dfparm.blklen-1];
if (!npadding || npadding > dfparm.blklen)
{
log_error ("invalid padding with value %d\n", npadding);
rc = seterr (Invalid_Data);
goto leave;
}
rc = ksba_writer_write (writer,
dfparm.lastblock,
dfparm.blklen - npadding);
if (rc)
{
rc = map_ksba_err (rc);
goto leave;
}
for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
{
if (dfparm.lastblock[i] != npadding)
{
log_error ("inconsistent padding\n");
rc = seterr (Invalid_Data);
goto leave;
}
}
}
}
}
while (stopreason != KSBA_SR_READY);
@ -217,6 +452,8 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
keydb_release (kh);
if (in_fp)
fclose (in_fp);
if (dfparm.hd)
gcry_cipher_close (dfparm.hd);
return rc;
}

View File

@ -167,5 +167,10 @@ int gpgsm_agent_pksign (const char *keygrip,
size_t digestlen,
int digestalgo,
char **r_buf, size_t *r_buflen);
int gpgsm_agent_pkdecrypt (const char *keygrip,
const char *ciphertext, size_t ciphertextlen,
char **r_buf, size_t *r_buflen);
#endif /*GPGSM_H*/