/[winpt]/trunk/MyGPGME/encrypt.c
ViewVC logotype

Annotation of /trunk/MyGPGME/encrypt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 15663 byte(s)
WinPT initial checkin.


1 twoaday 2 /* encrypt.c - Encrypt functions
2     * Copyright (C) 2000, 2001 Werner Koch (dd9jn), g10 Code GmbH
3     * Copyright (C) 2002-2005 Timo Schulz
4     *
5     * This file is part of MyGPGME.
6     *
7     * MyGPGME is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * MyGPGME is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software Foundation,
19     * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20     */
21    
22     #include <stdio.h>
23     #include <stdlib.h>
24     #include <string.h>
25     #include <assert.h>
26    
27     #include "util.h"
28     #include "context.h"
29     #include "ops.h"
30    
31    
32     #define use_symmetric(rset) (!(rset) || !gpgme_recipients_count ((rset)))
33    
34     struct recp_info_s {
35     struct recp_info_s * next;
36     gpgme_error_t code;
37     char recp[1];
38     };
39    
40     struct encrypt_result_s {
41     int okay;
42     int no_recp;
43     int inv_recp;
44     int file_start;
45     int file_done;
46     struct recp_info_s * inf;
47     };
48    
49    
50     static gpgme_error_t
51     create_result_struct( gpgme_ctx_t ctx )
52     {
53     assert ( !ctx->result.encrypt );
54     ctx->result.encrypt = calloc( 1, sizeof *ctx->result.encrypt );
55     if( !ctx->result.encrypt )
56     return mk_error( Out_Of_Core );
57     ctx->result_type = RESULT_TYPE_ENCRYPT;
58     return 0;
59     } /* create_result_struct */
60    
61    
62     static gpgme_error_t
63     add_recp_info( _encrypt_result_t res, int code, const char * name )
64     {
65     struct recp_info_s * r;
66    
67     r = calloc( 1, sizeof * r + strlen( name ) + 1 );
68     if( !r )
69     return mk_error( Out_Of_Core );
70     r->code = code;
71     strcpy (r->recp , name);
72     r->next = res->inf;
73     res->inf = r;
74    
75     return 0;
76     } /* add_recp_info */
77    
78    
79     void
80     _gpgme_release_encrypt_result( _encrypt_result_t res )
81     {
82     struct recp_info_s * r, * r2;
83    
84     if( !res )
85     return;
86     r = res->inf;
87     while( r ) {
88     r2 = r->next;
89     safe_free( r );
90     r = r2;
91     }
92     safe_free( res->inf );
93     safe_free( res );
94     } /* _gpgme_release_encrypt_result */
95    
96    
97     void
98     _gpgme_encrypt_add_cipher (gpgme_ctx_t ctx)
99     {
100     if (ctx->cipher_algo == -1)
101     return;
102     _gpgme_gpg_add_arg (ctx->gpg, "--cipher-algo");
103     switch (ctx->cipher_algo) {
104     case GPGME_CIPHER_3DES: _gpgme_gpg_add_arg (ctx->gpg, "3DES");break;
105     case GPGME_CIPHER_CAST5: _gpgme_gpg_add_arg (ctx->gpg, "CAST5");break;
106     case GPGME_CIPHER_BLOWFISH: _gpgme_gpg_add_arg (ctx->gpg, "BLOWFISH");break;
107     case GPGME_CIPHER_AES128: _gpgme_gpg_add_arg (ctx->gpg, "AES");break;
108     case GPGME_CIPHER_AES192: _gpgme_gpg_add_arg (ctx->gpg, "AES192");break;
109     case GPGME_CIPHER_AES256: _gpgme_gpg_add_arg (ctx->gpg, "AES256");break;
110     case GPGME_CIPHER_TWOFISH: _gpgme_gpg_add_arg (ctx->gpg, "TWOFISH");break;
111     default: _gpgme_gpg_add_arg (ctx->gpg, "AES");break;
112     }
113     if (ctx->s2k.used) {
114     char buf[32];
115     if (ctx->s2k.mode < 0 || ctx->s2k.mode > 3)
116     ctx->s2k.mode = GPGME_S2K_ITERSALTED;
117     sprintf( buf, "%d", ctx->s2k.mode );
118     _gpgme_gpg_add_arg (ctx->gpg, "--s2k-mode");
119     _gpgme_gpg_add_arg (ctx->gpg, buf);
120     _gpgme_gpg_add_arg (ctx->gpg, "--s2k-digest-algo");
121     switch (ctx->s2k.digest_algo) {
122     case GPGME_MD_SHA1: _gpgme_gpg_add_arg (ctx->gpg, "SHA1"); break;
123     case GPGME_MD_RMD160:_gpgme_gpg_add_arg (ctx->gpg, "RIPEMD160"); break;
124     default: _gpgme_gpg_add_arg (ctx->gpg, "SHA1"); break;
125     }
126     }
127     } /* _gpgme_encrypt_add_cipher */
128    
129    
130     static void
131     encrypt_status_handler( gpgme_ctx_t ctx, gpg_statcode_t code, char * args )
132     {
133     int i = 0;
134     gpgme_error_t err;
135    
136     if( ctx->out_of_core )
137     return;
138    
139     if( ctx->result_type == RESULT_TYPE_NONE ) {
140     if( create_result_struct ( ctx ) ) {
141     ctx->out_of_core = 1;
142     return;
143     }
144     }
145     assert( ctx->result_type == RESULT_TYPE_ENCRYPT );
146    
147     switch( code ) {
148     case STATUS_END_ENCRYPTION:
149     ctx->result.encrypt->okay = 1;
150     break;
151    
152     case STATUS_NO_RECP:
153     ctx->result.encrypt->no_recp = 1;
154     break;
155    
156     case STATUS_INV_RECP:
157     while( args[i] && args[i] != ' ' )
158     i++;
159     while( args[i] && args[i] != ' ' )
160     i++;
161     err = add_recp_info( ctx->result.encrypt, atol( args ), args + i );
162     if( err )
163     ctx->out_of_core = 1;
164     ctx->result.encrypt->inv_recp++;
165     break;
166    
167     case STATUS_FILE_START:
168     ctx->result.encrypt->file_start++;
169     if( ctx->cb.interactiv )
170     ctx->cb.interactiv( ctx->cb.interactiv_value, code, NULL, args+2 );
171     break;
172    
173     case STATUS_FILE_DONE:
174     ctx->result.encrypt->file_done++;
175     if( ctx->cb.interactiv )
176     ctx->cb.interactiv( ctx->cb.interactiv_value, code, NULL, NULL );
177     break;
178    
179     case STATUS_PROGRESS:
180     if (ctx->cb.progress)
181     _gpgme_progress_handler (ctx, args);
182     break;
183     }
184     } /* encrypt_status_handler */
185    
186    
187     static const char *
188     encrypt_command_handler (void * opaque, gpg_statcode_t code, const char * key)
189     {
190     gpgme_ctx_t ctx = opaque;
191    
192     if (!ctx)
193     return NULL;
194     if (!strcmp (key, "untrusted_key.override"))
195     return "N";
196     if (!ctx->cb.interactiv)
197     return NULL;
198     if ((code == STATUS_GET_BOOL && !strcmp (key, "openfile.overwrite.okay"))
199     ||(code == STATUS_GET_LINE && !strcmp (key, "openfile.askoutname" )) )
200     return ctx->cb.interactiv (ctx->cb.interactiv_value, code, key, NULL);
201    
202     return NULL;
203     } /* encrypt_command_handler */
204    
205    
206     static gpgme_error_t
207     encrypt_start( gpgme_ctx_t ctx, gpgme_recipients_t recp,
208     gpgme_data_t plain, gpgme_data_t ciph )
209    
210     {
211     gpgme_error_t rc = 0;
212    
213     fail_on_pending_request( ctx );
214     ctx->pending = 1;
215    
216     /* do some checks */
217     if( !gpgme_recipients_count ( recp ) ) {
218     rc = mk_error( No_Recipients );
219     goto leave;
220     }
221    
222     /* create a process object */
223     _gpgme_gpg_release( &ctx->gpg );
224     rc = _gpgme_gpg_new( &ctx->gpg );
225     if( rc )
226     goto leave;
227    
228     _gpgme_gpg_set_status_handler (ctx->gpg, encrypt_status_handler, ctx);
229     _gpgme_gpg_set_command_handler (ctx->gpg, encrypt_command_handler, ctx);
230    
231     /* build the commandline */
232     _gpgme_gpg_add_arg( ctx->gpg, "--encrypt" );
233     if( ctx->use_armor )
234     _gpgme_gpg_add_arg( ctx->gpg, "--armor" );
235     if (ctx->no_compress)
236     _gpgme_gpg_add_arg (ctx->gpg, "-z 0");
237     if (ctx->force_mdc)
238     _gpgme_gpg_add_arg (ctx->gpg, "--force-mdc");
239     _gpgme_add_comment (ctx);
240     if (ctx->cb.progress)
241     _gpgme_gpg_add_arg (ctx->gpg, "--enable-progress-filter");
242     /* If we know that all recipients are valid (full or ultimate trust)
243     we can pass suppress further checks */
244     if( ctx->force_trust || _gpgme_recipients_all_valid( recp ) )
245     _gpgme_gpg_add_arg( ctx->gpg, "--always-trust" );
246    
247     _gpgme_append_gpg_args_from_recipients( recp, ctx->gpg );
248     if (ctx->use_logging)
249     _gpgme_gpg_set_logging_handler (ctx->gpg, ctx);
250    
251     /* Check the supplied data */
252     if( gpgme_data_get_type( plain ) == GPGME_DATA_TYPE_NONE ) {
253     rc = mk_error( No_Data );
254     goto leave;
255     }
256     _gpgme_data_set_mode( plain, GPGME_DATA_MODE_OUT );
257     if( !ciph || gpgme_data_get_type( ciph ) != GPGME_DATA_TYPE_NONE ) {
258     rc = mk_error( Invalid_Value );
259     goto leave;
260     }
261     _gpgme_data_set_mode( ciph, GPGME_DATA_MODE_IN );
262     /* Tell the gpg object about the data */
263     if( ctx->use_tmpfiles ) {
264     _gpgme_gpg_add_arg( ctx->gpg, "--yes" );
265     _gpgme_gpg_add_arg( ctx->gpg, "--output" );
266     _gpgme_gpg_add_arg( ctx->gpg, _gpgme_get_tmpfile( 0 ) );
267     _gpgme_data_write_to_tmpfile( plain );
268     _gpgme_gpg_add_arg( ctx->gpg, _gpgme_get_tmpfile( 1 ) );
269     }
270     else {
271     _gpgme_gpg_add_arg( ctx->gpg, "--output" );
272     _gpgme_gpg_add_arg( ctx->gpg, "-" );
273     _gpgme_gpg_add_data( ctx->gpg, ciph, 1 );
274     _gpgme_gpg_add_arg( ctx->gpg, "--" );
275     _gpgme_gpg_add_data( ctx->gpg, plain, 0 );
276     }
277    
278     /* and kick off the process */
279     rc = _gpgme_gpg_spawn ( ctx->gpg, ctx );
280    
281     leave:
282     if( rc ) {
283     ctx->pending = 0;
284     _gpgme_gpg_release( &ctx->gpg );
285     }
286    
287     return rc;
288     } /* encrypt_start */
289    
290    
291     gpgme_error_t
292     file_encrypt_start( gpgme_ctx_t ctx, gpgme_recipients_t recp,
293     const char ** input, size_t nfiles, const char * output )
294     {
295     gpgme_error_t rc = 0;
296     int symmetric = 0;
297    
298     if( !input )
299     return mk_error( Invalid_Value );
300    
301     fail_on_pending_request( ctx );
302     ctx->pending = 1;
303    
304     if( use_symmetric( recp ) )
305     symmetric = 1;
306    
307     _gpgme_gpg_release( &ctx->gpg );
308     rc = _gpgme_gpg_new( &ctx->gpg );
309     if( rc ) {
310     gpgme_release( ctx );
311     return rc;
312     }
313    
314     _gpgme_gpg_set_status_handler( ctx->gpg, encrypt_status_handler, ctx );
315     if( ctx->cb.interactiv )
316     _gpgme_gpg_set_command_handler( ctx->gpg, encrypt_command_handler, ctx );
317     else
318     _gpgme_gpg_add_arg (ctx->gpg, "--yes");
319     if( ctx->use_armor )
320     _gpgme_gpg_add_arg (ctx->gpg, "--armor");
321     if (ctx->no_compress)
322     _gpgme_gpg_add_arg (ctx->gpg, "-z 0");
323     if (ctx->force_mdc)
324     _gpgme_gpg_add_arg (ctx->gpg, "--force-mdc");
325     _gpgme_add_comment (ctx);
326     if( ctx->cb.progress )
327     _gpgme_gpg_add_arg( ctx->gpg, "--enable-progress-filter" );
328     if( !output )
329     _gpgme_gpg_add_arg( ctx->gpg, "--no-mangle-dos-filenames" );
330    
331     if( symmetric ) {
332     _gpgme_gpg_add_arg( ctx->gpg, "--symmetric" );
333     _gpgme_encrypt_add_cipher( ctx );
334     rc = _gpgme_add_passphrase( ctx );
335     if( rc ) {
336     _gpgme_gpg_release( &ctx->gpg );
337     return rc;
338     }
339     }
340     else {
341     if( ctx->use_throwkeyid )
342     _gpgme_gpg_add_arg( ctx->gpg, "--throw-keyid" );
343     if( ctx->force_trust )
344     _gpgme_gpg_add_arg( ctx->gpg, "--always-trust" );
345     if( recp )
346     _gpgme_append_gpg_args_from_recipients( recp, ctx->gpg );
347     if( ctx->pipemode || nfiles > 1 )
348     _gpgme_gpg_add_arg( ctx->gpg, "--encrypt-files" );
349     else
350     _gpgme_gpg_add_arg( ctx->gpg, "--encrypt" );
351    
352     }
353    
354     /* we cannot use --output for --encrypt-files */
355     if( nfiles == 1 && !ctx->pipemode && output ) {
356     _gpgme_gpg_add_arg( ctx->gpg, "--output" );
357     _gpgme_gpg_add_arg( ctx->gpg, output );
358     }
359     while( nfiles-- )
360     _gpgme_gpg_add_arg( ctx->gpg, *input++ );
361     rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
362     if( rc ) {
363     ctx->pending = 0;
364     _gpgme_gpg_release( &ctx->gpg );
365     }
366    
367     return rc;
368     } /* file_encrypt_start */
369    
370    
371     static gpgme_error_t
372     get_encrypt_result( gpgme_ctx_t ctx )
373     {
374     struct encrypt_result_s * res;
375     gpgme_error_t err = 0;
376     int rc;
377    
378     assert( ctx->result.encrypt );
379     res = ctx->result.encrypt;
380     if( res->okay )
381     return mk_error( No_Error );
382     if( res->no_recp )
383     err = mk_error( No_Recipients );
384     else if( res->inv_recp )
385     err = mk_error( Inv_Recipients );
386     else if( (rc = gpgme_get_process_rc( ctx )) ) {
387     DEBUG1( "gpg return code=%d\n", rc );
388     err = mk_error( Interal_GPG_Problem );
389     }
390     else if( !res->okay || (res->file_start != res->file_done) )
391     err = mk_error( Encryption_Failed );
392     return err;
393     } /* get_encrypt_result */
394    
395    
396     /**
397     * gpgme_op_encrypt:
398     * @ctx: The context
399     * @recp: A set of recipients
400     * @in: plaintext input
401     * @out: ciphertext output
402     *
403     * This function encrypts @in to @out for all recipients from
404     * @recp. Other parameters are take from the context @c.
405     * The function does wait for the result.
406     *
407     * Return value: 0 on success or an errorcode.
408     **/
409     gpgme_error_t
410     gpgme_op_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t recp,
411     gpgme_data_t in, gpgme_data_t out )
412    
413     {
414     gpgme_error_t err;
415    
416     err = encrypt_start( ctx, recp, in, out );
417     if( !err ) {
418     gpgme_wait( ctx, 1 );
419     ctx->pending = 0;
420     if( ctx->use_tmpfiles ) {
421     _gpgme_data_read_from_tmpfile( out );
422     _gpgme_del_tmpfiles( ctx->wipe_fnc );
423     }
424     err = get_encrypt_result( ctx );
425     }
426    
427     return err;
428     } /* gpgme_op_encrypt */
429    
430    
431     gpgme_error_t
432     gpgme_op_file_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t rset,
433     const char * input, const char * output )
434     {
435     gpgme_error_t err;
436     const char * files[1];
437    
438     files[0] = input;
439     err = file_encrypt_start( ctx, rset, files, 1, output );
440     if( !err ) {
441     gpgme_wait( ctx, 1 );
442     ctx->pending = 0;
443     err = get_encrypt_result( ctx );
444     }
445    
446     return err;
447     } /* gpgme_op_file_encrypt */
448    
449    
450     gpgme_error_t
451     gpgme_op_files_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t rset,
452     const char ** files, size_t nfiles )
453     {
454     gpgme_error_t err;
455    
456     /* fixme: the result is actually only for the last file. we need
457     a notification system which informs us with a callback
458     after each file is processed. */
459     if( use_symmetric( rset ) ) {
460     const char * s[1];
461     size_t i;
462    
463     for( i=0; i < nfiles; i++ ) {
464     s[0] = files[i];
465     err = file_encrypt_start( ctx, NULL, s, 1, NULL );
466     if( !err ) {
467     gpgme_wait( ctx, 1 );
468     ctx->pending = 0;
469     err = get_encrypt_result( ctx );
470     }
471     if( err )
472     break;
473     }
474     }
475     else {
476     err = file_encrypt_start( ctx, rset, files, nfiles, NULL );
477     if( !err ) {
478     gpgme_wait( ctx, 1 );
479     ctx->pending = 0;
480     err = get_encrypt_result( ctx );
481     }
482     }
483     return err;
484     }
485    
486    
487     gpgme_error_t
488     gpgme_op_clip_encrypt( gpgme_recipients_t rset, int opts, gpgme_ctx_t *r_ctx )
489     {
490     gpgme_error_t err;
491     gpgme_ctx_t ctx = NULL;
492     gpgme_data_t plain = NULL;
493     gpgme_data_t ciph = NULL;
494    
495     err = gpgme_new( &ctx );
496     if( err )
497     return err;
498    
499     if( opts & GPGME_CTRL_TMPFILES )
500     gpgme_control( ctx, GPGME_CTRL_TMPFILES, 1 );
501     if( opts & GPGME_CTRL_FORCETRUST )
502     gpgme_control( ctx, GPGME_CTRL_FORCETRUST, 1 );
503     gpgme_control( ctx, GPGME_CTRL_ARMOR, 1 );
504    
505     err = gpgme_data_new_from_clipboard (&plain);
506     if( !err )
507     err = gpgme_data_new( &ciph );
508     if( !err )
509     err = gpgme_op_encrypt( ctx, rset, plain, ciph );
510     if( !err ) {
511     gpgme_data_change_version( &ciph );
512     gpgme_data_release_and_set_clipboard( ciph );
513     }
514     if( r_ctx )
515     *r_ctx = ctx;
516     else
517     gpgme_release( ctx );
518     gpgme_data_release( plain );
519     return err;
520     } /* gpgme_op_clip_encrypt */
521    
522    
523     int
524     gpgme_recperr_count_items( gpgme_ctx_t ctx )
525     {
526     struct recp_info_s * r;
527     int ncount = 0;
528    
529     if( !ctx )
530     return 0;
531     if( ctx->result_type != RESULT_TYPE_ENCRYPT )
532     return -1;
533     for( r = ctx->result.encrypt->inf; r; r = r->next )
534     ncount++;
535    
536     return ncount;
537     } /* gpgme_recperr_count_items */
538    
539    
540     const char*
541     gpgme_recperr_get( gpgme_ctx_t ctx, int idx, gpgme_error_t *r_code )
542     {
543     struct recp_info_s * r;
544    
545     if( !ctx )
546     return NULL;
547     if( idx > gpgme_recperr_count_items( ctx ) )
548     return NULL;
549     for( r = ctx->result.encrypt->inf; r && idx--; r = r->next )
550     ;
551     if( r ) {
552     if( r_code )
553     *r_code = r->code;
554     return r->recp;
555     }
556    
557     return NULL;
558     } /* gpgme_recperr_get_code */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26