'g10/gpg2 --encrypt --debug 15 -r ecdsa -a -o _e.asc _' and 'g10/gpg2 --debug 15...
[gnupg.git] / g10 / ecdh.c
1 /* ecdh.c - ECDH public key operations used in public key glue code
2  *      Copyright (C) 2000, 2003 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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
26
27 #include "gpg.h"
28 #include "util.h"
29 #include "pkglue.h"
30 #include "main.h"
31 #include "options.h"
32
33 gcry_mpi_t
34 pk_ecdh_default_params_to_mpi( int qbits )  {
35   gpg_error_t err;
36   gcry_mpi_t result;
37   /* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */
38   byte kek_params[4] = { 
39         3       /*size of following field*/, 
40         1       /*fixed version for KDF+AESWRAP*/, 
41         DIGEST_ALGO_SHA512      /* KEK MD */, 
42         CIPHER_ALGO_AES256      /*KEK AESWRAP alg*/
43   };
44   int i;
45
46   static const struct {
47     int qbits;
48     int openpgp_hash_id;
49     int openpgp_cipher_id;
50   } kek_params_table[] = {
51     { 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES    },
52     { 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
53     { 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 }     // 528 is 521 rounded to the 8 bit boundary
54   };
55
56   for( i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++ )  {
57     if( kek_params_table[i].qbits >= qbits )  {
58       kek_params[2] = kek_params_table[i].openpgp_hash_id;
59       kek_params[3] = kek_params_table[i].openpgp_cipher_id;
60       break;
61     }
62   }
63   if( DBG_CIPHER )
64       log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params) );
65
66   err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, kek_params, sizeof(kek_params), NULL);
67   if (err)
68     log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
69
70   return result;
71 }
72
73 /* returns allocated (binary) KEK parameters; the size is returned in sizeout. 
74  * The caller must free returned value with xfree. 
75  * Returns NULL on error 
76  */
77 byte *
78 pk_ecdh_default_params( int qbits, size_t *sizeout )  {
79   /* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */
80   byte kek_params[4] = { 
81         3       /*size of following field*/, 
82         1       /*fixed version for KDF+AESWRAP*/, 
83         DIGEST_ALGO_SHA512      /* KEK MD */, 
84         CIPHER_ALGO_AES256      /*KEK AESWRAP alg*/
85   };
86   int i;
87
88   static const struct {
89     int qbits;
90     int openpgp_hash_id;
91     int openpgp_cipher_id;
92   } kek_params_table[] = {
93     { 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES    },
94     { 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
95     { 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 }     // 528 is 521 rounded to the 8 bit boundary
96   };
97
98   byte *p;
99
100   *sizeout = 0;
101
102   for( i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++ )  {
103     if( kek_params_table[i].qbits >= qbits )  {
104       kek_params[2] = kek_params_table[i].openpgp_hash_id;
105       kek_params[3] = kek_params_table[i].openpgp_cipher_id;
106       break;
107     }
108   }
109   if( DBG_CIPHER )
110       log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params) );
111
112   p = xtrymalloc( sizeof(kek_params) );
113   if( p == NULL )
114     return NULL;
115   memcpy( p, kek_params, sizeof(kek_params) );
116   *sizeout = sizeof(kek_params);
117   return p;
118 }
119
120 /* Encrypts/decrypts 'data' with a key derived from shared_mpi ECC point using FIPS SP 800-56A compliant method, which is
121  * key derivation + key wrapping. The direction is determined by the first parameter (is_encrypt=1 --> this is encryption).
122  * The result is returned in out as a size+value MPI.
123  * TODO: memory leaks (x_secret).
124  */
125 static int
126 pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi, 
127         const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey, gcry_mpi_t *out)
128 {
129   byte *secret_x;
130   int secret_x_size;
131   byte kdf_params[256];
132   int kdf_params_size=0;
133   int nbits;
134   int kdf_hash_algo;
135   int kdf_encr_algo;
136   int rc;
137
138   *out = NULL;
139
140   nbits = pubkey_nbits( PUBKEY_ALGO_ECDH, pkey );
141
142   {
143     size_t nbytes;
144     /* extract x component of the shared point: this is the actual shared secret */
145     nbytes = (mpi_get_nbits (pkey[1] /* public point */)+7)/8;
146     secret_x = xmalloc_secure( nbytes );
147     rc = gcry_mpi_print (GCRYMPI_FMT_USG, secret_x, nbytes, &nbytes, shared_mpi);
148     if( rc )  {
149       xfree( secret_x );
150       log_error ("ec ephemeral export of shared point failed: %s\n", gpg_strerror (rc) );
151       return rc;
152     }
153     secret_x_size = (nbits+7)/8; 
154     assert( nbytes > secret_x_size );
155     memmove( secret_x, secret_x+1, secret_x_size );
156     memset( secret_x+secret_x_size, 0, nbytes-secret_x_size );
157
158     if( DBG_CIPHER )
159         log_printhex ("ecdh shared secret X is:", secret_x, secret_x_size );
160   }
161
162   /*** We have now the shared secret bytes in secret_x ***/
163
164   /* At this point we are done with PK encryption and the rest of the function uses symmetric 
165    *  key encryption techniques to protect the input 'data'. The following two sections will
166    *  simply replace current secret_x with a value derived from it. This will become a KEK. 
167    */
168   {
169     IOBUF obuf = iobuf_temp(); 
170     rc = iobuf_write_size_body_mpi ( obuf, pkey[2]  );  /* KEK params */
171
172     kdf_params_size = iobuf_temp_to_buffer( obuf, kdf_params, sizeof(kdf_params) );
173
174     if( DBG_CIPHER )
175         log_printhex ("ecdh KDF public key params are:", kdf_params, kdf_params_size );
176
177     if( kdf_params_size != 4 || kdf_params[0] != 3 || kdf_params[1] != 1  )     /* expect 4 bytes  03 01 hash_alg symm_alg */
178       return GPG_ERR_BAD_PUBKEY;
179
180     kdf_hash_algo = kdf_params[2];
181     kdf_encr_algo = kdf_params[3];
182
183     if( DBG_CIPHER )
184       log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n", gcry_md_algo_name (kdf_hash_algo), openpgp_cipher_algo_name (kdf_encr_algo) );
185
186     if( kdf_hash_algo != GCRY_MD_SHA256 && kdf_hash_algo != GCRY_MD_SHA384 && kdf_hash_algo != GCRY_MD_SHA512 )
187       return GPG_ERR_BAD_PUBKEY;
188     if( kdf_encr_algo != GCRY_CIPHER_AES128 && kdf_encr_algo != GCRY_CIPHER_AES192 && kdf_encr_algo != GCRY_CIPHER_AES256 )
189       return GPG_ERR_BAD_PUBKEY;
190   }
191
192   /* build kdf_params */
193   {
194     IOBUF obuf;
195
196     obuf = iobuf_temp();
197     /* variable-length field 1, curve name OID */
198     rc = iobuf_write_size_body_mpi ( obuf, pkey[0] );
199     /* fixed-length field 2 */
200     iobuf_put (obuf, PUBKEY_ALGO_ECDH);
201     /* variable-length field 3, KDF params */
202     rc = (rc ? rc : iobuf_write_size_body_mpi ( obuf, pkey[2] ));
203     /* fixed-length field 4 */
204     iobuf_write (obuf, "Anonymous Sender    ", 20);
205     /* fixed-length field 5, recipient fp */
206     iobuf_write (obuf, pk_fp, 20);      
207
208     kdf_params_size = iobuf_temp_to_buffer( obuf, kdf_params, sizeof(kdf_params) );
209     iobuf_close( obuf );
210     if( rc )  {
211       return rc;
212     }
213     if( DBG_CIPHER )
214         log_printhex ("ecdh KDF message params are:", kdf_params, kdf_params_size );
215   }
216
217   /* Derive a KEK (key wrapping key) using kdf_params and secret_x. */
218   {
219     gcry_md_hd_t h;
220     int old_size;
221
222     rc = gcry_md_open (&h, kdf_hash_algo, 0);
223     if(rc)
224         log_bug ("gcry_md_open failed for algo %d: %s",
225                         kdf_hash_algo, gpg_strerror (gcry_error(rc)));
226     gcry_md_write(h, "\x00\x00\x00\x01", 4);    /* counter = 1 */
227     gcry_md_write(h, secret_x, secret_x_size);  /* x of the point X */
228     gcry_md_write(h, kdf_params, kdf_params_size);      /* KDF parameters */
229
230     gcry_md_final (h);
231
232     assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 );
233
234     memcpy (secret_x, gcry_md_read (h, kdf_hash_algo), gcry_md_get_algo_dlen (kdf_hash_algo));
235     gcry_md_close (h);
236
237     old_size = secret_x_size;
238     assert( old_size >= gcry_cipher_get_algo_keylen( kdf_encr_algo ) );
239     secret_x_size = gcry_cipher_get_algo_keylen( kdf_encr_algo );
240     assert( secret_x_size <= gcry_md_get_algo_dlen (kdf_hash_algo) );
241
242     memset( secret_x+secret_x_size, old_size-secret_x_size, 0 );        /* we could have allocated more, so clean the tail before returning */
243     if( DBG_CIPHER )
244       log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
245    }
246
247   /* And, finally, aeswrap with key secret_x */
248   {
249     gcry_cipher_hd_t hd;
250     size_t nbytes;
251
252     byte *data_buf;
253     int data_buf_size;
254
255     gcry_mpi_t result;
256
257     rc = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
258     if (rc)
259     {
260       log_error( "ecdh failed to initialize AESWRAP: %s\n", gpg_strerror (rc));
261       return rc;
262     }
263
264     rc = gcry_cipher_setkey (hd, secret_x, secret_x_size);
265     xfree( secret_x );
266     if (rc)
267     {
268       gcry_cipher_close (hd);
269       log_error("ecdh failed in gcry_cipher_setkey: %s\n", gpg_strerror (rc));
270       return rc;
271     }
272
273     data_buf_size = (gcry_mpi_get_nbits(data)+7)/8;
274     assert( (data_buf_size & 7) == (is_encrypt ? 0 : 1) );
275
276     data_buf = xmalloc_secure( 1 + 2*data_buf_size + 8 );
277     if( !data_buf )  {
278       gcry_cipher_close (hd);
279       return GPG_ERR_ENOMEM;
280     }
281
282     if( is_encrypt )  {
283       byte *in = data_buf+1+data_buf_size+8;
284
285       /* write data MPI into the end of data_buf. data_buf is  size aeswrap data */
286       rc = gcry_mpi_print (GCRYMPI_FMT_USG, in, data_buf_size, &nbytes, data/*in*/);
287       if( rc )   {
288         log_error("ecdh failed to export DEK: %s\n", gpg_strerror (rc));
289         gcry_cipher_close (hd);
290         xfree( data_buf );
291         return rc;
292       }
293
294       if( DBG_CIPHER )
295          log_printhex ("ecdh encrypting  :", in, data_buf_size );
296
297       rc = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8, in, data_buf_size);
298       memset( in, 0, data_buf_size);
299       gcry_cipher_close (hd);
300       if(rc)
301       {
302         log_error("ecdh failed in gcry_cipher_encrypt: %s\n", gpg_strerror (rc));
303         xfree( data_buf );
304         return rc;
305       }
306       data_buf[0] = data_buf_size+8;
307
308       if( DBG_CIPHER )
309          log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] );
310
311       rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, data_buf, 1+data_buf[0], NULL); /* (byte)size + aeswrap of DEK */
312       xfree( data_buf );
313       if(rc)
314       {
315         log_error("ecdh failed to create an MPI: %s\n", gpg_strerror (rc));
316         return rc;
317       }
318
319       *out = result;
320     }
321     else  {
322       byte *in;
323
324       rc = gcry_mpi_print (GCRYMPI_FMT_USG, data_buf, data_buf_size, &nbytes, data/*in*/);
325       if( nbytes != data_buf_size || data_buf[0] != data_buf_size-1 )  {
326         log_error("ecdh inconsistent size\n");
327         xfree( data_buf );
328         return GPG_ERR_BAD_MPI;
329       }
330       in = data_buf+data_buf_size;
331       data_buf_size = data_buf[0];
332
333       if( DBG_CIPHER )
334          log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size );
335       
336       rc = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1, data_buf_size );
337       gcry_cipher_close (hd);
338       if(rc)
339       {
340         log_error("ecdh failed in gcry_cipher_decrypt: %s\n", gpg_strerror (rc));
341         xfree( data_buf );
342         return rc;
343       }
344
345       data_buf_size-=8;
346
347       if( DBG_CIPHER )
348          log_printhex ("ecdh decrypted to :", in, data_buf_size );
349
350       /* padding is removed later */
351       //if( in[data_buf_size-1] > 8 )  {
352       //  log_error("ecdh failed at decryption: invalid padding. %02x > 8\n", in[data_buf_size-1] );
353       //  return GPG_ERR_BAD_KEY;
354       //}
355  
356       rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, in, data_buf_size, NULL);
357       xfree( data_buf );
358       if(rc)
359       {
360         log_error("ecdh failed to create a plain text MPI: %s\n", gpg_strerror (rc));
361         return rc;
362       }
363
364       *out = result;
365     }
366   }
367
368   return rc;
369 }
370
371
372 static gcry_mpi_t
373 gen_k (unsigned nbits)
374 {
375   gcry_mpi_t k;
376
377   k = gcry_mpi_snew (nbits);
378   if (DBG_CIPHER)
379     log_debug ("choosing a random k of %u bits\n", nbits);
380
381   gcry_mpi_randomize (k, nbits-1, GCRY_STRONG_RANDOM);
382
383   if( DBG_CIPHER )  {
384         unsigned char *buffer;
385         if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k))
386           BUG ();
387         log_debug("ephemeral scalar MPI #0: %s\n", buffer);
388         gcry_free( buffer );
389   }
390
391   return k;
392 }
393
394 /* Perform ECDH encryption, which involves ECDH key generation.
395  */
396 int
397 pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey)
398 {
399   gcry_sexp_t s_ciph, s_data, s_pkey;
400
401   int nbits;
402   int rc;
403   gcry_mpi_t k;
404
405   nbits = pubkey_nbits( PUBKEY_ALGO_ECDH, pkey );
406
407   /*** Generate an ephemeral key, actually, a scalar ***/
408
409   k = gen_k (nbits);
410   if( k == NULL )
411     BUG ();
412
413   /*** Done with ephemeral key generation. 
414    * Now use ephemeral secret to get the shared secret. ***/
415
416   rc = gcry_sexp_build (&s_pkey, NULL,
417                     "(public-key(ecdh(c%m)(q%m)(p%m)))", pkey[0], pkey[1], pkey[2]);
418   if (rc)
419     BUG ();
420  
421   /* put the data into a simple list */
422   if (gcry_sexp_build (&s_data, NULL, "%m", k)) /* ephemeral scalar goes as data */
423     BUG ();
424
425   /* pass it to libgcrypt */
426   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
427   gcry_sexp_release (s_data);
428   gcry_sexp_release (s_pkey);
429   if (rc)
430     return rc;
431
432   /* finally, perform encryption */
433
434   {
435     gcry_mpi_t shared = mpi_from_sexp (s_ciph, "a");            /* ... and get the shared point */
436     gcry_sexp_release (s_ciph);
437     resarr[0] = mpi_from_sexp (s_ciph, "b");                    /* ephemeral public key */
438
439     if( DBG_CIPHER )  {
440         unsigned char *buffer;
441         if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, resarr[0]))
442           BUG ();
443         log_debug("ephemeral key MPI: %s\n", buffer);
444         gcry_free( buffer );
445     }
446
447     rc = pk_ecdh_encrypt_with_shared_point ( 1 /*=encrypton*/, shared, pk_fp, data, pkey, resarr+1 );
448     mpi_release( shared );
449   }
450
451   return rc;
452 }
453
454 /* Perform ECDH decryption. 
455  */
456 int
457 pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey)  {
458   if (!data)
459     return gpg_error (GPG_ERR_BAD_MPI);
460   return pk_ecdh_encrypt_with_shared_point ( 0 /*=decryption*/, shared, sk_fp, data/*encr data as an MPI*/, skey, result );
461 }
462
463