diff options
Diffstat (limited to 'appl/lib/auth9.b')
| -rw-r--r-- | appl/lib/auth9.b | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/appl/lib/auth9.b b/appl/lib/auth9.b new file mode 100644 index 00000000..06accb53 --- /dev/null +++ b/appl/lib/auth9.b @@ -0,0 +1,351 @@ +implement Auth9; + +# +# elements of Plan 9 authentication +# +# this is a near transliteration of Plan 9 source, subject to the Lucent Public License 1.02 +# + +include "sys.m"; + sys: Sys; + +include "keyring.m"; + +include "auth9.m"; + +debug := 0; + +init() +{ + sys = load Sys Sys->PATH; +} + +setdebug(i: int) +{ + debug = i; +} + +put2(a: array of byte, v: int) +{ + a[0] = byte v; + a[1] = byte (v>>8); +} + +get2(a: array of byte): int +{ + return (int a[1]<<8) | int a[0]; +} + +put4(a: array of byte, v: int) +{ + a[0] = byte v; + a[1] = byte (v>>8); + a[2] = byte (v>>16); + a[3] = byte (v>>24); +} + +get4(a: array of byte): int +{ + return (int a[3]<<24) | (int a[2]<<16) | (int a[1]<<8) | int a[0]; +} + +puts(a: array of byte, s: string, n: int) +{ + b := array of byte s; + l := len b; + if(l > n) + b = b[0:n]; + a[0:] = b; + for(; l < n; l++) + a[l] = byte 0; +} + +gets(a: array of byte, n: int): string +{ + for(i:=0; i<n; i++) + if(a[i] == byte 0) + break; + return string a[0:i]; +} + +geta(a: array of byte, n: int): array of byte +{ + b := array[n] of byte; + b[0:] = a[0:n]; + return b; +} + +Authenticator.pack(f: self ref Authenticator, key: array of byte): array of byte +{ + p := array[AUTHENTLEN] of {* => byte 0}; + p[0] = byte f.num; + p[1:] = f.chal; + put4(p[1+CHALLEN:], f.id); + if(key != nil) + encrypt(key, p, len p); + return p; +} + +Authenticator.unpack(a: array of byte, key: array of byte): (int, ref Authenticator) +{ + if(key != nil) + decrypt(key, a, AUTHENTLEN); + f := ref Authenticator; + f.num = int a[0]; + f.chal = geta(a[1:], CHALLEN); + f.id = get4(a[1+CHALLEN:]); + return (AUTHENTLEN, f); +} + +Passwordreq.pack(f: self ref Passwordreq, key: array of byte): array of byte +{ + a := array[PASSREQLEN] of {* => byte 0}; + a[0] = byte f.num; + a[1:] = f.old; + a[1+ANAMELEN:] = f.new; + a[1+2*ANAMELEN] = byte f.changesecret; + a[1+2*ANAMELEN+1:] = f.secret; + if(key != nil) + encrypt(key, a, len a); + return a; +} + +Passwordreq.unpack(a: array of byte, key: array of byte): (int, ref Passwordreq) +{ + if(key != nil) + decrypt(key, a, PASSREQLEN); + f := ref Passwordreq; + f.num = int a[0]; + f.old = geta(a[1:], ANAMELEN); + f.old[ANAMELEN-1] = byte 0; + f.new = geta(a[1+ANAMELEN:], ANAMELEN); + f.new[ANAMELEN-1] = byte 0; + f.changesecret = int a[1+2*ANAMELEN]; + f.secret = geta(a[1+2*ANAMELEN+1:], SECRETLEN); + f.secret[SECRETLEN-1] = byte 0; + return (PASSREQLEN, f); +} + +Ticket.pack(f: self ref Ticket, key: array of byte): array of byte +{ + a := array[TICKETLEN] of {* => byte 0}; + a[0] = byte f.num; + a[1:] = f.chal; + puts(a[1+CHALLEN:], f.cuid, ANAMELEN); + puts(a[1+CHALLEN+ANAMELEN:], f.suid, ANAMELEN); + a[1+CHALLEN+2*ANAMELEN:] = f.key; + if(key != nil) + encrypt(key, a, len a); + return a; +} + +Ticket.unpack(a: array of byte, key: array of byte): (int, ref Ticket) +{ + if(key != nil) + decrypt(key, a, TICKETLEN); + f := ref Ticket; + f.num = int a[0]; + f.chal = geta(a[1:], CHALLEN); + f.cuid = gets(a[1+CHALLEN:], ANAMELEN); + f.suid = gets(a[1+CHALLEN+ANAMELEN:], ANAMELEN); + f.key = geta(a[1+CHALLEN+2*ANAMELEN:], DESKEYLEN); + return (TICKETLEN, f); +} + +Ticketreq.unpack(a: array of byte): (int, ref Ticketreq) +{ + f := ref Ticketreq; + f.rtype = int a[0]; + f.authid = gets(a[1:], ANAMELEN); + f.authdom = gets(a[1+ANAMELEN:], DOMLEN); + f.chal = geta(a[1+ANAMELEN+DOMLEN:], CHALLEN); + f.hostid = gets(a[1+ANAMELEN+DOMLEN+CHALLEN:], ANAMELEN); + f.uid = gets(a[1+ANAMELEN+DOMLEN+CHALLEN+ANAMELEN:], ANAMELEN); + return (TICKREQLEN, f); +} + +Ticketreq.pack(f: self ref Ticketreq): array of byte +{ + a := array[TICKREQLEN] of {* => byte 0}; + a[0] = byte f.rtype; + puts(a[1:], f.authid, ANAMELEN); + puts(a[1+ANAMELEN:], f.authdom, DOMLEN); + a[1+ANAMELEN+DOMLEN:] = f.chal; + puts(a[1+ANAMELEN+DOMLEN+CHALLEN:], f.hostid, ANAMELEN); + puts(a[1+ANAMELEN+DOMLEN+CHALLEN+ANAMELEN:], f.uid, ANAMELEN); + return a; +} + +netcrypt(key: array of byte, chal: string): string +{ + buf := array[8] of {* => byte 0}; + a := array of byte chal; + if(len a > 7) + a = a[0:7]; + buf[0:] = a; + encrypt(key, buf, len buf); + return sys->sprint("%.2ux%.2ux%.2ux%.2ux", int buf[0], int buf[1], int buf[2], int buf[3]); +} + +passtokey(p: string): array of byte +{ + a := array of byte p; + n := len a; + if(n >= ANAMELEN) + n = ANAMELEN-1; + buf := array[ANAMELEN] of {* => byte ' '}; + buf[0:] = a[0:n]; + buf[n] = byte 0; + key := array[DESKEYLEN] of {* => byte 0}; + t := 0; + for(;;){ + for(i := 0; i < DESKEYLEN; i++) + key[i] = byte ((int buf[t+i] >> i) + (int buf[t+i+1] << (8 - (i+1)))); + if(n <= 8) + return key; + n -= 8; + t += 8; + if(n < 8){ + t -= 8 - n; + n = 8; + } + encrypt(key, buf[t:], 8); + } +} + +parity := array[] of { + byte 16r01, byte 16r02, byte 16r04, byte 16r07, byte 16r08, byte 16r0b, byte 16r0d, byte 16r0e, + byte 16r10, byte 16r13, byte 16r15, byte 16r16, byte 16r19, byte 16r1a, byte 16r1c, byte 16r1f, + byte 16r20, byte 16r23, byte 16r25, byte 16r26, byte 16r29, byte 16r2a, byte 16r2c, byte 16r2f, + byte 16r31, byte 16r32, byte 16r34, byte 16r37, byte 16r38, byte 16r3b, byte 16r3d, byte 16r3e, + byte 16r40, byte 16r43, byte 16r45, byte 16r46, byte 16r49, byte 16r4a, byte 16r4c, byte 16r4f, + byte 16r51, byte 16r52, byte 16r54, byte 16r57, byte 16r58, byte 16r5b, byte 16r5d, byte 16r5e, + byte 16r61, byte 16r62, byte 16r64, byte 16r67, byte 16r68, byte 16r6b, byte 16r6d, byte 16r6e, + byte 16r70, byte 16r73, byte 16r75, byte 16r76, byte 16r79, byte 16r7a, byte 16r7c, byte 16r7f, + byte 16r80, byte 16r83, byte 16r85, byte 16r86, byte 16r89, byte 16r8a, byte 16r8c, byte 16r8f, + byte 16r91, byte 16r92, byte 16r94, byte 16r97, byte 16r98, byte 16r9b, byte 16r9d, byte 16r9e, + byte 16ra1, byte 16ra2, byte 16ra4, byte 16ra7, byte 16ra8, byte 16rab, byte 16rad, byte 16rae, + byte 16rb0, byte 16rb3, byte 16rb5, byte 16rb6, byte 16rb9, byte 16rba, byte 16rbc, byte 16rbf, + byte 16rc1, byte 16rc2, byte 16rc4, byte 16rc7, byte 16rc8, byte 16rcb, byte 16rcd, byte 16rce, + byte 16rd0, byte 16rd3, byte 16rd5, byte 16rd6, byte 16rd9, byte 16rda, byte 16rdc, byte 16rdf, + byte 16re0, byte 16re3, byte 16re5, byte 16re6, byte 16re9, byte 16rea, byte 16rec, byte 16ref, + byte 16rf1, byte 16rf2, byte 16rf4, byte 16rf7, byte 16rf8, byte 16rfb, byte 16rfd, byte 16rfe, +}; + +des56to64(k56: array of byte): array of byte +{ + k64 := array[8] of byte; + hi := (int k56[0]<<24)|(int k56[1]<<16)|(int k56[2]<<8)|int k56[3]; + lo := (int k56[4]<<24)|(int k56[5]<<16)|(int k56[6]<<8); + + k64[0] = parity[(hi>>25)&16r7f]; + k64[1] = parity[(hi>>18)&16r7f]; + k64[2] = parity[(hi>>11)&16r7f]; + k64[3] = parity[(hi>>4)&16r7f]; + k64[4] = parity[((hi<<3)|int ((big lo & big 16rFFFFFFFF)>>29))&16r7f]; # watch the sign extension + k64[5] = parity[(lo>>22)&16r7f]; + k64[6] = parity[(lo>>15)&16r7f]; + k64[7] = parity[(lo>>8)&16r7f]; + return k64; +} + +encrypt(key: array of byte, data: array of byte, n: int) +{ + if(n < 8) + return; + kr := load Keyring Keyring->PATH; + ds := kr->dessetup(des56to64(key), nil); + n--; + r := n % 7; + n /= 7; + j := 0; + for(i := 0; i < n; i++){ + kr->desecb(ds, data[j:], 8, Keyring->Encrypt); + j += 7; + } + if(r) + kr->desecb(ds, data[j-7+r:], 8, Keyring->Encrypt); +} + +decrypt(key: array of byte, data: array of byte, n: int) +{ + if(n < 8) + return; + kr := load Keyring Keyring->PATH; + ds := kr->dessetup(des56to64(key), nil); + n--; + r := n % 7; + n /= 7; + j := n*7; + if(r) + kr->desecb(ds, data[j-7+r:], 8, Keyring->Decrypt); + for(i := 0; i < n; i++){ + j -= 7; + kr->desecb(ds, data[j:], 8, Keyring->Decrypt); + } +} + +readn(fd: ref Sys->FD, nb: int): array of byte +{ + buf:= array[nb] of byte; + for(n:=0; n<nb;){ + m := sys->read(fd, buf[n:], nb-n); + if(m <= 0) + return nil; + n += m; + } + return buf; +} + +pbmsg: con "AS protocol botch"; + +_asgetticket(fd: ref Sys->FD, tr: ref Ticketreq, key: array of byte): (ref Ticket, array of byte) +{ + a := tr.pack(); + if(sys->write(fd, a, len a) < 0){ + sys->werrstr(pbmsg); + return (nil, nil); + } + a = _asrdresp(fd, 2*TICKETLEN); + if(a == nil) + return (nil, nil); + (nil, t) := Ticket.unpack(a, key); + return (t, a[TICKETLEN:]); # can't unpack both since the second uses server key +} + +_asrdresp(fd: ref Sys->FD, n: int): array of byte +{ + b := array[1] of byte; + if(sys->read(fd, b, 1) != 1){ + sys->werrstr(pbmsg); + return nil; + } + + buf: array of byte; + case int b[0] { + AuthOK => + buf = readn(fd, n); + AuthOKvar => + b = readn(fd, 5); + if(b == nil) + break; + n = int string b; + if(n<= 0 || n > 4096) + break; + buf = readn(fd, n); + AuthErr => + b = readn(fd, 64); + if(b == nil) + break; + for(i:=0; i<len b && b[i] != byte 0; i++) + ; + sys->werrstr(sys->sprint("remote: %s", string b[0:i])); + return nil; + * => + sys->werrstr(sys->sprint("%s: resp %d", pbmsg, int b[0])); + return nil; + } + if(buf == nil) + sys->werrstr(pbmsg); + return buf; +} |
