.TITLE HPWD - hash user password .IDENT 'X-2' ; ;**************************************************************************** ;* * ;* COPYRIGHT (c) 1978, 1980, 1982, 1984 BY * ;* DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. * ;* ALL RIGHTS RESERVED. * ;* * ;* THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED * ;* ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE * ;* INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER * ;* COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY * ;* OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY * ;* TRANSFERRED. * ;* * ;* THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE * ;* AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT * ;* CORPORATION. * ;* * ;* DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS * ;* SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. * ;* * ;* * ;**************************************************************************** ;++ ; FACILITY: User Verification Subroutine ; ; ABSTRACT: ; ; ENVIRONMENT: ; ; AUTHOR: H. M. Levy , CREATION DATE: 20-Sep-1977 ; ; MODIFIED BY: ; ; X-2 DDP0282 Derrell D. Piper 20-APR-1988 13:58 ; Only test low word of password descriptor. Otherwise, a ; descriptor with TYPE/CLASS information filled in will confuse ; this routine. While it is reasonable to ignore the TYPE/CLASS ; information, we shouldn't assume that it is zero. ; ; V03-002 SHZ0002 Stephen H. Zalewski, 02-Mar-1984 ; If zero length password is passed in, return a null password. ; If PURGY_V algorithm used, add check to prevent us from searching ; beyond length of username buffer. ; ; V03-001 SHZ0001 Stephen H. Zalewski 14-Feb-1984 ; Add support for PURDY and PURDY_V encryption. ; ;-- .SBTTL DECLARATIONS ; ; MACROS: ; .macro pushq Src movq Src,-(sp) .endm .macro popq Dst movq (sp)+,Dst .endm ; ; EQUATED SYMBOLS: ; OUTDSC = 4 ; adr of encrypted output descriptor PWDDSC = OUTDSC + 4 ; adr of password descriptor ENCRYPT = PWDDSC + 4 ; encryption algorithm index (byte) SALT = ENCRYPT + 4 ; random number (word) USRDSC = SALT + 4 ; adr of username descriptor ; ; OWN STORAGE: ; .psect _LIB$CODE RD,NOWRT,PIC,SHR,BYTE,EXE ; ; AUTODIN-II polynomial table used by CRC algorithm ; AUTODIN: .LONG ^O00000000000,^O03555610144,^O07333420310,^O04666230254 .LONG ^O16667040620,^O15332650764,^O11554460530,^O12001270474 .LONG ^O35556101440,^O36003711504,^O32665521750,^O31330331614 .LONG ^O23331141260,^O20664751324,^O24002561170,^O27557371034 ; The following table of coefficients is used by the Purdy polynomial ; algorithm. They are prime, but the algorithm does not require this. C: .long -83, -1 ; C1 .long -179, -1 ; C2 .long -257, -1 ; C3 .long -323, -1 ; C4 .long -363, -1 ; C5 .SBTTL Dispatch - select encryption algorithm ;++ ; ; FUNCTIONAL DESCRIPTION: ; ; Smash up the password into a non-reversable number. ; ; CALLINGS SEQUENCE: ; ; CALLS/CALLG ; ; INPUTS: ; ; PWDDSC - Address of password descriptor ; ENCRYPT - Encryption algorithm index (byte) ; SALT - random number (word) ; USRDSC - Address of username descriptor ; ; IMPLICIT INPUTS: ; ; none ; ; OUTPUTS: ; ; OUTDSC - Address of output buffer descriptor ; ; IMPLICIT OUTPUTS: ; ; none ; ; ROUTINE VALUE: ; ; Success status ; ; SIDE EFFECTS: ; ; none ;-- .entry LGI$HPWD,^M ; entry mask tstb ENCRYPT(ap) ; using CRC algorithm? beql 20$ ; yes, no processing of user desc necessay. subl2 #20,sp ; Get temp desc and buffer off stack movl sp,r6 ; Put address into r6 movq @USRDSC(ap),(r6) ; Put current user desc into stack desc. cmpb #1,ENCRYPT(ap) ; Which PURDY algorithm? bneq 10$ movc5 (r6),@4(r6),#32,#12,8(r6) ; PURDY. 12 character blank pad username movw #12,(r6) ; size of desc is now 12 movab 8(r6),4(r6) ; Point desc to buffer on stack. brb 20$ ; goto main line ; PURDY_V. Remove padding from username. 10$: movzwl (r6),r5 ; Save length of username in r5. clrw (r6) movl 4(r6),r0 ; Get address of username buffer into R0. 15$: cmpb (r0)+,#32 ; Search until we find first blank. beql 20$ incw (r6) ; Increment byte count until blank found cmpw #31,(r6) ; or 31 characters have been encountered beql 20$ ; (31 is max username length). cmpw r5,(r6) ; or entire buffer has been parsed. beql 20$ ; (someone not playing by the rules) brb 15$ 20$: movaq @PWDDSC(ap),r4 ; If password is zero length tstw (r4) ; (only check low word) bneq 25$ movaq @OUTDSC(ap),r4 ; Then return null password clrw (r4) movc5 #0,(r4),#0,#8,@4(r4) ; (quadword of zeros) brb 40$ 25$: movaq @OUTDSC(ap),r4 ; Get pointer to output buffer movaq @4(r4),r4 tstb ENCRYPT(ap) ; Use the CRC algorithm if the index bgtru 30$ ; is zero mnegl #1,r0 ; initial CRC movaq @PWDDSC(ap),r1 ; get descriptor address crc AUTODIN,r0,(r1),@4(r1) ; convert password to 32-bit number clrl r1 ; high order longword will be zero movq r0,(r4) ; copy result to the output buffer brb 40$ 30$: clrq (r4) ; Initialize output buffer movaq @PWDDSC(ap),r3 ; Collapse password to a quadword bsbb COLLAPSE_R2 addw2 SALT(ap),3(r4) ; Add random salt into middle of U movl r6,r3 ; Collapse username into the quadword bsbb COLLAPSE_R2 pushaq (r4) ; Push pointer to U calls #1,Purdy ; Run U through the polynomial mod P 40$: movl #1,r0 ret COLLAPSE_R2: .enabl LSB ; This routine takes a string of bytes (the descriptor for which is pointed ; to by r3) and collapses them into a quadword (pointed to by r4). It does ; this by cycling around the bytes of the output buffer adding in the bytes ; of the input string. movzwl (r3),r0 ; Obtain the number of input bytes beqlu 20$ moval @4(r3),r2 ; Obtain pointer to input string 10$: bicl3 #-8,r0,r1 ; Obtain cyclic index into output buffer addb2 (r2)+,(r4)[r1] sobgtr r0,10$ ; Loop until input string is exhausted 20$: rsb .dsabl LSB .sbttl Purdy - evaluate Purdy polynomial a=59 ; 2^64 - 59 is the biggest quadword prime n0=1@24 - 3 ; These exponents are prime, but this is n1=1@24 - 63 ; not required by the algorithm. .entry Purdy,^M ; ; This routine computes f(U) = p(U) mod P. Where P is a prime of the form ; P = 2^64 - a. The function p is the following polynomial: ; X^n0 + X^n1*C1 + X^3*C2 + X^2*C3 + X*C4 + C5 ; The input U is an unsigned quadword. ; pushq @4(ap) ; Push U bsbw PQMOD_R0 ; Ensure U less than P movaq (sp),r4 ; Maintain a pointer to X movaq C,r5 ; Point to the table of coefficients pushq (r4) pushl #n1 bsbb PQEXP_R3 ; X^n1 pushq (r4) pushl #n0-n1 bsbb PQEXP_R3 pushq (r5)+ ; C1 bsbw PQADD_R0 ; X^(n0 - n1) + C1 bsbw PQMUL_R2 ; X^n0 + X^n1*C1 pushq (r5)+ ; C2 pushq (r4) bsbw PQMUL_R2 ; X*C2 pushq (r5)+ ; C3 bsbw PQADD_R0 ; X*C2 + C3 pushq (r4) bsbb PQMUL_R2 ; X^2*C2 + X*C3 pushq (r5)+ ; C4 bsbw PQADD_R0 ; X^2*C2 + X*C3 + C4 pushq (r4) bsbb PQMUL_R2 ; X^3*C2 + X^2*C3 + C4*X pushq (r5)+ ; C5 bsbw PQADD_R0 ; X^3*C2 + X^2*C3 + C4*X + C5 bsbw PQADD_R0 ; Add in the high order terms popq @4(ap) ; Replace U with f(X) movl #1,r0 ret PQEXP_R3: .enabl LSB ; Replaces the inputs with U^n mod P where P is of the form P = 2^64 - a. ; U is a quadword, n is an unsigned longword. popr #^M ; Record return address pushq #1 ; Initialize pushq 8+4(sp) ; Copy U to top of stack for speed tstl 8+8(sp) ; Only handle n greater than 0 beqlu 30$ 10$: blbc 8+8(sp),20$ pushq (sp) ; Copy the current power of U pushq 8+8(sp) ; Multiply with current value bsbb PQMUL_R2 popq 8(sp) ; Replace current value cmpzv #1,#31,8+8(sp),#0 beqlu 30$ 20$: pushq (sp) ; Proceed to next power of U bsbb PQMUL_R2 extzv #1,#31,8+8(sp),8+8(sp) brb 10$ 30$: movq 8(sp),8+8+4(sp) ; Copy the return value movaq 8+8+4(sp),sp ; Discard the exponent jmp (r3) ; return .dsabl LSB u=0 ; Low longword of U v=u+4 ; High longword of U y=u+8 ; Low longword of Y z=y+4 ; High longword of Y PQMOD_R0: .enabl LSB ; Replaces the quadword U on the stack with U mod P where P is of the ; form P = 2^64 - a. popr #^M ; Record return address cmpl v(sp),#-1 ; Replace U with U mod P blssu 10$ cmpl u(sp),#-a blssu 10$ addl2 #a,u(sp) adwc #0,v(sp) 10$: jmp (r0) ; return .dsabl LSB PQMUL_R2: ; Computes the product U*Y mod P where P is of the form P = 2^64 - a. ; U, Y are quadwords less than P. The product replaces U and Y on the stack. ; The product may be formed as the sum of four longword multiplications ; which are scaled by powers of 2^32 by evaluating: ; 2^64*v*z + 2^32*(v*y + u*z) + u*y ; The result is computed such that division by the modulus P is avoided. popr #^M ; Record return address movl sp,r2 ; Record initial stack value pushl z(r2) pushl v(r2) bsbb EMULQ bsbb PQMOD_R0 bsbb PQLSH_R0 ; Obtain 2^32*v*z pushl y(r2) pushl v(r2) bsbb EMULQ bsbb PQMOD_R0 pushl z(r2) pushl u(r2) bsbb EMULQ bsbb PQMOD_R0 bsbb PQADD_R0 ; Obtain (v*y + u*z) bsbb PQADD_R0 ; Add in 2^32*v*z bsbb PQLSH_R0 ; Obtain the first two terms pushl y(r2) pushl u(r2) bsbb EMULQ bsbb PQMOD_R0 ; Obtain the third term: u*y bsbb PQADD_R0 ; Add it in popq Y(r2) ; Copy the return value movaq Y(r2),sp ; Point the stack to the return value jmp (r1) ; return EMULQ: .enabl LSB ; This routine knows how to multiply two unsigned longwords, replacing them ; with the unsigned quadword product on the stack. emul 4(sp),8(sp),#0,-(sp) clrl -(sp) tstl 4+8+4(sp) ; Check both longwords to see if we must bgeq 10$ ; compensate for the unsigned bias. addl 4+8+8(sp),(sp) 10$: tstl 4+8+8(sp) bgeq 20$ addl 4+8+4(sp),(sp) 20$: addl (sp)+,4(sp) ; Add in the compensation. popq 4(sp) ; Replace the longwords with their product. rsb .dsabl LSB PQLSH_R0: .enabl LSB ; Computes the product 2^32*U mod P where P is of the form P = 2^64 - a. ; U is a quadword less than P. The product replaces U on the stack. ; This routine is used by PQMUL in the formation of quadword products in ; such a way as to avoid division by the modulus P. ; The product 2^64*v + 2^32*u is congruent a*v + 2^32*u mod P (where u, v ; are longwords). popr #^M ; Record return address pushl v(sp) pushl #a bsbb EMULQ ; Push a*v ashq #32,Y(sp),Y(sp) ; Form Y = 2^32*u brb 10$ ; Return the sum U + Y mod P. PQADD_R0: ; Computes the sum U + Y mod P where P is of the form P = 2^64 - a. ; U, Y are quadwords less than P. The sum replaces U and Y on the stack. popr #^M ; Record return address 10$: addl2 u(sp),y(sp) ; Add the low longwords adwc v(sp),z(sp) ; Add the high longwords with the carry bcs 20$ ; If the result is greater than a quadword cmpl z(sp),#-1 blssu 30$ cmpl y(sp),#-a ; or simply greater than or equal to P blssu 30$ 20$: addl2 #a,y(sp) ; we must subtract P. adwc #0,z(sp) 30$: movaq Y(sp),sp ; Point the stack to the return value jmp (r0) ; return .dsabl LSB .END