FILE CRYPT.TXT		VAN SWAAY	13-MAY-81

Author:	Maarten van Swaay
	Department of Chemistry
	Kansas State University
	Manhattan, Kansas 66506

Operating System: RT11 V3 or later
SYSGEN  options: SJ with .TWAIT support, or FB

CRYPT is a program that will encrypt and decrypt files. It is primarily
intended for use on text files, although it will operate on all file types.
CRYPT is called with a standard monitor command: .R CRYPT <RETURN>.

CRYPT performs the following actions:

1. CRYPT requests an encryption string, which may be any string of at least
   8 keystrokes and a <CR>. If the encryption string contains 20 or more
   keystrokes before the <CR>, only the first 20 are used. If the string
   contains between 9 and 19 keystrokes before the <CR>, the <CR>, and the
   <LF> that comes with it, will be used as part of the encryption string.

   CRYPT does not write or retain any record of the encryption string. It is
   the responsibility of the user to keep a record of that string; without it
   there is no way to regenerate the plaintext after a pass through CRYPT.

   The operation performed by CRYPT is symmetrical: an even number of passes
   through CRYPT, with the same encryption string, will regenerate the
   the original input.

   CRYPT is also symmetrical with respect to the crypt string and the input
   text. If the input is nonrandom, e.g. if it contains long strings of space
   codes, information about the crypt string can be retrieved from the output
   file. For the intended applications (exams, etc.), that should not be a
   major shortcoming.

2. After CRYPT has accepted the encryption string, it requests a file
   command. That command may not contain wildcards (% and *). The command
   can have the following structures:

   a.	indev:infile
   b.	oudev:=indev:infile
   c.	oudev:outfile=indev:infile

   DK: will be inserted by CSI if indev: or oudev: are omitted from the
   string. More than one input and/or output file may be specified, but only
   the first of each will be recognized.

   Type <a> will encrypt the input file in-place on the disk. This is the
   recommended use, because no plaintext records will then remain anywhere.

   Type <b> will create a new output file if the output device is not
   file-structured, e.g. if TT: is used for output. If the output device
   specified is file-structured, the input file will be encrypted in-place,
   even if the output device is not the same as the input device. Note that
   this action differs from the standard interpretation of the CSI string.

   Type <c> will create a new output file if the input and output filespecs
   are not identical. If the two filespecs are identical, the input file
   will be encrypted in-place.
3. CRYPT assumes no responsibility for the disposition of privileged
   information elsewhere on a disk, e.g. in the form of backup files or
   deleted early versions.

For the protection of sensitive information, such as exams etc., it will
be the responsibility of the user to insure that no unencrypted versions
of the text are left on a disk. Although it is not a simple job to gain
access to deleted files, it is by no means impossible.

To avoid the existence of plaintext information on a disk one should do
the following:

a.  Encrypt each backup file as it is made, and before it is deleted by
    a subsequent edit session. At the end of the work session, encrypt
    the current version of the file in-place, and convert it back into
    plaintext before the start of the next edit session.

b.  If a backup file is accidentally deleted before it is encrypted,
    retrieve it with the help of the DIR/DEL command and a session with
    DUP, which can create directory entries without moving files.

c.  If neither of the above approaches are practical, copy some large files
    beyond all existing files, and then squeeze the disk. That will roll
    the newly written files over the blocks that previously held the
    deleted versions of your plaintext.

Methods <b> and <c> require some familiarity with file manipulations beyond
what the average user is aware of. More information about that can be found
in the chapters on DIR, DUP, and PIP in RT11 Vol. 2A.

It is safe to print plaintext output from CRYPT via the SPOOL, even though
that will involve the temporary presence of a plaintext copy of the file on
on the system disk. The spooler can be compiled with a condition DSTROY=1,
and will then destroy the content of all files it prints, in addition to
deleting those files from the directory.

PROGRAM NOTES

