tests: Fix memory leak.
[libgcrypt.git] / tests / t-cv25519.c
1 /* t-cv25519.c - Check the cv25519 crypto
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt 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 Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include "../src/gcrypt-int.h"
31
32 #include "stopwatch.h"
33
34 #define PGM "t-cv25519"
35 #define N_TESTS 18
36
37 #define my_isascii(c) (!((c) & 0x80))
38 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
39 #define hexdigitp(a) (digitp (a)                     \
40                       || (*(a) >= 'A' && *(a) <= 'F')  \
41                       || (*(a) >= 'a' && *(a) <= 'f'))
42 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
43                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
44 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
45 #define xmalloc(a)    gcry_xmalloc ((a))
46 #define xcalloc(a,b)  gcry_xcalloc ((a),(b))
47 #define xstrdup(a)    gcry_xstrdup ((a))
48 #define xfree(a)      gcry_free ((a))
49 #define pass()        do { ; } while (0)
50
51 static int verbose;
52 static int debug;
53 static int error_count;
54
55 static void
56 print_mpi (const char *text, gcry_mpi_t a)
57 {
58   gcry_error_t err;
59   char *buf;
60   void *bufaddr = &buf;
61
62   err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
63   if (err)
64     fprintf (stderr, "%s: [error printing number: %s]\n",
65              text, gpg_strerror (err));
66   else
67     {
68       fprintf (stderr, "%s: %s\n", text, buf);
69       gcry_free (buf);
70     }
71 }
72
73 static void
74 die (const char *format, ...)
75 {
76   va_list arg_ptr ;
77
78   fflush (stdout);
79   fprintf (stderr, "%s: ", PGM);
80   va_start( arg_ptr, format ) ;
81   vfprintf (stderr, format, arg_ptr );
82   va_end(arg_ptr);
83   if (*format && format[strlen(format)-1] != '\n')
84     putc ('\n', stderr);
85   exit (1);
86 }
87
88 static void
89 fail (const char *format, ...)
90 {
91   va_list arg_ptr;
92
93   fflush (stdout);
94   fprintf (stderr, "%s: ", PGM);
95   /* if (wherestr) */
96   /*   fprintf (stderr, "%s: ", wherestr); */
97   va_start (arg_ptr, format);
98   vfprintf (stderr, format, arg_ptr);
99   va_end (arg_ptr);
100   if (*format && format[strlen(format)-1] != '\n')
101     putc ('\n', stderr);
102   error_count++;
103   if (error_count >= 50)
104     die ("stopped after 50 errors.");
105 }
106
107 static void
108 show (const char *format, ...)
109 {
110   va_list arg_ptr;
111
112   if (!verbose)
113     return;
114   fprintf (stderr, "%s: ", PGM);
115   va_start (arg_ptr, format);
116   vfprintf (stderr, format, arg_ptr);
117   if (*format && format[strlen(format)-1] != '\n')
118     putc ('\n', stderr);
119   va_end (arg_ptr);
120 }
121
122
123 static void
124 show_note (const char *format, ...)
125 {
126   va_list arg_ptr;
127
128   if (!verbose && getenv ("srcdir"))
129     fputs ("      ", stderr);  /* To align above "PASS: ".  */
130   else
131     fprintf (stderr, "%s: ", PGM);
132   va_start (arg_ptr, format);
133   vfprintf (stderr, format, arg_ptr);
134   if (*format && format[strlen(format)-1] != '\n')
135     putc ('\n', stderr);
136   va_end (arg_ptr);
137 }
138
139
140 /* Convert STRING consisting of hex characters into its binary
141    representation and return it as an allocated buffer. The valid
142    length of the buffer is returned at R_LENGTH.  The string is
143    delimited by end of string.  The function returns NULL on
144    error.  */
145 static void *
146 hex2buffer (const char *string, size_t *r_length)
147 {
148   const char *s;
149   unsigned char *buffer;
150   size_t length;
151
152   buffer = xmalloc (strlen(string)/2+1);
153   length = 0;
154   for (s=string; *s; s +=2 )
155     {
156       if (!hexdigitp (s) || !hexdigitp (s+1))
157         return NULL;           /* Invalid hex digits. */
158       ((unsigned char*)buffer)[length++] = xtoi_2 (s);
159     }
160   *r_length = length;
161   return buffer;
162 }
163
164 static void
165 reverse_buffer (unsigned char *buffer, unsigned int length)
166 {
167   unsigned int tmp, i;
168
169   for (i=0; i < length/2; i++)
170     {
171       tmp = buffer[i];
172       buffer[i] = buffer[length-1-i];
173       buffer[length-1-i] = tmp;
174     }
175 }
176
177
178 /*
179  * Test X25519 functionality through higher layer crypto routines.
180  *
181  * Input: K (as hex string), U (as hex string), R (as hex string)
182  *
183  * where R is expected result of X25519 (K, U).
184  *
185  * It calls gcry_pk_decrypt with Curve25519 private key and let
186  * it compute X25519.
187  */
188 static void
189 test_cv (int testno, const char *k_str, const char *u_str,
190          const char *result_str)
191 {
192   gpg_error_t err;
193   void *buffer = NULL;
194   size_t buflen;
195   gcry_sexp_t s_pk = NULL;
196   gcry_mpi_t mpi_k = NULL;
197   gcry_sexp_t s_data = NULL;
198   gcry_sexp_t s_result = NULL;
199   gcry_sexp_t s_tmp = NULL;
200   unsigned char *res = NULL;
201   size_t res_len;
202
203   if (verbose > 1)
204     show ("Running test %d\n", testno);
205
206   if (!(buffer = hex2buffer (k_str, &buflen)) || buflen != 32)
207     {
208       fail ("error building s-exp for test %d, %s: %s",
209             testno, "k", "invalid hex string");
210       goto leave;
211     }
212
213   reverse_buffer (buffer, buflen);
214   if ((err = gcry_mpi_scan (&mpi_k, GCRYMPI_FMT_USG, buffer, buflen, NULL)))
215     {
216       fail ("error converting MPI for test %d: %s", testno, gpg_strerror (err));
217       goto leave;
218     }
219
220   if ((err = gcry_sexp_build (&s_data, NULL, "%m", mpi_k)))
221     {
222       fail ("error building s-exp for test %d, %s: %s",
223             testno, "data", gpg_strerror (err));
224       goto leave;
225     }
226
227   xfree (buffer);
228   if (!(buffer = hex2buffer (u_str, &buflen)) || buflen != 32)
229     {
230       fail ("error building s-exp for test %d, %s: %s",
231             testno, "u", "invalid hex string");
232       goto leave;
233     }
234
235   /*
236    * The procedure of decodeUCoordinate will be done internally
237    * by _gcry_ecc_mont_decodepoint.  So, we just put the little-endian
238    * binary to build S-exp.
239    *
240    * We could add the prefix 0x40, but libgcrypt also supports
241    * format with no prefix.  So, it is OK not to put the prefix.
242    */
243   if ((err = gcry_sexp_build (&s_pk, NULL,
244                               "(public-key"
245                               " (ecc"
246                               "  (curve \"Curve25519\")"
247                               "  (flags djb-tweak)"
248                               "  (q%b)))", (int)buflen, buffer)))
249     {
250       fail ("error building s-exp for test %d, %s: %s",
251             testno, "pk", gpg_strerror (err));
252       goto leave;
253     }
254
255   xfree (buffer);
256   buffer = NULL;
257
258   if ((err = gcry_pk_encrypt (&s_result, s_data, s_pk)))
259     fail ("gcry_pk_encrypt failed for test %d: %s", testno,
260           gpg_strerror (err));
261
262   s_tmp = gcry_sexp_find_token (s_result, "s", 0);
263   if (!s_tmp || !(res = gcry_sexp_nth_buffer (s_tmp, 1, &res_len)))
264     fail ("gcry_pk_encrypt failed for test %d: %s", testno, "missing value");
265   else
266     {
267       char *r, *r0;
268       int i;
269
270       /* To skip the prefix 0x40, for-loop start with i=1 */
271       r0 = r = xmalloc (2*(res_len)+1);
272       if (!r0)
273         {
274           fail ("memory allocation", testno);
275           goto leave;
276         }
277
278       for (i=1; i < res_len; i++, r += 2)
279         snprintf (r, 3, "%02x", res[i]);
280       if (strcmp (result_str, r0))
281         {
282           fail ("gcry_pk_encrypt failed for test %d: %s",
283                 testno, "wrong value returned");
284           show ("  expected: '%s'", result_str);
285           show ("       got: '%s'", r0);
286         }
287       xfree (r0);
288     }
289
290  leave:
291   xfree (res);
292   gcry_mpi_release (mpi_k);
293   gcry_sexp_release (s_tmp);
294   gcry_sexp_release (s_result);
295   gcry_sexp_release (s_data);
296   gcry_sexp_release (s_pk);
297   xfree (buffer);
298 }
299
300 /*
301  * Test iterative X25519 computation through lower layer MPI routines.
302  *
303  * Input: K (as hex string), ITER, R (as hex string)
304  *
305  * where R is expected result of iterating X25519 by ITER times.
306  *
307  */
308 static void
309 test_it (int testno, const char *k_str, int iter, const char *result_str)
310 {
311   gcry_ctx_t ctx;
312   gpg_error_t err;
313   void *buffer = NULL;
314   size_t buflen;
315   gcry_mpi_t mpi_k = NULL;
316   gcry_mpi_t mpi_x = NULL;
317   gcry_mpi_point_t P = NULL;
318   gcry_mpi_point_t Q;
319   int i;
320   gcry_mpi_t mpi_kk = NULL;
321
322   if (verbose > 1)
323     show ("Running test %d: iteration=%d\n", testno, iter);
324
325   gcry_mpi_ec_new (&ctx, NULL, "Curve25519");
326   Q = gcry_mpi_point_new (0);
327
328   if (!(buffer = hex2buffer (k_str, &buflen)) || buflen != 32)
329     {
330       fail ("error scanning MPI for test %d, %s: %s",
331             testno, "k", "invalid hex string");
332       goto leave;
333     }
334   reverse_buffer (buffer, buflen);
335   if ((err = gcry_mpi_scan (&mpi_x, GCRYMPI_FMT_USG, buffer, buflen, NULL)))
336     {
337       fail ("error scanning MPI for test %d, %s: %s",
338             testno, "x", gpg_strerror (err));
339       goto leave;
340     }
341
342   xfree (buffer);
343   buffer = NULL;
344
345   P = gcry_mpi_point_set (NULL, mpi_x, NULL, GCRYMPI_CONST_ONE);
346
347   mpi_k = gcry_mpi_copy (mpi_x);
348   if (debug)
349     print_mpi ("k", mpi_k);
350
351   for (i = 0; i < iter; i++)
352     {
353       /*
354        * Another variant of decodeScalar25519 thing.
355        */
356       mpi_kk = gcry_mpi_set (mpi_kk, mpi_k);
357       gcry_mpi_set_bit (mpi_kk, 254);
358       gcry_mpi_clear_bit (mpi_kk, 255);
359       gcry_mpi_clear_bit (mpi_kk, 0);
360       gcry_mpi_clear_bit (mpi_kk, 1);
361       gcry_mpi_clear_bit (mpi_kk, 2);
362
363       gcry_mpi_ec_mul (Q, mpi_kk, P, ctx);
364
365       P = gcry_mpi_point_set (P, mpi_k, NULL, GCRYMPI_CONST_ONE);
366       gcry_mpi_ec_get_affine (mpi_k, NULL, Q, ctx);
367
368       if (debug)
369         print_mpi ("k", mpi_k);
370     }
371
372   {
373     unsigned char res[32];
374     char *r, *r0;
375
376     gcry_mpi_print (GCRYMPI_FMT_USG, res, 32, NULL, mpi_k);
377     reverse_buffer (res, 32);
378
379     r0 = r = xmalloc (65);
380     if (!r0)
381       {
382         fail ("memory allocation", testno);
383         goto leave;
384       }
385
386     for (i=0; i < 32; i++, r += 2)
387       snprintf (r, 3, "%02x", res[i]);
388
389     if (strcmp (result_str, r0))
390       {
391         fail ("curv25519 failed for test %d: %s",
392               testno, "wrong value returned");
393         show ("  expected: '%s'", result_str);
394         show ("       got: '%s'", r0);
395       }
396     xfree (r0);
397   }
398
399  leave:
400   gcry_mpi_release (mpi_kk);
401   gcry_mpi_release (mpi_k);
402   gcry_mpi_point_release (P);
403   gcry_mpi_release (mpi_x);
404   xfree (buffer);
405   gcry_mpi_point_release (Q);
406   gcry_ctx_release (ctx);
407 }
408
409 /*
410  * X-coordinate of generator of the Curve25519.
411  */
412 #define G_X "0900000000000000000000000000000000000000000000000000000000000000"
413
414 /*
415  * Test Diffie-Hellman in RFC-7748.
416  *
417  * Note that it's not like the ECDH of OpenPGP, where we use
418  * ephemeral public key.
419  */
420 static void
421 test_dh (int testno, const char *a_priv_str, const char *a_pub_str,
422           const char *b_priv_str, const char *b_pub_str,
423           const char *result_str)
424 {
425   /* Test A for private key corresponds to public key. */
426   test_cv (testno, a_priv_str, G_X, a_pub_str);
427   /* Test B for private key corresponds to public key. */
428   test_cv (testno, b_priv_str, G_X, b_pub_str);
429   /* Test DH with A's private key and B's public key. */
430   test_cv (testno, a_priv_str, b_pub_str, result_str);
431   /* Test DH with B's private key and A's public key. */
432   test_cv (testno, b_priv_str, a_pub_str, result_str);
433 }
434
435
436 static void
437 check_cv25519 (void)
438 {
439   int ntests;
440
441   show ("Checking Curve25519.\n");
442
443   ntests = 0;
444
445   /*
446    * Values are cited from RFC-7748: 5.2.  Test Vectors.
447    * Following two tests are for the first type test.
448    */
449   test_cv (1,
450            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
451            "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
452            "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552");
453   ntests++;
454   test_cv (2,
455            "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d",
456            "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493",
457            "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957");
458   ntests++;
459
460   /*
461    * Additional test.  Value is from second type test.
462    */
463   test_cv (3,
464            G_X,
465            G_X,
466            "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079");
467   ntests++;
468
469   /*
470    * Following two tests are for the second type test,
471    * with one iteration and 1,000 iterations.  (1,000,000 iterations
472    * takes too long.)
473    */
474   test_it (4,
475            G_X,
476            1,
477            "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079");
478   ntests++;
479
480   test_it (5,
481            G_X,
482            1000,
483            "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51");
484   ntests++;
485
486   /*
487    * Last test is from: 6.  Diffie-Hellman, 6.1.  Curve25519
488    */
489   test_dh (6,
490            /* Alice's private key, a */
491            "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
492            /* Alice's public key, X25519(a, 9) */
493            "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
494            /* Bob's private key, b */
495            "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb",
496            /* Bob's public key, X25519(b, 9) */
497            "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
498            /* Their shared secret, K */
499            "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
500   ntests++;
501
502   /* Seven tests which results 0. */
503   test_cv (7,
504            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
505            "0000000000000000000000000000000000000000000000000000000000000000",
506            "0000000000000000000000000000000000000000000000000000000000000000");
507   ntests++;
508
509   test_cv (8,
510            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
511            "0100000000000000000000000000000000000000000000000000000000000000",
512            "0000000000000000000000000000000000000000000000000000000000000000");
513   ntests++;
514
515   test_cv (9,
516            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
517            "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800",
518            "0000000000000000000000000000000000000000000000000000000000000000");
519   ntests++;
520
521   test_cv (10,
522            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
523            "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157",
524            "0000000000000000000000000000000000000000000000000000000000000000");
525   ntests++;
526
527   test_cv (11,
528            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
529            "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
530            "0000000000000000000000000000000000000000000000000000000000000000");
531   ntests++;
532
533   test_cv (12,
534            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
535            "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
536            "0000000000000000000000000000000000000000000000000000000000000000");
537   ntests++;
538
539   test_cv (13,
540            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
541            "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
542            "0000000000000000000000000000000000000000000000000000000000000000");
543   ntests++;
544
545   /* Five tests which resulted 0 if decodeUCoordinate didn't change MSB. */
546   test_cv (14,
547            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
548            "cdeb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",
549            "7ce548bc4919008436244d2da7a9906528fe3a6d278047654bd32d8acde9707b");
550   ntests++;
551
552   test_cv (15,
553            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
554            "4c9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",
555            "e17902e989a034acdf7248260e2c94cdaf2fe1e72aaac7024a128058b6189939");
556   ntests++;
557
558   test_cv (16,
559            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
560            "d9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
561            "ea6e6ddf0685c31e152d5818441ac9ac8db1a01f3d6cb5041b07443a901e7145");
562   ntests++;
563
564   test_cv (17,
565            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
566            "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
567            "845ddce7b3a9b3ee01a2f1fd4282ad293310f7a232cbc5459fb35d94bccc9d05");
568   ntests++;
569
570   test_cv (18,
571            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
572            "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
573            "6989e2cb1cea159acf121b0af6bf77493189c9bd32c2dac71669b540f9488247");
574   ntests++;
575
576   if (ntests != N_TESTS)
577     fail ("did %d tests but expected %d", ntests, N_TESTS);
578   else if ((ntests % 256))
579     show_note ("%d tests done\n", ntests);
580 }
581
582
583 int
584 main (int argc, char **argv)
585 {
586   int last_argc = -1;
587
588   if (argc)
589     { argc--; argv++; }
590
591   while (argc && last_argc != argc )
592     {
593       last_argc = argc;
594       if (!strcmp (*argv, "--"))
595         {
596           argc--; argv++;
597           break;
598         }
599       else if (!strcmp (*argv, "--help"))
600         {
601           fputs ("usage: " PGM " [options]\n"
602                  "Options:\n"
603                  "  --verbose       print timings etc.\n"
604                  "  --debug         flyswatter\n",
605                  stdout);
606           exit (0);
607         }
608       else if (!strcmp (*argv, "--verbose"))
609         {
610           verbose++;
611           argc--; argv++;
612         }
613       else if (!strcmp (*argv, "--debug"))
614         {
615           verbose += 2;
616           debug++;
617           argc--; argv++;
618         }
619       else if (!strncmp (*argv, "--", 2))
620         die ("unknown option '%s'", *argv);
621     }
622
623   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
624   if (!gcry_check_version (GCRYPT_VERSION))
625     die ("version mismatch\n");
626   if (debug)
627     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
628   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
629   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
630
631   start_timer ();
632   check_cv25519 ();
633   stop_timer ();
634
635   show ("All tests completed in %s.  Errors: %d\n",
636         elapsed_time (1), error_count);
637   return !!error_count;
638 }