// Password.Bcpl -- OS password routines // Bob Sproull and Leo Guibas // Copyright Xerox Corporation 1979, 1981 // Last modified October 4, 1981 2:58 PM by Taft external [ //outgoing procedures Password //incoming procedures Zero; Timer //incoming system static UserName ] // One function (Password) does it all: // result = Password(string,vector,new) // // If "new" is true, it fills vector (9 words long) with encrypted // password. Sets vector!0 to -1 to indicate there is a password // If "new" is false, compares string with password. Returns // true if password string was good. // // The standard OS stores the 9-word vector starting at word // #600 in the file Sys.Boot // (location #1200 in memory if Sys.Boot is InLd'ed) // 9-word vector format: // flag ne 0 (1 word) // a: next 2 words (derived from time when password set) // b: next 2 words (derived from UserName when password set) // c: next 4 words (actual encrypted password) // Note that a and b simply ensure that a given password encrypts // differently at different times and for different users. // // -- computation is: // x ← 16-bit number extracted from ps // y ← 32-bit number extracted from ps // c ← -a*x*x + b*y structure String [ length byte ; char↑1,255 byte ] //--------------------------------------------------------------------------- let Password(ps, v, newFlag) = valof //--------------------------------------------------------------------------- [ // temps used by machine code -- must immediately follow args in frame let tempa, tempb, tempc = nil, nil, nil manifest [ pa = 7; pb = 8; pc = 9 ] let Add4 = table // Add4(lvA, lvB, lvC): a ← b+c (b and c are 4 words long) [ 55001B // sta 3 1 2 176520B // mkone 3 3 175140B // movol 3 3 ; ac3 ← 3 163000B // add 3 0 41007B // sta 0 pa 2 ; -> last word of a 167000B // add 3 1 45010B // sta 1 pb 2 ; -> last word of b 21003B // lda 0 3 2 163000B // add 3 0 41011B // sta 0 pc 2 ; -> last word of c 174020B // comz 3 3 ; ac3 ← -4, carry ← 0 23010B // loop: lda 0 @pb 2 ; current word of b 27011B // lda 1 @pc 2 ; current word of c 101012B // mov# 0 0 szc ; carry from previous iteration? 101420B // incz 0 0 ; yes, add it in and zero carry 123000B // add 1 0 ; b+c 43007B // sta 0 @pa 2 15007B // dsz pa 2 15010B // dsz pb 2 15011B // dsz pc 2 175404B // inc 3 3 szr ; skip if 4th iteration 766B // jmp loop 35001B // lda 3 1 2 1401B // jmp 1 3 ] let Mult1 = table // Mult1(lvA, lvB, lvC): a ← b*c (b and c are 1 word each) [ 55001B // sta 3 1 2 41002B // sta 0 2 2 ; -> a 135000B // mov 1 3 ; -> b 25400B // lda 1 0 3 ; b 102460B // mkzero 0 0 155000B // mov 2 3 ; preserve stack 33403B // lda 2 @3 3 ; c 61020B // mul ; ac0,,ac1 ← ac0 + ac1*ac2 171000B // mov 3 2 ; restore stack 43002B // sta 0 @2 2 ; store high word of a 11002B // isz 2 2 47002B // sta 1 @2 2 ; store low word of a 35001B // lda 3 1 2 1401B // jmp 1 3 ] // Password (cont'd) let Mult2 = table // Mult2(lvA, lvB, lvC): a ← b*c (b and c are 2 words each) [ 55001B // sta 3 1 2 155000B // mov 2 3 ; preserve stack 41407B // sta 0 pa 3 ; -> a 45410B // sta 1 pb 3 ; -> b 102460B // mkzero 0 0 131000B // mov 1 2 25001B // lda 1 1 2 ; low word of b 31403B // lda 2 3 3 ; -> c 31001B // lda 2 1 2 ; low word of c 61020B // mul ; ac0,,ac1 ← ac0 + ac1*ac2 31407B // lda 2 pa 3 45003B // sta 1 3 2 ; store low word of low product 27410B // lda 1 @pb 3 ; high word of b 31403B // lda 2 3 3 31001B // lda 2 1 2 ; low word of c 61020B // mul ; ac0,,ac1 ← ac0 + ac1*ac2 41402B // sta 0 2 3 ; save high word of cross product 121000B // mov 1 0 ; add low word into other cross product 31410B // lda 2 pb 3 25001B // lda 1 1 2 ; low word of b 33403B // lda 2 @3 3 ; high word of c 61020B // mul ; ac0,,ac1 ← ac0 + ac1*ac2 31407B // lda 2 pa 3 45002B // sta 1 2 2 ; store low word of cross products 25402B // lda 1 2 3 ; combine high words of cross products 123020B // addz 1 0 ; this may carry out 27410B // lda 1 @pb 3 ; high word of b 33403B // lda 2 @3 3 ; high word of c 61020B // mul ; ac0,,ac1 ← ac0 + ac1*ac2 171002B // mov 3 2 szc ; restore stack, test carry from add 101400B // inc 0 0 35007B // lda 3 pa 2 45401B // sta 1 1 3 ; store low word of high product 41400B // sta 0 0 3 ; store high word of high product 35001B // lda 3 1 2 1401B // jmp 1 3 ] let a = v+1 let b = v+3 let c = vec 4 if newFlag then [ v!0 = -1 for i = 1 to UserName>>String.length do [ a!1 = a!0 lshift 9 + a!1 rshift 7 a!0 = (UserName>>String.char↑i) lshift 9 + a!0 rshift 7 ] Timer(b) // Manufactured b c = v+5 ] // Password (cont'd) // Compute c from a and b: let x = vec 4 let y = x+2 Zero(x, 4) for i = 1 to ps>>String.length do [ let c = ps>>String.char↑i if c eq $*S then break //In case he typed in a space. let p = ((i rem 3) eq 1)? x, y if c ge $a & c le $z then c = c-($a-$A) p!1 = p!0 lshift 9 + p!1 rshift 7 p!0 = c lshift 9 + p!0 rshift 7 ] // Now we have a,b,x,y let t = vec 4 Mult1(t, x, x) // t ← x*x Mult2(t, t, a) // t ← a*x*x // Now negate t. Bug -- should be: // for i = 0 to 3 do t!i = not (t!i) // but fixing it now would invalidate all existing passwords! t!0 = not t!0; t!1 = not t!1 Add4(t, t, table [ 0; 0; 0; 1 ]) let s = vec 4 Mult2(s, b, y) // s ← b*y Add4(c, t, s) // c ← t+s // All finished; now check it. for i = 0 to 3 do if v!(i+5) ne c!i then resultis false resultis true ]