1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-09-22 15:11:41 +02:00

* g10.c (main): Add --symmetric --encrypt command. This generates a

message that can be decrypted via a passphrase or public key system.

* main.h, encode.c (encode_seskey): Allow passing in an already-created
session key dek. (encode_simple): Use the actual symmetric cipher when
encrypting a session key for a symmetric message. (encode_crypt): Add a
flag to trigger a hybrid mode that can be decrypted via a passphrase or a
pk.  Change all callers.

* mainproc.c (symkey_decrypt_sesskey): There is no way to tell the
difference here between a bad passphrase and a cipher algorithm that we
don't have, so use a error message that makes that clear. Use the actual
list of ciphers when checking whether a cipher is invalid.  Return error
if the decrypted cipher algorithm is invalid. (proc_symkey_enc): In a
mixed passphrase/pk message, if a valid dek already exists from decrypting
via pk, do not try to process the passphrase. (proc_symkey_enc): Indicate
when we're decrypting a session key as opposed to decrypting data.  If a
passphrase is invalid, discard the dek so we'll keep trying.
This commit is contained in:
David Shaw 2003-10-26 03:26:14 +00:00
parent d30da9ebdc
commit bb7986e9a6
5 changed files with 185 additions and 53 deletions

View File

@ -1,3 +1,29 @@
2003-10-25 David Shaw <dshaw@jabberwocky.com>
* g10.c (main): Add --symmetric --encrypt command. This generates
a message that can be decrypted via a passphrase or public key
system.
* main.h, encode.c (encode_seskey): Allow passing in an
already-created session key dek.
(encode_simple): Use the actual symmetric cipher when encrypting a
session key for a symmetric message.
(encode_crypt): Add a flag to trigger a hybrid mode that can be
decrypted via a passphrase or a pk. Change all callers.
* mainproc.c (symkey_decrypt_sesskey): There is no way to tell the
difference here between a bad passphrase and a cipher algorithm
that we don't have, so use a error message that makes that clear.
Use the actual list of ciphers when checking whether a cipher is
invalid. Return error if the decrypted cipher algorithm is
invalid.
(proc_symkey_enc): In a mixed passphrase/pk message, if a valid
dek already exists from decrypting via pk, do not try to process
the passphrase.
(proc_symkey_enc): Indicate when we're decrypting a session key as
opposed to decrypting data. If a passphrase is invalid, discard
the dek so we'll keep trying.
2003-10-25 Werner Koch <wk@gnupg.org> 2003-10-25 Werner Koch <wk@gnupg.org>
* ccid-driver.c (ccid_open_reader): Return an error if no USB * ccid-driver.c (ccid_open_reader): Return an error if no USB

View File

