gnunet-ecc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012, 2013 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file util/gnunet-ecc.c
  18. * @brief tool to manipulate EDDSA key files
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_testing_lib.h"
  24. #include <gcrypt.h>
  25. /**
  26. * Number of characters a Base32-encoded public key requires.
  27. */
  28. #define KEY_STR_LEN sizeof(struct GNUNET_CRYPTO_EddsaPublicKey) * 8 / 5 + 1
  29. /**
  30. * Flag for listing public key.
  31. */
  32. static int list_keys;
  33. /**
  34. * Flag for listing public key.
  35. */
  36. static unsigned int list_keys_count;
  37. /**
  38. * Flag for printing public key.
  39. */
  40. static int print_public_key;
  41. /**
  42. * Flag for printing private key.
  43. */
  44. static int print_private_key;
  45. /**
  46. * Flag for printing public key in hex.
  47. */
  48. static int print_public_key_hex;
  49. /**
  50. * Flag for printing the output of random example operations.
  51. */
  52. static int print_examples_flag;
  53. /**
  54. * Option set to create a bunch of keys at once.
  55. */
  56. static unsigned int make_keys;
  57. /**
  58. * Create a flat file with a large number of key pairs for testing.
  59. *
  60. * @param fn File name to store the keys.
  61. * @param prefix Desired prefix for the public keys, NULL if any key is OK.
  62. */
  63. static void
  64. create_keys (const char *fn, const char *prefix)
  65. {
  66. FILE *f;
  67. struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
  68. struct GNUNET_CRYPTO_EddsaPublicKey target_pub;
  69. static char vanity[KEY_STR_LEN + 1];
  70. size_t len;
  71. size_t n;
  72. size_t rest;
  73. unsigned char mask;
  74. unsigned target_byte;
  75. char *s;
  76. if (NULL == (f = fopen (fn, "w+")))
  77. {
  78. fprintf (stderr, _ ("Failed to open `%s': %s\n"), fn, strerror (errno));
  79. return;
  80. }
  81. if (NULL != prefix)
  82. {
  83. len = GNUNET_strlcpy (vanity, prefix, sizeof(vanity));
  84. n = len * 5 / 8;
  85. rest = len * 5 % 8;
  86. memset (&vanity[len], '0', KEY_STR_LEN - len);
  87. vanity[KEY_STR_LEN] = '\0';
  88. GNUNET_assert (GNUNET_OK ==
  89. GNUNET_CRYPTO_eddsa_public_key_from_string (vanity,
  90. KEY_STR_LEN,
  91. &target_pub));
  92. if (0 != rest)
  93. {
  94. /**
  95. * Documentation by example:
  96. * vanity = "A"
  97. * len = 1
  98. * n = 5/8 = 0 (bytes)
  99. * rest = 5%8 = 5 (bits)
  100. * mask = ~(2**(8 - 5) - 1) = ~(2**3 - 1) = ~(8 - 1) = ~b111 = b11111000
  101. */mask = ~((int) pow (2, 8 - rest) - 1);
  102. target_byte = ((unsigned char *) &target_pub)[n] & mask;
  103. }
  104. else
  105. {
  106. /* Just so old (debian) versions of GCC calm down with the warnings. */
  107. mask = target_byte = 0;
  108. }
  109. s = GNUNET_CRYPTO_eddsa_public_key_to_string (&target_pub);
  110. fprintf (stderr,
  111. _ ("Generating %u keys like %s, please wait"),
  112. make_keys,
  113. s);
  114. GNUNET_free (s);
  115. fprintf (stderr, "\nattempt %s [%u, %X]\n", vanity, (unsigned int) n, mask);
  116. }
  117. else
  118. {
  119. fprintf (stderr, _ ("Generating %u keys, please wait"), make_keys);
  120. /* Just so old (debian) versions of GCC calm down with the warnings. */
  121. n = rest = target_byte = mask = 0;
  122. }
  123. while (0 < make_keys--)
  124. {
  125. fprintf (stderr, ".");
  126. if (NULL == (pk = GNUNET_CRYPTO_eddsa_key_create ()))
  127. {
  128. GNUNET_break (0);
  129. break;
  130. }
  131. if (NULL != prefix)
  132. {
  133. struct GNUNET_CRYPTO_EddsaPublicKey newkey;
  134. GNUNET_CRYPTO_eddsa_key_get_public (pk, &newkey);
  135. if (0 != memcmp (&target_pub, &newkey, n))
  136. {
  137. make_keys++;
  138. continue;
  139. }
  140. if (0 != rest)
  141. {
  142. unsigned char new_byte;
  143. new_byte = ((unsigned char *) &newkey)[n] & mask;
  144. if (target_byte != new_byte)
  145. {
  146. make_keys++;
  147. continue;
  148. }
  149. }
  150. }
  151. if (GNUNET_TESTING_HOSTKEYFILESIZE !=
  152. fwrite (pk, 1, GNUNET_TESTING_HOSTKEYFILESIZE, f))
  153. {
  154. fprintf (stderr,
  155. _ ("\nFailed to write to `%s': %s\n"),
  156. fn,
  157. strerror (errno));
  158. GNUNET_free (pk);
  159. break;
  160. }
  161. GNUNET_free (pk);
  162. }
  163. if (UINT_MAX == make_keys)
  164. fprintf (stderr, _ ("\nFinished!\n"));
  165. else
  166. fprintf (stderr, _ ("\nError, %u keys not generated\n"), make_keys);
  167. fclose (f);
  168. }
  169. static void
  170. print_hex (const char *msg, const void *buf, size_t size)
  171. {
  172. printf ("%s: ", msg);
  173. for (size_t i = 0; i < size; i++)
  174. {
  175. printf ("%02hhx", ((const uint8_t *) buf)[i]);
  176. }
  177. printf ("\n");
  178. }
  179. static void
  180. print_examples_ecdh ()
  181. {
  182. struct GNUNET_CRYPTO_EcdhePrivateKey *dh_priv1;
  183. struct GNUNET_CRYPTO_EcdhePublicKey *dh_pub1;
  184. struct GNUNET_CRYPTO_EcdhePrivateKey *dh_priv2;
  185. struct GNUNET_CRYPTO_EcdhePublicKey *dh_pub2;
  186. struct GNUNET_HashCode hash;
  187. char buf[128];
  188. dh_pub1 = GNUNET_new (struct GNUNET_CRYPTO_EcdhePublicKey);
  189. dh_priv1 = GNUNET_CRYPTO_ecdhe_key_create ();
  190. dh_pub2 = GNUNET_new (struct GNUNET_CRYPTO_EcdhePublicKey);
  191. dh_priv2 = GNUNET_CRYPTO_ecdhe_key_create ();
  192. GNUNET_CRYPTO_ecdhe_key_get_public (dh_priv1, dh_pub1);
  193. GNUNET_CRYPTO_ecdhe_key_get_public (dh_priv2, dh_pub2);
  194. GNUNET_assert (NULL !=
  195. GNUNET_STRINGS_data_to_string (dh_priv1, 32, buf, 128));
  196. printf ("ECDHE key 1:\n");
  197. printf ("private: %s\n", buf);
  198. print_hex ("private(hex)", dh_priv1, sizeof *dh_priv1);
  199. GNUNET_assert (NULL != GNUNET_STRINGS_data_to_string (dh_pub1, 32, buf, 128));
  200. printf ("public: %s\n", buf);
  201. print_hex ("public(hex)", dh_pub1, sizeof *dh_pub1);
  202. GNUNET_assert (NULL !=
  203. GNUNET_STRINGS_data_to_string (dh_priv2, 32, buf, 128));
  204. printf ("ECDHE key 2:\n");
  205. printf ("private: %s\n", buf);
  206. print_hex ("private(hex)", dh_priv2, sizeof *dh_priv2);
  207. GNUNET_assert (NULL != GNUNET_STRINGS_data_to_string (dh_pub2, 32, buf, 128));
  208. printf ("public: %s\n", buf);
  209. print_hex ("public(hex)", dh_pub2, sizeof *dh_pub2);
  210. GNUNET_assert (GNUNET_OK ==
  211. GNUNET_CRYPTO_ecc_ecdh (dh_priv1, dh_pub2, &hash));
  212. GNUNET_assert (NULL != GNUNET_STRINGS_data_to_string (&hash, 64, buf, 128));
  213. printf ("ECDH shared secret: %s\n", buf);
  214. GNUNET_free (dh_priv1);
  215. GNUNET_free (dh_priv2);
  216. GNUNET_free (dh_pub1);
  217. GNUNET_free (dh_pub2);
  218. }
  219. /**
  220. * Print some random example operations to stdout.
  221. */
  222. static void
  223. print_examples ()
  224. {
  225. print_examples_ecdh ();
  226. // print_examples_ecdsa ();
  227. // print_examples_eddsa ();
  228. }
  229. static void
  230. print_key (const char *filename)
  231. {
  232. struct GNUNET_DISK_FileHandle *fd;
  233. struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
  234. struct GNUNET_CRYPTO_EddsaPublicKey public_key;
  235. char *hostkeys_data;
  236. char *hostkey_str;
  237. uint64_t fs;
  238. unsigned int total_hostkeys;
  239. unsigned int c;
  240. ssize_t sret;
  241. if (GNUNET_YES != GNUNET_DISK_file_test (filename))
  242. {
  243. fprintf (stderr, _ ("Hostkeys file `%s' not found\n"), filename);
  244. return;
  245. }
  246. /* Check hostkey file size, read entire thing into memory */
  247. if (GNUNET_OK !=
  248. GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
  249. fs = 0;
  250. if (0 == fs)
  251. {
  252. fprintf (stderr, _ ("Hostkeys file `%s' is empty\n"), filename);
  253. return; /* File is empty */
  254. }
  255. if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
  256. {
  257. fprintf (stderr, _ ("Incorrect hostkey file format: %s\n"), filename);
  258. return;
  259. }
  260. fd = GNUNET_DISK_file_open (filename,
  261. GNUNET_DISK_OPEN_READ,
  262. GNUNET_DISK_PERM_NONE);
  263. if (NULL == fd)
  264. {
  265. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
  266. return;
  267. }
  268. hostkeys_data = GNUNET_malloc (fs);
  269. sret = GNUNET_DISK_file_read (fd, hostkeys_data, fs);
  270. if ((sret < 0) || (fs != (size_t) sret))
  271. {
  272. fprintf (stderr, _ ("Could not read hostkey file: %s\n"), filename);
  273. GNUNET_free (hostkeys_data);
  274. GNUNET_DISK_file_close (fd);
  275. return;
  276. }
  277. GNUNET_DISK_file_close (fd);
  278. if (NULL == hostkeys_data)
  279. return;
  280. total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
  281. for (c = 0; (c < total_hostkeys) && (c < list_keys_count); c++)
  282. {
  283. GNUNET_memcpy (&private_key,
  284. hostkeys_data + (c * GNUNET_TESTING_HOSTKEYFILESIZE),
  285. GNUNET_TESTING_HOSTKEYFILESIZE);
  286. GNUNET_CRYPTO_eddsa_key_get_public (&private_key, &public_key);
  287. hostkey_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&public_key);
  288. if (NULL != hostkey_str)
  289. {
  290. fprintf (stderr, "%4u: %s\n", c, hostkey_str);
  291. GNUNET_free (hostkey_str);
  292. }
  293. else
  294. fprintf (stderr, "%4u: %s\n", c, "invalid");
  295. }
  296. GNUNET_free (hostkeys_data);
  297. }
  298. /**
  299. * Main function that will be run by the scheduler.
  300. *
  301. * @param cls closure, NULL
  302. * @param args remaining command-line arguments
  303. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  304. * @param cfg configuration
  305. */
  306. static void
  307. run (void *cls,
  308. char *const *args,
  309. const char *cfgfile,
  310. const struct GNUNET_CONFIGURATION_Handle *cfg)
  311. {
  312. (void) cls;
  313. (void) cfgfile;
  314. (void) cfg;
  315. if (print_examples_flag)
  316. {
  317. print_examples ();
  318. return;
  319. }
  320. if (NULL == args[0])
  321. {
  322. fprintf (stderr, "%s", _ ("No hostkey file specified on command line\n"));
  323. return;
  324. }
  325. if (list_keys)
  326. {
  327. print_key (args[0]);
  328. return;
  329. }
  330. if (make_keys > 0)
  331. {
  332. create_keys (args[0], args[1]);
  333. return;
  334. }
  335. if (print_public_key || print_public_key_hex || print_private_key)
  336. {
  337. char *str;
  338. struct GNUNET_DISK_FileHandle *keyfile;
  339. struct GNUNET_CRYPTO_EddsaPrivateKey pk;
  340. struct GNUNET_CRYPTO_EddsaPublicKey pub;
  341. keyfile = GNUNET_DISK_file_open (args[0],
  342. GNUNET_DISK_OPEN_READ,
  343. GNUNET_DISK_PERM_NONE);
  344. if (NULL == keyfile)
  345. return;
  346. while (sizeof(pk) == GNUNET_DISK_file_read (keyfile, &pk, sizeof(pk)))
  347. {
  348. GNUNET_CRYPTO_eddsa_key_get_public (&pk, &pub);
  349. if (print_public_key_hex)
  350. {
  351. print_hex ("HEX:", &pub, sizeof(pub));
  352. }
  353. else if (print_public_key)
  354. {
  355. str = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
  356. fprintf (stdout, "%s\n", str);
  357. GNUNET_free (str);
  358. }
  359. else if (print_private_key)
  360. {
  361. str = GNUNET_CRYPTO_eddsa_private_key_to_string (&pk);
  362. fprintf (stdout, "%s\n", str);
  363. GNUNET_free (str);
  364. }
  365. }
  366. GNUNET_DISK_file_close (keyfile);
  367. }
  368. }
  369. /**
  370. * Program to manipulate ECC key files.
  371. *
  372. * @param argc number of arguments from the command line
  373. * @param argv command line arguments
  374. * @return 0 ok, 1 on error
  375. */
  376. int
  377. main (int argc, char *const *argv)
  378. {
  379. struct GNUNET_GETOPT_CommandLineOption options[] =
  380. { GNUNET_GETOPT_option_flag ('i',
  381. "iterate",
  382. gettext_noop (
  383. "list keys included in a file (for testing)"),
  384. &list_keys),
  385. GNUNET_GETOPT_option_uint (
  386. 'e',
  387. "end=",
  388. "COUNT",
  389. gettext_noop ("number of keys to list included in a file (for testing)"),
  390. &list_keys_count),
  391. GNUNET_GETOPT_option_uint (
  392. 'g',
  393. "generate-keys",
  394. "COUNT",
  395. gettext_noop ("create COUNT public-private key pairs (for testing)"),
  396. &make_keys),
  397. GNUNET_GETOPT_option_flag ('p',
  398. "print-public-key",
  399. gettext_noop (
  400. "print the public key in ASCII format"),
  401. &print_public_key),
  402. GNUNET_GETOPT_option_flag ('P',
  403. "print-private-key",
  404. gettext_noop (
  405. "print the private key in ASCII format"),
  406. &print_private_key),
  407. GNUNET_GETOPT_option_flag ('x',
  408. "print-hex",
  409. gettext_noop (
  410. "print the public key in HEX format"),
  411. &print_public_key_hex),
  412. GNUNET_GETOPT_option_flag (
  413. 'E',
  414. "examples",
  415. gettext_noop (
  416. "print examples of ECC operations (used for compatibility testing)"),
  417. &print_examples_flag),
  418. GNUNET_GETOPT_OPTION_END };
  419. int ret;
  420. list_keys_count = UINT32_MAX;
  421. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  422. return 2;
  423. ret = (GNUNET_OK ==
  424. GNUNET_PROGRAM_run (argc,
  425. argv,
  426. "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]",
  427. gettext_noop (
  428. "Manipulate GNUnet private ECC key files"),
  429. options,
  430. &run,
  431. NULL))
  432. ? 0
  433. : 1;
  434. GNUNET_free ((void *) argv);
  435. return ret;
  436. }
  437. /* end of gnunet-ecc.c */