! CIPHER -- Basic subroutine to encode or decode a string of
!           up to 504 characters with a user-supplied password
! Hytek International, Inc. / P.O. Box 670 / Joplin, MO 64802
!   Created by Brad Horine. All rights are reserved to the author.
!   Donated to Alpha Micro Users' Society (AMUS) on 29 January 1986
! No party, including but not limited to Brad Horine, Hytek International
!   Inc., or Alpha Micro Users' Society, may be held liable for any damages,
!   whether actual or consequential, resulting from the use of this routine.
! Permission granted to copy and use freely, provided that all notices
!   and disclaimers remain intact.
!
! ************************************************************************
! * NOTE: Any use of this product for commercial gain, including but not *
! *       limited to inclusion of this routine in whole or in part with  *
! *       any commercial hardware or software, is expressly forbidden,   *
! *       unless prior written authorization is obtained from the        *
! *       author.                                                        *
! ************************************************************************
!
! Variables:
!   MAP1 C'FILENAME,S,24
!   MAP1 C'PASSWORD,X,512
!   MAP1 C'BUFFER,X,512
!   MAP1 C'LENGTH,F
!   MAP1 C'CONTROL,F
!   MAP1 C'WORKBUFF,X,512
!
! ********** ENCODING DATA **********
!
! Input:
!   C'FILENAME    Filename to be created, which will contain the
!                   encrypted data
!   C'PASSWORD    Encryption key supplied by user
!   C'BUFFER      Data to be encrypted (504 characters max.)
!   C'LENGTH      Number of valid characters in C'BUFFER
!   C'CONTROL     value of -1
!
!  Output:        Data is encrypted into FILENAME with a verification
!                   code added
!
! ********** DECODING DATA **********
!
!  Input:
!    C'FILENAME   Filename containing data to be decoded
!    C'PASSWORD   Encryption key supplied by user
!    C'CONTROL    value of 0
!
!  Output:        Unencrypted data is returned in bytes 1 thru C'LENGTH
!                   of C'BUFFER
!
! ********** ERRORS **********
! 
! Errors are returned to the calling program as codes contained in
!   the variable C'CONTROL as follows:
!
!   1 -- C'FILENAME was not found when trying to decode
!   2 -- C'FILENAME already existed when trying to encode
!   3 -- C'FILENAME was found, when trying to deocde, but was not in
!           the correct format (ie, was not random or was not exactly
!           1 block in length)
!   4 -- C'PASSWORD given to decode data was not the same as the
!           one used to encode the data, OR data was not encoded
!   5 -- C'CONTROL was not -1 or 0
!   6 -- C'LENGTH was invalid (less than 1 or greater than 504)
!
!
!  Please note that neither the PASSWORD nor the original data are
!    stored anywhere on the disk.  This helps to make the encrypted 
!    data more secure.
!
!  Since the routine pads the unused space in C'BUFFER with random
!    data before encoding it, there IS a remote chance that the
!    'recognition' pattern of "<DEL>cIpHeR" COULD appear in the
!    uncoded data.  The chances of this are approximately 1 in
!    9,223,370,000,000,000,000 (1 in 256^7).  This still would
!    not pose a problem, because the decoding routine will remove
!    the first occurrence of the recognition pattern, and the second
!    occurrence will ALWAYS be in the 'unused' area of C'BUFFER.
!    Think it through for yourself if you have any doubts about this.
!    Also, the 'security' of the encoded data is in direct relation
!    to the length of the password.  That is, a 1-character password
!    would take 256 attempts to crack, while a 2-character one takes
!    65,536 tries, on up to a 512-character password taking 256^256
!    tries, a bigger number than an Alpha Micro can even store!
!
!  One possible use of this routine would be as part of a LOGON-type
!    security system, where data pertaining to a user's security
!    level, disk account, etc. is stored in a file with the same
!    name as his user-id name, and is decoded by using his password.
!
!**************************************************************************
!
CIPHER:					! data encryption routine
!
! check for correct parameters
!
	IF C'CONTROL<>0 AND C'CONTROL<>-1 THEN  &
		C'CONTROL=5: RETURN
	IF C'CONTROL=-1 AND (C'LENGTH<1 OR C'LENGTH>504) THEN &
		C'CONTROL=6: RETURN

	LOOKUP C'FILENAME, C'FOUND
	IF C'FOUND=0 AND C'CONTROL=0 THEN &
		C'CONTROL=1: RETURN
	IF C'FOUND<>0 AND C'CONTROL=-1 THEN &
		C'CONTROL=2: RETURN
	IF C'FOUND<-1 OR C'FOUND>0 THEN &
		C'CONTROL=3: RETURN
	IF C'FOUND=0 AND C'CONTROL=-1 THEN &
		ALLOCATE C'FILENAME,1

	IF C'CONTROL=0 THEN &
		OPEN #9991, C'FILENAME, RANDOM, 512, REC9991: &
		REC9991=0: READ #9991, C'BUFFER: CLOSE #9991

ENCODE:
	IF C'CONTROL=0 THEN GOTO DECODE
!
! insert verification code into raw data at a random spot
!
	RANDOMIZE
	IF C'LENGTH=504 THEN GOTO NOFILL
	FOR C'FILL = C'LENGTH+1 TO 512
		C'BUFFER[C'FILL;1] = CHR(INT((RND(0)*512)+1))
	NEXT C'FILL
NOFILL:
	C'SPLIT = INT((RND(0)*504)+1)
	C'BUFFER[C'SPLIT+8,512] = C'BUFFER[C'SPLIT,504]
	C'BUFFER[C'SPLIT;8] = CHR(127)+"cIpHeR"+CHR(C'LENGTH)

DECODE:
!
! perform the encryption/decryption algorithm on the data in C'BUFFER
!
	C'PWLEN = INSTR(1,C'PASSWORD,CHR(0)): C'PWPOINT = 0

	FOR C'BPOINT = 1 TO 512

	C'PWPOINT = C'PWPOINT + 1
	IF C'PWPOINT > C'PWLEN THEN C'PWPOINT=1

	C'WORKBUFF[C'BPOINT;1] = &
		CHR(ASC(C'BUFFER[C'BPOINT;1]) XOR ASC(C'PASSWORD[C'PWPOINT;1]))

	NEXT C'BPOINT
!
! if we are encoding, then write the pattern to disk and exit
!
	IF C'CONTROL=0 THEN GOTO VERIFY
	OPEN #9991, C'FILENAME, RANDOM, 512, REC9991
	REC9991=0: WRITEL #9991, C'WORKBUFF: CLOSE #9991
	C'WORKBUFF = SPACE(512): C'CONTROL = 0 : RETURN
!
! IF DECODING, verify that correct password was used by checking
!    for verification code
!
VERIFY:

	C'VERPOS = INSTR(1,C'WORKBUFF,CHR(127)+"cIpHeR")
	IF C'VERPOS = 0 THEN C'CONTROL=4: RETURN
!
! verification passed -- remove verification code and return
!
	C'LENGTH = ASC(C'WORKBUFF[C'VERPOS+7;1])
	IF C'VERPOS=1 THEN C'BUFFER[1,504]=C'WORKBUFF[9,512]: &
		 C'CONTROL=0: RETURN
	C'BUFFER[1,C'VERPOS-1] = C'WORKBUFF[1,C'VERPOS-1]
	C'BUFFER[C'VERPOS,504] = C'WORKBUFF[C'VERPOS+8,512]
	C'WORKBUFF = SPACE(512): C'CONTROL=0: RETURN
!
! end of routine
!