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 45usage(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 59extern int crypto_scalarmult_curve25519(uint8_t [CURVE25519_SIZE], 60 const uint8_t [CURVE25519_SIZE], const uint8_t [CURVE25519_SIZE]); 61 62static void 63gen_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 70static void 71normalize_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 80static char * 81base64(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 94int 95main(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