04aebefdb66974859d9b5bf1089172dd41977ccb
[gnupg.git] / g10 / encode.c
1 /* encode.c - encode 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 static int encode_simple( const char *filename, int mode );
40 static int write_pubkey_enc_from_list( PKC_LIST pkc_list, DEK *dek, IOBUF out );
41
42
43
44 /****************
45  * Encode FILENAME only with the symmetric cipher. Take input from
46  * stdin if FILENAME is NULL.
47  */
48 int
49 encode_symmetric( const char *filename )
50 {
51     return encode_simple( filename, 1 );
52 }
53
54 /****************
55  * Encode FILENAME as literal data packet only. Take input from
56  * stdin if FILENAME is NULL.
57  */
58 int
59 encode_store( const char *filename )
60 {
61     return encode_simple( filename, 0 );
62 }
63
64
65 static int
66 encode_simple( const char *filename, int mode )
67 {
68     IOBUF inp, out;
69     PACKET pkt;
70     PKT_plaintext *pt;
71     int rc = 0;
72     u32 filesize;
73     cipher_filter_context_t cfx;
74     armor_filter_context_t afx;
75     compress_filter_context_t zfx;
76
77     memset( &cfx, 0, sizeof cfx);
78     memset( &afx, 0, sizeof afx);
79     memset( &zfx, 0, sizeof zfx);
80
81     /* prepare iobufs */
82     if( !(inp = iobuf_open(filename)) ) {
83         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
84                                         strerror(errno) );
85         return G10ERR_OPEN_FILE;
86     }
87
88     cfx.dek = NULL;
89     if( mode ) {
90         cfx.dek = m_alloc_secure( sizeof *cfx.dek );
91         cfx.dek->algo = opt.def_cipher_algo;
92         if( (rc = make_dek_from_passphrase( cfx.dek , 2 )) ) {
93             m_free(cfx.dek);
94             iobuf_close(inp);
95             log_error("error creating passphrase: %s\n", g10_errstr(rc) );
96             return rc;
97         }
98     }
99
100     if( !(out = open_outfile( filename, opt.armor? 1:0 )) ) {
101         iobuf_close(inp);
102         m_free(cfx.dek);
103         return G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
104     }
105
106     if( opt.armor )
107         iobuf_push_filter( out, armor_filter, &afx );
108
109     write_comment( out, "#Created by G10 pre-release " VERSION );
110
111     if( opt.compress )
112         iobuf_push_filter( out, compress_filter, &zfx );
113
114
115     /* setup the inner packet */
116     if( filename ) {
117         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
118         pt->namelen = strlen(filename);
119         memcpy(pt->name, filename, pt->namelen );
120         if( !(filesize = iobuf_get_filelength(inp)) )
121             log_info("warning: '%s' is an empty file\n", filename );
122     }
123     else { /* no filename */
124         pt = m_alloc( sizeof *pt - 1 );
125         pt->namelen = 0;
126         filesize = 0; /* stdin */
127     }
128     pt->timestamp = make_timestamp();
129     pt->mode = 'b';
130     pt->len = filesize;
131     pt->buf = inp;
132     pkt.pkttype = PKT_PLAINTEXT;
133     pkt.pkt.plaintext = pt;
134     cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
135
136     /* register the cipher filter */
137     if( mode )
138         iobuf_push_filter( out, cipher_filter, &cfx );
139
140     /* do the work */
141     if( (rc = build_packet( out, &pkt )) )
142         log_error("build_packet failed: %s\n", g10_errstr(rc) );
143
144     /* finish the stuff */
145     iobuf_close(inp);
146     iobuf_close(out); /* fixme: check returncode */
147     pt->buf = NULL;
148     free_packet(&pkt);
149     m_free(cfx.dek);
150     return rc;
151 }
152
153 /****************
154  * Encrypt the file with the given userids (or ask if none
155  * is supplied).
156  */
157 int
158 encode_crypt( const char *filename, STRLIST remusr )
159 {
160     IOBUF inp = NULL, out = NULL;
161     PACKET pkt;
162     PKT_plaintext *pt = NULL;
163     int rc = 0;
164     u32 filesize;
165     cipher_filter_context_t cfx;
166     armor_filter_context_t afx;
167     compress_filter_context_t zfx;
168     PKC_LIST pkc_list;
169
170     memset( &cfx, 0, sizeof cfx);
171     memset( &afx, 0, sizeof afx);
172     memset( &zfx, 0, sizeof zfx);
173
174     if( (rc=build_pkc_list( remusr, &pkc_list)) )
175         return rc;
176
177     /* prepare iobufs */
178     if( !(inp = iobuf_open(filename)) ) {
179         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
180                                         strerror(errno) );
181         rc = G10ERR_OPEN_FILE;
182         goto leave;
183     }
184     else if( opt.verbose )
185         log_error("reading from '%s'\n", filename? filename: "[stdin]");
186
187     if( !(out = open_outfile( filename, opt.armor? 1:0 )) ) {
188         rc = G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
189         goto leave;
190     }
191
192     if( opt.armor )
193         iobuf_push_filter( out, armor_filter, &afx );
194
195     write_comment( out, "#Created by G10 pre-release " VERSION );
196
197     if( opt.compress )
198         iobuf_push_filter( out, compress_filter, &zfx );
199
200     /* create a session key */
201     cfx.dek = m_alloc_secure( sizeof *cfx.dek );
202     cfx.dek->algo = opt.def_cipher_algo;
203     make_session_key( cfx.dek );
204     if( DBG_CIPHER )
205         log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
206
207     rc = write_pubkey_enc_from_list( pkc_list, cfx.dek, out );
208     if( rc  )
209         goto leave;
210
211     /* setup the inner packet */
212     if( filename ) {
213         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
214         pt->namelen = strlen(filename);
215         memcpy(pt->name, filename, pt->namelen );
216         if( !(filesize = iobuf_get_filelength(inp)) )
217             log_info("warning: '%s' is an empty file\n", filename );
218     }
219     else { /* no filename */
220         pt = m_alloc( sizeof *pt - 1 );
221         pt->namelen = 0;
222         filesize = 0; /* stdin */
223     }
224     pt->timestamp = make_timestamp();
225     pt->mode = 'b';
226     pt->len = filesize;
227     pt->buf = inp;
228     init_packet(&pkt);
229     pkt.pkttype = PKT_PLAINTEXT;
230     pkt.pkt.plaintext = pt;
231     cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
232
233     /* register the cipher filter */
234     iobuf_push_filter( out, cipher_filter, &cfx );
235
236     /* do the work */
237     if( (rc = build_packet( out, &pkt )) )
238         log_error("build_packet failed: %s\n", g10_errstr(rc) );
239
240     /* finish the stuff */
241   leave:
242     iobuf_close(inp);
243     if( rc )
244         iobuf_cancel(out);
245     else
246         iobuf_close(out); /* fixme: check returncode */
247     if( pt )
248         pt->buf = NULL;
249     free_packet(&pkt);
250     m_free(cfx.dek);
251     release_pkc_list( pkc_list );
252     return rc;
253 }
254
255
256 /****************
257  * Filter to do a complete public key encryption.
258  */
259 int
260 encrypt_filter( void *opaque, int control,
261                IOBUF a, byte *buf, size_t *ret_len)
262 {
263     size_t size = *ret_len;
264     encrypt_filter_context_t *efx = opaque;
265     int rc=0;
266
267     if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
268         BUG(); /* not used */
269     }
270     else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
271         if( !efx->header_okay ) {
272             efx->cfx.dek = m_alloc_secure( sizeof *efx->cfx.dek );
273             efx->cfx.dek->algo = opt.def_cipher_algo;
274             make_session_key( efx->cfx.dek );
275             if( DBG_CIPHER )
276                 log_hexdump("DEK is: ",
277                              efx->cfx.dek->key, efx->cfx.dek->keylen );
278
279             rc = write_pubkey_enc_from_list( efx->pkc_list, efx->cfx.dek, a );
280             if( rc )
281                 return rc;
282
283             iobuf_push_filter( a, cipher_filter, &efx->cfx );
284
285             efx->header_okay = 1;
286         }
287         rc = iobuf_write( a, buf, size );
288
289     }
290     else if( control == IOBUFCTRL_FREE ) {
291     }
292     else if( control == IOBUFCTRL_DESC ) {
293         *(char**)buf = "encrypt_filter";
294     }
295     return rc;
296 }
297
298
299 /****************
300  * Write pubkey-enc packets from the list of PKCs to OUT.
301  */
302 static int
303 write_pubkey_enc_from_list( PKC_LIST pkc_list, DEK *dek, IOBUF out )
304 {
305     PACKET pkt;
306     PKT_public_cert *pkc;
307     PKT_pubkey_enc  *enc;
308     int rc;
309
310     for( ; pkc_list; pkc_list = pkc_list->next ) {
311
312         pkc = pkc_list->pkc;
313         enc = m_alloc_clear( sizeof *enc );
314         enc->pubkey_algo = pkc->pubkey_algo;
315         if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
316             g10_elg_encrypt( pkc, enc, dek );
317         else if( enc->pubkey_algo == PUBKEY_ALGO_RSA )
318             g10_rsa_encrypt( pkc, enc, dek );
319         else
320             BUG();
321         /* and write it */
322         init_packet(&pkt);
323         pkt.pkttype = PKT_PUBKEY_ENC;
324         pkt.pkt.pubkey_enc = enc;
325         rc = build_packet( out, &pkt );
326         free_pubkey_enc(enc);
327         if( rc ) {
328             log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) );
329             return rc;
330         }
331     }
332     return 0;
333 }
334