GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libskey/skeysubr.c Lines: 61 128 47.7 %
Date: 2017-11-07 Branches: 12 66 18.2 %

Line Branch Exec Source
1
/* OpenBSD S/Key (skeysubr.c)
2
 *
3
 * Authors:
4
 *          Neil M. Haller <nmh@thumper.bellcore.com>
5
 *          Philip R. Karn <karn@chicago.qualcomm.com>
6
 *          John S. Walden <jsw@thumper.bellcore.com>
7
 *          Scott Chasin <chasin@crimelab.com>
8
 *          Todd C. Miller <Todd.Miller@courtesan.com>
9
 *
10
 * S/Key misc routines.
11
 *
12
 * $OpenBSD: skeysubr.c,v 1.34 2015/10/06 15:07:45 tim Exp $
13
 */
14
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <string.h>
18
#include <ctype.h>
19
#include <signal.h>
20
#include <termios.h>
21
#include <unistd.h>
22
#include <md5.h>
23
#include <sha1.h>
24
#include <rmd160.h>
25
26
#include "skey.h"
27
28
/* Default hash function to use (index into skey_algorithm_table array) */
29
#ifndef SKEY_HASH_DEFAULT
30
#define SKEY_HASH_DEFAULT	0	/* md5 */
31
#endif
32
33
static void keycrunch_md5(char *, char *, size_t);
34
static void keycrunch_sha1(char *, char *, size_t);
35
static void keycrunch_rmd160(char *, char *, size_t);
36
static void skey_echo(int);
37
static void trapped(int);
38
39
/* Current hash type (index into skey_algorithm_table array) */
40
static int skey_hash_type = SKEY_HASH_DEFAULT;
41
42
/*
43
 * Hash types we support.
44
 * Each has an associated keycrunch() and f() function.
45
 */
46
struct skey_algorithm_table {
47
	const char *name;
48
	void (*keycrunch)(char *, char *, size_t);
49
};
50
static struct skey_algorithm_table skey_algorithm_table[] = {
51
	{ "md5", keycrunch_md5 },
52
	{ "sha1", keycrunch_sha1 },
53
	{ "rmd160", keycrunch_rmd160 },
54
	{ NULL }
55
};
56
57
58
/*
59
 * Crunch a key:
60
 *  Concatenate the seed and the password, run through hash function and
61
 *  collapse to 64 bits.  This is defined as the user's starting key.
62
 *  The result pointer must have at least SKEY_BINKEY_SIZE bytes of storage.
63
 *  The seed and password may be of any length.
64
 */
