xref: /netbsd-src/usr.sbin/wg-keygen/wg-keygen.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
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@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