; ;Scramble.asm - program to scramble CP/M files ;using an 8 byte password ; month equ 3 ;last.. day equ 14 ;..modification.. year equ 79 ;..date ; ;Scrambling is done in place, i.e. the file is ;modified on top of itself. The same password ;used to scramble the file is used to unscramble ;it, using the exact same command. This is because ;the scrambling code is exclusive-or'ed with the ;data file, and two same exclusive ors result ;in the original value being returned. ; ;Command format: ; ; scramble filename.type password ; ;where password is any 8 character string which ;is allowable as a file name (i.e. no '.', etc). ; MF SET 0 ;SHOW MOVE NOT REQUESTED CF SET 0 ;SHOW COMP NOT REQUESTED ; ;(FROM EQU8.LIB...) ;DEFINE SOME MACROS TO MAKE THINGS EASIER ; ;DEFINE DATA MOVE MACRO: MOVE from,to,length ; from may be addr, or quoted string ; MOVE MACRO ?F,?T,?L IF NOT NUL ?F IRPC ?C,?F ?Q SET '&?C&?C' ;;TEST FOR QUOTE EXITM ENDM IF ?Q EQ '''' LOCAL ?B,?Z CALL ?Z ?B DB ?F ?Z POP H ;GET FROM LXI B,?Z-?B ;GET LEN ELSE LXI H,?F ENDIF ENDIF IF NOT NUL ?T LXI D,?T ENDIF IF NOT NUL ?L LXI B,?L ENDIF CALL MOVER MF SET -1 ;;SHOW EXPANSION ENDM ; ;DEFINE CP/M MACRO - CPM FNC,PARM ; CPM MACRO ?F,?P PUSH B PUSH D PUSH H IF NOT NUL ?F MVI C,?F ENDIF IF NOT NUL ?P LXI D,?P ENDIF CALL BDOS POP H POP D POP B ENDM ; ORG 100H CALL START DB 'SCRAMBLE.COM AS OF ' DB '0'+MONTH/10 DB '0'+MONTH MOD 10,'/' DB '0'+DAY/10 DB '0'+DAY MOD 10,'/' DB '0'+YEAR/10 DB '0'+YEAR MOD 10 DB 0DH,0AH,'$' START POP D ;GET ID MVI C,PRINT CALL BDOS ;PRINT ID ; ;INIT LOCAL STACK ; LXI H,0 DAD SP SHLD STACK LXI SP,STACK ; ;START OF PROGRAM EXECUTION ; ;SCRAMBLE A WHILE TO MIX UP THE SEED ; MVI H,0 ;GET 256 #'S MIXUP CALL PSEURAN ;GET A # DCR H ;MORE? JNZ MIXUP ;LOOP IF SO ; ;SEE THAT THE PASSWORD IS 8 CHARACTERS ; LDA FCB2+8 CPI ' ' JNZ PWIS8 CALL ERXIT DB '++ PASSWORD NOT 8 BYTES ++$' ; ;SAVE THE PASSWORD ; PWIS8 MOVE FCB2+1,PASSWD,8 ; ;PASSWORD IS 8 BYTES, NOW MAKE SURE NO CHARACTER ;IS REPEATED MORE THAN 2 TIMES ; LXI H,PASSWD MVI B,8 ;8 CHARS TO TEST DUPTEST CALL CKDUP ;ABORTS IF 3 = CHARS INX H ;TO NEXT CHAR DCR B JNZ DUPTEST ; ;SEE THAT THE INPUT FILE EXISTS ; CPM OPEN,FCB INR A ;OK? JNZ SCRAMLP ;YES, SCRAMBLE IT CALL ERXIT DB '++NO SUCH FILE++$' ; ;READ THE FILE, SCRAMBLE A SECTOR, RE-WRITE IT. ; SCRAMLP CALL RDSECT ;READ A SECTOR JC FINISH ;EXIT LOOP IF EOF CALL SCRAMBL ;SCRAMBLE IT CALL BACKUP ;RE-POSITION FOR WRITE CALL WRSECT ;RE-WRITE THE SECTOR JMP SCRAMLP ;LOOP UNTIL EOF ; ;ALL DONE - ON A "NORMAL" CP/M SYSTEM, WE WOULDN'T ;HAVE TO DO ANYTHING, BECAUSE WE RE-WROTE IN PLACE. ; ;HOWEVER, FOR SUCH SYSTEMS AS THE NORTHSTAR CP/M, ;WE MUST EXPLICITLY CLOSE THE FILE, BECAUSE THE WRITE ;TO THE DIRECTORY WILL CAUSE THE CLEVER LIFEBOAT- ;DESIGNED BIOS TO FLUSH IT'S MEMORY-RESIDENT DISK ;BUFFERS ; FINISH CPM CLOSE,FCB INR A ;THIS BETTER WORK.. JNZ EXIT DB '++ CLOSE ERROR - FILE LEFT IN ' DB 'UNKNOWN CONDITION ++$' ; ;SECTOR READ ROUTINE ; RDSECT CPM READ,FCB ORA A RZ ;ALL OK ; ;READ ERROR OR EOF ; CPI 1 ;EOF? STC ;CARRY SHOWS EOF RZ ;RET, CARRY SET CALL ERXIT DB '++ READ ERROR - FILE MAY BE ' DB 'DESTROYED ++$' ; ;SCRAMBLE THE SECTOR ; SCRAMBL LXI H,80H ;POINT TO SECTOR SCRLP CALL PSEURAN ;GET PSEUDO RANDOM # XRA M ;SCRAMBLE MOV M,A INR L ;MORE IN SECTOR? JNZ SCRLP RET ; ;BACKUP THE FILE POINTER FOR THE RE-WRITE ; BACKUP LDA FCBRNO ;GET SECTOR # DCR A ;BACK UP STA FCBRNO RP ;RETURN IF OK ; ;WE BACKED UP INTO PREVIOUS EXTENT, WILL HAVE ;TO RE-OPEN IT ; LDA FCBEXT ;GET EXTENT DCR A ;BACK UP 1 STA FCBEXT CPM OPEN,FCB ;RE-OPEN INR A JNZ OPEN2OK CALL ERXIT DB '++ RE-OPENING EXTENT FAILED',0DH,0AH DB '++ FILE IS CLOBBERED $' OPEN2OK MVI A,7FH ;GET HI SECTOR STA FCBRNO RET ; ;WRITE BACK THE SECTOR ; WRSECT CPM WRITE,FCB ORA A RZ CALL ERXIT DB '++ WRITE ERROR - FILE CLOBBERED ++$' ; ;GET A PSEUDO-RANDOM 8 BIT NUMBER USING THE PASSWORD ;AS A SEED ; ; FOR SPEED, THIS ROUTINE DOES NO REGISTER ; PUSHES AND POPS, HOWEVER HL AREN'T USED. ; PSEURAN MVI C,4 ;GRAB EVERY 4TH PSEU. # PSEULP0 MVI B,8 ;SHIFT THRU 8 BYTES LXI D,PASSWD ORA A ;CLEAR INITIAL CARRY PSEULP1 LDAX D ;GET A CHAR RAR ;SHIFT STAX D INX D DCR B JNZ PSEULP1 ;EXCLUSIVE-OR THE LAST FEW BITS INTO THE FIRST ONE DCX D ;BACK UP TO LAST RAR RAR ;SHIFT A FEW MORE XCHG XRA M RRC ;SHIFT LO BIT INTO HI ANI 80H ;ISOLATE SINGLE BIT LXI H,PASSWD ;GET FIRST BYTE ORA M ;'OR' IN THE BIT MOV M,A ;MOVE IT BACK XCHG ;RESTORE HL DCR C JNZ PSEULP0 ;LOOP IF MORE PASSES RET ; ;ROUTINE TO CHECK FOR DUPLICATE CHARS IN PASSWORD ; CKDUP MVI C,3 ;DUP CHAR COUNTER LXI D,PASSWD MVI A,8 ;CHAR COUNT CKDLP PUSH PSW ;SAVE COUNT LDAX D ;GET CHAR CMP M ;DUP? JNZ CKNDUP DCR C ;COUNT DUPS JNZ CKNDUP STA DUPCHAR ;SAVE FOR PRINT CALL ERXIT DB '++ NO CHARACTER MAY APPEAR MORE ' DB 'THAN TWICE IN THE PASSWORD. ',0DH,0AH DB '''' DUPCHAR DB $-$,''' DOES IN YOURS ++$' CKNDUP INX D POP PSW ;GET COUNT DCR A JNZ CKDLP RET ;OK, NOT 3 DUP ; ;FOLLOWING FROM 'EQU7.LIB'----> ; ;MOVE SUBROUTINES ; IF MF ;MACRO EXPANSION FLAG SET? MOVER MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ MOVER RET ENDIF ; ;EXIT WITH ERROR MESSAGE MSGEXIT EQU $ ;EXIT W/"INFORMATIONAL" MSG ERXIT POP D ;GET MSG MVI C,PRINT CALL BDOS ;EXIT, RESTORING STACK AND RETURN EXIT LHLD STACK SPHL RET ;TO CCP PASSWD DS 8 ;PASSWORD KEPT HERE DS 40H ;STACK AREA STACK DS 2 ;BDOS/CBIOS EQUATES (VERSION 7) RDCON EQU 1 WRCON EQU 2 PRINT EQU 9 CONST EQU 11 OPEN EQU 15 CLOSE EQU 16 SRCHF EQU 17 SRCHN EQU 18 ERASE EQU 19 READ EQU 20 WRITE EQU 21 MAKE EQU 22 REN EQU 23 STDMA EQU 26 BDOS EQU 5 FCB EQU 5CH FCB2 EQU 6CH FCBEXT EQU FCB+12 FCBRNO EQU FCB+32