xref: /inferno-os/appl/lib/auth9.b (revision e45fa0eb0763b57d6fb0649c064bc3b95ccdea6c)
1implement Auth9;
2
3#
4# elements of Plan 9 authentication
5#
6# this is a near transliteration of Plan 9 source, subject to the Lucent Public License 1.02
7#
8
9include "sys.m";
10	sys: Sys;
11
12include "ipints.m";
13
14include "crypt.m";
15
16include "auth9.m";
17
18init()
19{
20	sys = load Sys Sys->PATH;
21}
22
23put2(a: array of byte, v: int)
24{
25	a[0] = byte v;
26	a[1] = byte (v>>8);
27}
28
29get2(a: array of byte): int
30{
31	return (int a[1]<<8) | int a[0];
32}
33
34put4(a: array of byte, v: int)
35{
36	a[0] = byte v;
37	a[1] = byte (v>>8);
38	a[2] = byte (v>>16);
39	a[3] = byte (v>>24);
40}
41
42get4(a: array of byte): int
43{
44	return (int a[3]<<24) | (int a[2]<<16) | (int a[1]<<8) | int a[0];
45}
46
47puts(a: array of byte, s: string, n: int)
48{
49	b := array of byte s;
50	l := len b;
51	if(l > n)
52		b = b[0:n];
53	a[0:] = b;
54	for(; l < n; l++)
55		a[l] = byte 0;
56}
57
58gets(a: array of byte, n: int): string
59{
60	for(i:=0; i<n; i++)
61		if(a[i] == byte 0)
62			break;
63	return string a[0:i];
64}
65
66geta(a: array of byte, n: int): array of byte
67{
68	b := array[n] of byte;
69	b[0:] = a[0:n];
70	return b;
71}
72
73Authenticator.pack(f: self ref Authenticator, key: array of byte): array of byte
74{
75	p := array[AUTHENTLEN] of {* => byte 0};
76	p[0] = byte f.num;
77	p[1:] = f.chal;
78	put4(p[1+CHALLEN:], f.id);
79	if(key != nil)
80		encrypt(key, p, len p);
81	return p;
82}
83
84Authenticator.unpack(a: array of byte, key: array of byte): (int, ref Authenticator)
85{
86	if(key != nil)
87		decrypt(key, a, AUTHENTLEN);
88	f := ref Authenticator;
89	f.num = int a[0];
90	f.chal = geta(a[1:], CHALLEN);
91	f.id = get4(a[1+CHALLEN:]);
92	return (AUTHENTLEN, f);
93}
94
95Passwordreq.pack(f: self ref Passwordreq, key: array of byte): array of byte
96{
97	a := array[PASSREQLEN] of {* => byte 0};
98	a[0] = byte f.num;
99	a[1:] = f.old;
100	a[1+ANAMELEN:] = f.new;
101	a[1+2*ANAMELEN] = byte f.changesecret;
102	a[1+2*ANAMELEN+1:] = f.secret;
103	if(key != nil)
104		encrypt(key, a, len a);
105	return a;
106}
107
108Passwordreq.unpack(a: array of byte, key: array of byte): (int, ref Passwordreq)
109{
110	if(key != nil)
111		decrypt(key, a, PASSREQLEN);
112	f := ref Passwordreq;
113	f.num = int a[0];
114	f.old = geta(a[1:], ANAMELEN);
115	f.old[ANAMELEN-1] = byte 0;
116	f.new = geta(a[1+ANAMELEN:], ANAMELEN);
117	f.new[ANAMELEN-1] = byte 0;
118	f.changesecret = int a[1+2*ANAMELEN];
119	f.secret = geta(a[1+2*ANAMELEN+1:], SECRETLEN);
120	f.secret[SECRETLEN-1] = byte 0;
121	return (PASSREQLEN, f);
122}
123
124Ticket.pack(f: self ref Ticket, key: array of byte): array of byte
125{
126	a := array[TICKETLEN] of {* => byte 0};
127	a[0] = byte f.num;
128	a[1:] = f.chal;
129	puts(a[1+CHALLEN:], f.cuid, ANAMELEN);
130	puts(a[1+CHALLEN+ANAMELEN:], f.suid, ANAMELEN);
131	a[1+CHALLEN+2*ANAMELEN:] = f.key;
132	if(key != nil)
133		encrypt(key, a, len a);
134	return a;
135}
136
137Ticket.unpack(a: array of byte, key: array of byte): (int, ref Ticket)
138{
139	if(key != nil)
140		decrypt(key, a, TICKETLEN);
141	f := ref Ticket;
142	f.num = int a[0];
143	f.chal = geta(a[1:], CHALLEN);
144	f.cuid = gets(a[1+CHALLEN:], ANAMELEN);
145	f.suid = gets(a[1+CHALLEN+ANAMELEN:], ANAMELEN);
146	f.key = geta(a[1+CHALLEN+2*ANAMELEN:], DESKEYLEN);
147	return (TICKETLEN, f);
148}
149
150Ticketreq.unpack(a: array of byte): (int, ref Ticketreq)
151{
152	f := ref Ticketreq;
153	f.rtype = int a[0];
154	f.authid = gets(a[1:], ANAMELEN);
155	f.authdom = gets(a[1+ANAMELEN:], DOMLEN);
156	f.chal = geta(a[1+ANAMELEN+DOMLEN:], CHALLEN);
157	f.hostid = gets(a[1+ANAMELEN+DOMLEN+CHALLEN:], ANAMELEN);
158	f.uid = gets(a[1+ANAMELEN+DOMLEN+CHALLEN+ANAMELEN:], ANAMELEN);
159	return (TICKREQLEN, f);
160}
161
162Ticketreq.pack(f: self ref Ticketreq): array of byte
163{
164	a := array[TICKREQLEN] of {* => byte 0};
165	a[0] = byte f.rtype;
166	puts(a[1:], f.authid, ANAMELEN);
167	puts(a[1+ANAMELEN:], f.authdom, DOMLEN);
168	a[1+ANAMELEN+DOMLEN:] = f.chal;
169	puts(a[1+ANAMELEN+DOMLEN+CHALLEN:], f.hostid, ANAMELEN);
170	puts(a[1+ANAMELEN+DOMLEN+CHALLEN+ANAMELEN:], f.uid, ANAMELEN);
171	return a;
172}
173
174netcrypt(key: array of byte, chal: string): string
175{
176	buf := array[8] of {* => byte 0};
177	a := array of byte chal;
178	if(len a > 7)
179		a = a[0:7];
180	buf[0:] = a;
181	encrypt(key, buf, len buf);
182	return sys->sprint("%.2ux%.2ux%.2ux%.2ux", int buf[0], int buf[1], int buf[2], int buf[3]);
183}
184
185passtokey(p: string): array of byte
186{
187	a := array of byte p;
188	n := len a;
189	if(n >= ANAMELEN)
190		n = ANAMELEN-1;
191	buf := array[ANAMELEN] of {* => byte ' '};
192	buf[0:] = a[0:n];
193	buf[n] = byte 0;
194	key := array[DESKEYLEN] of {* => byte 0};
195	t := 0;
196	for(;;){
197		for(i := 0; i < DESKEYLEN; i++)
198			key[i] = byte ((int buf[t+i] >> i) + (int buf[t+i+1] << (8 - (i+1))));
199		if(n <= 8)
200			return key;
201		n -= 8;
202		t += 8;
203		if(n < 8){
204			t -= 8 - n;
205			n = 8;
206		}
207		encrypt(key, buf[t:], 8);
208	}
209}
210
211parity := array[] of {
212	byte 16r01, byte 16r02, byte 16r04, byte 16r07, byte 16r08, byte 16r0b, byte 16r0d, byte 16r0e,
213	byte 16r10, byte 16r13, byte 16r15, byte 16r16, byte 16r19, byte 16r1a, byte 16r1c, byte 16r1f,
214	byte 16r20, byte 16r23, byte 16r25, byte 16r26, byte 16r29, byte 16r2a, byte 16r2c, byte 16r2f,
215	byte 16r31, byte 16r32, byte 16r34, byte 16r37, byte 16r38, byte 16r3b, byte 16r3d, byte 16r3e,
216	byte 16r40, byte 16r43, byte 16r45, byte 16r46, byte 16r49, byte 16r4a, byte 16r4c, byte 16r4f,
217	byte 16r51, byte 16r52, byte 16r54, byte 16r57, byte 16r58, byte 16r5b, byte 16r5d, byte 16r5e,
218	byte 16r61, byte 16r62, byte 16r64, byte 16r67, byte 16r68, byte 16r6b, byte 16r6d, byte 16r6e,
219	byte 16r70, byte 16r73, byte 16r75, byte 16r76, byte 16r79, byte 16r7a, byte 16r7c, byte 16r7f,
220	byte 16r80, byte 16r83, byte 16r85, byte 16r86, byte 16r89, byte 16r8a, byte 16r8c, byte 16r8f,
221	byte 16r91, byte 16r92, byte 16r94, byte 16r97, byte 16r98, byte 16r9b, byte 16r9d, byte 16r9e,
222	byte 16ra1, byte 16ra2, byte 16ra4, byte 16ra7, byte 16ra8, byte 16rab, byte 16rad, byte 16rae,
223	byte 16rb0, byte 16rb3, byte 16rb5, byte 16rb6, byte 16rb9, byte 16rba, byte 16rbc, byte 16rbf,
224	byte 16rc1, byte 16rc2, byte 16rc4, byte 16rc7, byte 16rc8, byte 16rcb, byte 16rcd, byte 16rce,
225	byte 16rd0, byte 16rd3, byte 16rd5, byte 16rd6, byte 16rd9, byte 16rda, byte 16rdc, byte 16rdf,
226	byte 16re0, byte 16re3, byte 16re5, byte 16re6, byte 16re9, byte 16rea, byte 16rec, byte 16ref,
227	byte 16rf1, byte 16rf2, byte 16rf4, byte 16rf7, byte 16rf8, byte 16rfb, byte 16rfd, byte 16rfe,
228};
229
230des56to64(k56: array of byte): array of byte
231{
232	k64 := array[8] of byte;
233	hi := (int k56[0]<<24)|(int k56[1]<<16)|(int k56[2]<<8)|int k56[3];
234	lo := (int k56[4]<<24)|(int k56[5]<<16)|(int k56[6]<<8);
235
236	k64[0] = parity[(hi>>25)&16r7f];
237	k64[1] = parity[(hi>>18)&16r7f];
238	k64[2] = parity[(hi>>11)&16r7f];
239	k64[3] = parity[(hi>>4)&16r7f];
240	k64[4] = parity[((hi<<3)|int ((big lo & big 16rFFFFFFFF)>>29))&16r7f];	# watch the sign extension
241	k64[5] = parity[(lo>>22)&16r7f];
242	k64[6] = parity[(lo>>15)&16r7f];
243	k64[7] = parity[(lo>>8)&16r7f];
244	return k64;
245}
246
247encrypt(key: array of byte, data: array of byte, n: int)
248{
249	if(n < 8)
250		return;
251	crypt := load Crypt Crypt->PATH;
252	ds := crypt->dessetup(des56to64(key), nil);
253	n--;
254	r := n % 7;
255	n /= 7;
256	j := 0;
257	for(i := 0; i < n; i++){
258		crypt->desecb(ds, data[j:], 8, Crypt->Encrypt);
259		j += 7;
260	}
261	if(r)
262		crypt->desecb(ds, data[j-7+r:], 8, Crypt->Encrypt);
263}
264
265decrypt(key: array of byte, data: array of byte, n: int)
266{
267	if(n < 8)
268		return;
269	crypt := load Crypt Crypt->PATH;
270	ds := crypt->dessetup(des56to64(key), nil);
271	n--;
272	r := n % 7;
273	n /= 7;
274	j := n*7;
275	if(r)
276		crypt->desecb(ds, data[j-7+r:], 8, Crypt->Decrypt);
277	for(i := 0; i < n; i++){
278		j -= 7;
279		crypt->desecb(ds, data[j:], 8, Crypt->Decrypt);
280	}
281}
282
283readn(fd: ref Sys->FD, nb: int): array of byte
284{
285	buf:= array[nb] of byte;
286	if(sys->readn(fd, buf, nb) != nb)
287		return nil;
288	return buf;
289}
290
291pbmsg: con "AS protocol botch";
292
293_asgetticket(fd: ref Sys->FD, tr: ref Ticketreq, key: array of byte): (ref Ticket, array of byte)
294{
295	a := tr.pack();
296	if(sys->write(fd, a, len a) < 0){
297		sys->werrstr(pbmsg);
298		return (nil, nil);
299	}
300	a = _asrdresp(fd, 2*TICKETLEN);
301	if(a == nil)
302		return (nil, nil);
303	(nil, t) := Ticket.unpack(a, key);
304	return (t, a[TICKETLEN:]);	# can't unpack both since the second uses server key
305}
306
307_asrdresp(fd: ref Sys->FD, n: int): array of byte
308{
309	b := array[1] of byte;
310	if(sys->read(fd, b, 1) != 1){
311		sys->werrstr(pbmsg);
312		return nil;
313	}
314
315	buf: array of byte;
316	case int b[0] {
317	AuthOK =>
318		buf = readn(fd, n);
319	AuthOKvar =>
320		b = readn(fd, 5);
321		if(b == nil)
322			break;
323		n = int string b;
324		if(n<= 0 || n > 4096)
325			break;
326		buf = readn(fd, n);
327	AuthErr =>
328		b = readn(fd, 64);
329		if(b == nil)
330			break;
331		for(i:=0; i<len b && b[i] != byte 0; i++)
332			;
333		sys->werrstr(sys->sprint("remote: %s", string b[0:i]));
334		return nil;
335	* =>
336		sys->werrstr(sys->sprint("%s: resp %d", pbmsg, int b[0]));
337		return nil;
338	}
339	if(buf == nil)
340		sys->werrstr(pbmsg);
341	return buf;
342}
343