@ -42,8 +42,6 @@
static int encode_simple( const char *filename, int mode, int use_seskey ); static int encode_simple( const char *filename, int mode, int use_seskey );
static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out ); static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out );
/**************** /****************
* Encode FILENAME with only the symmetric cipher. Take input from * Encode FILENAME with only the symmetric cipher. Take input from
* stdin if FILENAME is NULL. * stdin if FILENAME is NULL.
@ -65,32 +63,32 @@ encode_store( const char *filename )
} }
static void static void
encode_sesskey( DEK *dek, DEK **ret_dek, byte *enckey ) encode_seskey( DEK *dek, DEK **seskey, byte *enckey )
{ {
CIPHER_HANDLE hd; CIPHER_HANDLE hd;
DEK *c;
byte buf[33]; byte buf[33];
assert ( dek->keylen <= 32 ); assert ( dek->keylen <= 32 );
if(!*seskey)
c = m_alloc_clear( sizeof *c ); {
c->keylen = dek->keylen; *seskey=m_alloc_clear(sizeof(DEK));
c->algo = dek->algo; (*seskey)->keylen=dek->keylen;
make_session_key( c ); (*seskey)->algo=dek->algo;
/*log_hexdump( "thekey", c->key, c->keylen );*/ make_session_key(*seskey);
/*log_hexdump( "thekey", c->key, c->keylen );*/
}
buf[0] = c->algo; buf[0] = (*seskey)->algo;
memcpy( buf + 1, c->key, c->keylen ); memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );
hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 ); hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
cipher_setkey( hd, dek->key, dek->keylen ); cipher_setkey( hd, dek->key, dek->keylen );
cipher_setiv( hd, NULL, 0 ); cipher_setiv( hd, NULL, 0 );
cipher_encrypt( hd, buf, buf, c->keylen + 1 ); cipher_encrypt( hd, buf, buf, (*seskey)->keylen + 1 );
cipher_close( hd ); cipher_close( hd );
memcpy( enckey, buf, c->keylen + 1 ); memcpy( enckey, buf, (*seskey)->keylen + 1 );
wipememory( buf, sizeof buf ); /* burn key */ wipememory( buf, sizeof buf ); /* burn key */
*ret_dek = c;
} }
/* We try very hard to use a MDC */ /* We try very hard to use a MDC */
@ -152,7 +150,6 @@ encode_simple( const char *filename, int mode, int use_seskey )
{ {
IOBUF inp, out; IOBUF inp, out;
PACKET pkt; PACKET pkt;
DEK *dek = NULL;
PKT_plaintext *pt = NULL; PKT_plaintext *pt = NULL;
STRING2KEY *s2k = NULL; STRING2KEY *s2k = NULL;
byte enckey[33]; byte enckey[33];
@ -212,11 +209,13 @@ encode_simple( const char *filename, int mode, int use_seskey )
"due to the S2K mode\n")); "due to the S2K mode\n"));
} }
if ( use_seskey ) { if ( use_seskey )
seskeylen = cipher_get_keylen( opt.s2k_cipher_algo ) / 8; {
encode_sesskey( cfx.dek, &dek, enckey ); DEK *dek = NULL;
seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8;
encode_seskey( cfx.dek, &dek, enckey );
m_free( cfx.dek ); cfx.dek = dek; m_free( cfx.dek ); cfx.dek = dek;
} }
cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo); cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
} }
@ -378,11 +377,13 @@ encode_simple( const char *filename, int mode, int use_seskey )
* is supplied). * is supplied).
*/ */
int int
encode_crypt( const char *filename, STRLIST remusr ) encode_crypt( const char *filename, STRLIST remusr, int use_symkey )
{ {
IOBUF inp = NULL, out = NULL; IOBUF inp = NULL, out = NULL;
PACKET pkt; PACKET pkt;
PKT_plaintext *pt = NULL; PKT_plaintext *pt = NULL;
DEK *symkey_dek = NULL;
STRING2KEY *symkey_s2k = NULL;
int rc = 0, rc2 = 0; int rc = 0, rc2 = 0;
u32 filesize; u32 filesize;
cipher_filter_context_t cfx; cipher_filter_context_t cfx;
@ -393,7 +394,6 @@ encode_crypt( const char *filename, STRLIST remusr )
PK_LIST pk_list,work_list; PK_LIST pk_list,work_list;
int do_compress = opt.compress && !RFC1991; int do_compress = opt.compress && !RFC1991;
memset( &cfx, 0, sizeof cfx); memset( &cfx, 0, sizeof cfx);
memset( &afx, 0, sizeof afx); memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx); memset( &zfx, 0, sizeof zfx);
@ -403,6 +403,22 @@ encode_crypt( const char *filename, STRLIST remusr )
if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) ) if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
return rc; return rc;
if(use_symkey)
{
symkey_s2k=m_alloc_clear(sizeof(STRING2KEY));
symkey_s2k->mode = opt.s2k_mode;
symkey_s2k->hash_algo = opt.s2k_digest_algo;
symkey_dek=passphrase_to_dek(NULL,0,opt.s2k_cipher_algo,
symkey_s2k,2,NULL,NULL);
if(!symkey_dek || !symkey_dek->keylen)
{
m_free(symkey_dek);
m_free(symkey_s2k);
return G10ERR_PASSPHRASE;
}
}
if(PGP2) { if(PGP2) {
for(work_list=pk_list; work_list; work_list=work_list->next) for(work_list=pk_list; work_list; work_list=work_list->next)
if(!(is_RSA(work_list->pk->pubkey_algo) && if(!(is_RSA(work_list->pk->pubkey_algo) &&
@ -505,6 +521,37 @@ encode_crypt( const char *filename, STRLIST remusr )
if( rc ) if( rc )
goto leave; goto leave;
/* 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
point in prompting a user for a passphrase if they have the
secret key needed to decrypt. */
if(use_symkey)
{
int seskeylen=cipher_get_keylen(cfx.dek->algo)/8;
PKT_symkey_enc *enc;
byte enckey[33];
enc=m_alloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1);
encode_seskey(symkey_dek,&cfx.dek,enckey);
enc->version = 4;
enc->cipher_algo = opt.s2k_cipher_algo;
enc->s2k = *symkey_s2k;
enc->seskeylen = seskeylen + 1; /* algo id */
memcpy( enc->seskey, enckey, seskeylen + 1 );
pkt.pkttype = PKT_SYMKEY_ENC;
pkt.pkt.symkey_enc = enc;
if( (rc = build_packet( out, &pkt )) )
{
log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
m_free(enc);
goto leave;
}
m_free(enc);
}
if (!opt.no_literal) { if (!opt.no_literal) {
/* setup the inner packet */ /* setup the inner packet */
if( filename || opt.set_filename ) { if( filename || opt.set_filename ) {
@ -618,6 +665,8 @@ encode_crypt( const char *filename, STRLIST remusr )
pt->buf = NULL; pt->buf = NULL;
free_packet(&pkt); free_packet(&pkt);
m_free(cfx.dek); m_free(cfx.dek);
m_free(symkey_dek);
m_free(symkey_s2k);
release_pk_list( pk_list ); release_pk_list( pk_list );
return rc; return rc;
} }
@ -788,7 +837,7 @@ encode_crypt_files(int nfiles, char **files, STRLIST remusr)
} }
line[strlen(line)-1] = '\0'; line[strlen(line)-1] = '\0';
print_file_status(STATUS_FILE_START, line, 2); print_file_status(STATUS_FILE_START, line, 2);
if ( (rc = encode_crypt(line, remusr)) ) if ( (rc = encode_crypt(line, remusr, 0)) )
log_error("%s: encryption failed: %s\n", log_error("%s: encryption failed: %s\n",
print_fname_stdin(line), g10_errstr(rc) ); print_fname_stdin(line), g10_errstr(rc) );
write_status( STATUS_FILE_DONE ); write_status( STATUS_FILE_DONE );
@ -799,7 +848,7 @@ encode_crypt_files(int nfiles, char **files, STRLIST remusr)
while (nfiles--) while (nfiles--)
{ {
print_file_status(STATUS_FILE_START, *files, 2); print_file_status(STATUS_FILE_START, *files, 2);
if ( (rc = encode_crypt(*files, remusr)) ) if ( (rc = encode_crypt(*files, remusr, 0)) )
log_error("%s: encryption failed: %s\n", log_error("%s: encryption failed: %s\n",
print_fname_stdin(*files), g10_errstr(rc) ); print_fname_stdin(*files), g10_errstr(rc) );
write_status( STATUS_FILE_DONE ); write_status( STATUS_FILE_DONE );

View File

@ -80,7 +80,8 @@ enum cmd_and_opt_values
oShowNotation, oShowNotation,
oNoShowNotation, oNoShowNotation,
aEncrFiles, aEncrFiles,
aDecryptFiles, aEncrSym,
aDecryptFiles,
aClearsign, aClearsign,
aStore, aStore,
aKeygen, aKeygen,
@ -866,6 +867,10 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
cmd = aSignSym; cmd = aSignSym;
else if( cmd == aSym && new_cmd == aSign ) else if( cmd == aSym && new_cmd == aSign )
cmd = aSignSym; cmd = aSignSym;
else if( cmd == aSym && new_cmd == aEncr )
cmd = aEncrSym;
else if( cmd == aEncr && new_cmd == aSym )
cmd = aEncrSym;
else if( cmd == aKMode && new_cmd == aSym ) else if( cmd == aKMode && new_cmd == aSym )
cmd = aKModeC; cmd = aKModeC;
else if( ( cmd == aSign && new_cmd == aClearsign ) else if( ( cmd == aSign && new_cmd == aClearsign )
@ -2255,6 +2260,9 @@ main( int argc, char **argv )
case aSym: case aSym:
cmdname="--symmetric"; cmdname="--symmetric";
break; break;
case aEncrSym:
cmdname="--symmetric --encrypt";
break;
case aStore: case aStore:
cmdname="--store"; cmdname="--store";
break; break;
@ -2450,12 +2458,32 @@ main( int argc, char **argv )
{ {
if( argc > 1 ) if( argc > 1 )
wrong_args(_("--encrypt [filename]")); wrong_args(_("--encrypt [filename]"));
if( (rc = encode_crypt(fname,remusr)) ) if( (rc = encode_crypt(fname,remusr,0)) )
log_error("%s: encryption failed: %s\n", log_error("%s: encryption failed: %s\n",
print_fname_stdin(fname), g10_errstr(rc) ); print_fname_stdin(fname), g10_errstr(rc) );
} }
break; break;
case aEncrSym:
/* This works with PGP 8. It doesn't work with 2 or 6. It
might work with 7, but alas, I don't have a copy to test
with right now. */
if( argc > 1 )
wrong_args(_("--symmetric --encrypt [filename]"));
else if(opt.s2k_mode==0)
log_error(_("you cannot use --symmetric --encrypt"
" with --s2k-mode 0\n"));
else if(PGP2 || PGP6 || PGP7 || RFC1991)
log_error(_("you cannot use --symmetric --encrypt"
" while in %s mode\n"),compliance_option_string());
else
{
if( (rc = encode_crypt(fname,remusr,1)) )
log_error("%s: encryption failed: %s\n",
print_fname_stdin(fname), g10_errstr(rc) );
}
break;
case aSign: /* sign the given file */ case aSign: /* sign the given file */
sl = NULL; sl = NULL;
if( detached_sig ) { /* sign all files */ if( detached_sig ) { /* sign all files */

View File

@ -112,7 +112,7 @@ void display_online_help( const char *keyword );
/*-- encode.c --*/ /*-- encode.c --*/
int encode_symmetric( const char *filename ); int encode_symmetric( const char *filename );
int encode_store( const char *filename ); int encode_store( const char *filename );
int encode_crypt( const char *filename, STRLIST remusr ); int encode_crypt( const char *filename, STRLIST remusr, int use_symkey );
void encode_crypt_files(int nfiles, char **files, STRLIST remusr); void encode_crypt_files(int nfiles, char **files, STRLIST remusr);
int encrypt_filter( void *opaque, int control, int encrypt_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len); IOBUF a, byte *buf, size_t *ret_len);

View File

@ -1,5 +1,6 @@
/* mainproc.c - handle packets /* mainproc.c - handle packets
* Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc. * Copyright (C) 1998, 1999, 2000, 2001, 2002,
* 2003 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -238,8 +239,8 @@ add_signature( CTX c, PACKET *pkt )
return 1; return 1;
} }
static void static int
symkey_decrypt_sesskey( DEK *dek, byte *sesskey, size_t slen ) symkey_decrypt_seskey( DEK *dek, byte *seskey, size_t slen )
{ {
CIPHER_HANDLE hd; CIPHER_HANDLE hd;
int n; int n;
@ -247,28 +248,35 @@ symkey_decrypt_sesskey( DEK *dek, byte *sesskey, size_t slen )
if ( slen < 17 || slen > 33 ) { if ( 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; return G10ERR_BAD_KEY;
} }
hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 ); hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
cipher_setkey( hd, dek->key, dek->keylen ); cipher_setkey( hd, dek->key, dek->keylen );
cipher_setiv( hd, NULL, 0 ); cipher_setiv( hd, NULL, 0 );
cipher_decrypt( hd, sesskey, sesskey, slen ); cipher_decrypt( hd, seskey, seskey, slen );
cipher_close( hd ); cipher_close( hd );
/* check first byte (the cipher algo) */ /* check first byte (the cipher algo) */
if ( sesskey[0] > 10 ) { if(check_cipher_algo(seskey[0]))
log_error ( _("invalid symkey algorithm detected (%d)\n"), {
sesskey[0] ); /* There is no way to tell the difference here between a bad
return; passphrase and a cipher algorithm that we don't have. */
} log_error(_("bad passphrase or unknown cipher algorithm (%d)\n"),
n = cipher_get_keylen (sesskey[0]) / 8; seskey[0]);
if(seskey[0]==CIPHER_ALGO_IDEA)
idea_cipher_warn(0);
return G10ERR_PASSPHRASE;
}
n = cipher_get_keylen (seskey[0]) / 8;
if (n > DIM(dek->key)) if (n > DIM(dek->key))
BUG (); BUG ();
/* now we replace the dek components with the real session key /* now we replace the dek components with the real session key
to decrypt the contents of the sequencing packet. */ to decrypt the contents of the sequencing packet. */
dek->keylen = cipher_get_keylen( sesskey[0] ) / 8; dek->keylen = cipher_get_keylen( seskey[0] ) / 8;
dek->algo = sesskey[0]; dek->algo = seskey[0];
memcpy( dek->key, sesskey + 1, dek->keylen ); memcpy( dek->key, seskey + 1, dek->keylen );
/*log_hexdump( "thekey", dek->key, dek->keylen );*/ /*log_hexdump( "thekey", dek->key, dek->keylen );*/
return 0;
} }
static void static void
@ -279,26 +287,47 @@ proc_symkey_enc( CTX c, PACKET *pkt )
enc = pkt->pkt.symkey_enc; enc = pkt->pkt.symkey_enc;
if (!enc) if (!enc)
log_error ("invalid symkey encrypted packet\n"); log_error ("invalid symkey encrypted packet\n");
else { else if(!c->dek)
{
int algo = enc->cipher_algo; int algo = enc->cipher_algo;
const char *s; const char *s = cipher_algo_to_string (algo);
s = cipher_algo_to_string (algo);
if( s ) if( s )
log_info(_("%s encrypted data\n"), s ); {
if(enc->seskeylen)
log_info(_("%s encrypted session key\n"), s );
else
log_info(_("%s encrypted data\n"), s );
}
else else
log_info(_("encrypted with unknown algorithm %d\n"), algo ); log_info(_("encrypted with unknown algorithm %d\n"), algo );
c->last_was_session_key = 2; c->last_was_session_key = 2;
if ( opt.list_only ) if ( opt.list_only )
goto leave; goto leave;
c->dek = passphrase_to_dek( NULL, 0, algo, &enc->s2k, 0, NULL, NULL ); c->dek = passphrase_to_dek( NULL, 0, algo, &enc->s2k, 0, NULL, NULL );
if (c->dek) if(c->dek)
c->dek->algo_info_printed = 1; {
if ( c->dek && enc->seskeylen ) /* FIXME: This doesn't work perfectly if a symmetric key
symkey_decrypt_sesskey( c->dek, enc->seskey, enc->seskeylen ); comes before a public key in the message - if the user
} doesn't know the passphrase, then there is a chance
leave: that the "decrypted" algorithm will happen to be a
valid one, which will make the returned dek appear
valid, so we won't try any public keys that come
later. */
if(enc->seskeylen)
{
if(symkey_decrypt_seskey(c->dek, enc->seskey, enc->seskeylen))
{
m_free(c->dek);
c->dek=NULL;
}
}
else
c->dek->algo_info_printed = 1;
}
}
leave:
free_packet(pkt); free_packet(pkt);
} }