! 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
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
!