272462d4728be01478d52ecdc49c583e366283c0
[gnupg.git] / g10 / encode.c
1 /* encode.c - encode/sign data
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 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  * G10 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
38
39
40
41 static int encode_simple( const char *filename, int mode );
42 static IOBUF open_outfile( const char *iname );
43
44
45 /****************
46  * Encode FILENAME only with the symmetric cipher. Take input from
47  * stdin if FILENAME is NULL.
48  */
49 int
50 encode_symmetric( const char *filename )
51 {
52     return encode_simple( filename, 1 );
53 }
54
55 /****************
56  * Encode FILENAME as literal data packet only. Take input from
57  * stdin if FILENAME is NULL.
58  */
59 int
60 encode_store( const char *filename )
61 {
62     return encode_simple( filename, 0 );
63 }
64
65 static void
66 write_comment( IOBUF out, const char *s )
67 {
68     PACKET pkt;
69     size_t n = strlen(s);
70     int rc;
71
72     pkt.pkttype = PKT_COMMENT;
73     pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 );
74     pkt.pkt.comment->len = n;
75     strcpy(pkt.pkt.comment->data, s);
76     if( (rc = build_packet( out, &pkt )) )
77         log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) );
78     free_packet( &pkt );
79 }
80
81
82 static int
83 encode_simple( const char *filename, int mode )
84 {
85     IOBUF inp, out;
86     PACKET pkt;
87     PKT_plaintext *pt;
88     int rc = 0;
89     u32 filesize;
90     cipher_filter_context_t cfx;
91     armor_filter_context_t afx;
92     compress_filter_context_t zfx;
93
94     memset( &cfx, 0, sizeof cfx);
95     memset( &afx, 0, sizeof afx);
96     memset( &zfx, 0, sizeof zfx);
97
98     /* prepare iobufs */
99     if( !(inp = iobuf_open(filename)) ) {
100         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
101                                         strerror(errno) );
102         return G10ERR_OPEN_FILE;
103     }
104
105     cfx.dek = NULL;
106     if( mode ) {
107         cfx.dek = m_alloc_secure( sizeof *cfx.dek );
108         cfx.dek->algo = DEFAULT_CIPHER_ALGO;
109         if( (rc = make_dek_from_passphrase( cfx.dek , 2 )) ) {
110             m_free(cfx.dek);
111             iobuf_close(inp);
112             log_error("error creating passphrase: %s\n", g10_errstr(rc) );
113             return rc;
114         }
115     }
116
117     if( !(out = open_outfile( filename )) ) {
118         iobuf_close(inp);
119         m_free(cfx.dek);
120         return G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
121     }
122
123     if( opt.armor )
124         iobuf_push_filter( out, armor_filter, &afx );
125
126     write_comment( out, "#Created by G10 pre-release " VERSION );
127
128     if( opt.compress )
129         iobuf_push_filter( out, compress_filter, &zfx );
130
131
132     /* setup the inner packet */
133     if( filename ) {
134         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
135         pt->namelen = strlen(filename);
136         memcpy(pt->name, filename, pt->namelen );
137         if( !(filesize = iobuf_get_filelength(inp)) )
138             log_info("warning: '%s' is an empty file\n", filename );
139     }
140     else { /* no filename */
141         pt = m_alloc( sizeof *pt - 1 );
142         pt->namelen = 0;
143         filesize = 0; /* stdin */
144     }
145     pt->timestamp = make_timestamp();
146     pt->mode = 'b';
147     pt->len = filesize;
148     pt->buf = inp;
149     pkt.pkttype = PKT_PLAINTEXT;
150     pkt.pkt.plaintext = pt;
151     cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
152
153     /* register the cipher filter */
154     if( mode )
155         iobuf_push_filter( out, cipher_filter, &cfx );
156
157     /* do the work */
158     if( (rc = build_packet( out, &pkt )) )
159         log_error("build_packet failed: %s\n", g10_errstr(rc) );
160
161     /* finish the stuff */
162     iobuf_close(inp);
163     iobuf_close(out); /* fixme: check returncode */
164     pt->buf = NULL;
165     free_packet(&pkt);
166     m_free(cfx.dek);
167     return rc;
168 }
169
170 /****************
171  * Encrypt the file with the given userids (or ask if none
172  * is supplied).
173  */
174 int
175 encode_crypt( const char *filename, STRLIST remusr )
176 {
177     IOBUF inp, out;
178     PACKET pkt;
179     PKT_plaintext *pt;
180     PKT_pubkey_cert *pkc = NULL;
181     PKT_pubkey_enc  *enc = NULL;
182     int last_rc, rc = 0;
183     u32 filesize;
184     cipher_filter_context_t cfx;
185     armor_filter_context_t afx;
186     compress_filter_context_t zfx;
187     int any_names = 0;
188     STRLIST local_remusr = NULL;
189     char *ustr;
190
191     memset( &cfx, 0, sizeof cfx);
192     memset( &afx, 0, sizeof afx);
193     memset( &zfx, 0, sizeof zfx);
194
195     if( !remusr ) {
196         remusr = NULL; /* fixme: ask */
197         local_remusr = remusr;
198     }
199
200     /* prepare iobufs */
201     if( !(inp = iobuf_open(filename)) ) {
202         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
203                                         strerror(errno) );
204         free_strlist(local_remusr);
205         return G10ERR_OPEN_FILE;
206     }
207     else if( opt.verbose )
208         log_error("reding from '%s'\n", filename? filename: "[stdin]");
209
210     if( !(out = open_outfile( filename )) ) {
211         iobuf_close(inp);
212         free_strlist(local_remusr);
213         return G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
214     }
215
216     if( opt.armor )
217         iobuf_push_filter( out, armor_filter, &afx );
218
219     write_comment( out, "#Created by G10 pre-release " VERSION );
220
221     if( opt.compress )
222         iobuf_push_filter( out, compress_filter, &zfx );
223
224     /* create a session key */
225     cfx.dek = m_alloc_secure( sizeof *cfx.dek );
226     cfx.dek->algo = DEFAULT_CIPHER_ALGO;
227     make_session_key( cfx.dek );
228     if( DBG_CIPHER )
229         log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
230
231     /* loop over all user ids and build public key packets for each */
232     for(last_rc=0 ; remusr; remusr = remusr->next ) {
233         if( pkc )
234             free_pubkey_cert( pkc );
235         pkc = m_alloc_clear( sizeof *pkc );
236         pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
237
238         if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) {
239             last_rc = rc;
240             log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
241             continue;
242         }
243         /* build the pubkey packet */
244         enc = m_alloc_clear( sizeof *enc );
245         enc->pubkey_algo = pkc->pubkey_algo;
246         if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
247             RSA_public_key pkey;
248
249             mpi_get_keyid( pkc->d.rsa.rsa_n, enc->keyid );
250             enc->d.rsa.rsa_integer = encode_session_key( cfx.dek,
251                                         mpi_get_nbits(pkc->d.rsa.rsa_n) );
252             pkey.n = pkc->d.rsa.rsa_n;
253             pkey.e = pkc->d.rsa.rsa_e;
254             if( DBG_CIPHER )
255                 log_mpidump("Plain DEK frame: ", enc->d.rsa.rsa_integer);
256             rsa_public( enc->d.rsa.rsa_integer, enc->d.rsa.rsa_integer, &pkey);
257             if( DBG_CIPHER )
258                 log_mpidump("Encry DEK frame: ", enc->d.rsa.rsa_integer);
259             if( opt.verbose ) {
260                 ustr = get_user_id_string( enc->keyid );
261                 log_info("RSA enciphered for: %s\n", ustr );
262                 m_free(ustr);
263             }
264         }
265         else {
266             last_rc = rc = G10ERR_PUBKEY_ALGO;
267             log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
268             free_pubkey_enc(enc);
269             continue;
270         }
271         /* and write it */
272         init_packet(&pkt);
273         pkt.pkttype = PKT_PUBKEY_ENC;
274         pkt.pkt.pubkey_enc = enc;
275         if( (rc = build_packet( out, &pkt )) ) {
276             last_rc = rc;
277             log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) );
278             free_pubkey_enc(enc);
279             continue;
280         }
281         /* okay: a pubkey packet has been written */
282         free_pubkey_enc(enc);
283         any_names = 1;
284     }
285     if( pkc ) {
286         free_pubkey_cert( pkc );
287         pkc = NULL;
288     }
289     if( !any_names ) {
290         log_error("no valid keys - aborting further processing\n");
291         iobuf_close(inp);
292         iobuf_cancel(out);
293         m_free(cfx.dek); /* free and burn the session key */
294         free_strlist(local_remusr);
295         return last_rc;
296     }
297
298     /* setup the inner packet */
299     if( filename ) {
300         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
301         pt->namelen = strlen(filename);
302         memcpy(pt->name, filename, pt->namelen );
303         if( !(filesize = iobuf_get_filelength(inp)) )
304             log_info("warning: '%s' is an empty file\n", filename );
305     }
306     else { /* no filename */
307         pt = m_alloc( sizeof *pt - 1 );
308         pt->namelen = 0;
309         filesize = 0; /* stdin */
310     }
311     pt->timestamp = make_timestamp();
312     pt->mode = 'b';
313     pt->len = filesize;
314     pt->buf = inp;
315     init_packet(&pkt);
316     pkt.pkttype = PKT_PLAINTEXT;
317     pkt.pkt.plaintext = pt;
318     cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
319
320     /* register the cipher filter */
321     iobuf_push_filter( out, cipher_filter, &cfx );
322
323     /* do the work */
324     if( (rc = build_packet( out, &pkt )) )
325         log_error("build_packet failed: %s\n", g10_errstr(rc) );
326
327     /* finish the stuff */
328     iobuf_close(inp);
329     iobuf_close(out); /* fixme: check returncode */
330     pt->buf = NULL;
331     free_packet(&pkt);
332     m_free(cfx.dek);
333     free_strlist(local_remusr);
334     return rc;
335 }
336
337
338 /****************
339  * Make an output filename for the inputfile INAME.
340  * Returns an
341  */
342 static IOBUF
343 open_outfile( const char *iname )
344 {
345     IOBUF a = NULL;
346     int rc;
347
348     if( (!iname && !opt.outfile) || opt.outfile_is_stdout ) {
349         if( !(a = iobuf_create(NULL)) )
350             log_error("can't open [stdout]: %s\n", strerror(errno) );
351         else if( opt.verbose )
352             log_info("writing to stdout\n");
353     }
354     else {
355         char *buf=NULL;
356         const char *name;
357
358         if( opt.outfile )
359             name = opt.outfile;
360         else {
361             buf = m_alloc(strlen(iname)+4+1);
362             strcpy(stpcpy(buf,iname), ".g10");
363             name = buf;
364         }
365         if( !(rc=overwrite_filep( name )) ) {
366             if( !(a = iobuf_create( name )) )
367                 log_error("can't create %s: %s\n", name, strerror(errno) );
368             else if( opt.verbose )
369                 log_info("writing to '%s'\n", name );
370         }
371         else if( rc != -1 )
372             log_error("oops: overwrite_filep(%s): %s\n", name, g10_errstr(rc) );
373         m_free(buf);
374     }
375     return a;
376 }
377
378