mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Decryption does now work
This commit is contained in:
parent
e4a72423ff
commit
ce32f6b6c8
@ -553,8 +553,3 @@ gpgsm_destroy_writer (Base64Context ctx)
|
||||
{
|
||||
xfree (ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
279
sm/decrypt.c
279
sm/decrypt.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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*/
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user