.TITLE FDHostcry - AXP/VMS VIRT DISK Host Process (crypto disk) .IDENT 'V01-004b' .enable SUP ;whatever this does evax = 1 alpha=1 bigpage=1 addressbits=32 ; Uncopyright 1988, 1989, 1990 Glenn C. Everhart ; Public Domain. May be used by all for any purpose. ; Enjoy! ; changes : ; Mods to key generation algorithm to allow for ; 1. Longer base keys (128 blocks, not 32) ; 2. Better "confusion propagation" by not using the same CRC ; we start with as part of what we XOR everything with. ; 3. Somewhat better confusion factor added to guard against ; someone who tries known plaintext attack by doing a ; better job randomizing the block number based part ; of messing up the data. ; ; It occurred to me that the fdhostcry2 host had a basic key generated ; from a known CRC polynomial series, modified by further XORs with ; other known CRCs and an XOR of the product of block number with ; part of the generated key, further confused by having the key order ; picked by yet another blocknumber * part of key product. ; ; The potential codebreaker will know much of the cleartext of a valid ; ODS2 disk, so can probably figure out the cipher too easily. I don't ; know how exactly, but suspect this. ; Therefore, the algorithm now generates a CRC of the key and uses ; parts of it for part of the CRC polynomial used to fill in 128 blocks ; worth of key xor data, and another part for the interval between ; CRC polynomials used. Thus the potential codebreaker now lacks a priori ; knowledge of the main CRC polynomial and interval used. By making the ; block number product larger, he now must handle a far larger block ; range also. I also have added another byte out of the key to the ; input block number prior to using it, so block zero is not guaranteed ; to use the first key block as before, but can use any of them. ; This should make a cracker's life more difficult. Since this stuff ; is mainly done at setup time, the cryptodisk is still reasonably ; fast. One can of course obtain, say, a DES implementation (the Finnish ; one and variants of the 1977 ham radio one are widely available on ; networks and have appeared in the usenet) and use that. It can ; either replace these algorithms, or be used to re-encrypt the ; ciphertext. Software DES is quite slow, though, and this is probably ; NOT a good idea. That's why no special hooks are provided. Remember ; that a shared machine cannot be totally safe from people with privs ; and that the essential ingredient to using a cryptodisk is to be ; watchful of privilege use while data is in use on the cryptodisks. ; ; FACILITY: ; ; Host process for FD: unit that uses a disk file as an encrypted virtual ; disk. The disk file and encryption key must be specified. ; The file need not be contiguous. ; ; Command format: ; FDHost/switches VDn: filespec ; where a .CLD file is expected so that this can all be parsed by ; the CLI. The legal switches will just be /KEY="charstring" ; to specify the encryption key to use to encrypt/decrypt the data. ; All data will be encrypted on write or decrypted on read from the ; file so that the information will be in the clear ONLY where read. Since ; this process handles all this operation, the key will reside in this process ; and not in some readily-locatable system area. Therefore it will be quite ; difficult to find a key even when it is in memory. ; ; FDHOST/CLEAR will zero the ref. count only...nothing more. ; Note deassign normally will NOT be via command (I don't see how a ; command could ever be read) but via exit AST. We could in principle arrange ; an I/O that fddrv would store somewhere, so that if this process exited the ; fddrv driver would be informed of it and could complete the I/O AND set ; itself offline, but I am uncomfortable with this kind of jiggery-pokery. ; Better to just let the ref count be zeroed, since that's the only "dirty" trace ; around. This may allow playing some games later with multiple hosts also. ; The expectation is that an fd: unit being assigned will have FDHOST/CLEAR ; run on the FD: unit before assigning it if the unit was set incorrectly. ; ; Note: define VMS$V5 to build for Version 5.x of VMS. ; vms$v5=0 ; ; AUTHOR: ; ; G. EVERHART ; 5/17/1989 - Added stronger encryption logic. Still not incredibly ; strong, but at least more resistant to decryption by inspection. ; Algorithm is now good enough that I can't see any easy way to break it, ; even given the code, without a very long disk and lots of time. Thus I ; now consider it adequate for protecting sensitive information. Remember: ; your systems guy may be very very GOOD at his job, but it still might not ; be a good idea for him to be able to print out the payroll file. This ; device is designed to help you keep him from being tempted. *I* find it ; good to know that some information on the system is secure and I cannot ; be blamed for any disclosures of it. ; ; 3/29/90 - Longer keys etc. ; Resulting cryptodisks are not compatible with the ; fdhostcry2 versions, so don't mix them up. ;-- .PAGE .SBTTL EXTERNAL AND LOCAL DEFINITIONS .LIBRARY /ALPHA$LIBRARY:LIB/ .nocross ;save trees ; ; EXTERNAL SYMBOLS ; $ADPDEF ;DEFINE ADAPTER CONTROL BLOCK $CRBDEF ;DEFINE CHANNEL REQUEST BLOCK $DCDEF ;DEFINE DEVICE CLASS $DDBDEF ;DEFINE DEVICE DATA BLOCK $DEVDEF ;DEFINE DEVICE CHARACTERISTICS $DPTDEF ;DEFINE DRIVER PROLOGUE TABLE $EMBDEF ;DEFINE ERROR MESSAGE BUFFER $IDBDEF ;DEFINE INTERRUPT DATA BLOCK $IODEF ;DEFINE I/O FUNCTION CODES $IRPDEF ;DEFINE I/O REQUEST PACKET $PRDEF ;DEFINE PROCESSOR REGISTERS $PCBDEF ;DEFINE PCB OFFSETS $SCSDEF $SBDEF $STSDEF $STSDEF ; Symbols for returned status. $DVIDEF ; Symbols for $GETDVI service. $DCDEF ; Symbols for device type. $SSDEF ;DEFINE SYSTEM STATUS CODES $UCBDEF ;DEFINE UNIT CONTROL BLOCK $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK ; $ACBDEF ; Define AST Control Block offsets. $DYNDEF ;define dynamic data types $DDTDEF ; DEFINE DISPATCH TBL... $ptedef $vadef $irpedef $ipldef $pcbdef $jibdef .IF DF,VMS$V5 ;VMS V5 + LATER ONLY $cpudef ;thanks to Chris Ho for V5 fix $SPLCODDEF .ENDC $FIBDEF ; Symbols for file information block. $IODEF ; Symbols for QIO functions. $DVIDEF ; Symbols for $GETDVI calls. $TPADEF ; Symbols for LIB$TPARSE calls. $ATRDEF $FABDEF ; define lotsa' more rubbish we might want... $FATDEF $FIBDEF $IODEF $NAMDEF $RMSDEF $XABDEF .cross ; ; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS ; $DEFINI UCB ;START OF UCB DEFINITIONS ;.=UCB$L_BCR+2 ;BEGIN DEFINITIONS AT END OF UCB .=UCB$K_LCL_DISK_LENGTH ;v4 def end of ucb ; USE THESE FIELDS TO HOLD OUR LOCAL DATA FOR VIRT DISK. ; Add our stuff at the end to ensure we don't mess some fields up that some ; areas of VMS may want. ;The following must match the same-named data in the ACB extension .blkl 2 ;safety $DEF UCB_L_UCB .BLKL 1 ;Save UCB address here $DEF UCB_L_MEMBUF .BLKL 1 ;Address of buffer for this transfer $DEF UCB_L_NSPTS .BLKL 1 ;Number of SPTs required for buffer $DEF UCB_L_SVPN .BLKL 1 ;Starting system page number $DEF UCB_L_ADRSPT .BLKL 1 ;Address of first SPT used $DEF UCB_L_SVABUF .BLKL 1 ;System virtual address of user buffer ; $DEF UCB$HPID .BLKL 1 ;ADDRESS OF HOST UCB $DEF UCB$HLBN .BLKL 1 ;LBN OF HOST FILE $DEF UCB$HFSZ .BLKL 1 ;SIZE OF HOST FILE, BLKS $DEF UCB$PPID .BLKL 1 ;PID OF ORIGINAL PROCESS FROM IRP BLK $def ucb$irps .BLKL 1 ;IRP save area during host proc action $def ucb$smbx .BLKL 1 ;mailbox UCB for work notices ; Define save areas for UCB fields needed for I/O copies and used in ; driver to process copies here. $def ucb$lsvapte .blkl 1 ;saves ucb$l_svapte $def ucb$lsts .blkl 1 ;saves ucb$l_sts $def ucb$lsvpn .blkl 1 ; similar $def ucb$wboff .blkl 1 ; similar $def ucb$lmedia .blkl 1 $def ucb$irplmedia .blkl 1 ;irp$l_media save $def ucb$wdirseq .blkl 1 $def ucb$lbcr .blkl 1 ; NOTE: It is important to ENSURE that we never clobber IRP$L_PID twice! ; therefore, adopt convention that UCB$PPID is cleared whenever we put ; back the old PID value in the IRP. Only clobber the PID where ; UCB$PPID is zero!!! $DEF UCB$L_MEMBUF .BLKL 1 ; MEMORY AREA $DEF UCB$L_MEMBF .BLKL 1 ; MEMORY BUFFER FOR CONTROL PROCESS $DEF UCB$stats .BLKL 1 ;STATUS CODE SAVE AREA $def ucb$jiggery .blkl 1 ;adjust to refcnt to fix up ; Since I/O postprocessing on virtual or paging I/O makes lots of ; assumptions about location of window blocks, etc., which are ; not true here (wrong UCB mainly), we'll bash the function status ; we send to the host driver to look like physical I/O is being ; done and save the real function code here. Later when ZR: does ; I/O completion processing, we'll replace the original function ; from here back in the IRP. This will be saved/restored along with ; ucb$ppid (irp$l_pid field) and so synchronization will be detected ; with ucb$ppid usage. ; $def ucb$l_blk .blkl 1 ;block i/o if nonzero $def ucb$l_ucbtbl .blkl 1 ;table of ucb addresses ;$def ucb$l_bufpol .blkl 1 ;buffer addresses table $def ucb$l_ctlfgs .blkl 1 ;control flags $def ucb$l_sanity .blkl 1 ;sanity test .if df,delayun $def ucb$l_unload .blkl 1 ;set nonzero for unload .endc .if ndf,xcldbg $def ucb$l_misc .blkl 20 ;debug .endc ; (bit 1 set implies disallow create, delete, or extend) $DEF UCB$K_ZR_LEN .BLKL 1 ;LENGTH OF UCB ;UCB$K_ZR_LEN=. ;LENGTH OF UCB $DEFEND UCB ;END OF UCB DEFINITONS ; ; No need for direct UCB access here; this is done via the driver ; itself. We just worry about the files, etc. ; ; Macro to check return status of system calls. ; .MACRO ON_ERR THERE,?HERE BLBS R0,HERE BRW THERE HERE: .ENDM ON_ERR .PSECT FDHostD_DATA,RD,WRT,NOEXE,LONG dvl: .long 0 DESBLK: .LONG 0 .ADDRESS XITHDL ;EXIT HANDLER ADDRESS .long 0 .address dvl .LONG 0,0 ;REST OF EXIT HANDLER CONTROL BLK ; DEFAULT_DEVICE: .ASCID /SYS$DISK/ .ALIGN LONG DFAB_BLK: $FAB FNM=,XAB=FNXAB,FAC=,rfm=fix,DNM=,mrs=512 DRAB_BLK: $RAB FAB=DFAB_BLK,BKT=0,RBF=RECBUF,UBF=RECBUF,USZ=512 .align long RECBUF: .BLKL 128 ;512 BYTES = 128 LONGS .long 0,0 ;safety ; FNXAB: $XABFHC ; XAB STUFF TO GET LBN, SIZE .BLKL 20 ;SAFETY .ALIGN LONG IOSTATUS: .BLKQ 1 ;** VDV_BUF: ; Buffer to hold VDVice name. .BLKB 40 VDV_BUF_SIZ = . - VDV_BUF VDV_BUF_DESC: ; Descriptor pointing to VDVice name. .LONG VDV_BUF_SIZ .ADDRESS VDV_BUF VPID: ; Owner of VDVice (if any). .BLKL 1 VDV_ITEM_LIST: ; VDVice list for $GETDVI. .WORD VDV_BUF_SIZ ; Make sure we a have a physical device name. .WORD DVI$_DEVNAM .ADDRESS VDV_BUF .ADDRESS VDV_BUF_DESC .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS VPID .LONG 0 .WORD 4 .WORD DVI$_DEVCLASS ; Check for a terminal. .ADDRESS VDV_CLASS .LONG 0 .LONG 0 ; End if item list. VDV_CLASS: .LONG 1 ;^^^ mbx_BUF: ; Buffer to hold mbxice name. .BLKB 40 mbx_BUF_SIZ = . - mbx_BUF mbx_BUF_DESC: ; Descriptor pointing to mbxice name. .LONG mbx_BUF_SIZ .ADDRESS mbx_BUF mPID: ; Owner of mbxice (if any). .BLKL 1 mbx_ITEM_LIST: ; mbxice list for $GETDVI. .WORD mbx_BUF_SIZ ; Make sure we a have a physical device name. .WORD DVI$_DEVNAM .ADDRESS mbx_BUF .ADDRESS mbx_BUF_DESC .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS mPID .LONG 0 .WORD 4 .WORD DVI$_DEVCLASS ; Check for a terminal. .ADDRESS mbx_CLASS .LONG 0 .LONG 0 ; End if item list. mbx_CLASS: .LONG 1 ;^^^ DEFNAM: WRK: .BLKL 1 ;SCRATCH INTEGER ; DESCRIPTOR FOR VDn: "FILENAME" .ALIGN LONG VDFNM: .WORD 255. ;LENGTH VDFTP: .BYTE DSC$K_DTYPE_T ;TEXT TYPE .BYTE 1 ; STATIC STRING .ADDRESS VDFNMD VDFNMD: .BLKB 256. ; DATA AREA ; VDCHN: .LONG 0 ;CHANNEL HOLDERS ; ; FOR initial use, don't bother allocating the file. Assume the ; user can somehow allocate a contiguous file of the size he wants ; for himself. ; MBCHN: .long 0 ; channel for mailbox MBUCB: .long 0 ; UCB address for mailbox weakflg: .long 0 ;1 if "weak" mode used plaflg: .long 0 rdallf: .long 0 cacrbf: .long 0 CLRDS: .ASCID /CLEAR/ KEYDS: .ASCID /KEY/ ;CRYPTO KEY weakds: .ascid /WEAK/ ;"weak" keyword ... compatibe with old cryptodisk. ; ; (well, not REALLY compatible. Just cruddier...) pladsc: .ascid /PLAIN/ ;plaintext, no encryption at all. ;ASDSC: .ASCID /ASSIGN/ ;DASDSC: .ASCID /DEASSIGN/ P1DSC: .ASCID /UNIT/ P2DSC: .ASCID /FNAM/ rdall: .ascid /READTHRU/ ;suppress cache if set cacrvb: .ascid /VBCACHE/ ; cache virtual i/o as well as logical .EVEN ; DESCRIPTOR FOR DVn:DSKFIL "FILENAME" .ALIGN LONG DDFNM: .WORD 255. ;LENGTH DDFTP: .BYTE DSC$K_DTYPE_T ;TEXT TYPE .BYTE 1 ; STATIC STRING DDFNA: .ADDRESS DDFNMD DDFNMD: .BLKB 256. ; DATA AREA DDCHN: .LONG 0 ; ;key descriptor .ALIGN LONG KYFNM: .WORD 255. ;LENGTH KYFTP: .BYTE DSC$K_DTYPE_T ;TEXT TYPE .BYTE 1 ; STATIC STRING KYFNA: .ADDRESS KYFNMD KYFNMD: .BLKB 256. ; DATA AREA ; ; ; Data area for "disk" ; .align long fd_cyl=5 ;make it 5 cyls of 64 blocks each fd_blocks=fd_cyl*64 ; blocks... fd_longs=fd_blocks*128 ; longwords needed ;fd_data:: ; .BLKL fd_longs ; .blkl 128 ;guard area for safety during debug... ; ucb data area HSTUCB: .LONG 0 ;HOST UCB ADDRESS ourpid: .long 0 ;;;store this locally CLRCNT: .long 0 ;1 if clearing ref cnt ucb$w_refc iosb: .long 0,0,0,0 ;iosb ioprog: .long 0 ; i/o in progress flag if nonzero ; BUFFER FOR COPIES OF DRIVR DATA bufrwh: .long 0 ;r/w virt flag BUFHDR: .LONG 0,0,0,0,0 BUF: .BLKL 8192. ; DATA AREA .LONG 0,0 ;SAFETY BUFFERS SETFD: .LONG 0 ;DECLARE PROCESS .LONG 0 ;PID HSTFZ: .LONG 1 ;DISK SIZE .LONG 0,0,0,0 ;EXTRA STUFF FOR OTHER CALLS SETFDL=.-SETFD .LONG 0,0,0,0,0 ;SAFETY HSTFSZ: .LONG 0 ;DISK SIZE ; ; KERNEL ARG LIST K_ARG: .LONG 2 ;2 ARGS: fd device name, mb device name .ADDRESS VDV_BUF_DESC .address mbx_buf_desc ;;;(avoid paging problems in kernel) ; ; cache area. Two will be provided: 1. First 256K blocks of the ; container. 2. Everything else. Thus if one inits /index=beg ; the header and maybe dirs will tend to be in the first cache. ; Thus if you put a file on a vol.set on jukebox this may ; perform better than some... ; csiz=64 ;8k blocks cgmax=256000 locac: .rept csiz .blkl 128 .endr .blkl 128 ;safety locidx: .blkl csiz locwhn: .blkl csiz hicac: .rept csiz .blkl 128 .endr .blkl 128 ;safety hicidx: .blkl csiz ; lbn in this cache blk hicwhn: .blkl csiz ; when (in opcnt) this blk was filled. cgblk: .long 0 ;blk to lkp opcnt: .long 0 cgloc: .long 0 ;where to move blk .PSECT FDHostD_CODE,RD,WRT,EXE,LONG .ENTRY FDHostD,^M movab hicidx,r0 movc5 #0,(r0),#0,#<4*csiz>,(r0) movab locidx,r0 movc5 #0,(r0),#0,#<4*csiz>,(r0) movab hicwhn,r0 movc5 #0,(r0),#0,#<4*csiz>,(r0) movab locwhn,r0 movc5 #0,(r0),#0,#<4*csiz>,(r0) clrl cacrbf ; initially don't cache virtual i/o pushab cacrvb ;/vbcache ? calls #1,g^cli$present CMPL R0,#CLI$_PRESENT bneq 5290$ incl cacrbf ;/readthru means ignore cache 5290$: clrl opcnt clrl rdallf pushab rdall ;/readthru? calls #1,g^cli$present CMPL R0,#CLI$_PRESENT bneq 4290$ incl rdallf ;/readthru means ignore cache 4290$: clrl plaflg pushab pladsc calls #1,g^cli$present CMPL R0,#CLI$_PRESENT bneq 3290$ incl plaflg ;/plain means don't encrypt at all. Just disk on file. 3290$: ; only fdn: name on command line PUSHAB WRK ;PUSH LONGWORD ADDR FOR RETLENGTH PUSHAB VDFNM ;ADDRESS OF DESCRIPTOR TO RETURN PUSHAB P1DSC ; GET P1 (VDn: UNIT) CALLS #3,G^CLI$GET_VALUE ;GET VALUE OF NAME TO VDFNM ON_ERR FDHostD_EXIT 290$: clrl clrcnt ;flag clear count if 1 PUSHAB clrds ; 'CLEAR' CALLS #1,G^CLI$PRESENT ; IS /CLEAR USED? CMPL R0,#CLI$_PRESENT ; IF EQ YES BNEQ 293$ incl clrcnt ; FLAG CLEARING USAGE BRW 295$ ;ON CLEAR DON'T BOTHER WITH 2ND FILENAME 293$: PUSHAB WRK ; GET 2ND FILE (REAL FILE) LONGWORD FOR LEN PUSHAB DDFNM ; & ITS DESCRIPTOR PUSHAB P2DSC ; & PARAMETER NAME 'P2' CALLS #3,G^CLI$GET_VALUE ; GET FNM ON_ERR fdhostd_EXIT ; $ASSIGN_S - ; Get a channel to the ; DEVNAM=DDFNM,- ; device for host file ; CHAN=DDCHN ; ON_ERR fdhostd_EXIT ; OPEN THE FILE, CHECK ITS INITIAL LBN ; IF ERROR OR NOT CONTIG, EXIT... ; DO VIA OPENING FILE AND READING ITS' STATBLOCK VIA ; QIO... ; SET UP FOR FILENAME WE REALLY FOUND IN FAB... MOVL DDFNA,DFAB_BLK+FAB$L_FNA ;SET UP FILENAME ADDR MOVB DDFNM,DFAB_BLK+FAB$B_FNS ;AND LENGTH brb 159$ 149$: brw fdhostd_exit 159$: $OPEN FAB=DFAB_BLK BLBC R0,149$ ; FAILURE IF FILE WON'T OPEN ; FNXAB HAS INFO ON LBN, SIZE ; MOVL FNXAB+XAB$L_SBN,HSTLBN ; GET HOST'S start LBN (0 IF NON CONTIG.) MOVL FNXAB+XAB$L_HBK,HSTFSZ ; GET FILE SIZE. (CHECK THAT BELOW) ; No need to decrement size, but must make it a multiple of 64 ; blocks for a 64-sector geometry. ; DECL HSTFSZ ;;;COUNT DOWN 1 TO ACCOUNT FOR BOOT BLOCK BICL2 #63,HSTFSZ ;;;MAKE A MULTIPLE OF 64 BLKS MOVL HSTFSZ,HSTFZ ;FILE SIZE $CONNECT RAB=DRAB_BLK ;FINISH OPEN BLBC R0,149$ ; FAILURE IF FILE WON'T OPEN PUSHAB keyds ; 'KEY' clrl kyfnmd ;zero out key info initially clrq binkey ;null binary key also clrl weakflg ;zero "weak" flag CALLS #1,G^CLI$PRESENT ; IS /KEY USED? CMPL R0,#CLI$_PRESENT ; IF EQ YES bneq 295$ ; if no /key given, ignore PUSHAB WRK ; GET LONGWORD FOR LEN of key PUSHAB KYFNM ; & ITS DESCRIPTOR PUSHAB KEYDS ; & PARAMETER NAME 'KEY' CALLS #3,G^CLI$GET_VALUE ; GET FNM ON_ERR fdhostd_EXIT ; now kyfnmd should contain data of key string as text movl wrk,kyfnm ;store data length of returned string tstl plaflg bneq 3159$ jsb keyset ;set up key binary 3159$: ; Now test for possible specified "weak" flag and save the info for our crypt/decrypt ; routines. pushab weakds ;'weak' calls #1,g^cli$present ;did user say /weak ? cmpl r0,#cli$_present ;if neql no bneq 295$ ; so branch if no /weak seen incl weakflg 295$: ; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE. $ASSIGN_S - DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR $GETDVI_S - CHAN=vdchn,- ; Command line has device name. ITMLST=VDV_ITEM_LIST BLBS R0,140$ BRW FDHostd_EXIT 140$: tstl clrcnt bneq 162$ ;if just clearing ref count, no need for mbx ; Set up mailbox channel $crembx_s prmflg=#0,chan=mbchn,maxmsg=#576,bufquo=#5760,- promsk=#0 On_ERR fdhostd_exit ; need to get UCB address here somehow... $GETDVI_S - CHAN=mbchn,- ; Command line has device name. ITMLST=mbx_item_list BLBS R0,176$ 161$: BRW FDHostd_EXIT 176$: ; Got now the actual device name of the mailbox ; Let the kernel call perform the UCB lookup for us. ; ; FOUND A UNIT. NOW DECLARE EXIT HANDLER TO CLEAN UP ; IF WE GET A $FORCEX TO TERMINATE THE HOST PROCESS. PUSHAB DESBLK ; ADDRESS OF DESBLK CALLS #1,G^SYS$DCLEXH ; DECLARE EXIT HANDLER ; NOW GET OUR PID FOR USE LATER ; 162$: $CMKRNL_S - ROUTIN=BASHUCB,ARGLST=K_ARG ; Now we have the PID for our process in OURPID and are ready to tell ; the driver we're here! tstl clrcnt bneq 161$ ;exit now if just zeroing count MOVL OURPID,SETFD+4 ;STORE PID (IPID!!!) movl HSTFSZ,setfd+8 ;size of disk (preset also) movl mbucb,setfd+12 ; Comm mailbox UCB address CLRL SETFD ; flag that this is the setup movl #setfdl,r4 ; length of buffer ; Note we must modified func code from io$_format to something with ; a modifier bit set so FDDRV will treat this as OUR special QIO. $qiow_s efn=#1,chan=vdchn, - iosb=iosb,func=#,p1=setfd,p2=R4 ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR clrl ioprog ; no i/o in progress yet ; now we're ready to await work from the driver EVTLOOP: ; When FDDRV has work, it sends the buffer header it has via a ; mailbox message. Read that here to get our indication there ; is something to do, and incidentally to get initial info on I/O ; direction and size. ; ; Read the mailbox to get our data ; Use QIOW$ to assure that we don't do anything until there is work. ; (this also avoids having to use internal routines to control ; host execution.) $qiow_s efn=#10,chan=mbchn,- iosb=iosb,func=#io$_readlblk,p1=bufhdr,p2=#20 ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR incl opcnt ; $qiow_s efn=#1,chan=vdchn,func=#io$_format,p1=#setfd,p2=#setfdl ;SHOULD NOW HAVE HEADER... ; check for io$_available (ignore here) or io$_unload (so we exit) cmpw bufhdr,#512 ;got it? bneq 643$ ;if neq br cmpw bufhdr+4,#1024 bneq 643$ cmpw bufhdr+8,#2048 bneq 643$ cmpw bufhdr+12,#4096 bneq 643$ ;if we get here, user just issued io$_available or io$_unload so is dismounting ; the disk. Therefore call the bufdmo function ; If this is an unload, by the way, bufhdr+16 will be 14747 (decimal) cmpw bufhdr+16,#14747 ;unload magic number? bneq 654$ brw awscram ;unload flag seen 654$: 644$: brw evtloop ;then look for more to do 643$: ; Check call is not spurious. Driver sets 255 in buffer header when it ; gets done an i/o for client, and puts 0 or 1 there for a real ; transfer. ; Check only the low word of bufhdr so we can use the top word to flag ; virt/log i/o movl bufhdr,bufrwh ;capture r/w virt flag in hi word clrw bufhdr+2 ;zero the top word of bufhdr cmpw bufhdr,#2 bgtru 644$ ;if not really doing i/o, spurious ef ; set, just ignore MOVL #1,IOPROG ;FLAG AN I/O IN PROGRESS THAT NEEDS TO ;BE COMPLETED CMPW BUFHDR,#1 ;1=WRITE, SOMETHING'S WAITING IN THE DRIVER beql writeop jmp readop ; BNEQ READOP WRITEOP: ; BUFHDR+8 CONTAINS BYTECOUNT FOR DATA PART OF TRANSFER MOVL #20,SETFD+8 ;BUFFER HEADER size ADDL2 BUFHDR+8,SETFD+8 ;SO ADD HEADER SIZE MOVL #3,SETFD ;GET DATA MOVAB BUFHDR,SETFD+4 ;BUFFER HDR ADDRESS movl #1,setfd+12 ;success indicator movl #setfdl,r4 $qiow_s efn=#1,chan=vdchn, - iosb=iosb,func=#,p1=setfd,p2=R4 ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR ; $qiow_s efn=#1,chan=vdchn,func=#io$_format,p1=#setfd,p2=#setfdl ; LOADS DATA INTO LOCAL BUFFER FROM DRIVER ; NOW HAVE TO MOVE IT INTO STORAGE HERE MOVL BUFHDR+4,R0 ;GET BLOCK NUMBER INCL R0 ;MAP TO VBN MOVL R0,DRAB_BLK+RAB$L_BKT ;SET IT UP movw #512.,drab_blk+rab$w_rsz ;512 byte blks ; LOOP OVER BLKS IN REQUEST movl bufhdr+8,r6 ;get bytecount to move addl2 #511,r6 ;round up ashl #-9,r6,r6 ;convert to blks ; r6 is not messed up by movc3... movab buf,r7 ;scratch buffer address 15$: movab recbuf,r9 ;data to here movl r7,r8 ;data from here MOVC3 #512,(r8),(R9) ; STORE THE DATA IN OUR SPACE pushl r6 movl drab_blk+rab$l_bkt,r6 ;pass block number to crypt tstl plaflg bneq 315$ jsb crypt ;encrypt recbuf 315$: popl r6 ;don't bash r6 ; if using cryptodisk, keep the blk buffers in mem encrypted. ; blkput - ; loc of data in cgloc ; blk # in cgblk ; r0=1 if data put in right tstl rdallf ;is cache suppressed? bneq 6315$ tstw bufrwh+2 ; virtual I/O if nonzero, log/phy if 0 beql 5315$ tstl cacrbf ; cache virtual stuff? beql 6315$ 5315$: movl r6,cgblk ;save blk # we are using movab recbuf,cgloc ;save address where data is jsb blkput ;store in cache 6315$: $write rab=drab_blk ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR addl2 #512,r7 ;pass this blk's data incl drab_blk+rab$l_bkt ;pass this blk in file too decl r6 ;count down blks to do bgtr 15$ ;copy all blks JMP COMMON READOP: ; READING DATA TO CLIENT. MUST GET DATA, THEN SEND TO DRIVER. MOVL BUFHDR+4,R0 ;GET BLOCK NUMBER INCL R0 ;MAP TO VBN MOVL R0,DRAB_BLK+RAB$L_BKT ;SET IT UP movw #512.,drab_blk+rab$w_rsz ;512 byte blks ; LOOP OVER BLKS IN REQUEST movl bufhdr+8,r6 ;get bytecount to move addl2 #511,r6 ;round up ashl #-9,r6,r6 ;convert to blks ; r6 is not messed up by movc3... movab buf,r7 ;scratch buffer address ;(8K + header) 16$: ; first look in cache for the block tstl rdallf ; no cache bneq 8016$ tstw bufrwh+2 ; virtual i/o? beql 9016$ tstl cacrbf ; cache virtual stuff? beql 8016$ ; if eql no 9016$: movl drab_blk+rab$l_bkt,cgblk ;pass block number to crypt movab recbuf,cgloc ;save address where data is jsb blkget ;store in cache blbs r0,4016$ 8016$: ; If we didn't find the block in cache, go read it. $read rab=drab_blk ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR 4016$: pushl r6 movl drab_blk+rab$l_bkt,r6 ;pass block number to crypt ; Save the block in cache (if it was already saved, no harm) tstl rdallf ; no cache? bneq 7016$ tstw bufrwh+2 ; virtual i/o? beql 5016$ tstl cacrbf ; cache virtual stuff? beql 7016$ ; if eql no 5016$: movl r6,cgblk ;save blk # we are using movab recbuf,cgloc ;save address where data is jsb blkput ;store in cache 7016$: tstl plaflg bneq 316$ jsb decrypt ; decrypt recbuf 316$: popl r6 movab recbuf,r9 ;data from here movl r7,r8 ;data to here MOVC3 #512,(r9),(R8) ; STORE THE DATA IN OUR SPACE addl2 #512,r7 ;pass this blk's data incl drab_blk+rab$l_bkt ;pass this blk in file too decl r6 ;count down blks to do bgtr 16$ ;copy all blks movab buf,r2 ADDL3 #20,BUFHDR+8,SETFD+8 ; GET LENGTH TO XFER MOVAB BUFHDR,SETFD+4 ;BUFFER HDR ADDRESS MOVL #2,SETFD ;HOST TO DRIVER COPY movl #setfdl,r4 movl #1,setfd+12 ;success... movl bufhdr+8,setfd+16 ;/length sent $qiow_s efn=#1,chan=vdchn, - iosb=iosb,func=#,p1=setfd,p2=R4 ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR ; NOW DATA IS IN DRIVER SPACE AS REQUIRED COMMON: ; NOW TERMINATE THE I/O AND AWAIT MORE WORK. MOVL #1,SETFD ;TERMINATE I/O PACKET MOVL BUFHDR,SETFD+4 ;SAVE TRANSFER DIRECTION MOVL BUFHDR+4,SETFD+8 ; BLOCK # MOVL BUFHDR+8,SETFD+12 ; NO. BYTES IN BUFFER MOVZWL #SS$_NORMAL,SETFD+16 ; IOSB 1 CLRL SETFD+20 ; IOSB 2 ; ALWAYS SUCCESS movl #setfdl,r4 $qiow_s efn=#1,chan=vdchn, - iosb=iosb,func=#,p1=setfd,p2=R4 ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR ; NOW DONE TRANSFER CLRL IOPROG ; SAY NO I/O IN PROCESS IF WE ARE FORCED TO EXIT JMP EVTLOOP ; Come here to exit when we see io$_unload (i.e., dism/unload) ; Note we terminate the i/o so the driver cleans up too & is marked offline awscram: ; exiting, so mark disk offline first ; First deassign the mailbox so the driver won't send us any more ; operations $dassgn_s chan=mbchn ; Now terminate the I/O for the user MOVL #1,SETFD ;TERMINATE I/O PACKET MOVL BUFHDR+4,SETFD+8 ; BLOCK # MOVL #1,SETFD+4 ;Set transfer direction=1, write, so ;there will be no data copy needed at done ; processing. For a real write the ; data will have been copied in startio. Here ; there's none to copy; we just want the ; IRP to be returned. MOVL #0,SETFD+12 ; NO. BYTES IN BUFFER MOVZWL #SS$_NORMAL,SETFD+16 ; IOSB 1 CLRL SETFD+20 ; IOSB 2 ; ALWAYS SUCCESS movl #setFDL,r4 $qiow_s efn=#1,chan=vdchn, - iosb=iosb,func=#,p1=setFD,p2=R4 CLRL SETFD ;DECLARE/UNDECLARE PUSHAB DESBLK ; ADDRESS OF DESBLK CALLS #1,G^SYS$CANEXH ; CANCEL EXIT HANDLER clrl setFD+4 ;FLAG NOBODY HOME NOW clrl setFD+8 movl #setFDL,r4 $qiow_s efn=#1,chan=vdchn, - iosb=iosb,func=#,p1=setFD,p2=R4 $DASSGN_S CHAN=VDCHN RET ; BE SURE WE DON'T LEAVE THE CHANNELS ASSIGNED TO THE DEVICES ; EITHER... FDHostd_exit: tstl ioprog ;i/o going on to fd:? beql 1$ ;if not, just return brw ioxit ;else clean up 1$: RET ; ; BASHUCB - AREA TO MESS UP UCB WITH OUR FILE DATA ; BEWARE BEWARE BEWARE ; runs in KERNEL mode ... HAS to be right. .ENTRY BASHUCB,^M ; TAKEN LOOSELY FROM ZERO.MAR ; Obtains host's PID, and also sets up correct size in driver UCB ; both by cylinder and by block. .if df,$$xdt jsb g^ini$brk ;call xdt .endc .if ndf,vms$v5 MOVL G^SCH$GL_CURPCB,R4 ;;; NEED OUR PCB .iff MOVL G^CTL$GL_PCB,R4 ;;; NEED OUR PCB (VMS V5) ;;; (gets it in internal form, just as needed) .endc ;;; NEED IPID FOR DRIVER'S CALL TO SCH$POSTEF TO THIS HOST!! MOVL PCB$L_PID(R4),OURPID ;;;SAVE OUR PID IN INTERNAL FORM JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASE CLRL HSTUCB ;;; ZERO "HOST" UCB tstl clrcnt ;;;just zeroing count? bneq 126$ movl 8(ap),r1 ;;;get mailbox info first jsb g^ioc$searchdev blbc r0,59$ ;;;on failure, give up movl r1,mbucb ;;;store away mailbox UCB 126$: MOVL 4(AP),R1 ;;; ADDRESS DVC NAME DESCRIPTORS JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 BLBS R0,60$ 59$: BRW BSH_XIT 60$: ; BUGGER THE UCB ; ASSUMES FILE LBN AND SIZE ALREADY RECORDED ; ALSO ASSUMES THAT ZERO LBN OR SIZE MEANS THIS ENTRY NEVER CALLED. ; (REALLY ONLY WORRY ABOUT ZERO SIZE; IF WE OVERMAP A REAL DEVICE ; THEN ZERO INITIAL LBN COULD BE OK.) ; ; Set device size. Since this is true of any disk, just use the offsets. ; No need for duplicating the UCB defs here. tstl clrcnt ;;;just zeroing use count beql 127$ ;;;if eql, no, normal ops movl #1,ucb$l_refc(r1) ;;;zero ref count (in case it got set -1) ;;; (note we set it to 1 so it decrements to 0 on our exit.) ; reset the buffer size so fddriver's internal buffer is matched fdbuf=8192. movl #fdbuf,ucb$l_maxbcnt(r1) ;;;reset max byte cnt tstl ucb$irps(r1) ;;;is an I/O hanging and uncompleted? beql 159$ ;;;if eql no incl ioprog ;;;flag cleanup needed BISL #UCB$M_ONLINE,UCB$L_STS(R1) ;;; FLAG ONLINE BISL #UCB$M_VALID,UCB$L_STS(R1) ;;; AND VOL VALID brb 128$ ;;; and do NOT leave offline yet 159$: BICL #UCB$M_ONLINE,UCB$L_STS(R1) ;;; FLAG OFFLINE BICL #UCB$M_VALID,UCB$L_STS(R1) ;;; AND VOL INVALID brb 128$ ;;;exit, success 127$: ; tstl ucb$l_refc(r1) ;;;fix up stray ref counts bneq 140$ ;;; 142$: movl #1,ucb$l_refc(r1) ;;;if it was 0, keep from getting 65535 brb 141$ 140$: cmpw ucb$l_refc(r1),#65533 ;;;small neg numbers also look bugus bgtru 142$ ;;;so fix these up also 141$: MOVL HSTFSZ,UCB$L_MAXBLOCK(R1) ;;; (SAVE SIZE TWICE, FOR RMS MOVL HSTFSZ,R0 ;;; GET HOST SIZE IN CYLINDERS ASHL #-6,R0,R0 ;;; GET # CYLINDERS IN SIZE NOW MOVW R0,UCB$W_CYLINDERS(R1) ;;; SAVE IN UCB FOR REST OF VMS ; This computation is redone in fddrv itself, but do it here also. ; It assumes in fddrv that there are 64 sectors/cylinder. BISL #UCB$M_ONLINE,UCB$L_STS(R1) ;;; FLAG ONLINE NOW BISL #UCB$M_VALID,UCB$L_STS(R1) ;;; AND VOL VALID ;;; THAT'S IT... SHOULD BE OK NOW. 128$: MOVL #SS$_NORMAL,R0 BSH_XIT: PUSHL R0 JSB G^SCH$IOUNLOCK ;;; UNLOCK I/O DATABASE (DROP IPL) POPL R0 ;;; REMEMBER R0 RET ;;; BACK TO USER MODE NOW ; EXIT HANDLER ; CLEARS I/O ASSIGNMENT TO FD: UNIT ; .ENTRY XITHDL,^M ioxit: TSTL IOPROG ; Clean out any existing pending I/O with special call to FDdrv to ; finish it off. BEQL 1$ MOVL #1,SETFD ;TERMINATE I/O PACKET MOVL BUFHDR,SETFD+4 ;SAVE TRANSFER DIRECTION MOVL BUFHDR+4,SETFD+8 ; BLOCK # MOVL BUFHDR+8,SETFD+12 ; NO. BYTES IN BUFFER MOVZWL #SS$_ACCVIO,SETFD+16 ; IOSB 1 CLRL SETFD+20 ; IOSB 2 ; FAILURE movl #setfdl,r4 $qiow_s efn=#1,chan=vdchn, - iosb=iosb,func=#,p1=setfd,p2=R4 1$: CLRL SETFD ;DECLARE/UNDECLARE PUSHAB DESBLK ; ADDRESS OF DESBLK CALLS #1,G^SYS$CANEXH ; CANCEL EXIT HANDLER clrl setfd+4 ;FLAG NOBODY HOME NOW clrl setfd+8 movl #setfdl,r4 $qiow_s efn=#1,chan=vdchn, - iosb=iosb,func=#,p1=setfd,p2=R4 ; declare host no longer is home. RET ; FINISH EXIT .PSECT CRY_DATA,RD,WRT,NOEXE,LONG ; ; Encrypt / Decrypt routines ; Inputs: ; Key string in KYFNMD, length in KYFNM ; 3 entries: ; ; KEYSET builds a binary key from the data entered ; Crypt encrypts 512 byte RECBUF in place ; Decrypt decrypts 512 byte RECBUF in place ; ; All are called by JSB and assume registers saved/restored as used. polygw: .long 2 ;2 args .address polyw wta: .address crcwrk polyw: .long 0 ;scratch copy of crc poly crcwrk: .blkl 16 ;crc working table binkey: .long 0,0 jkkey: .long 0 ;junk key jkadd: .long 0 ;amt to add to polynomials crcjk: .long ^XDE683251 ; random poly crcpo: .long ^XEDB88320 ;AUTODIN POLY ;crcta: .address crcpo crcp1: .long ^XBACC8010 ;CRCTB: .ADDRESS CRCP1 crck: .long ^xf03ba241 ;random crc crcv: .long ^xf03ba200 ;crcvt: .address crcv crctab: .blkl 128 ;storage for "variable" crc xor .blkl 3968 ;total 4096 longs = 32 blocks .blkl 12288 ;another 96 blocks worth (total 128) .long 0 ;safety crcblk: .long 0 keyblk: .long 0 .PSECT Cry_CODE,RD,WRT,EXE,LONG Keyset: .jsb_entry pushr #^M clrq binkey ;just for now, assume data's numeric ascii & convert to ;CRC ; Use autodin CRC and another random CRC to get 64 bits from the key ; entered. This allows a fairly fast crypt/decrypt operation though ; security is not high. Nevertheless, it should keep random browsers ; out, even with privs, unless they enjoy lots of decrypting. ; If the user specified "/WEAK", the algorithm will use a simple XOR ; derived from the key. However, if not, this routine will compute another ; 512 bytes of random CRCs of the key and the crypt and decrypt routines ; will XOR with these also. This will mean that in general the same data ; quadword in the data buffer will crypt to something different. To further ; prevent decryption-by-inspection, the block number will be passed to the ; crypt and decrypt routines in r6. This will be multiplied by a constant (that ; depends on the key so that the pattern will be obscured a bit) and the data will ; again be XORed with the (block # * const) product. This means that identical ; blocks will NOT have identical ciphertext. The resulting cipher should be ; adequate against folks who don't know the algorithm. Given the algorithm and ; enough time, one could probably figure out the key to the file, but it will ; be quite difficult. To make matters even harder, the key table will be made ; 32 blocks long and the block used on each disk block will derive from the disk ; block number times ANOTHER constant which depends on the key. ; movab crcwrk,r11 clrl binkey clrl binkey+4 movl crcjk,polyw ;set up 1st poly callg g^polygw,g^lib$crc_table movl kyfnm,r5 beql 1$ movab kyfnmd,r6 ;data addr crc (r11),#-1,r5,(r6) movl r0,jkkey ;save crc from nonstd poly. movl crcpo,polyw ;set up 1st poly callg g^polygw,g^lib$crc_table movl kyfnm,r5 beql 1$ movab kyfnmd,r6 ;data addr crc (r11),#-1,r5,(r6) movl r0,binkey movl crcp1,polyw ;next poly to make tbl for callg g^polygw,g^lib$crc_table crc (r11),#-1,r5,(r6) ;another crc movl r0,binkey+4 1$: movab crctab,r6 addl2 #32768,r6 clrl r7 clrl (r6) movc5 #0,(r6),r7,#32768,(r6) ;zero xor key area out movab crctab,r6 clrl r7 clrl (r6) movc5 #0,(r6),r7,#32768,(r6) ;zero xor key area out tstl weakflg ;/weak key? bneq 4$ ;if so use weak algorithm movl #16384,r7 movab crctab,r6 ;fill in tbl of crc's ; It is barely conceivable someone might be able to find and filter ; out the "weak" key CRCs and filter that stuff out of the data here. ; The 32 block values all derive from the same initial CRC polynomial, ; so this seems like a possible weakness. Therefore, we generated a ; CRC which is never used in the actual XOR'd pattern, but parts of the ; result are used to generate some of the CRC polynomial that IS used ; to produce each CRC, and another bit of it is used to generate the ; interval between these generating polynomials. Thus an error in the ; initial CRC cascades in uncertainty faster than if the CRCs here ; all were made from a known polynomial series. Not being a cryptologist, ; I have no idea how one might penetrate even the old cipher, but ; it seems good to deny a code cracker even the knowledge of the ; initial polynomials being used. movl crck,crcv ;init crc tbl movw jkkey+1,crcv+1 ;replace middle 16 bits of ; crc polynomial with 16 bits of CRC from ; our key, so the new polynomials all depend ; on the key also. movzbl jkkey,jkadd ; get amount to add to our next CRC polynomial addl2 #5,jkadd ; and make sure it is never zero 2$: movl crcv,polyw ;make next crctbl callg g^polygw,g^lib$crc_table ;now wrk tbl reflects this polynomial movl kyfnm,r5 beql 4$ movab kyfnmd,r8 crc (r11),#-1,r5,(r8) movl r0,(r6)+ addl2 jkadd,crcv ;bump crc polynomial by some amount ; derived from original key. sobgtr r7,2$ ;do 4096 of them (32 blocks altogether) ; now have 512 bytes of crc. 4$: ;v004a mod ; NOW for safety zero out the key area ; that way nobody can peer into our address space and find the originally ; entered key. clrl r7 movab kyfnmd,r6 movc5 #0,(r6),r7,#255,(r6) ; zero 255 bytes of key ;end v004a mod popr #^M rsb ; at entry to crypt, block number is in r6 Crypt: .jsb_entry pushr #^M ; sneaky... don't use blk number, but multiply it first. Ignore overflow movzbl crctab+184,r5 addl2 r5,r6 ; add something to blk # first so blk 0 is ; not known either movzbl crctab,r5 ;get byte out of keytbl bneq 7$ movl #211,r5 7$: mull3 r6,r5,crcblk ; get some multiple of the block ; now extract a bit of it and xor the block with the CRC code so ; that we are not doing anything affine and hence readily ; invertible. movl crcblk,r5 bicl2 #^xffff0003,r5 ;make a longword offset ; get crctab movl crctab(r5),r5 ;get crc table info xorl3 r5,crctab+202,r5 ;xor with something xorl3 crcblk,r5,crcblk ;xor crcblk with both ; now crcblk is not just const + n*blk number ; (WHICH is affine). Rather it is fairly well randomized. The ; xor with a constant here is to scramble the result so that ; the whole transform won't be affine and therefore it'll be harder ; even with known plaintext to figure out the working key (i.e., the ; 128 blocks worth of key). movzbl crctab+514,r5 bneq 8$ ;don't mult by zero movl #51,r5 8$: mull3 r6,r5,r5 ;convert blk# to hashcode bicl2 #^xffffff80,r5 ;zero all but low 7 bits (now 0-127) ashl #9,r5,r5 ;convert to byte offset in long table (now 0-15872 in 512 incr.) movl r5,keyblk ;store offset into crctab here tstl weakflg ;/weak algorithm? beql 5$ ;if eql no clrl crcblk ;if weak, noblock number dependency 5$: movl #64,r6 ;64 * 8 = 512 bytes movab recbuf,r1 ;address to start with movl binkey,r2 ;1st half of key movl binkey+4,r3 ;2nd half of key movab crctab,r4 ;variable crc tbl (or 0's) addl2 keyblk,r4 ;add offset to block of keys to use movl crcblk,r5 ;get blk*const which serves to obscure what's going on 2$: xorl3 (r1),(r4)+,(r1) xorl3 (r1),r5,(r1) xorl3 (r1),r2,(r1)+ ;xor 1st half xorl3 (r1),(r4)+,(r1) xorl3 (r1),r5,(r1) xorl3 (r1),r3,(r1)+ sobgtr r6,2$ ; buffer now transformed. popr #^M rsb ; at entry to decrypt, block number is in r6 Decrypt: .jsb_entry pushr #^M movzbl crctab+184,r5 addl2 r5,r6 ; add something to blk # first so blk 0 is ; not known either movzbl crctab,r5 bneq 7$ movl #211,r5 ;ensure we don't multiply blk# by 0 ;211 is prime. 7$: mull3 r6,r5,crcblk ; get some multiple of the block ; now extract a bit of it and xor the block with the CRC code so ; that we are not doing anything affine and hence readily ; invertible. movl crcblk,r5 bicl2 #^xffff0003,r5 ;make a longword offset ; get crctab movl crctab(r5),r5 ;get crc table info xorl3 r5,crctab+202,r5 ;xor with something ; Notice the crctab+202 is a halfword (16 bit) offset, not a ; longword aligned offset. This increases randomness a bit ; when we xor this with the crctab(r5) offset. xorl3 crcblk,r5,crcblk ;xor crcblk with both ; now crcblk is not just const + n*blk number ; (WHICH is affine). Rather it is fairly well randomized. The ; xor with a constant here is to scramble the result so that ; the whole transform won't be affine and therefore it'll be harder ; even with known plaintext to figure out the working key (i.e., the ; 128 blocks worth of key). movzbl crctab+514,r5 bneq 8$ ;don't mult by zero movl #51,r5 8$: mull3 r6,r5,r5 ;convert blk# to hashcode bicl2 #^xffffff80,r5 ;zero all but low 7 bits (now 0-127) ashl #9,r5,r5 ;convert to byte offset in long table (now 0-15872 in 512 incr.) movl r5,keyblk ;store offset into crctab here tstl weakflg ;/weak algorithm? beql 5$ ;if eql no clrl crcblk 5$: movl #64,r6 ;64 * 8 = 512 bytes movab recbuf,r1 ;address to start with movl binkey,r2 ;1st half of key movl binkey+4,r3 ;2nd half of key movab crctab,r4 ;variable crc tbl (or 0's) addl2 keyblk,r4 ;add offset to block of keys to use movl crcblk,r5 3$: xorl3 (r1),(r4)+,(r1) xorl3 (r1),r5,(r1) xorl3 (r1),r2,(r1)+ ;xor 1st half xorl3 (r1),(r4)+,(r1) xorl3 (r1),r5,(r1) xorl3 (r1),r3,(r1)+ sobgtr r6,3$ ; buffer now transformed. ;note this is (for now) identical to crypt logic. Keep the routine ;separate however in case we decide to alter this later. ; (1st cut would be to add something to the buffer on encrypt and ; subtract it again on decrypt. If we added yet another CRC of the ; key, it would make decoding a cryptodisk noticeably harder.) popr #^M rsb ; note we write thru always! ; blkget ; input: cgblk is blk to get ; cgloc = where to copy blk ; returns r0=1 if ok blkget: .jsb_entry output= pushr #^m clrl r0 ;initially no data cmpl cgblk,#cgmax ;in low or high area? bgtru 1000$ ; branch if higher ; first see if blk is in cache now movab locidx,r1 movl #csiz,r11 101$: cmpl (r1),cgblk beql 23$ tstl (r1)+ sobgtr r11,101$ ; nope, nothing there. Find a space if writing. brb 104$ 23$: addl2 #,r1 brw 3$ 104$: brw 3000$ 3$: movl opcnt,(r1) ; reflect last use of this blk movl cgloc,r6 ; where to put blk movab locwhn,r7 subl3 r1,r7,r8 ;r8 is long offset ashl #7,r8,r8 ;make an lbn offset (9 bits - 2 = 7) movab locac,r9 addl2 r8,r9 ; now copy the data from the block to our desired place movc3 #512,(r9),(r6) ; signal we got it movl #1,r0 brw 3000$ 1000$: movab hicidx,r1 movl #csiz,r11 1101$: cmpl (r1),cgblk beql 123$ tstl (r1)+ sobgtr r11,1101$ ; nope, nothing there. Find a space if writing. brb 1104$ 123$: addl2 #,r1 brw 1003$ 1104$: brw 3000$ 1003$: movl opcnt,(r1) movl cgloc,r6 ; where to put blk movab hicwhn,r7 subl3 r1,r7,r8 ;r8 is long offset ashl #7,r8,r8 ;make an lbn offset movab hicac,r9 addl2 r8,r9 movc3 #512,(r9),(r6) movl #1,r0 3000$: popr #^m rsb ; blkput - ; loc of data in cgloc ; blk # in cgblk ; r0=1 if data put in right ; use this to store data in cache. Store on write or after read. blkput: .jsb_entry output= ; save the regs properly so vax is ok too. pushr #^m clrl r0 ;initially no data cmpl cgblk,#cgmax ;in low or high area? bgtru 1000$ ; branch if higher ; first see if blk is in cache now movab locidx,r1 movl #csiz,r11 101$: cmpl (r1),cgblk ;is this our block? beql 23$ tstl (r1)+ sobgtr r11,101$ ; nope, nothing there. Find a space if writing. brb 104$ 23$: addl2 #,r1 ;got our blk. brw 3$ ; did not find blk. Grab one 104$: ;; .if df,bk..wrt clrl r3 ;lru addr clrl r2 decl r2 ; r2 = 4 billion movab locwhn,r1 ;opcnt...find unused or lowest blk movl #csiz,r11 1$: tstl (r1) ;0 = unused beql 3$ cmpl (r1),r2 ;r2 = lowest bgtru 4$ movl (r1),r2 ;keep lowest val movl r1,r3 ;and pointer too 4$: tstl (r1)+ ;pass entry sobgtr r11,1$ movl r3,r1 ; r1 is index of best one ;; .endc 3$: movl opcnt,(r1) ; reflect last use of this blk ;; .if df,bk..wrt movl cgloc,(r1) ;claim the blk (ok if already claim'd) ;; .endc movl cgloc,r6 ; where to get blk data movab locwhn,r7 subl3 r7,r1,r8 ;r8 is long offset ashl #7,r8,r8 ;make an lbn offset movab locac,r9 ;get cache addr addl2 r8,r9 ; now copy the data from the block to our desired place movc3 #512,(r6),(r9) ; copy data to cache ; signal we got it movl #1,r0 brw 3000$ 1000$: ; ditto for the high cache movab hicidx,r1 movl #csiz,r11 1101$: cmpl (r1),cgblk beql 123$ tstl (r1)+ sobgtr r11,1101$ ; nope, nothing there. Find a space if writing. brb 1104$ 123$: addl2 #,r1 brw 1003$ 1104$: ; gotta alloc a blk clrl r3 clrl r2 decl r2 ; r2 = 4 billion movab hicwhn,r1 movl #csiz,r11 1091$: tstl (r1) ;0 = unused beql 3$ ; grab unused first if any cmpl (r1),r2 ;r2 = lowest bgtru 1004$ movl (r1),r2 ;keep lowest val movl r1,r3 ;and pointer too 1004$: tstl (r1)+ ;pass entry sobgtr r11,1091$ movl r3,r1 ; r1 is index of best one 1003$: movl opcnt,(r1) movl cgblk,(r1) ;claim the blk movl cgloc,r6 ; where to put blk movab hicwhn,r7 subl3 r1,r7,r8 ;r8 is long offset ashl #7,r8,r8 ;make an lbn offset movab hicac,r9 addl2 r8,r9 movc3 #512,(r6),(r9) ;copy data to cache movl #1,r0 3000$: popr #^m rsb .END FDHostD