65
int
66
keycrunch(char *result, char *seed, char *passwd)
67
{
68
	char *buf, *p;
69
	size_t buflen;
70
71
72
	buflen = strlen(seed) + strlen(passwd);
72
36
	if ((buf = malloc(buflen + 1)) == NULL)
73
		return(-1);
74
75
36
	(void)strlcpy(buf, seed, buflen + 1);
76
480
	for (p = buf; *p; p++)
77
204
		*p = (char)tolower((unsigned char)*p);
78
79
36
	(void)strlcat(buf, passwd, buflen + 1);
80
36
	sevenbit(buf);
81
82
36
	skey_algorithm_table[skey_hash_type].keycrunch(result, buf, buflen);
83
84
36
	(void)free(buf);
85
36
	return(0);
86
36
}
87
88
static void
89
keycrunch_md5(char *result, char *buf, size_t buflen)
90
{
91
2400
	MD5_CTX md;
92
1200
	u_int32_t results[4];
93
94
	/* Crunch the key through MD5 */
95
1200
	MD5Init(&md);
96
1200
	MD5Update(&md, (unsigned char *)buf, buflen);
97
1200
	MD5Final((unsigned char *)results, &md);
98
99
	/* Fold result from 128 to 64 bits */
100
1200
	results[0] ^= results[2];
101
1200
	results[1] ^= results[3];
102
103
1200
	(void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE);
104
1200
}
105
106
static void
107
keycrunch_sha1(char *result, char *buf, size_t buflen)
108
{
109
2400
	SHA1_CTX sha;
110
	int i, j;
111
112
	/* Crunch the key through SHA1 */
113
1200
	SHA1Init(&sha);
114
1200
	SHA1Update(&sha, (unsigned char *)buf, buflen);
115
1200
	SHA1Pad(&sha);
116
117
	/* Fold 160 to 64 bits */
118
1200
	sha.state[0] ^= sha.state[2];
119
1200
	sha.state[1] ^= sha.state[3];
120
1200
	sha.state[0] ^= sha.state[4];
121
122
	/*
123
	 * SHA1 is a big endian algorithm but RFC2289 mandates that
124
	 * the result be in little endian form, so we copy to the
125
	 * result buffer manually.
126
	 */
127
7200
	for (i = 0, j = 0; j < 8; i++, j += 4) {
128
2400
		result[j]   = (u_char)(sha.state[i] & 0xff);
129
2400
		result[j+1] = (u_char)((sha.state[i] >> 8)  & 0xff);
130
2400
		result[j+2] = (u_char)((sha.state[i] >> 16) & 0xff);
131
2400
		result[j+3] = (u_char)((sha.state[i] >> 24) & 0xff);
132
	}
133
1200
}
134
135
static void
136
keycrunch_rmd160(char *result, char *buf, size_t buflen)
137
{
138
2400
	RMD160_CTX rmd;
139
1200
	u_int32_t results[5];
140
141
	/* Crunch the key through RMD-160 */
142
1200
	RMD160Init(&rmd);
143
1200
	RMD160Update(&rmd, (unsigned char *)buf, buflen);
144
1200
	RMD160Final((unsigned char *)results, &rmd);
145
146
	/* Fold 160 to 64 bits */
147
1200
	results[0] ^= results[2];
148
1200
	results[1] ^= results[3];
149
1200
	results[0] ^= results[4];
150
151
1200
	(void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE);
152
1200
}
153
154
/*
155
 * The one-way hash function f().
156
 * Takes SKEY_BINKEY_SIZE bytes and returns SKEY_BINKEY_SIZE bytes in place.
157
 */
158
void
159
f(char *x)
160
{
161
7128
	skey_algorithm_table[skey_hash_type].keycrunch(x, x, SKEY_BINKEY_SIZE);
162
3564
}
163
164
/* Strip trailing cr/lf from a line of text */
165
void
166
rip(char *buf)
167
{
168
	buf += strcspn(buf, "\r\n");
169
170
	if (*buf)
171
		*buf = '\0';
172
}
173
174
/* Read in secret password (turns off echo) */
175
char *
176
readpass(char *buf, int n)
177
{
178
	void (*old_handler)(int);
179
180
	/* Turn off echoing */
181
	skey_echo(0);
182
183
	/* Catch SIGINT and save old signal handler */
184
	old_handler = signal(SIGINT, trapped);
185
186
	if (fgets(buf, n, stdin) == NULL)
187
		buf[0] = '\0';
188
	rip(buf);
189
190
	(void)putc('\n', stderr);
191
	(void)fflush(stderr);
192
193
	/* Restore signal handler and turn echo back on */
194
	if (old_handler != SIG_ERR)
195
		(void)signal(SIGINT, old_handler);
196
	skey_echo(1);
197
198
	sevenbit(buf);
199
200
	return(buf);
201
}
202
203
/* Read in an s/key OTP (does not turn off echo) */
204
char *
205
readskey(char *buf, int n)
206
{
207
	if (fgets(buf, n, stdin) == NULL)
208
		buf[0] = '\0';
209
	rip(buf);
210
211
	sevenbit(buf);
212
213
	return(buf);
214
}
215
216
/* Signal handler for trapping ^C */
217
/*ARGSUSED*/
218
static void
219
trapped(int sig)
220
{
221
	write(STDERR_FILENO, "^C\n", 3);
222
223
	/* Turn on echo if necessary */
224
	skey_echo(1);
225
226
	_exit(1);
227
}
228
229
/*
230
 * Convert 16-byte hex-ascii string to 8-byte binary array
231
 * Returns 0 on success, -1 on error
232
 */
