; title 'PASSWORD.ASM'
; page 60
;
;
; PASSWORD.ASM
; Version 3.0
; By Bo McCormick 8/6/81
;
; This is a program that adds password protection
; to programs. Format:
;
; PASSWORD name_of_file
;
; Then answer the prompt with the password to be
; applied to the program:
;
; Password? enter password here
;
; If everything goes well, the program will be saved to disk.
; If not, a message is printed and control is passed
; to the CCP.
;
; The good part of this is, when you type in the program
; program name next time, instead of running the program
; right away, the program asks you for the password. If you
; reply with something other than the original password, the
; program doesn't run, and it returns to the ccp.
;
; 2/10/82: Set DMA before open because 1.4 CP/M uses buffer at 80H
; Removed "$" from labels so other assemblers can be used. Fixed
; "offset" to use tpa instead of 100H so it would work with
; modified CP/M. Added encryption of password so dumping .COM
; file will not reveal it. (Thanks to author of XYZZY.COM)
; Fixed test of supplied password to check all characters.
; Ted Shapin
;
; 12/10/81: changed ot$pw routine to input password one character
; at a time invisibly from BIOS rather than using BDOS's string input
; function. This allows password to be typed in without anyone
; seeing what it was that was typed. Jim Mills
;
;EQUATES
rdchar: equ 1
mesout: equ 9 ;BDOS functions
incon: equ 10
open: equ 15
close: equ 16
delete: equ 19
read: equ 20
write: equ 21
setdma: equ 26
;
cr equ 0dh ;ascii values
lf equ 0ah
eos equ '$'
;
boot equ 0;4200H ;0 for standard CP/M
;4200H for ALT. CP/M;
bdos equ boot+5
fcb equ boot+5ch
defbuf equ boot+80h
tpa equ boot+100h
stack equ tpa ;out of way of tpa
;
org tpa
;
;
start: lxi h,0 ;save stack pointer
dad sp ;put stack in hl
shld oldstack-offset ;save it
lxi sp,stack ;get new stack
;
; stack saved so program can return to CCP without
; intervening warm start.
;
lda fcb+9 ;get first char of extension
cpi ' ' ;if ' ' then change to .COM
jz notype
cpi 'C' ;If there is an extension,
jnz notright ;make sure it's .COM
lda fcb+10 ;check second letter
cpi 'O'
jnz notright
lda fcb+11
cpi 'M' ;last letter
jz iscom ;if it is a COM, then cont.
notright:
call endmes ;it's not a com file, so tell
;
db cr,lf,'Must be a command (.COM) file'
db cr,lf,eos
;
endmes:
pop d ;get address of message
mvi c,mesout ;PRINT STRING command
call bdos ;print error message
;
finish: lhld oldstack-offset ;get old stack
sphl ;put it in HL
ret ;return to CP/M
;
notype: mvi a,'C' ;if there was space, change
sta fcb+9 ;to COM
mvi a,'O'
sta fcb+10
mvi a,'M'
sta fcb+11
;
iscom: lxi d,buffer-offset ;point to where program goes
mvi c,setdma ;SET DMA command
push d ;save it
call bdos ;and tell CP/M
mvi a,0 ;zero record count
sta fcb+32
mvi c,open ;OPEN file command
lxi d,fcb ;load address of FCB in DE
call bdos ;Open file
inr a ;successful?
jnz openok ;if so, then continue
call endmes ;if not, then tell
;
db cr,lf,'Cannot open file',cr,lf,eos
;
openok: pop d ;get starting dma back
rloop: mvi c,setdma ;and set it in loop
push d ;save it
call bdos
lxi d,fcb ;point to FCB
mvi c,read ;READ sector command
call bdos ;do it
pop d ;get DMA address back
ana a ;EOF?
jnz doneread ;if so, then ask for password
lxi h,80h ;length of sector
dad d ;bump DMA
xchg ;put new address in DE
jmp rloop ;and read some more
;
doneread:
xchg ;dma ==> hl
shld endprog-offset ;save last address
gpasag call getpas ;print password message
;
pasmes db 'Password? ',eos
;
getpas pop d ;get address of message
mvi c,mesout ;PRINT STRING function
call bdos ;print it
lxi d,defbuf ;point to default buffer
mvi a,8 ;tell CP/M max chars
stax d ;put it there
mvi c,incon ;READ LINE command
call bdos ;do it
lxi h,defbuf+1 ;point to length
lxi d,password-offset ;point to storage
mov a,m ;get length
ana a ;set flags
jz gpasag ;if 0 then ask again
inr a ;plus 1 for length byte
mov b,a ;put length in B
xra b ;cancel first xra in loop
mov m,a ;and put it back
mploop mov a,m ;get char
xra b ;encrypt it
stax d ;save it
inx h ;increment pointer
inx d ; " "
dcr b ;decrement length
jnz mploop ;if not zero, then next char
xra a ;zero a
sta fcb+12 ;zero bytes in FCB
sta fcb+14
sta fcb+32
mvi c,open ;OPEN file command
lxi d,fcb ;point to FCB
call bdos ;open the file
lxi d,nstart ;point to new program start
;
push d
wloop1 pop d ;get DMA
push d ;put it back on stack
mvi c,setdma ;SET DMA command
call bdos ;tell CP/M
lxi d,fcb ;point to FCB
mvi c,write ;WRITE SECTOR command
call bdos ;do it
pop h ;get DMA address from stack
lxi d,80h ;length of sector
dad d ;HL has new DMA
push h ;put it on stack
mov a,h ;this is to get 2's complement
cma ;of address. We are subtracting
mov d,a ;the current address from the
mov a,l ;high address. If the high byte
cma ;<1 , we are done
mov e,a ;
inx d ;Now 2's comp. of address in DE
lhld endprog-offset ;get ending address
dad d ;Subtract (add 2's comp)
mov a,h ;get high byte
inr a ;is it FF (-1)?
ana a ;set flags
jnz wloop1 ;if not, write another sector
;
mvi c,close ;That's it. Close the file
lxi d,fcb ;point to FCB
call bdos ;do it
jmp finish ;goto finish
;
;
nstart:
offset equ tpa-nstart
;
; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
; %% WARNING - %%
; %% From now on, all labels are in %%
; %% the form: %%
; %% LABEL EQU $+OFFSET %%
; %% This is to allow the program to run at100H %%
; %% when it is saved by the earlier portion. %%
; %% ALL new labels added MUST be in the form %%
; %% LABEL EQU $+OFFSET for this program to work %%
; %% properly. %%
; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;
;This is portion of the program is placed at the beginning
;of the program to be PASSWORDed. When it is executed, it will
;ask for a password. If the password is incorrect, the program
;warm starts. If the password is correct, the program is moved
;to the TPA and executed.
;
lxi h,0 ;save stack pointer
dad sp ;stack is in HL
shld oldstack ;save it
lxi sp,stack ;get new stack
call otpw ;print password message
;
db cr,lf,'Password? '
db eos
;
otpw equ $+offset
pop d ;get address of message
mvi c,mesout ;PRINT STRING command
call bdos ;print it
lxi d,newbuf+1 ;point to storage area
xra a
mov b,a ;init counter
stax d ;# of chars typed (for compare)
inx d ;and point to string
;
; we don't want to allow 'lookers' to see the password, so call
; bios instead of bdos to prevent echo. also allows control chars.
;
lhld boot+1 ;get addr of warm start routine
push d
lxi d,6 ;+ offset to kbd input routine
dad d
pop d
shld bconin+1 ;now init'd to bios conin
otpw1 equ $+offset
push b ;save counter..
push d ;..& pointer
bconin equ $+offset
call $-$ ;to be filled in by above routine
pop d ;restore pointer..
pop b ;..& counter
stax d ;store char
inx d ;bump pointer..
inr b ;..& counter
cpi cr
jnz otpw1 ;loop until cr typed
; B has the length of password furnished + 1 for count.
lxi h,password ;point to actual password
lxi d,newbuf+1 ;point to user's input
xra a ;this 0 xra with length in B
stax d ;should equal count in passwd
;
; first char compared is a count of # of chars in password,
; followed by password itself.
;
clp equ $+offset
ldax d ;get char
xra b ;encrypt it
cmp m ;are they the same?
jnz boot ;if not, restart
inx h ;point to next characters
inx d ; " " " "
dcr b ;decrement length
jnz clp ;if not done, then loop
;
; Now we move a segment of code to a part of the default
; buffer. This segment moves the actual program down to the
; TPA
;
lxi h,nmv ;point to code
lxi d,defbuf+20h ;point to new postion
mvi b,nmlen ;length
;
move equ $+offset
mov a,m ;get byte
stax d ;save it
inx d ;point to next addresses
inx h ; " " " "
dcr b ;decrement length
jnz move ;if not done, loop
jmp defbuf+20h ;go to segment
;
nmv equ $+offset ;segment that gets moved
lhld oldstack ;get stack pointer
push h ;save it on stack
lxi h,buffer ;get start of actual program
mov a,h ;We have to compute the length
cma ;and because X-Y equals
mov d,a ;X + Two's complent(Y), we have
mov a,l ;to find the 2's comp. of the
cma ;first address
mov e,a ;
inx d ;Y is in DE
lhld endprog ;get last address
dad d ;subtract (add 2's comp)
mov b,h ;put length in BC
mov c,l ; " " " "
lxi d,tpa ;point to TPA
lxi h,buffer ;point to first address
nmlp equ defbuf+20h+$+offset-nmv
mov a,m ;get byte
stax d ;save byte
inx h ;increment address
inx d ; " "
dcx b ;decrement length
mov a,b ;check for zero left
ora c ;Are we done?
jnz nmlp ;if not, loop some more
pop h ;get stack from stack
sphl ;put stack in SP
jmp tpa ;run program
;
nmlen equ $+offset-nmv ;length of segment
;
;
password equ $+offset ;password storage
db 0,' '
;
;12/10/81 changed to allow use of tbuf as input area
;
newbuf equ $+offset ;Users input buffer
db 10H,0,' '
;
oldstack equ $+offset ;place for stack
ds 2
;
endprog equ $+offset ;place for address
ds 2
;
buffer equ $+offset ;where actual program goes
end