Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / lib / libskey / skeysubr.c
blob7ec25bdf0c84ca495e34d3fce3bb443a93a98960
1 /* $NetBSD: skeysubr.c,v 1.25 2005/12/05 02:07:07 christos Exp $ */
3 /* S/KEY v1.1b (skeysubr.c)
5 * Authors:
6 * Neil M. Haller <nmh@thumper.bellcore.com>
7 * Philip R. Karn <karn@chicago.qualcomm.com>
8 * John S. Walden <jsw@thumper.bellcore.com>
10 * Modifications:
11 * Scott Chasin <chasin@crimelab.com>
12 * Todd C. Miller <Todd.Miller@courtesan.com>
14 * S/KEY misc routines.
17 #include <sys/cdefs.h>
18 __RCSID("$NetBSD: skeysubr.c,v 1.25 2005/12/05 02:07:07 christos Exp $");
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <termios.h>
27 #include <md4.h>
28 #include <md5.h>
29 #include <sys/rmd160.h>
30 #include <sha1.h>
32 #include "skey.h"
34 /* Default hash function to use (index into skey_hash_types array) */
35 #ifndef SKEY_HASH_DEFAULT
36 #define SKEY_HASH_DEFAULT 0 /* MD4 */
37 #endif
39 static void f_md4(char *);
40 static void f_md5(char *);
41 static void f_sha1(char *);
42 /* static void f_rmd160(char *x); */
43 static int keycrunch_md4(char *, const char *, const char *);
44 static int keycrunch_md5(char *, const char *, const char *);
45 static int keycrunch_sha1(char *, const char *, const char *);
46 /* static int keycrunch_rmd160(char *, const char *, const char *); */
47 static void lowcase(char *);
48 static void skey_echo(int);
49 static void trapped(int);
50 static char *mkSeedPassword(const char *, const char *, size_t *);
52 /* Current hash type (index into skey_hash_types array) */
53 static int skey_hash_type = SKEY_HASH_DEFAULT;
56 * Hash types we support.
57 * Each has an associated keycrunch() and f() function.
60 struct skey_algorithm_table {
61 const char *name;
62 int (*keycrunch)(char *, const char *, const char *);
63 void (*f)(char *);
65 static struct skey_algorithm_table skey_algorithm_table[] = {
66 { "md4", keycrunch_md4, f_md4 },
67 { "md5", keycrunch_md5, f_md5 },
68 { "sha1", keycrunch_sha1, f_sha1 },
69 #if 0
70 { "rmd160", keycrunch_rmd160, f_rmd160 },
71 #endif
72 { NULL }
76 * Crunch a key:
77 * concatenate the (lower cased) seed and the password, run through
78 * the hash algorithm and collapse to 64 bits.
79 * This is defined as the user's starting key.
81 int keycrunch(char *result, /* SKEY_BINKEY_SIZE result */
82 const char *seed, /* Seed, any length */
83 const char *passwd) /* Password, any length */
85 return(skey_algorithm_table[skey_hash_type].keycrunch(result, seed, passwd));
88 static char *mkSeedPassword(const char *seed, const char *passwd,
89 size_t *buflen)
91 char *buf;
93 *buflen = strlen(seed) + strlen(passwd);
94 if ((buf = (char *) malloc(*buflen + 1)) == NULL)
95 return NULL;
96 strcpy(buf, seed);
97 lowcase(buf);
98 strcat(buf, passwd);
99 sevenbit(buf);
101 return buf;
104 static int keycrunch_md4(char *result, /* SKEY_BINKEY_SIZE result */
105 const char *seed, /* Seed, any length */
106 const char *passwd) /* Password, any length */
108 char *buf;
109 MD4_CTX md;
110 size_t buflen;
111 u_int32_t results[4];
113 if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
114 return -1;
116 /* Crunch the key through MD4 */
117 MD4Init(&md);
118 MD4Update(&md, (unsigned char *) buf, buflen);
119 MD4Final((unsigned char *) (void *) results, &md);
120 free(buf);
122 /* Fold result from 128 to 64 bits */
123 results[0] ^= results[2];
124 results[1] ^= results[3];
126 (void)memcpy(result, results, SKEY_BINKEY_SIZE);
128 return 0;
131 static int keycrunch_md5(char *result, /* SKEY_BINKEY_SIZE result */
132 const char *seed, /* Seed, any length */
133 const char *passwd) /* Password, any length */
135 char *buf;
136 MD5_CTX md;
137 u_int32_t results[4];
138 size_t buflen;
140 if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
141 return -1;
143 /* Crunch the key through MD5 */
144 MD5Init(&md);
145 MD5Update(&md, (unsigned char *)buf, buflen);
146 MD5Final((unsigned char *) (void *)results, &md);
147 free(buf);
149 /* Fold result from 128 to 64 bits */
150 results[0] ^= results[2];
151 results[1] ^= results[3];
153 (void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE);
155 return(0);
158 static int keycrunch_sha1(char *result, /* SKEY_BINKEY_SIZE result */
159 const char *seed, /* Seed, any length */
160 const char *passwd) /* Password, any length */
162 char *buf;
163 SHA1_CTX sha;
164 size_t buflen;
165 int i, j;
167 if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
168 return -1;
170 /* Crunch the key through SHA1 */
171 SHA1Init(&sha);
172 SHA1Update(&sha, (unsigned char *)buf, buflen);
173 SHA1Final(NULL, &sha);
174 free(buf);
176 /* Fold 160 to 64 bits */
177 sha.state[0] ^= sha.state[2];
178 sha.state[1] ^= sha.state[3];
179 sha.state[0] ^= sha.state[4];
182 * SHA1 is a big endian algorithm but RFC2289 mandates that
183 * the result be in little endian form, so we copy to the
184 * result buffer manually.
187 for(i=j=0; j<8; i++, j+=4) {
188 result[j] = (unsigned char)(sha.state[i] & 0xff);
189 result[j+1] = (unsigned char)((sha.state[i] >> 8) & 0xff);
190 result[j+2] = (unsigned char)((sha.state[i] >> 16) & 0xff);
191 result[j+3] = (unsigned char)((sha.state[i] >> 24) & 0xff);
194 return(0);
197 #if 0
198 static int keycrunch_rmd160(char *result, /* SKEY_BINKEY_SIZE result */
199 const char *seed, /* Seed, any length */
200 const char *passwd) /* Password, any length */
202 char *buf;
203 RMD160_CTX rmd;
204 u_int32_t results[5];
205 size_t buflen;
207 if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
208 return -1;
210 /* Crunch the key through RMD-160 */
211 RMD160Init(&rmd);
212 RMD160Update(&rmd, (unsigned char *)buf, buflen);
213 RMD160Final((unsigned char *)(void *)results, &rmd);
214 free(buf);
216 /* Fold 160 to 64 bits */
217 results[0] ^= results[2];
218 results[1] ^= results[3];
219 results[0] ^= results[4];
221 (void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE);
223 return(0);
225 #endif
227 /* The one-way function f(). Takes 8 bytes and returns 8 bytes in place */
228 void f(char *x)
230 skey_algorithm_table[skey_hash_type].f(x);
233 static void f_md4(char *x)
235 MD4_CTX md;
236 u_int32_t results[4];
238 MD4Init(&md);
239 MD4Update(&md, (unsigned char *) x, SKEY_BINKEY_SIZE);
240 MD4Final((unsigned char *) (void *) results, &md);
242 /* Fold 128 to 64 bits */
243 results[0] ^= results[2];
244 results[1] ^= results[3];
246 (void)memcpy(x, results, SKEY_BINKEY_SIZE);
249 static void f_md5(char *x)
251 MD5_CTX md;
252 u_int32_t results[4];
254 MD5Init(&md);
255 MD5Update(&md, (unsigned char *)x, SKEY_BINKEY_SIZE);
256 MD5Final((unsigned char *) (void *)results, &md);
258 /* Fold 128 to 64 bits */
259 results[0] ^= results[2];
260 results[1] ^= results[3];
262 (void)memcpy((void *)x, (void *)results, SKEY_BINKEY_SIZE);
265 static void f_sha1(char *x)
267 SHA1_CTX sha;
268 int i, j;
270 SHA1Init(&sha);
271 SHA1Update(&sha, (unsigned char *)x, SKEY_BINKEY_SIZE);
272 SHA1Final(NULL, &sha);
274 /* Fold 160 to 64 bits */
275 sha.state[0] ^= sha.state[2];
276 sha.state[1] ^= sha.state[3];
277 sha.state[0] ^= sha.state[4];
279 for(i=j=0; j<8; i++, j+=4) {
280 x[j] = (unsigned char)(sha.state[i] & 0xff);
281 x[j+1] = (unsigned char)((sha.state[i] >> 8) & 0xff);
282 x[j+2] = (unsigned char)((sha.state[i] >> 16) & 0xff);
283 x[j+3] = (unsigned char)((sha.state[i] >> 24) & 0xff);
287 #if 0
288 static void f_rmd160(char *x)
290 RMD160_CTX rmd;
291 u_int32_t results[5];
293 RMD160Init(&rmd);
294 RMD160Update(&rmd, (unsigned char *)x, SKEY_BINKEY_SIZE);
295 RMD160Final((unsigned char *)(void *)results, &rmd);
297 /* Fold 160 to 64 bits */
298 results[0] ^= results[2];
299 results[1] ^= results[3];
300 results[0] ^= results[4];
302 (void)memcpy((void *)x, (void *)results, SKEY_BINKEY_SIZE);
304 #endif
306 /* Strip trailing cr/lf from a line of text */
307 void rip(char *buf)
309 buf += strcspn(buf, "\r\n");
311 if (*buf)
312 *buf = '\0';
315 /* Read in secret password (turns off echo) */
316 char *readpass(char *buf, int n)
318 void *old_handler;
320 /* Turn off echoing */
321 skey_echo(0);
323 /* Catch SIGINT and save old signal handler */
324 old_handler = signal(SIGINT, trapped);
326 fgets(buf, n, stdin);
327 rip(buf);
329 putc('\n', stderr);
330 fflush(stderr);
332 /* Restore signal handler and turn echo back on */
333 if (old_handler != SIG_ERR)
334 (void)signal(SIGINT, old_handler);
335 skey_echo(1);
337 sevenbit(buf);
339 return buf;
342 /* Read in an s/key OTP (does not turn off echo) */
343 char *readskey(char *buf, int n)
345 fgets(buf, n, stdin);
347 rip(buf);
349 sevenbit (buf);
351 return buf;
354 /* Signal handler for trapping ^C */
355 /*ARGSUSED*/
356 static void trapped(int sig)
358 fputs("^C\n", stderr);
359 fflush(stderr);
361 /* Turn on echo if necessary */
362 skey_echo(1);
364 exit(1);
368 * Convert 8-byte hex-ascii string to binary array
369 * Returns 0 on success, -1 on error
371 int atob8(char *out, const char *in)
373 int i;
374 int val;
376 if (in == NULL || out == NULL)
377 return -1;
379 for (i=0; i<8; i++) {
380 if ((in = skipspace(in)) == NULL)
381 return -1;
382 if ((val = htoi(*in++)) == -1)
383 return -1;
384 *out = val << 4;
386 if ((in = skipspace(in)) == NULL)
387 return -1;
388 if ((val = htoi(*in++)) == -1)
389 return -1;
390 *out++ |= val;
392 return 0;
395 /* Convert 8-byte binary array to hex-ascii string */
396 int btoa8(char *out, const char *in)
398 int i;
400 if (in == NULL || out == NULL)
401 return -1;
403 for (i=0;i<8;i++) {
404 sprintf(out, "%02x", *in++ & 0xff);
405 out += 2;
407 return 0;
411 /* Convert hex digit to binary integer */
412 int htoi(int c)
414 if ('0' <= c && c <= '9')
415 return c - '0';
416 if ('a' <= c && c <= 'f')
417 return 10 + c - 'a';
418 if ('A' <= c && c <= 'F')
419 return 10 + c - 'A';
420 return -1;
423 /* Skip leading spaces from the string */
424 const char *skipspace(const char *cp)
426 while (*cp == ' ' || *cp == '\t')
427 cp++;
429 if (*cp == '\0')
430 return NULL;
431 else
432 return cp;
435 /* Remove backspaced over charaters from the string */
436 void backspace(char *buf)
438 char bs = 0x8;
439 char *cp = buf;
440 char *out = buf;
442 while (*cp) {
443 if (*cp == bs) {
444 if (out == buf) {
445 cp++;
446 continue;
447 } else {
448 cp++;
449 out--;
451 } else {
452 *out++ = *cp++;
456 *out = '\0';
459 /* Make sure line is all seven bits */
460 void sevenbit(char *s)
462 while (*s)
463 *s++ &= 0x7f;
466 /* Set hash algorithm type */
467 const char *skey_set_algorithm(const char *new)
469 int i;
471 for (i = 0; skey_algorithm_table[i].name; i++) {
472 if (strcmp(new, skey_algorithm_table[i].name) == 0) {
473 skey_hash_type = i;
474 return(new);
478 return(NULL);
481 /* Get current hash type */
482 const char *skey_get_algorithm()
484 return(skey_algorithm_table[skey_hash_type].name);
487 /* Turn echo on/off */
488 static void skey_echo(int action)
490 static struct termios term;
491 static int echo = 0;
493 if (action == 0) {
494 /* Turn echo off */
495 (void) tcgetattr(fileno(stdin), &term);
496 if ((echo = (term.c_lflag & ECHO)) != 0) {
497 term.c_lflag &= ~ECHO;
498 (void) tcsetattr(fileno(stdin), TCSAFLUSH|TCSASOFT, &term);
500 } else if (action && echo) {
501 /* Turn echo on */
502 term.c_lflag |= ECHO;
503 (void) tcsetattr(fileno(stdin), TCSAFLUSH|TCSASOFT, &term);
504 echo = 0;
508 /* Convert string to lower case */
509 static void lowcase(char *s)
511 u_char *p;
513 for (p = (u_char *) s; *p; p++)
514 if (isupper(*p))
515 *p = tolower(*p);