Home | History | Annotate | Line # | Download | only in wg-keygen
wg-keygen.c revision 1.1
      1 /*	$NetBSD: wg-keygen.c,v 1.1 2020/08/20 21:28:02 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Ryota Ozaki <ozaki.ryota (at) gmail.com>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the project nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __RCSID("$NetBSD: wg-keygen.c,v 1.1 2020/08/20 21:28:02 riastradh Exp $");
     34 
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <err.h>
     38 #include <resolv.h>
     39 #include <string.h>
     40 
     41 #define KEY_LEN			32
     42 #define KEY_BASE64_LEN		44
     43 
     44 __dead static void
     45 usage(void)
     46 {
     47 	const char *progname = getprogname();
     48 
     49 	fprintf(stderr, "Usage:\n");
     50 	fprintf(stderr, "\t%s       : Generate a private key\n", progname);
     51 	fprintf(stderr, "\t%s --pub : Generate a public key from a private key via stdin\n", progname);
     52 	fprintf(stderr, "\t%s --psk : Generate a pre-shared key\n", progname);
     53 
     54 	exit(EXIT_FAILURE);
     55 }
     56 
     57 /* Mimic crypto/external/bsd/openssh/dist/kexc25519.c */
     58 #define CURVE25519_SIZE	32
     59 extern int crypto_scalarmult_curve25519(uint8_t [CURVE25519_SIZE],
     60     const uint8_t [CURVE25519_SIZE], const uint8_t [CURVE25519_SIZE]);
     61 
     62 static void
     63 gen_pubkey(uint8_t key[CURVE25519_SIZE], uint8_t pubkey[CURVE25519_SIZE])
     64 {
     65 	static const uint8_t basepoint[CURVE25519_SIZE] = {9};
     66 
     67 	crypto_scalarmult_curve25519(pubkey, key, basepoint);
     68 }
     69 
     70 static void
     71 normalize_key(uint8_t key[KEY_LEN])
     72 {
     73 
     74 	/* Mimic the official implementation, wg */
     75 	key[0] &= 248;
     76 	key[31] &= 127;
     77 	key[31] |= 64;
     78 }
     79 
     80 static char *
     81 base64(uint8_t key[KEY_LEN])
     82 {
     83 	static char key_b64[KEY_BASE64_LEN + 1];
     84 	int error;
     85 
     86 	error = b64_ntop(key, KEY_LEN, key_b64, KEY_BASE64_LEN + 1);
     87 	if (error == -1)
     88 		errx(EXIT_FAILURE, "b64_ntop failed");
     89 	key_b64[KEY_BASE64_LEN] = '\0'; /* just in case */
     90 
     91 	return key_b64;
     92 }
     93 
     94 int
     95 main(int argc, char *argv[])
     96 {
     97 	uint8_t key[KEY_LEN];
     98 
     99 	if (!(argc == 1 || argc == 2))
    100 		usage();
    101 
    102 	if (argc == 1) {
    103 		arc4random_buf(key, KEY_LEN);
    104 		normalize_key(key);
    105 		printf("%s\n", base64(key));
    106 		return 0;
    107 	}
    108 
    109 	if (strcmp(argv[1], "--psk") == 0) {
    110 		arc4random_buf(key, KEY_LEN);
    111 		printf("%s\n", base64(key));
    112 		return 0;
    113 	}
    114 
    115 	if (strcmp(argv[1], "--pub") == 0) {
    116 		char key_b64[KEY_BASE64_LEN + 1];
    117 		int ret;
    118 		char *retc;
    119 		uint8_t pubkey[KEY_LEN];
    120 
    121 		retc = fgets(key_b64, KEY_BASE64_LEN + 1, stdin);
    122 		if (retc == NULL)
    123 			err(EXIT_FAILURE, "fgets");
    124 		key_b64[KEY_BASE64_LEN] = '\0';
    125 		if (strlen(key_b64) != KEY_BASE64_LEN)
    126 			errx(EXIT_FAILURE, "Invalid length of a private key");
    127 		ret = b64_pton(key_b64, key, KEY_LEN);
    128 		if (ret == -1)
    129 			errx(EXIT_FAILURE, "b64_pton failed");
    130 		gen_pubkey(key, pubkey);
    131 		printf("%s\n", base64(pubkey));
    132 		return 0;
    133 	}
    134 
    135 	usage();
    136 }
    137