See ChangeLog: Sat May 8 19:28:33 CEST 1999 Werner Koch
[gnupg.git] / g10 / encode.c
1 /* encode.c - encode data
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "options.h"
29 #include "packet.h"
30 #include "errors.h"
31 #include "iobuf.h"
32 #include "keydb.h"
33 #include "memory.h"
34 #include "util.h"
35 #include "main.h"
36 #include "filter.h"
37 #include "trustdb.h"
38 #include "i18n.h"
39
40
41 static int encode_simple( const char *filename, int mode );
42 static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out );
43
44
45
46 /****************
47  * Encode FILENAME with only the symmetric cipher.  Take input from
48  * stdin if FILENAME is NULL.
49  */
50 int
51 encode_symmetric( const char *filename )
52 {
53     return encode_simple( filename, 1 );
54 }
55
56 /****************
57  * Encode FILENAME as a literal data packet only. Take input from
58  * stdin if FILENAME is NULL.
59  */
60 int
61 encode_store( const char *filename )
62 {
63     return encode_simple( filename, 0 );
64 }
65
66
67 static int
68 encode_simple( const char *filename, int mode )
69 {
70     IOBUF inp, out;
71     PACKET pkt;
72     PKT_plaintext *pt;
73     STRING2KEY *s2k = NULL;
74     int rc = 0;
75     u32 filesize;
76     cipher_filter_context_t cfx;
77     armor_filter_context_t afx;
78     compress_filter_context_t zfx;
79     text_filter_context_t tfx;
80     int do_compress = opt.compress && !opt.rfc1991;
81
82     memset( &cfx, 0, sizeof cfx);
83     memset( &afx, 0, sizeof afx);
84     memset( &zfx, 0, sizeof zfx);
85     memset( &tfx, 0, sizeof tfx);
86     init_packet(&pkt);
87
88     /* prepare iobufs */
89     if( !(inp = iobuf_open(filename)) ) {
90         log_error(_("%s: can't open: %s\n"), filename? filename: "[stdin]",
91                                         strerror(errno) );
92         return G10ERR_OPEN_FILE;
93     }
94
95     if( opt.textmode )
96         iobuf_push_filter( inp, text_filter, &tfx );
97
98     cfx.dek = NULL;
99     if( mode ) {
100         s2k = m_alloc_clear( sizeof *s2k );
101         s2k->mode = opt.rfc1991? 0:opt.s2k_mode;
102         s2k->hash_algo = opt.def_digest_algo ? opt.def_digest_algo
103                                              : opt.s2k_digest_algo;
104         cfx.dek = passphrase_to_dek( NULL,
105                        opt.def_cipher_algo ? opt.def_cipher_algo
106                                            : opt.s2k_cipher_algo , s2k, 2 );
107         if( !cfx.dek || !cfx.dek->keylen ) {
108             rc = G10ERR_PASSPHRASE;
109             m_free(cfx.dek);
110             m_free(s2k);
111             iobuf_close(inp);
112             log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
113             return rc;
114         }
115     }
116
117     if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
118         iobuf_close(inp);
119         m_free(cfx.dek);
120         m_free(s2k);
121         return rc;
122     }
123
124     if( opt.armor )
125         iobuf_push_filter( out, armor_filter, &afx );
126   #ifdef ENABLE_COMMENT_PACKETS
127     else {
128         write_comment( out, "#created by GNUPG v" VERSION " ("
129                                             PRINTABLE_OS_NAME ")");
130         if( opt.comment_string )
131             write_comment( out, opt.comment_string );
132     }
133   #endif
134     if( s2k && !opt.rfc1991 ) {
135         PKT_symkey_enc *enc = m_alloc_clear( sizeof *enc );
136         enc->version = 4;
137         enc->cipher_algo = cfx.dek->algo;
138         enc->s2k = *s2k;
139         pkt.pkttype = PKT_SYMKEY_ENC;
140         pkt.pkt.symkey_enc = enc;
141         if( (rc = build_packet( out, &pkt )) )
142             log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
143         m_free(enc);
144     }
145
146     /* setup the inner packet */
147     if( filename || opt.set_filename ) {
148         char *s = make_basename( opt.set_filename ? opt.set_filename : filename );
149         pt = m_alloc( sizeof *pt + strlen(s) - 1 );
150         pt->namelen = strlen(s);
151         memcpy(pt->name, s, pt->namelen );
152         m_free(s);
153     }
154     else { /* no filename */
155         pt = m_alloc( sizeof *pt - 1 );
156         pt->namelen = 0;
157     }
158     /* pgp5 has problems to decrypt symmetrically encrypted data from
159      * GnuPG if the filelength is in the inner packet.  It works
160      * when only partial length headers are use.  Until we have
161      * tracked this problem down. We use this temporary fix
162      * (fixme: remove the && !mode )
163      */
164     if( filename && !opt.textmode && !mode ) {
165         if( !(filesize = iobuf_get_filelength(inp)) )
166             log_info(_("%s: WARNING: empty file\n"), filename );
167     }
168     else
169         filesize = 0; /* stdin */
170     pt->timestamp = make_timestamp();
171     pt->mode = opt.textmode? 't' : 'b';
172     pt->len = filesize;
173     pt->buf = inp;
174     pkt.pkttype = PKT_PLAINTEXT;
175     pkt.pkt.plaintext = pt;
176     cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
177
178     /* register the cipher filter */
179     if( mode )
180         iobuf_push_filter( out, cipher_filter, &cfx );
181     /* register the compress filter */
182     if( do_compress )
183         iobuf_push_filter( out, compress_filter, &zfx );
184
185     /* do the work */
186     if( (rc = build_packet( out, &pkt )) )
187         log_error("build_packet failed: %s\n", g10_errstr(rc) );
188
189     /* finish the stuff */
190     iobuf_close(inp);
191     iobuf_close(out); /* fixme: check returncode */
192     pt->buf = NULL;
193     free_packet(&pkt);
194     m_free(cfx.dek);
195     m_free(s2k);
196     return rc;
197 }
198
199 /****************
200  * Encrypt the file with the given userids (or ask if none
201  * is supplied).
202  */
203 int
204 encode_crypt( const char *filename, STRLIST remusr )
205 {
206     IOBUF inp = NULL, out = NULL;
207     PACKET pkt;
208     PKT_plaintext *pt = NULL;
209     int rc = 0;
210     u32 filesize;
211     cipher_filter_context_t cfx;
212     armor_filter_context_t afx;
213     compress_filter_context_t zfx;
214     text_filter_context_t tfx;
215     PK_LIST pk_list;
216     int do_compress = opt.compress && !opt.rfc1991;
217
218
219     memset( &cfx, 0, sizeof cfx);
220     memset( &afx, 0, sizeof afx);
221     memset( &zfx, 0, sizeof zfx);
222     memset( &tfx, 0, sizeof tfx);
223     init_packet(&pkt);
224
225     if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
226         return rc;
227
228     /* prepare iobufs */
229     if( !(inp = iobuf_open(filename)) ) {
230         log_error(_("can't open %s: %s\n"), filename? filename: "[stdin]",
231                                         strerror(errno) );
232         rc = G10ERR_OPEN_FILE;
233         goto leave;
234     }
235     else if( opt.verbose )
236         log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");
237
238     if( opt.textmode )
239         iobuf_push_filter( inp, text_filter, &tfx );
240
241     if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
242         goto leave;
243
244
245     if( opt.armor )
246         iobuf_push_filter( out, armor_filter, &afx );
247   #ifdef ENABLE_COMMENT_PACKETS
248     else {
249         write_comment( out, "#created by GNUPG v" VERSION " ("
250                                             PRINTABLE_OS_NAME ")");
251         if( opt.comment_string )
252             write_comment( out, opt.comment_string );
253     }
254   #endif
255     /* create a session key */
256     cfx.dek = m_alloc_secure( sizeof *cfx.dek );
257     if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
258         cfx.dek->algo = select_algo_from_prefs( pk_list, PREFTYPE_SYM );
259         if( cfx.dek->algo == -1 )
260             cfx.dek->algo = DEFAULT_CIPHER_ALGO;
261     }
262     else
263         cfx.dek->algo = opt.def_cipher_algo;
264     make_session_key( cfx.dek );
265     if( DBG_CIPHER )
266         log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
267
268     rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out );
269     if( rc  )
270         goto leave;
271
272     /* setup the inner packet */
273     if( filename || opt.set_filename ) {
274         char *s = make_basename( opt.set_filename ? opt.set_filename : filename );
275         pt = m_alloc( sizeof *pt + strlen(s) - 1 );
276         pt->namelen = strlen(s);
277         memcpy(pt->name, s, pt->namelen );
278         m_free(s);
279     }
280     else { /* no filename */
281         pt = m_alloc( sizeof *pt - 1 );
282         pt->namelen = 0;
283     }
284     if( filename && !opt.textmode ) {
285         if( !(filesize = iobuf_get_filelength(inp)) )
286             log_info(_("%s: WARNING: empty file\n"), filename );
287     }
288     else
289         filesize = 0; /* stdin */
290     pt->timestamp = make_timestamp();
291     pt->mode = opt.textmode ? 't' : 'b';
292     pt->len = filesize;
293     pt->new_ctb = !pt->len && !opt.rfc1991;
294     pt->buf = inp;
295     pkt.pkttype = PKT_PLAINTEXT;
296     pkt.pkt.plaintext = pt;
297     cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
298
299     /* register the cipher filter */
300     iobuf_push_filter( out, cipher_filter, &cfx );
301     /* register the compress filter */
302     if( do_compress ) {
303         int compr_algo = select_algo_from_prefs( pk_list, PREFTYPE_COMPR );
304         if( !compr_algo )
305             ; /* don't use compression */
306         else {
307             if( compr_algo == 1 )
308                 zfx.algo = 1; /* default is 2 */
309             iobuf_push_filter( out, compress_filter, &zfx );
310         }
311     }
312
313     /* do the work */
314     if( (rc = build_packet( out, &pkt )) )
315         log_error("build_packet failed: %s\n", g10_errstr(rc) );
316
317     /* finish the stuff */
318   leave:
319     iobuf_close(inp);
320     if( rc )
321         iobuf_cancel(out);
322     else
323         iobuf_close(out); /* fixme: check returncode */
324     if( pt )
325         pt->buf = NULL;
326     free_packet(&pkt);
327     m_free(cfx.dek);
328     release_pk_list( pk_list );
329     return rc;
330 }
331
332
333
334
335 /****************
336  * Filter to do a complete public key encryption.
337  */
338 int
339 encrypt_filter( void *opaque, int control,
340                IOBUF a, byte *buf, size_t *ret_len)
341 {
342     size_t size = *ret_len;
343     encrypt_filter_context_t *efx = opaque;
344     int rc=0;
345
346     if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
347         BUG(); /* not used */
348     }
349     else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
350         if( !efx->header_okay ) {
351             efx->cfx.dek = m_alloc_secure( sizeof *efx->cfx.dek );
352
353             if( !opt.def_cipher_algo  ) { /* try to get it from the prefs */
354                 efx->cfx.dek->algo =
355                           select_algo_from_prefs( efx->pk_list, PREFTYPE_SYM );
356                 if( efx->cfx.dek->algo == -1 )
357                     efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
358             }
359             else
360                 efx->cfx.dek->algo = opt.def_cipher_algo;
361             make_session_key( efx->cfx.dek );
362             if( DBG_CIPHER )
363                 log_hexdump("DEK is: ",
364                              efx->cfx.dek->key, efx->cfx.dek->keylen );
365
366             rc = write_pubkey_enc_from_list( efx->pk_list, efx->cfx.dek, a );
367             if( rc )
368                 return rc;
369
370             iobuf_push_filter( a, cipher_filter, &efx->cfx );
371
372             efx->header_okay = 1;
373         }
374         rc = iobuf_write( a, buf, size );
375
376     }
377     else if( control == IOBUFCTRL_FREE ) {
378     }
379     else if( control == IOBUFCTRL_DESC ) {
380         *(char**)buf = "encrypt_filter";
381     }
382     return rc;
383 }
384
385
386 /****************
387  * Write pubkey-enc packets from the list of PKs to OUT.
388  */
389 static int
390 write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
391 {
392     PACKET pkt;
393     PKT_public_key *pk;
394     PKT_pubkey_enc  *enc;
395     int rc;
396
397     for( ; pk_list; pk_list = pk_list->next ) {
398         MPI frame;
399
400         pk = pk_list->pk;
401
402         print_pubkey_algo_note( pk->pubkey_algo );
403         enc = m_alloc_clear( sizeof *enc );
404         enc->pubkey_algo = pk->pubkey_algo;
405         keyid_from_pk( pk, enc->keyid );
406         enc->throw_keyid = opt.throw_keyid;
407         frame = encode_session_key( dek, pubkey_nbits( pk->pubkey_algo,
408                                                           pk->pkey ) );
409         rc = pubkey_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey );
410         mpi_free( frame );
411         if( rc )
412             log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) );
413         else {
414             if( opt.verbose ) {
415                 char *ustr = get_user_id_string( enc->keyid );
416                 log_info(_("%s/%s encrypted for: %s\n"),
417                     pubkey_algo_to_string(enc->pubkey_algo),
418                     cipher_algo_to_string(dek->algo), ustr );
419                 m_free(ustr);
420             }
421             /* and write it */
422             init_packet(&pkt);
423             pkt.pkttype = PKT_PUBKEY_ENC;
424             pkt.pkt.pubkey_enc = enc;
425             rc = build_packet( out, &pkt );
426             if( rc )
427                log_error("build_packet(pubkey_enc) failed: %s\n", g10_errstr(rc));
428         }
429         free_pubkey_enc(enc);
430         if( rc )
431             return rc;
432     }
433     return 0;
434 }
435