summaryrefslogtreecommitdiffstats
path: root/usr.sbin/xntpd/authstuff/keyparity.c
blob: aed05d9c5ccb52fc55d7e94eeae06dc0a24a78ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/*
 * keyparity - add parity bits to key and/or change an ascii key to binary
 */

#include <stdio.h>
#include <sys/types.h>
#include <ctype.h>

#include "ntp_string.h"
#include "ntp_stdlib.h"

#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)

/*
 * Types of ascii representations for keys.  "Standard" means a 64 bit
 * hex number in NBS format, i.e. with the low order bit of each byte
 * a parity bit.  "NTP" means a 64 bit key in NTP format, with the
 * high order bit of each byte a parity bit.  "Ascii" means a 1-to-8
 * character string whose ascii representation is used as the key.
 */
#define	KEY_TYPE_STD	1
#define	KEY_TYPE_NTP	2
#define	KEY_TYPE_ASCII	3

#define	STD_PARITY_BITS	0x01010101

char *progname;
int debug;

int ntpflag = 0;
int stdflag = 0;
int asciiflag = 0;
int ntpoutflag = 0;
int gotoopt = 0;

static	int	parity	P((u_long *));
static	int	decodekey P((int, char *, u_long *));
static	void	output	P((u_long *, int));

/*
 * main - parse arguments and handle options
 */
void
main(argc, argv)
int argc;
char *argv[];
{
	int c;
	int errflg = 0;
	int keytype;
	u_long key[2];
	extern int ntp_optind;
	extern char *ntp_optarg;

	progname = argv[0];
	while ((c = ntp_getopt(argc, argv, "adno:s")) != EOF)
		switch (c) {
		case 'a':
			asciiflag = 1;
			break;
		case 'd':
			++debug;
			break;
		case 'n':
			ntpflag = 1;
			break;
		case 's':
			stdflag = 1;
			break;
		case 'o':
			if (*ntp_optarg == 'n') {
				ntpoutflag = 1;
				gotoopt = 1;
			} else if (*ntp_optarg == 's') {
				ntpoutflag = 0;
				gotoopt = 1;
			} else {
				(void) fprintf(stderr,
				    "%s: output format must be `n' or `s'\n",
				    progname);
				errflg++;
			}
			break;
		default:
			errflg++;
			break;
		}
	if (errflg || ntp_optind == argc) {
		(void) fprintf(stderr,
		    "usage: %s -n|-s [-a] [-o n|s] key [...]\n",
		    progname);
		exit(2);
	}

	if (!ntpflag && !stdflag) {
		(void) fprintf(stderr,
		    "%s: one of either the -n or -s flags must be specified\n",
		    progname);
		exit(2);
	}

	if (ntpflag && stdflag) {
		(void) fprintf(stderr,
		    "%s: only one of the -n and -s flags may be specified\n",
		    progname);
		exit(2);
	}

	if (!gotoopt) {
		if (ntpflag)
			ntpoutflag = 1;
	}

	if (asciiflag)
		keytype = KEY_TYPE_ASCII;
	else if (ntpflag)
		keytype = KEY_TYPE_NTP;
	else
		keytype = KEY_TYPE_STD;

	for (; ntp_optind < argc; ntp_optind++) {
		if (!decodekey(keytype, argv[ntp_optind], key)) {
			(void) fprintf(stderr,
			    "%s: format of key %s invalid\n",
			    progname, argv[ntp_optind]);
			exit(1);
		}
		(void) parity(key);
		output(key, ntpoutflag);
	}
	exit(0);
}



/*
 * parity - set parity on a key/check for odd parity
 */
static int
parity(key)
	u_long *key;
{
	u_long mask;
	int parity_err;
	int bitcount;
	int half;
	int byte;
	int i;

	/*
	 * Go through counting bits in each byte.  Check to see if
	 * each parity bit was set correctly.  If not, note the error
	 * and set it right.
	 */
	parity_err = 0;
	for (half = 0; half < 2; half++) {		/* two halves of key */
		mask = 0x80000000;
		for (byte = 0; byte < 4; byte++) {	/* 4 bytes per half */
			bitcount = 0;
			for (i = 0; i < 7; i++) {	/* 7 data bits / byte */
				if (key[half] & mask)
					bitcount++;
				mask >>= 1;
			}

			/*
			 * If bitcount is even, parity must be set.  If
			 * bitcount is odd, parity must be clear.
			 */
			if ((bitcount & 0x1) == 0) {
				if (!(key[half] & mask)) {
					parity_err++;
					key[half] |= mask;
				}
			} else {
				if (key[half] & mask) {
					parity_err++;
					key[half] &= ~mask;
				}
			}
			mask >>= 1;
		}
	}

	/*
	 * Return the result of the parity check.
	 */
	return (parity_err == 0);
}


static int
decodekey(keytype, str, key)
	int keytype;
	char *str;
	u_long *key;
{
	u_char keybytes[8];
	char *cp;
	char *xdigit;
	int len;
	int i;
	static char *hex = "0123456789abcdef";

	cp = str;
	len = strlen(cp);
	if (len == 0)
		return 0;

	switch(keytype) {
	case KEY_TYPE_STD:
	case KEY_TYPE_NTP:
		if (len != 16)		/* Lazy.  Should define constant */
			return 0;
		/*
		 * Decode hex key.
		 */
		key[0] = 0;
		key[1] = 0;
		for (i = 0; i < 16; i++) {
			if (!isascii(*cp))
				return 0;
			xdigit = strchr(hex, isupper(*cp) ? tolower(*cp) : *cp);
			cp++;
			if (xdigit == 0)
				return 0;
			key[i>>3] <<= 4;
			key[i>>3] |= (u_long)(xdigit - hex) & 0xf;
		}

		/*
		 * If this is an NTP format key, put it into NBS format
		 */
		if (keytype == KEY_TYPE_NTP) {
			for (i = 0; i < 2; i++)
				key[i] = ((key[i] << 1) & ~STD_PARITY_BITS)
				    | ((key[i] >> 7) & STD_PARITY_BITS);
		}
		break;
	
	case KEY_TYPE_ASCII:
		/*
		 * Make up key from ascii representation
		 */
		memset(keybytes, 0, sizeof(keybytes));
		for (i = 0; i < 8 && i < len; i++)
			keybytes[i] = *cp++ << 1;
		key[0] = keybytes[0] << 24 | keybytes[1] << 16
		    | keybytes[2] << 8 | keybytes[3];
		key[1] = keybytes[4] << 24 | keybytes[5] << 16
		    | keybytes[6] << 8 | keybytes[7];
		break;
	
	default:
		/* Oh, well */
		return 0;
	}

	return 1;
}


/*
 * output - print a hex key on the standard output
 */
static void
output(key, ntpformat)
	u_long *key;
	int ntpformat;
{
	int i;

	if (ntpformat) {
		for (i = 0; i < 2; i++)
			key[i] = ((key[i] & ~STD_PARITY_BITS) >> 1)
			    | ((key[i] & STD_PARITY_BITS) << 7);
	}
	(void) printf("%08x%08x\n", key[0], key[1]);
}
OpenPOWER on IntegriCloud