233
int
234
atob8(char *out, char *in)
235
{
236
	int i;
237
	int val;
238
239
	if (in == NULL || out == NULL)
240
		return(-1);
241
242
	for (i=0; i < 8; i++) {
243
		if ((in = skipspace(in)) == NULL)
244
			return(-1);
245
		if ((val = htoi(*in++)) == -1)
246
			return(-1);
247
		*out = val << 4;
248
249
		if ((in = skipspace(in)) == NULL)
250
			return(-1);
251
		if ((val = htoi(*in++)) == -1)
252
			return(-1);
253
		*out++ |= val;
254
	}
255
	return(0);
256
}
257
258
/* Convert 8-byte binary array to 16-byte hex-ascii string */
259
int
260
btoa8(char *out, char *in)
261
{
262
216
	if (in == NULL || out == NULL)
263
		return(-1);
264
265
108
	(void)snprintf(out, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
266
108
	    in[0] & 0xff, in[1] & 0xff, in[2] & 0xff, in[3] & 0xff,
267
108
	    in[4] & 0xff, in[5] & 0xff, in[6] & 0xff, in[7] & 0xff);
268
269
108
	return(0);
270
108
}
271
272
/* Convert hex digit to binary integer */
273
int
274
htoi(int c)
275
{
276
	if ('0' <= c && c <= '9')
277
		return(c - '0');
278
	if ('a' <= c && c <= 'f')
279
		return(10 + c - 'a');
280
	if ('A' <= c && c <= 'F')
281
		return(10 + c - 'A');
282
	return(-1);
283
}
284
285
/* Skip leading spaces from the string */
286
char *
287
skipspace(char *cp)
288
{
289
	while (*cp == ' ' || *cp == '\t')
290
		cp++;
291
292
	if (*cp == '\0')
293
		return(NULL);
294
	else
295
		return(cp);
296
}
297
298
/* Remove backspaced over characters from the string */
299
void
300
backspace(char *buf)
301
{
302
	char bs = 0x8;
303
	char *cp = buf;
304
	char *out = buf;
305
306
	while (*cp) {
307
		if (*cp == bs) {
308
			if (out == buf) {
309
				cp++;
310
				continue;
311
			} else {
312
				cp++;
313
				out--;
314
			}
315
		} else {
316
			*out++ = *cp++;
317
		}
318
319
	}
320
	*out = '\0';
321
}
322
323
/* Make sure line is all seven bits */
324
void
325
sevenbit(char *s)
326
{
327
1476
	while (*s)
328
684
		*s++ &= 0x7f;
329
36
}
330
331
/* Set hash algorithm type */
332
char *
333
skey_set_algorithm(char *new)
334
{
335
	int i;
336
337
216
	for (i = 0; skey_algorithm_table[i].name; i++) {
338
84
		if (strcmp(new, skey_algorithm_table[i].name) == 0) {
339
36
			skey_hash_type = i;
340
36
			return(new);
341
		}
342
	}
343
344
4
	return(NULL);
345
40
}
346
347
/* Get current hash type */
348
const char *
349
skey_get_algorithm(void)
350
{
351
80
	return(skey_algorithm_table[skey_hash_type].name);
352
}
353
354
/* Turn echo on/off */
355
static void
356
skey_echo(int action)
357
{
358
	static struct termios term;
359
	static int echo = 0;
360
361
	if (action == 0) {
362
		/* Turn echo off */
363
		(void) tcgetattr(fileno(stdin), &term);
364
		if ((echo = (term.c_lflag & ECHO))) {
365
			term.c_lflag &= ~ECHO;
366
			(void) tcsetattr(fileno(stdin), TCSAFLUSH|TCSASOFT, &term);
367
		}
368
	} else if (action && echo) {
369
		/* Turn echo on */
370
		term.c_lflag |= ECHO;
371
		(void) tcsetattr(fileno(stdin), TCSAFLUSH|TCSASOFT, &term);
372
		echo = 0;
373
	}
374
}