1 /* $NetBSD: skeysubr.c,v 1.25 2005/12/05 02:07:07 christos Exp $ */
3 /* S/KEY v1.1b (skeysubr.c)
6 * Neil M. Haller <nmh@thumper.bellcore.com>
7 * Philip R. Karn <karn@chicago.qualcomm.com>
8 * John S. Walden <jsw@thumper.bellcore.com>
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 $");
29 #include <sys/rmd160.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 */
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
{
62 int (*keycrunch
)(char *, const char *, const 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
},
70 { "rmd160", keycrunch_rmd160
, f_rmd160
},
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
,
93 *buflen
= strlen(seed
) + strlen(passwd
);
94 if ((buf
= (char *) malloc(*buflen
+ 1)) == NULL
)
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 */
111 u_int32_t results
[4];
113 if ((buf
= mkSeedPassword(seed
, passwd
, &buflen
)) == NULL
)
116 /* Crunch the key through MD4 */
118 MD4Update(&md
, (unsigned char *) buf
, buflen
);
119 MD4Final((unsigned char *) (void *) results
, &md
);
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
);
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 */
137 u_int32_t results
[4];
140 if ((buf
= mkSeedPassword(seed
, passwd
, &buflen
)) == NULL
)
143 /* Crunch the key through MD5 */
145 MD5Update(&md
, (unsigned char *)buf
, buflen
);
146 MD5Final((unsigned char *) (void *)results
, &md
);
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
);
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 */
167 if ((buf
= mkSeedPassword(seed
, passwd
, &buflen
)) == NULL
)
170 /* Crunch the key through SHA1 */
172 SHA1Update(&sha
, (unsigned char *)buf
, buflen
);
173 SHA1Final(NULL
, &sha
);
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);
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 */
204 u_int32_t results
[5];
207 if ((buf
= mkSeedPassword(seed
, passwd
, &buflen
)) == NULL
)
210 /* Crunch the key through RMD-160 */
212 RMD160Update(&rmd
, (unsigned char *)buf
, buflen
);
213 RMD160Final((unsigned char *)(void *)results
, &rmd
);
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
);
227 /* The one-way function f(). Takes 8 bytes and returns 8 bytes in place */
230 skey_algorithm_table
[skey_hash_type
].f(x
);
233 static void f_md4(char *x
)
236 u_int32_t results
[4];
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
)
252 u_int32_t results
[4];
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
)
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);
288 static void f_rmd160(char *x
)
291 u_int32_t results
[5];
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
);
306 /* Strip trailing cr/lf from a line of text */
309 buf
+= strcspn(buf
, "\r\n");
315 /* Read in secret password (turns off echo) */
316 char *readpass(char *buf
, int n
)
320 /* Turn off echoing */
323 /* Catch SIGINT and save old signal handler */
324 old_handler
= signal(SIGINT
, trapped
);
326 fgets(buf
, n
, stdin
);
332 /* Restore signal handler and turn echo back on */
333 if (old_handler
!= SIG_ERR
)
334 (void)signal(SIGINT
, old_handler
);
342 /* Read in an s/key OTP (does not turn off echo) */
343 char *readskey(char *buf
, int n
)
345 fgets(buf
, n
, stdin
);
354 /* Signal handler for trapping ^C */
356 static void trapped(int sig
)
358 fputs("^C\n", stderr
);
361 /* Turn on echo if necessary */
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
)
376 if (in
== NULL
|| out
== NULL
)
379 for (i
=0; i
<8; i
++) {
380 if ((in
= skipspace(in
)) == NULL
)
382 if ((val
= htoi(*in
++)) == -1)
386 if ((in
= skipspace(in
)) == NULL
)
388 if ((val
= htoi(*in
++)) == -1)
395 /* Convert 8-byte binary array to hex-ascii string */
396 int btoa8(char *out
, const char *in
)
400 if (in
== NULL
|| out
== NULL
)
404 sprintf(out
, "%02x", *in
++ & 0xff);
411 /* Convert hex digit to binary integer */
414 if ('0' <= c
&& c
<= '9')
416 if ('a' <= c
&& c
<= 'f')
418 if ('A' <= c
&& c
<= 'F')
423 /* Skip leading spaces from the string */
424 const char *skipspace(const char *cp
)
426 while (*cp
== ' ' || *cp
== '\t')
435 /* Remove backspaced over charaters from the string */
436 void backspace(char *buf
)
459 /* Make sure line is all seven bits */
460 void sevenbit(char *s
)
466 /* Set hash algorithm type */
467 const char *skey_set_algorithm(const char *new)
471 for (i
= 0; skey_algorithm_table
[i
].name
; i
++) {
472 if (strcmp(new, skey_algorithm_table
[i
].name
) == 0) {
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
;
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
) {
502 term
.c_lflag
|= ECHO
;
503 (void) tcsetattr(fileno(stdin
), TCSAFLUSH
|TCSASOFT
, &term
);
508 /* Convert string to lower case */
509 static void lowcase(char *s
)
513 for (p
= (u_char
*) s
; *p
; p
++)