root/openpgpsdk/trunk/src/symmetric.c

Revision 371 (checked in by ben, 7 years ago)

Make sure dmalloc happens last.

Line 
1 #include <openpgpsdk/crypto.h>
2 #include <string.h>
3 #include <assert.h>
4 #include <openssl/cast.h>
5 #include <openssl/idea.h>
6 #include "parse_local.h"
7
8 #include <openpgpsdk/final.h>
9
10 typedef struct
11     {
12     unsigned char decrypted[1024];
13     size_t decrypted_count;
14     size_t decrypted_offset;
15     ops_decrypt_t *decrypt;
16     ops_region_t *region;
17     ops_boolean_t prev_read_was_plain:1;
18     } encrypted_arg_t;
19
20 static ops_reader_ret_t encrypted_data_reader(unsigned char *dest,
21                                               unsigned *plength,
22                                               ops_reader_flags_t flags,
23                                               ops_error_t **errors,
24                                               ops_reader_info_t *rinfo,
25                                               ops_parse_cb_info_t *cbinfo)
26     {
27     encrypted_arg_t *arg=ops_reader_get_arg(rinfo);
28     unsigned length=*plength;
29
30     OPS_USED(flags);
31
32     // V3 MPIs have the count plain and the cipher is reset after each count
33     if(arg->prev_read_was_plain && !rinfo->pinfo->reading_mpi_length)
34         {
35         assert(rinfo->pinfo->reading_v3_secret);
36         arg->decrypt->resync(arg->decrypt);
37         arg->prev_read_was_plain=ops_false;
38         }
39     else if(rinfo->pinfo->reading_v3_secret
40             && rinfo->pinfo->reading_mpi_length)
41         arg->prev_read_was_plain=ops_true;
42
43     while(length > 0)
44         {
45         if(arg->decrypted_count)
46             {
47             unsigned n;
48
49             // if we are reading v3 we should never read more than
50             // we're asked for
51             assert(length >= arg->decrypted_count
52                    || !rinfo->pinfo->reading_v3_secret);
53
54             if(length > arg->decrypted_count)
55                 n=arg->decrypted_count;
56             else
57                 n=length;
58
59             memcpy(dest,arg->decrypted+arg->decrypted_offset,n);
60             arg->decrypted_count-=n;
61             arg->decrypted_offset+=n;
62             length-=n;
63             dest+=n;
64             }
65         else
66             {
67             unsigned n=arg->region->length;
68             unsigned char buffer[1024];
69
70             if(!n)
71                 return OPS_R_EARLY_EOF;
72
73             if(!arg->region->indeterminate)
74                 {
75                 n-=arg->region->length_read;
76                 if(n > sizeof buffer)
77                     n=sizeof buffer;
78                 }
79             else
80                 n=sizeof buffer;
81
82             // we can only read as much as we're asked for in v3 keys
83             // because they're partially unencrypted!
84             if(rinfo->pinfo->reading_v3_secret && n > length)
85                 n=length;
86
87             if(!ops_stacked_limited_read(buffer,n,arg->region,errors,rinfo,
88                                          cbinfo))
89                 return OPS_R_EARLY_EOF;
90
91             if(!rinfo->pinfo->reading_v3_secret
92                || !rinfo->pinfo->reading_mpi_length)
93                 arg->decrypted_count=arg->decrypt->decrypt(arg->decrypt,
94                                                            arg->decrypted,
95                                                            buffer,n);
96             else
97                 {
98                 memcpy(arg->decrypted,buffer,n);
99                 arg->decrypted_count=n;
100                 }
101
102             assert(arg->decrypted_count > 0);
103
104             arg->decrypted_offset=0;
105             }
106         }
107
108     return OPS_R_OK;
109     }
110
111 void ops_reader_push_decrypt(ops_parse_info_t *pinfo,ops_decrypt_t *decrypt,
112                              ops_region_t *region)
113     {
114     encrypted_arg_t *arg=ops_mallocz(sizeof *arg);
115
116     arg->decrypt=decrypt;
117     arg->region=region;
118
119     arg->decrypt->init(arg->decrypt);
120
121     ops_reader_push(pinfo,encrypted_data_reader,arg);
122     }
123
124 void ops_reader_pop_decrypt(ops_parse_info_t *pinfo)
125     {
126     encrypted_arg_t *arg=ops_reader_get_arg(ops_parse_get_rinfo(pinfo));
127
128     arg->decrypt->finish(arg->decrypt);
129     free(arg);
130    
131     ops_reader_pop(pinfo);
132     }
133
134 int ops_decrypt_data(ops_region_t *region,ops_parse_info_t *pinfo)
135     {
136     int r;
137
138     ops_reader_push_decrypt(pinfo,ops_parse_get_decrypt(pinfo),region);
139     r=ops_parse(pinfo);
140     ops_reader_pop_decrypt(pinfo);
141
142     return r;
143     }
144
145 static void std_set_iv(ops_decrypt_t *decrypt,const unsigned char *iv)
146     { memcpy(decrypt->iv,iv,decrypt->blocksize); }
147
148 static void std_set_key(ops_decrypt_t *decrypt,const unsigned char *key)
149     { memcpy(decrypt->key,key,decrypt->keysize); }
150
151 /* Only IDEA has a resync operation */
152 static void std_resync(ops_decrypt_t *decrypt)
153     {
154     OPS_USED(decrypt);
155
156     assert(0);
157     }
158
159 static void std_finish(ops_decrypt_t *decrypt)
160     {
161     free(decrypt->data);
162     decrypt->data=NULL;
163     }
164
165 static void cast5_init(ops_decrypt_t *decrypt)
166     {
167     free(decrypt->data);
168     decrypt->data=malloc(sizeof(CAST_KEY));
169     CAST_set_key(decrypt->data,decrypt->keysize,decrypt->key);
170     memcpy(decrypt->civ,decrypt->iv,decrypt->blocksize);
171     decrypt->num=0;
172     }
173
174 static size_t cast5_decrypt(ops_decrypt_t *decrypt,void *out,const void *in,
175                             int count)
176     {
177     CAST_cfb64_encrypt(in,out,count,decrypt->data,decrypt->civ,&decrypt->num,
178                        0);
179
180     return count;
181     }
182
183 #define TRAILER         "","","","",0,NULL
184
185 static ops_decrypt_t cast5=
186     {
187     OPS_SA_CAST5,
188     CAST_BLOCK,
189     CAST_KEY_LENGTH,
190     std_set_iv,
191     std_set_key,
192     cast5_init,
193     std_resync,
194     cast5_decrypt,
195     std_finish,
196     TRAILER
197     };
198
199 static void idea_init(ops_decrypt_t *decrypt)
200     {
201     assert(decrypt->keysize == IDEA_KEY_LENGTH);
202
203     free(decrypt->data);
204     decrypt->data=malloc(sizeof(IDEA_KEY_SCHEDULE));
205
206     // note that we don't invert the key for CFB mode
207     idea_set_encrypt_key(decrypt->key,decrypt->data);
208
209     memcpy(decrypt->civ,decrypt->iv,decrypt->blocksize);
210     idea_ecb_encrypt(decrypt->civ,decrypt->siv,decrypt->data);
211
212     decrypt->num=0;
213     }
214
215 static void idea_resync(ops_decrypt_t *decrypt)
216     {
217     if(decrypt->num == 8)
218         return;
219
220     memmove(decrypt->civ+8-decrypt->num,decrypt->civ,decrypt->num);
221     memcpy(decrypt->civ,decrypt->siv+decrypt->num,8-decrypt->num);
222     decrypt->num=0;
223     }
224
225 static size_t idea_decrypt(ops_decrypt_t *decrypt,void *out_,const void *in_,
226                            int count)
227     {
228     unsigned char *out=out_;
229     const unsigned char *in=in_;
230     int saved=count;
231
232     /* in order to support v3's weird resyncing we have to implement CFB mode
233        ourselves */
234     while(count-- > 0)
235         {
236         unsigned char t;
237
238         if(decrypt->num == 8)
239             {
240             memcpy(decrypt->siv,decrypt->civ,sizeof decrypt->siv);
241             idea_ecb_encrypt(decrypt->civ,decrypt->civ,decrypt->data);
242             decrypt->num=0;
243             }
244         t=decrypt->civ[decrypt->num];
245         *out++=t^(decrypt->civ[decrypt->num++]=*in++);
246         }
247
248     return saved;
249     }
250
251 static ops_decrypt_t idea=
252     {
253     OPS_SA_IDEA,
254     IDEA_BLOCK,
255     IDEA_KEY_LENGTH,
256     std_set_iv,
257     std_set_key,
258     idea_init,
259     idea_resync,
260     idea_decrypt,
261     std_finish,
262     TRAILER
263     };
264
265 static ops_decrypt_t *get_proto(ops_symmetric_algorithm_t alg)
266     {
267     switch(alg)
268         {
269     case OPS_SA_CAST5:
270         return &cast5;
271
272     case OPS_SA_IDEA:
273         return &idea;
274
275     default:
276         assert(0);
277         }
278
279     return NULL;
280     }
281
282 void ops_decrypt_any(ops_decrypt_t *decrypt,ops_symmetric_algorithm_t alg)
283     { *decrypt=*get_proto(alg); }
284
285 unsigned ops_block_size(ops_symmetric_algorithm_t alg)
286     {
287     ops_decrypt_t *p=get_proto(alg);
288
289     if(!p)
290         return 0;
291
292     return p->blocksize;
293     }
294
295 unsigned ops_key_size(ops_symmetric_algorithm_t alg)
296     {
297     ops_decrypt_t *p=get_proto(alg);
298
299     if(!p)
300         return 0;
301
302     return p->keysize;
303     }
Note: See TracBrowser for help on using the browser.