gnunet-ecc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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. GNUNET_CRYPTO_eddsa_key_create (&pk);
  127. if (NULL != prefix)
  128. {
  129. struct GNUNET_CRYPTO_EddsaPublicKey newkey;
  130. GNUNET_CRYPTO_eddsa_key_get_public (&pk,
  131. &newkey);
  132. if (0 != memcmp (&target_pub,
  133. &newkey,
  134. n))
  135. {
  136. make_keys++;
  137. continue;
  138. }
  139. if (0 != rest)
  140. {
  141. unsigned char new_byte;
  142. new_byte = ((unsigned char *) &newkey)[n] & mask;
  143. if (target_byte != new_byte)
  144. {
  145. make_keys++;
  146. continue;
  147. }
  148. }
  149. }
  150. if (GNUNET_TESTING_HOSTKEYFILESIZE !=
  151. fwrite (&pk,
  152. 1,
  153. GNUNET_TESTING_HOSTKEYFILESIZE,
  154. f))
  155. {
  156. fprintf (stderr,
  157. _ ("\nFailed to write to `%s': %s\n"),
  158. fn,
  159. strerror (errno));
  160. break;
  161. }
  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 (void)
  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. GNUNET_CRYPTO_ecdhe_key_create (&dh_priv1);
  189. GNUNET_CRYPTO_ecdhe_key_create (&dh_priv2);
  190. GNUNET_CRYPTO_ecdhe_key_get_public (&dh_priv1,
  191. &dh_pub1);
  192. GNUNET_CRYPTO_ecdhe_key_get_public (&dh_priv2,
  193. &dh_pub2);
  194. GNUNET_assert (NULL !=
  195. GNUNET_STRINGS_data_to_string (&dh_priv1,
  196. sizeof (dh_priv1),
  197. buf,
  198. sizeof (buf)));
  199. printf ("ECDHE key 1:\n");
  200. printf ("private: %s\n",
  201. buf);
  202. print_hex ("private(hex)",
  203. &dh_priv1, sizeof (dh_priv1));
  204. GNUNET_assert (NULL !=
  205. GNUNET_STRINGS_data_to_string (&dh_pub1,
  206. sizeof (dh_pub1),
  207. buf,
  208. sizeof (buf)));
  209. printf ("public: %s\n",
  210. buf);
  211. print_hex ("public(hex)",
  212. &dh_pub1,
  213. sizeof (dh_pub1));
  214. GNUNET_assert (NULL !=
  215. GNUNET_STRINGS_data_to_string (&dh_priv2,
  216. sizeof (dh_priv2),
  217. buf,
  218. sizeof (buf)));
  219. printf ("ECDHE key 2:\n");
  220. printf ("private: %s\n", buf);
  221. print_hex ("private(hex)",
  222. &dh_priv2,
  223. sizeof (dh_priv2));
  224. GNUNET_assert (NULL !=
  225. GNUNET_STRINGS_data_to_string (&dh_pub2,
  226. sizeof (dh_pub2),
  227. buf,
  228. sizeof (buf)));
  229. printf ("public: %s\n", buf);
  230. print_hex ("public(hex)",
  231. &dh_pub2,
  232. sizeof (dh_pub2));
  233. GNUNET_assert (GNUNET_OK ==
  234. GNUNET_CRYPTO_ecc_ecdh (&dh_priv1,
  235. &dh_pub2,
  236. &hash));
  237. GNUNET_assert (NULL !=
  238. GNUNET_STRINGS_data_to_string (&hash,
  239. sizeof (hash),
  240. buf,
  241. sizeof (buf)));
  242. printf ("ECDH shared secret: %s\n",
  243. buf);
  244. }
  245. /**
  246. * Print some random example operations to stdout.
  247. */
  248. static void
  249. print_examples (void)
  250. {
  251. print_examples_ecdh ();
  252. // print_examples_ecdsa ();
  253. // print_examples_eddsa ();
  254. }
  255. static void
  256. print_key (const char *filename)
  257. {
  258. struct GNUNET_DISK_FileHandle *fd;
  259. struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
  260. struct GNUNET_CRYPTO_EddsaPublicKey public_key;
  261. char *hostkeys_data;
  262. char *hostkey_str;
  263. uint64_t fs;
  264. unsigned int total_hostkeys;
  265. unsigned int c;
  266. ssize_t sret;
  267. if (GNUNET_YES != GNUNET_DISK_file_test (filename))
  268. {
  269. fprintf (stderr, _ ("Hostkeys file `%s' not found\n"), filename);
  270. return;
  271. }
  272. /* Check hostkey file size, read entire thing into memory */
  273. if (GNUNET_OK !=
  274. GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
  275. fs = 0;
  276. if (0 == fs)
  277. {
  278. fprintf (stderr, _ ("Hostkeys file `%s' is empty\n"), filename);
  279. return; /* File is empty */
  280. }
  281. if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
  282. {
  283. fprintf (stderr, _ ("Incorrect hostkey file format: %s\n"), filename);
  284. return;
  285. }
  286. fd = GNUNET_DISK_file_open (filename,
  287. GNUNET_DISK_OPEN_READ,
  288. GNUNET_DISK_PERM_NONE);
  289. if (NULL == fd)
  290. {
  291. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
  292. return;
  293. }
  294. hostkeys_data = GNUNET_malloc (fs);
  295. sret = GNUNET_DISK_file_read (fd, hostkeys_data, fs);
  296. if ((sret < 0) || (fs != (size_t) sret))
  297. {
  298. fprintf (stderr, _ ("Could not read hostkey file: %s\n"), filename);
  299. GNUNET_free (hostkeys_data);
  300. GNUNET_DISK_file_close (fd);
  301. return;
  302. }
  303. GNUNET_DISK_file_close (fd);
  304. if (NULL == hostkeys_data)
  305. return;
  306. total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
  307. for (c = 0; (c < total_hostkeys) && (c < list_keys_count); c++)
  308. {
  309. GNUNET_memcpy (&private_key,
  310. hostkeys_data + (c * GNUNET_TESTING_HOSTKEYFILESIZE),
  311. GNUNET_TESTING_HOSTKEYFILESIZE);
  312. GNUNET_CRYPTO_eddsa_key_get_public (&private_key, &public_key);
  313. hostkey_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&public_key);
  314. if (NULL != hostkey_str)
  315. {
  316. fprintf (stderr, "%4u: %s\n", c, hostkey_str);
  317. GNUNET_free (hostkey_str);
  318. }
  319. else
  320. fprintf (stderr, "%4u: %s\n", c, "invalid");
  321. }
  322. GNUNET_free (hostkeys_data);
  323. }
  324. /**
  325. * Main function that will be run by the scheduler.
  326. *
  327. * @param cls closure, NULL
  328. * @param args remaining command-line arguments
  329. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  330. * @param cfg configuration
  331. */
  332. static void
  333. run (void *cls,
  334. char *const *args,
  335. const char *cfgfile,
  336. const struct GNUNET_CONFIGURATION_Handle *cfg)
  337. {
  338. (void) cls;
  339. (void) cfgfile;
  340. (void) cfg;
  341. if (print_examples_flag)
  342. {
  343. print_examples ();
  344. return;
  345. }
  346. if (NULL == args[0])
  347. {
  348. fprintf (stderr, "%s", _ ("No hostkey file specified on command line\n"));
  349. return;
  350. }
  351. if (list_keys)
  352. {
  353. print_key (args[0]);
  354. return;
  355. }
  356. if (make_keys > 0)
  357. {
  358. create_keys (args[0], args[1]);
  359. return;
  360. }
  361. if (print_public_key || print_public_key_hex || print_private_key)
  362. {
  363. char *str;
  364. struct GNUNET_DISK_FileHandle *keyfile;
  365. struct GNUNET_CRYPTO_EddsaPrivateKey pk;
  366. struct GNUNET_CRYPTO_EddsaPublicKey pub;
  367. keyfile = GNUNET_DISK_file_open (args[0],
  368. GNUNET_DISK_OPEN_READ,
  369. GNUNET_DISK_PERM_NONE);
  370. if (NULL == keyfile)
  371. return;
  372. while (sizeof(pk) == GNUNET_DISK_file_read (keyfile, &pk, sizeof(pk)))
  373. {
  374. GNUNET_CRYPTO_eddsa_key_get_public (&pk, &pub);
  375. if (print_public_key_hex)
  376. {
  377. print_hex ("HEX:", &pub, sizeof(pub));
  378. }
  379. else if (print_public_key)
  380. {
  381. str = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
  382. fprintf (stdout, "%s\n", str);
  383. GNUNET_free (str);
  384. }
  385. else if (print_private_key)
  386. {
  387. str = GNUNET_CRYPTO_eddsa_private_key_to_string (&pk);
  388. fprintf (stdout, "%s\n", str);
  389. GNUNET_free (str);
  390. }
  391. }
  392. GNUNET_DISK_file_close (keyfile);
  393. }
  394. }
  395. /**
  396. * Program to manipulate ECC key files.
  397. *
  398. * @param argc number of arguments from the command line
  399. * @param argv command line arguments
  400. * @return 0 ok, 1 on error
  401. */
  402. int
  403. main (int argc, char *const *argv)
  404. {
  405. struct GNUNET_GETOPT_CommandLineOption options[] =
  406. { GNUNET_GETOPT_option_flag ('i',
  407. "iterate",
  408. gettext_noop (
  409. "list keys included in a file (for testing)"),
  410. &list_keys),
  411. GNUNET_GETOPT_option_uint (
  412. 'e',
  413. "end=",
  414. "COUNT",
  415. gettext_noop ("number of keys to list included in a file (for testing)"),
  416. &list_keys_count),
  417. GNUNET_GETOPT_option_uint (
  418. 'g',
  419. "generate-keys",
  420. "COUNT",
  421. gettext_noop ("create COUNT public-private key pairs (for testing)"),
  422. &make_keys),
  423. GNUNET_GETOPT_option_flag ('p',
  424. "print-public-key",
  425. gettext_noop (
  426. "print the public key in ASCII format"),
  427. &print_public_key),
  428. GNUNET_GETOPT_option_flag ('P',
  429. "print-private-key",
  430. gettext_noop (
  431. "print the private key in ASCII format"),
  432. &print_private_key),
  433. GNUNET_GETOPT_option_flag ('x',
  434. "print-hex",
  435. gettext_noop (
  436. "print the public key in HEX format"),
  437. &print_public_key_hex),
  438. GNUNET_GETOPT_option_flag (
  439. 'E',
  440. "examples",
  441. gettext_noop (
  442. "print examples of ECC operations (used for compatibility testing)"),
  443. &print_examples_flag),
  444. GNUNET_GETOPT_OPTION_END };
  445. int ret;
  446. list_keys_count = UINT32_MAX;
  447. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  448. return 2;
  449. ret = (GNUNET_OK ==
  450. GNUNET_PROGRAM_run (argc,
  451. argv,
  452. "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]",
  453. gettext_noop (
  454. "Manipulate GNUnet private ECC key files"),
  455. options,
  456. &run,
  457. NULL))
  458. ? 0
  459. : 1;
  460. GNUNET_free_nz ((void *) argv);
  461. return ret;
  462. }
  463. /* end of gnunet-ecc.c */