1/*- 2 * Copyright (c) 1991, 1993 3 * Dave Safford. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31#include <sys/cdefs.h> 32 33#ifdef notdef 34__FBSDID("$FreeBSD: src/contrib/telnet/libtelnet/pk.c,v 1.10 2002/08/22 06:19:07 nsayer Exp $"); 35#else 36__RCSID("$NetBSD: pk.c,v 1.3 2005/02/19 22:47:51 christos Exp $"); 37#endif 38 39/* public key routines */ 40/* functions: 41 genkeys(char *public, char *secret) 42 common_key(char *secret, char *public, desData *deskey) 43 pk_encode(char *in, *out, DesData *deskey); 44 pk_decode(char *in, *out, DesData *deskey); 45 where 46 char public[HEXKEYBYTES + 1]; 47 char secret[HEXKEYBYTES + 1]; 48 */ 49 50#include <sys/time.h> 51#include <des.h> 52#include <openssl/bn.h> 53#include <fcntl.h> 54#include <stdio.h> 55#include <stdlib.h> 56#include <string.h> 57 58#include "pk.h" 59 60static void adjust(char *, const char *); 61 62/* 63 * Choose top 128 bits of the common key to use as our idea key. 64 */ 65static void 66extractideakey(BIGNUM *ck, IdeaData *ideakey) 67{ 68 BIGNUM *a = BN_new(); 69 BIGNUM *z = BN_new(); 70 BIGNUM *base = BN_new(); 71 BN_CTX *ctx = BN_CTX_new(); 72 size_t i; 73 char *k; 74 75 (void)BN_zero(a); 76 (void)BN_zero(z); 77 (void)BN_set_word(base, 1 << 8); 78 BN_add(a, ck, z); 79 80 for (i = 0; i < ((KEYSIZE - 128) / 8); i++) 81 BN_div(a, z, a, base, ctx); 82 83 k = (char *)(void *)ideakey; 84 for (i = 0; i < 16; i++) { 85 BN_div(a, z, a, base, ctx); 86 *k++ = (char)BN_get_word(z); 87 } 88 89 BN_CTX_free(ctx); 90 BN_free(base); 91 BN_free(z); 92 BN_free(a); 93} 94 95/* 96 * Choose middle 64 bits of the common key to use as our des key, possibly 97 * overwriting the lower order bits by setting parity. 98 */ 99static void 100extractdeskey(BIGNUM *ck, DesData *deskey) 101{ 102 BIGNUM *a = BN_new(); 103 BIGNUM *z = BN_new(); 104 BIGNUM *base = BN_new(); 105 BN_CTX *ctx = BN_CTX_new(); 106 size_t i; 107 char *k; 108 109 (void)BN_zero(z); 110 (void)BN_zero(a); 111 (void)BN_set_word(base, 1 << 8); 112 BN_add(a, ck, z); 113 114 for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) 115 BN_div(a, z, a, base, ctx); 116 117 k = (char *)deskey; 118 for (i = 0; i < 8; i++) { 119 BN_div(a, z, a, base, ctx); 120 *k++ = (char)BN_get_word(z); 121 } 122 123 BN_CTX_free(ctx); 124 BN_free(base); 125 BN_free(z); 126 BN_free(a); 127} 128 129/* 130 * get common key from my secret key and his public key 131 */ 132void 133common_key(char *xsecret, char *xpublic, IdeaData *ideakey, DesData *deskey) 134{ 135 BIGNUM *public = BN_new(); 136 BIGNUM *secret = BN_new(); 137 BIGNUM *common = BN_new(); 138 BIGNUM *modulus = BN_new(); 139 BN_CTX *ctx = BN_CTX_new(); 140 141 (void)BN_hex2bn(&modulus, HEXMODULUS); 142 (void)BN_hex2bn(&public, xpublic); 143 (void)BN_hex2bn(&secret, xsecret); 144 (void)BN_zero(common); 145 146 BN_mod_exp(common, public, secret, modulus, ctx); 147 extractdeskey(common, deskey); 148 extractideakey(common, ideakey); 149 des_set_odd_parity(deskey); 150 151 BN_CTX_free(ctx); 152 BN_free(common); 153 BN_free(secret); 154 BN_free(public); 155 BN_free(modulus); 156} 157 158/* 159 * Generate a seed 160 */ 161static void 162getseed(char *seed, size_t seedsize) 163{ 164 size_t i; 165 166 for (i = 0; i < seedsize; i++) 167 seed[i] = arc4random() & 0xff; 168} 169 170/* 171 * Generate a random public/secret key pair 172 */ 173void 174genkeys(char *public, char *secret) 175{ 176 size_t i; 177 178# define BASEBITS (8 * sizeof(short) - 1) 179# define BASE (1 << BASEBITS) 180 181 BIGNUM *pk = BN_new(); 182 BIGNUM *sk = BN_new(); 183 BIGNUM *tmp = BN_new(); 184 BIGNUM *base = BN_new(); 185 BIGNUM *root = BN_new(); 186 BIGNUM *modulus = BN_new(); 187 BN_CTX *ctx = BN_CTX_new(); 188 short r; 189 unsigned short seed[KEYSIZE/BASEBITS + 1]; 190 char *xkey; 191 192 (void)BN_zero(pk); 193 (void)BN_zero(sk); 194 (void)BN_set_word(base, BASE); 195 (void)BN_set_word(root, PROOT); 196 (void)BN_hex2bn(&modulus, HEXMODULUS); 197 198 getseed((char *)seed, sizeof(seed)); 199 for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) { 200 r = seed[i] % BASE; 201 (void)BN_set_word(tmp, r); 202 BN_mul(sk, tmp, sk, ctx); 203 BN_add(sk, tmp, sk); 204 } 205 206 (void)BN_zero(tmp); 207 BN_div(tmp, sk, sk, modulus, ctx); 208 BN_mod_exp(pk, root, sk, modulus, ctx); 209 210 xkey = BN_bn2hex(sk); 211 adjust(secret, xkey); 212 xkey = BN_bn2hex(pk); 213 adjust(public, xkey); 214 215 BN_CTX_free(ctx); 216 BN_free(sk); 217 BN_free(base); 218 BN_free(pk); 219 BN_free(tmp); 220 BN_free(root); 221 BN_free(modulus); 222} 223 224/* 225 * Adjust the input key so that it is 0-filled on the left 226 */ 227static void 228adjust(char *keyout, const char *keyin) 229{ 230 const char *p; 231 char *s; 232 233 for (p = keyin; *p; p++) 234 continue; 235 for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) 236 *s = *p; 237 while (s >= keyout) 238 *s-- = '0'; 239} 240 241static const char hextab[] = "0123456789ABCDEF"; 242 243/* given a DES key, cbc encrypt and translate input to terminated hex */ 244void 245pk_encode(const char *in, char *out, DesData *key) 246{ 247 char buf[256]; 248 DesData i; 249 des_key_schedule k; 250 size_t l, op, deslen; 251 252 (void)memset(&i, 0, sizeof(i)); 253 (void)memset(buf, 0, sizeof(buf)); 254 deslen = ((strlen(in) + 7) / 8) * 8; 255 des_key_sched(key, k); 256 des_cbc_encrypt(in, buf, deslen, k, &i, DES_ENCRYPT); 257 for (l = 0, op = 0; l < deslen; l++) { 258 out[op++] = hextab[(buf[l] & 0xf0) >> 4]; 259 out[op++] = hextab[(buf[l] & 0x0f)]; 260 } 261 out[op] = '\0'; 262} 263 264/* given a DES key, translate input from hex and decrypt */ 265void 266pk_decode(const char *in, char *out, DesData *key) 267{ 268 char buf[256]; 269 DesData i; 270 des_key_schedule k; 271 int n1, n2, op; 272 size_t l; 273 size_t len = strlen(in) / 2; 274 275 (void)memset(&i, 0, sizeof(i)); 276 (void)memset(buf, 0, sizeof(buf)); 277 278 for (l = 0, op = 0; l < len; l++, op += 2) { 279 if (in[op] > '9') 280 n1 = in[op] - 'A' + 10; 281 else 282 n1 = in[op] - '0'; 283 if (in[op + 1] > '9') 284 n2 = in[op + 1] - 'A' + 10; 285 else 286 n2 = in[op + 1] - '0'; 287 buf[l] = (char)(n1 * 16 + n2); 288 } 289 des_key_sched(key, k); 290 des_cbc_encrypt(buf, out, len, k, &i, DES_DECRYPT); 291 out[len] = '\0'; 292} 293