The mechanisms used by CRYPT is a word-by-word XOR between the input file
and a text string that is entered at run-time. The encryption string must
be at least 10 bytes long (8 characters + CRLF). If the entered string is
longer than 20 bytes (including CRLF), it is truncated to 20 bytes (10 words).
A text string containing 8-19 characters closed by CRLF is acceptable; the
CRLF code will then be part of the encryption string. There are no
restrictions on the character set used in the encryption string, but monitor
control codes (^C, ^F, ^B, ^X) will be intercepted by the monitor. To avoid
the creation of copies of the crypt string at the end of the encrypted file,
null words in the input file are left unchanged.

CRYPT begins with a request for buffer space to hold the CSI I/O list and
enough queue space for the I/O, completion routines, and .TWAIT requests.
Then the encryption string is requested. Before input of that string, any
unused input in the ring buffer is discarded.

After the input string has been accepted, CSI is called in special mode,
to avoid lookup and enter functions. On return, the command string is
inspected for absence of wildcard specs.
Next, the input filespec is inspected: input from a non-file device is
refused. The absence of an input file is also ground for rejection of the
command string.

If no output file was specified, CRYPT will encrypt the input file in-place,
without modifying the directory of the input device.

If an output device was specified, its nature is inspected. If the output
device is non-file, output will be written to that device without further
tests. If the output device is file-structured, a test is made whether a
file name was given. If no file name was given for output, the input file
will be encrypted in-place. Note that this action differs from the standard
interpretation of a CSI string. If a file name was given, it is compared
against the input filespec. If the two filespecs are identical, the input
file will be rewritten in-place. Only if the output filespec differs from
the input filespec will a new file be created on a file-structured device.

CRYPT will announce its choice of in-place encryption or creation of a
new output file, and then perform the action.

The I/O loop contains a pair of .READC requests with separate staging
blocks and transfer buffers, and separate completion routines. Each
completion routine contains a call to the conversion subroutine and a
.WRITC request on the same buffer and staging block as the parent .READC.
Block numbers for the input requests are controlled from the I/O loop;
block numbers for the output requests are maintained in the completion
routines.

After the last .READC has been issued, an exit routine waits for release
of both transfer buffers. Between tests on the release flags, the program
puts itself to sleep for 2 time ticks, or about 33 msec.

There remain some unresolved questions:

1.  How should magtape and cassette be treated? At present, both are
    refused as input devices, but that may be overly restrictive.

2.  No space is requested for drivers, under the assumption that RMON
    is smart enough not to overlay occupied memory during a .FETCH. That
    sounds reasonable enough, but may not be watertight.

3.  The queue elements are 10 words long, but under XM a .FETCH is not
    allowed. Only LOADed drivers can be used under XM. That means that
    the program should be restricted to SJ and FB, in which case the
    queue elements need only be 7 words each. If the program must run under
    XM, it should do .DSTATUS on each driver, rather than .FETCH.

4.  If the input device can read a block in less than 6 msec, it would
    be possible to generate a re-entrant call to the conversion subroutine
    under the SJ monitor, because SJ allows interruption of completion
    routines by other completion routines. Under FB and XM all completion
    routines are queued up, so that they cannot interrupt each other.

5.  Items 3 and 4 would justify an up-front call to RMON to check for
    compatibility between the program and the monitor under which it is
    running. That has not been done yet.
6.  The .READC and .WRITC requests are made with brute force; they all
    fill the entire staging block. It should be possible to leave most
    or the argument fields blank in those requests. In the interest of
    readability that has not been done.

7.  After the crypt string is accepted, the program clears the lower-case
    bit in the JSW. For unknown reasons, lower-case input is still passed
    through when CSI accepts its filespec. CSI is bright enough to handle
    the conversion by itself, but that does not answer the question why
    the JSW is ignored at that time. An untested hypothesis is that CSIGEN
    has its own ideas about case conversion, although that sounds a bit
    farfetched.

Any user comments that can shed light on these questions will be very
welcome!
��