'===========================================================================
' Subject: XOR ENCRYPTION/DECRYPTION          Date: 08-10-96 (12:55)       
'  Author: Jonathan Leger                     Code: QB, QBasic, PDS        
'  Origin: leger@mail.dtx.net               Packet: BINARY.ABC
'===========================================================================
'(*** XOR.BAS ***)
'(*************************************************************************)
'(*** This is a small demonstration of the XOR encryption/decryption    ***)
'(*** method that will encrypt this file (assuming the name is XOR.BAS) ***)
'(*** and put it in the file XOR.XOR.  If you want it to decrypt the    ***)
'(*** XOR.XOR file once it's been encrypted, merely change the FILE$    ***)
'(*** to XOR.XOR and the OUTPUT$ to XOR.BAS (or whatever).  The key     ***)
'(*** we will be using is 15.  You can change that for your purposes,   ***)
'(*** but the key must be a value from 0 to 255.                        ***)
'(*************************************************************************)
'(*** This method of encryption is not very secure, since it can be     ***)
'(*** broken easily by the brute force method (though it used to be a   ***)
'(*** very popular form of encryption).  However, for most purposes,    ***)
'(*** such as game high scores or passwords, etc, it serves quite well, ***)
'(*** since the person has no way to know that the file was encrypted   ***)
'(*** using this method, and most people wouldn't think to try and      ***)
'(*** decrypt it themselves anyway.                                     ***)
'(*************************************************************************)
'(*** The File.XOR function returns a FALSE value (0) if the input file ***)
'(*** (FILE$) does ***) not exist, otherwise it returns TRUE (-1).      ***)
'(*************************************************************************)

DECLARE FUNCTION File.XOR% (FILE$, output$, ekey%, sbarx%, sbary%, sbarlen%)

SCREEN 0
WIDTH 80, 25
COLOR 7, 0
CLS

FILE$ = "xor.bas"       '(*** We'll encrypt this file... ***)
output$ = "xor.xor"     '(*** ...and put the results here. ***)
ekey% = 15              '(*** Our encryption key will be 15. ***)

LOCATE 1, 1
PRINT "Using XOR method of encryption/decription on " + UCASE$(FILE$) + "..."

'(*** Use a status bar for the encryption. ***)
COLOR 15, 1
ErrVal = File.XOR%(FILE$, output$, ekey%, 1, 2, 40)

IF ErrVal THEN    '(*** No errors! ***)
   LOCATE 1, 1: COLOR 7, 0
   PRINT STRING$(80, " ");
   LOCATE 1, 1
   PRINT "Success!  Results in file (" + UCASE$(output$) + ")."
ELSE
   '(*** The file didn't exist! ***)
   LOCATE 1, 1: COLOR 7, 0
   PRINT STRING$(80, " ");
   LOCATE 1, 1
   PRINT "Input file ("; UCASE$(FILE$); ") does not exist."
END IF

DEFINT A-Z
'(*** File.XOR () ****)
'(*** ----------- ****)
'(*** Thie function will take a file (INPUT$) and XOR each byte with  ***)
'(*** the given encryption key (EKEY), puting the results into a file ***)
'(*** (OUTPUT$).  If you want a status bar showing progress, pass the ***)
'(*** x and y location of the status bar on-screen (SBARX, SBARY). If ***)
'(*** no status bar is desired, pass a 0 for the x and y.  SBARLEN is ***)
'(*** the length you want the status bar to be.                       ***)
'(*** NOTICE:  To unXOR the file, just pass the XORed file the the    ***)
'(*** function with the _SAME_ encryption key.  Given the nature of   ***)
'(*** XOR, an individual decryption scheme is not needed.  Note, too, ***)
'(*** that EKEY can only be from 0 to 255.                            ***)
'(*** --------------------------------------------------------------- ***)
FUNCTION File.XOR (FILE$, output$, ekey, sbarx, sbary, sbarlen)

'(*** Check if the input file passed exist. ***)
'(*** If the input file doesn't exist, exit with error  ***)
'(*** value 0 [FALSE].                                  ***)
filenum = FREEFILE
OPEN FILE$ FOR BINARY AS filenum

IF LOF(filenum) = 0 THEN
   '(*** Pass error value back since file didn't exist. ***)
   File.XOR = 0
   CLOSE filenum
   '(*** Kill the 0 byte file we made by opening it. ***)
   KILL FILE$
   EXIT FUNCTION
END IF

'(*** Both files exist, open them. ***)
CLOSE filenum
OPEN FILE$ FOR INPUT AS filenum
outputnum = FREEFILE
OPEN output$ FOR OUTPUT AS outputnum

'(*** If we want a status bar, do the encryption with a status bar! ***)
IF sbarx > 0 THEN
   '(*** Draw empty status bar and reset the byte count# to 0. ***)
   LOCATE sbary, sbarx: PRINT STRING$(sbarlen, 177);
   count# = 0
   '(*** Encrypt/Decrypt the file. ***)
   DO WHILE NOT EOF(1)
   
      '(*** Read a byte from the file. ***)
      bytes.left# = LOF(filenum) - LOF(outputnum)
      IF bytes.left# < 100 THEN
         read.bytes$ = INPUT$(bytes.left#, filenum)
         chunk = bytes.left#
      ELSE
         read.bytes$ = INPUT$(100, filenum)
         chunk = 100
      END IF
     
      '(*** Increment byte count#. ***)
      count# = count# + chunk

      '(*** XOR the bytes with encryption key. ***)
      FOR byte.count = 1 TO chunk
         changed.byte$ = changed.byte$ + CHR$(ASC(MID$(read.bytes$, byte.count, 1)) XOR ekey)
      NEXT byte.count
     
      '(*** Print it to the output file. ***)
      PRINT #outputnum, changed.byte$;
      changed.byte$ = ""

      '(*** If a chunk of 100 bytes has been read, update status bar. ***)
      IF count# MOD 1000 = 0 THEN
         LOCATE sbary, sbarx
         PRINT STRING$(sbarlen * (count# / LOF(1)), 219);
      END IF

   LOOP
     
      LOCATE sbary, sbarx
      PRINT STRING$(sbarlen, 219);

ELSE
'(*** We didn't want a status bar, so skip the status bar.  This will ***)
'(*** give some extra speed because the print code is ignored.        ***)
  
   DO WHILE NOT EOF(1)
     
      '(*** Read a byte from the file. ***)
      bytes.left# = LOF(filenum) - LOF(outputnum)
      IF bytes.left# < 100 THEN
         read.bytes$ = INPUT$(bytes.left#, filenum)
         chunk = bytes.left#
      ELSE
         read.bytes$ = INPUT$(100, filenum)
         chunk = 100
      END IF
    
      '(*** XOR the bytes with encryption key. ***)
      FOR byte.count = 1 TO chunk
         changed.byte$ = changed.byte$ + CHR$(ASC(MID$(read.bytes$, byte.count, 1)) XOR ekey)
      NEXT byte.count
    
      '(*** Print it to the output file. ***)
      PRINT #outputnum, changed.byte$;
      changed.byte$ = ""

   LOOP

END IF

'(*** Close the files we used. ***)
CLOSE filenum, outputnum

'(*** All done with no errors, so return a TRUE value. ***)
File.XOR = -1

END FUNCTION

