;;; -*- Mode:LISP; Package:USER; Base:10; Readtable:CL -*- #|| Copyright LISP Machine, Inc. 1985, 1986 See filename "Copyright.Text" for licensing and release information. ********************************************************* ********************************************************* *** NOTE: This is an EXAMPLE, not LMI supported code. *** *** information contained in this example is subject *** *** to change without notice. The ways of doing *** *** the things contained in the example may change *** *** between system releases. Some techniques which *** *** are mere examples in one release may become built *** *** in system features in the next release. Use good *** *** judgement when copying these techniques. Most *** *** examples have been motivated by specific customer *** *** requests, and may not be the best engineered *** *** or most efficient solution for someone else. *** ********************************************************* ********************************************************* Here is something that is probably good enough for allowing some personal privacy on a public shared filesystem. Reducing the chance of accidental disclosure of personal mail etc. Be sure to turn off your TELNET and EVAL servers if you want to protect your buffers and passwords etc while in your running virtual memory environment. 9-Mar-86 17:06:39 -George Carrette Example usage: (add-crypt-host "LAMBDA-A") From then on (open "crypt-lambda-a:foo;bar.lisp") will return a crypt input stream, and (open "crypt-lambda-a:foo;bar.lisp" :direction :output) will return a crypt output stream. There is sufficient support here to allow one to read and write files from the editor as well. The default settings of *KEY-MAKER* and *ENCRYPTOR* give a simple algorithm that is easy to break when used with a short key. One might want to rework this to have different keys and encyptors for different hosts. Encryption of filenames may also be amusing, but potentially troublesome in practice since the target names must still be syntactically legal on the system. ||# ;;; section I, the Streams. (DEFVAR *KEY-MAKER* 'XOR-KEY-MAKER) (DEFVAR *ENCRYPTOR* 'XOR-CRYPT-STRING) (DEFFLAVOR CRYPT-MIXIN (KEY HANDLE BYTE-SIZE) () :initable-instance-variables) (DEFMETHOD (CRYPT-MIXIN :AFTER :INIT) (&REST IGNORED) (or (variable-boundp key) (setq key (FUNCALL *KEY-MAKER* (GET-KEYSTRING-LIST)))) nil) (DEFMETHOD (CRYPT-MIXIN :ENCRYPT-BUFFER) (ARRAY END) (SETQ KEY (FUNCALL *ENCRYPTOR* ARRAY END KEY)) NIL) (DEFMETHOD (CRYPT-MIXIN :ALLOCATE-BUFFER) () (ECASE BYTE-SIZE (8 (ALLOCATE-RESOURCE 'FS:SIMPLE-STRING-BUFFER 1024)) (16 (ALLOCATE-RESOURCE 'FS:SIMPLE-ART-16B-BUFFER 512)))) (DEFMETHOD (CRYPT-MIXIN :DEALLOCATE-BUFFER) (BUFFER) (ECASE BYTE-SIZE (8 (DEALLOCATE-RESOURCE 'FS:SIMPLE-STRING-BUFFER BUFFER)) (16 (DEALLOCATE-RESOURCE 'FS:SIMPLE-ART-16B-BUFFER BUFFER)))) (DEFMETHOD (CRYPT-MIXIN :INFO) () (IF (VARIABLE-BOUNDP HANDLE) (FUNCALL HANDLE :INFO))) (DEFMETHOD (CRYPT-MIXIN :PATHNAME) () (IF (VARIABLE-BOUNDP HANDLE) (FUNCALL HANDLE :PATHNAME))) (DEFMETHOD (CRYPT-MIXIN :TRUENAME) () (IF (VARIABLE-BOUNDP HANDLE) (FUNCALL HANDLE :TRUENAME))) (DEFMETHOD (CRYPT-MIXIN :GENERIC-PATHNAME) () (IF (VARIABLE-BOUNDP HANDLE) (FUNCALL HANDLE :GENERIC-PATHNAME))) (defflavor crypt-input-stream-mixin (input) (CRYPT-MIXIN) :initable-instance-variables) (defflavor crypt-character-input-stream () (crypt-input-stream-mixin si:buffered-input-character-stream)) (defflavor crypt-binary-input-stream () (crypt-input-stream-mixin si:buffered-input-stream)) (defmethod (crypt-input-stream-mixin :close) (&rest args) (and input (lexpr-send input :close args))) (defmethod (crypt-input-stream-mixin :next-input-buffer) (&optional no-hang-p) no-hang-p (and input (let ((buffer) (normalp nil)) (unwind-protect (let ((amount (send input :string-in nil (setq buffer (SEND SELF :ALLOCATE-BUFFER))))) (if (zerop amount) (close (prog1 input (setq input nil)))) (SEND SELF :ENCRYPT-BUFFER BUFFER AMOUNT) (setq normalp t) (values buffer 0 amount)) (and (not normalp) buffer (SEND SELF :DEALLOCATE-BUFFER BUFFER)))))) (defmethod (crypt-input-stream-mixin :discard-input-buffer) (array) (SEND SELF :DEALLOCATE-BUFFER ARRAY)) (defflavor crypt-output-stream-mixin (output) (CRYPT-MIXIN) :initable-instance-variables) (defflavor crypt-character-output-stream () (crypt-output-stream-mixin si:buffered-output-character-stream)) (defflavor crypt-binary-output-stream () (crypt-output-stream-mixin si:buffered-output-stream)) (defmethod (crypt-output-stream-mixin :new-output-buffer) () (LET ((BUFFER (SEND SELF :ALLOCATE-BUFFER))) (VALUES BUFFER 0 (LENGTH BUFFER)))) (defmethod (crypt-output-stream-mixin :send-output-buffer) (array end) (SEND SELF :ENCRYPT-BUFFER ARRAY END) (send output :string-out array 0 end) (SEND SELF :DEALLOCATE-BUFFER ARRAY)) (defmethod (crypt-output-stream-mixin :discard-output-buffer) (array) (SEND SELF :DEALLOCATE-BUFFER ARRAY)) (defmethod (crypt-output-stream-mixin :close) (&rest ignored) (and output (close output))) (compile-flavor-methods crypt-character-input-stream crypt-binary-input-stream crypt-character-output-stream crypt-binary-output-stream) ;;; Section II, a utility function using only the streams. (defun crypt-file (input-filename output-filename &optional (on-input t)) (with-open-file (from-stream input-filename) (with-open-file (to-stream output-filename :direction :output) (with-open-stream (crypt (if on-input (make-instance 'crypt-character-input-stream :input from-stream) (make-instance 'crypt-character-output-stream :output to-stream))) (if on-input (stream-copy-until-eof crypt to-stream) (stream-copy-until-eof from-stream crypt)))))) ;;; Section III, the default key maker and encryptor. (DEFUN XOR-KEY-MAKER (KEYS) (let ((e)) (dolist (k keys) (dotimes (j (length k)) (DO ((C (AREF K J) (MOD (1+ C) 256)) (N 0 (1+ N))) ((OR (NOT (MEM #'= C E)) (= N 256)) (PUSH (CHAR-CODE C) E))))) (RPLACD (LAST E) E))) (DEFUN XOR-CRYPT-STRING (A N L) (DO ((J 0 (1+ J))) ((= J N) L) (SETF (AREF A J) (LOGXOR (AREF A J) (POP L))))) (defvar *static-keystring-list* T "Set this to your keystring list if you dont want to be prompted, or to T if you want to be prompted only once") (add-initialization "flush xor-crypt keys" '(setq *static-keystring-list* nil) '(:logout)) (defun get-keystring-list () (cond ((eq *static-keystring-list* t) (setq *static-keystring-list* (let ((*static-keystring-list* nil)) (get-keystring-list)))) (*static-keystring-list*) ('else (labels ((prompt-and-readline (message) (terpri) (princ message) (do ((a (make-string 80 :fill-pointer 0)) (c (send standard-input :tyi) (send standard-input :tyi))) ((= c #\return) a) (vector-push-extend c a))) (prompt-and-readline-secretly (message) (do ((linin (prompt-and-readline message) (prompt-and-readline message))) ((equal linin (prompt-and-readline '"Once more to verify: ")) linin) (princ "They didn't match. Try again.")))) (do ((keys (ncons (prompt-and-readline-secretly '"First key = ")) (cons (prompt-and-readline-secretly '"Next key = ") keys))) ((zerop (string-length (car keys))) (setq keys (cdr keys)) (cond ((zerop (length keys)) (format t "You have to supply at least ONE key!") (get-keystring-list)) (t (format t "~% ~D keystring~p entered." (length keys) (length keys)) (nreverse keys))))))))) ;; Section IV, host and pathname interface. (DEFFLAVOR CRYPT-PROBE-STREAM (SUBSTREAM HOST) () :initable-instance-variables) (DEFMETHOD (CRYPT-PROBE-STREAM :INFO) () (LET ((I (SEND SUBSTREAM :INFO))) (AND I (CONS (SEND (CAR I) :NEW-PATHNAME :HOST HOST) (CDR I))))) (DEFMETHOD (CRYPT-PROBE-STREAM :CREATION-DATE) () (SEND SUBSTREAM :CREATION-DATE)) (DEFMETHOD (CRYPT-PROBE-STREAM :CLOSE) (&REST IGNORED) ()) (DEFFLAVOR CRYPT-HOST (NAME PHYSICAL-HOST) (FS:PATHNAME-HOST-MIXIN SI:BASIC-HOST) (:SETTABLE-INSTANCE-VARIABLES)) (DEFMETHOD (CRYPT-HOST :PATHNAME-FLAVOR) () 'CRYPT-PATHNAME) (DEFMETHOD (CRYPT-HOST :SYSTEM-TYPE) () :CRYPT) (DEFMETHOD (CRYPT-HOST :NETWORK-TYPE) () (SEND PHYSICAL-HOST :NETWORK-TYPE)) (DEFMETHOD (CRYPT-HOST :NETWORK-TYPEP) (TYPE) (SEND PHYSICAL-HOST :NETWORK-TYPEP TYPE)) (DEFMETHOD (CRYPT-HOST :ENABLE-CAPABILITIES) (&REST L) (LEXPR-SEND PHYSICAL-HOST :ENABLE-CAPABILITIES L)) (DEFMETHOD (CRYPT-HOST :DISABLE-CAPABILITIES) (&REST L) (LEXPR-SEND PHYSICAL-HOST :DISABLE-CAPABILITIES L)) (DEFFLAVOR CRYPT-PATHNAME () (FS:PATHNAME)) (DEFMETHOD (CRYPT-PATHNAME :INTERNAL-TRANSLATED-PATHNAME) () (MAKE-PATHNAME :HOST (SEND (SEND SELF :HOST) :PHYSICAL-HOST) :DEVICE (SEND SELF :DEVICE) :DIRECTORY (SEND SELF :DIRECTORY) :NAME (SEND SELF :NAME) :TYPE (SEND SELF :TYPE) :VERSION (SEND SELF :VERSION))) (DEFMETHOD (CRYPT-PATHNAME :PASS-ON) (MESSAGE &OPTIONAL L) (LEXPR-SEND (SEND SELF :INTERNAL-TRANSLATED-PATHNAME) MESSAGE L)) (DEFMETHOD (CRYPT-PATHNAME :STRING-FOR-PRINTING) () (LET ((S (SEND (SEND SELF :INTERNAL-TRANSLATED-PATHNAME) :STRING-FOR-PRINTING))) (STRING-APPEND (SEND (SEND SELF :HOST) :NAME) (SUBSTRING S (STRING-SEARCH ":" S))))) (DEFMETHOD (CRYPT-PATHNAME :STRING-FOR-DIRECTORY) () (SEND SELF :PASS-ON :STRING-FOR-DIRECTORY)) (DEFMETHOD (CRYPT-PATHNAME :PARSE-NAMESTRING) (&REST L) (SEND SELF :PASS-ON :PARSE-NAMESTRING L)) (DEFMETHOD (CRYPT-PATHNAME :QUOTE-CHARACTER) () (SEND SELF :PASS-ON :QUOTE-CHARACTER)) (DEFMETHOD (CRYPT-PATHNAME :CHARACTER-NEEDS-QUOTING-P) (&REST L) (SEND SELF :PASS-ON :CHARACTER-NEEDS-QUOTING-P L)) (DEFMETHOD (CRYPT-PATHNAME :PARSE-DIRECTORY-SPEC) (&REST L) (SEND SELF :PASS-ON :PARSE-DIRECTORY-SPEC L)) (DEFMETHOD (CRYPT-PATHNAME :STRING-FOR-HOST) () (SEND SELF :PASS-ON :STRING-FOR-HOST)) (DEFMETHOD (CRYPT-PATHNAME :STRING-FOR-WHOLINE) () (LET ((S (SEND (SEND SELF :INTERNAL-TRANSLATED-PATHNAME) :STRING-FOR-WHOLINE))) (STRING-APPEND (SEND (SEND SELF :HOST) :NAME) (SUBSTRING S (STRING-SEARCH ":" S))))) (DEFMETHOD (CRYPT-PATHNAME :STRING-FOR-EDITOR) () (STRING-APPEND (SEND SELF :PASS-ON :STRING-FOR-EDITOR) (SEND (SEND SELF :HOST) :NAME) ":")) (DEFMETHOD (CRYPT-PATHNAME :CHANGE-PROPERTIES) (&REST L) (SEND SELF :PASS-ON :CHANGE-PROPERTIES L)) (DEFMETHOD (CRYPT-PATHNAME :EXPUNGE) (&REST L) (SEND SELF :PASS-ON :EXPUNGE L)) (DEFMETHOD (CRYPT-PATHNAME :DELETE) (&REST L) (SEND SELF :PASS-ON :DELETE L)) (DEFMETHOD (CRYPT-PATHNAME :UNDELETE) (&REST L) (SEND SELF :PASS-ON :UNDELETE L)) (DEFMETHOD (CRYPT-PATHNAME :RENAME) (&REST L) (SEND SELF :PASS-ON :RENAME L)) (DEFMETHOD (CRYPT-PATHNAME :UNDELETABLE-P) (&REST L) (SEND SELF :PASS-ON :UNDELETABLE-P L)) (DEFMETHOD (CRYPT-PATHNAME :HOMEDIR) (&REST L) (SEND (SEND SELF :PASS-ON :HOMEDIR L) :NEW-PATHNAME :HOST (SEND SELF :HOST))) (DEFMETHOD (CRYPT-PATHNAME :MULTIPLE-FILE-PLISTS) (&REST L) (MAPCAR #'(LAMBDA (PLIST) (DO ((NEW (CONS (SEND (CAR PLIST) :NEW-PATHNAME :HOST (SEND SELF :HOST)) NIL)) (L (CDR PLIST) (CDDR PLIST))) ((NULL L) NEW) (COND ((EQ (CAR L) :TRUENAME) (PUTPROP NEW (SEND (CADR L) :NEW-PATHNAME :HOST (SEND SELF :HOST)) :TRUENAME)) ('ELSE (PUTPROP NEW (CADR L) (CAR L)))))) (SEND SELF :PASS-ON :MULTIPLE-FILE-PLISTS L))) (DEFMETHOD (CRYPT-PATHNAME :PARSE-TRUENAME) (&REST L) (SEND (SEND SELF :PASS-ON :PARSE-TRUENAME L) :NEW-PATHNAME :HOST (SEND SELF :HOST))) (DEFMETHOD (CRYPT-PATHNAME :DIRECTORY-LIST) (&REST L) (MAPCAR #'(LAMBDA (X) (COND ((CAR X) (CONS (SEND (CAR X) :NEW-PATHNAME :HOST (SEND SELF :HOST)) (CDR X))) ('ELSE X))) (SEND SELF :PASS-ON :DIRECTORY-LIST L))) (DEFMETHOD (CRYPT-PATHNAME :DIRECTORY-LIST-STREAM) (&REST L) (LET ((STREAM (SEND SELF :PASS-ON :DIRECTORY-LIST-STREAM L)) (NSELF SELF)) (IF (ERRORP STREAM) STREAM #'(LAMBDA (OPERATION &REST ARGS) (SI:SELECTQ-WITH-WHICH-OPERATIONS OPERATION (:ENTRY (LET ((X (SEND STREAM :ENTRY))) (COND ((CAR X) (CONS (SEND (CAR X) :NEW-PATHNAME :HOST (SEND NSELF :HOST)) (CDR X))) ('ELSE X)))) (:CLOSE (LEXPR-SEND STREAM :CLOSE ARGS))))))) (DEFMETHOD (CRYPT-PATHNAME :ALL-DIRECTORIES) () (MAPCAR #'(LAMBDA (X) (SEND X :NEW-PATHNAME :HOST (SEND SELF :HOST))) (SEND SELF :PASS-ON :ALL-DIRECTORIES))) (DEFMETHOD (CRYPT-PATHNAME :STRING-FOR-DIRED) () (SEND SELF :PASS-ON :STRING-FOR-DIRED)) (DEFMETHOD (CRYPT-PATHNAME :OPEN) (&REST OPTIONS) (CRYPT-OPEN SELF :OPEN OPTIONS)) (DEFMETHOD (CRYPT-PATHNAME :OPEN-CANONICAL-TYPE) (&REST OPTIONS) (CRYPT-OPEN SELF :OPEN-CANONICAL-TYPE OPTIONS)) (DEFUN CRYPT-OPEN (P OPERATION OPTIONS) (LET (SUBSTREAM NORMALP) (UNWIND-PROTECT (PROG1 (COND ((ERRORP (SETQ SUBSTREAM (LEXPR-SEND (SEND P :INTERNAL-TRANSLATED-PATHNAME) OPERATION OPTIONS))) SUBSTREAM) ('ELSE (ECASE (SEND SUBSTREAM :DIRECTION) (NIL (MAKE-INSTANCE 'CRYPT-PROBE-STREAM :SUBSTREAM SUBSTREAM :HOST (SEND P :HOST))) (:INPUT (MAKE-INSTANCE (IF (SEND SUBSTREAM :CHARACTERS) 'CRYPT-CHARACTER-INPUT-STREAM 'CRYPT-BINARY-INPUT-STREAM) :INPUT SUBSTREAM :BYTE-SIZE (IF (SEND SUBSTREAM :CHARACTERS) 8 ;; QFILE ACCESS STREAMS DONT ACCEPT ANY ;; :BYTE-SIZE KIND OF MESSAGE. SO WE GUESS 16) :HANDLE #'(LAMBDA (OPERATION) (CRYPT-STREAM-HANDLE OPERATION P SUBSTREAM)))) (:OUTPUT (MAKE-INSTANCE (IF (SEND SUBSTREAM :CHARACTERS) 'CRYPT-CHARACTER-OUTPUT-STREAM 'CRYPT-BINARY-OUTPUT-STREAM) :OUTPUT SUBSTREAM :BYTE-SIZE (IF (SEND SUBSTREAM :CHARACTERS) 8 ;; QFILE ACCESS STREAMS DONT ACCEPT ANY ;; :BYTE-SIZE KIND OF MESSAGE. SO WE GUESS 16) :HANDLE #'(LAMBDA (OPERATION) (CRYPT-STREAM-HANDLE OPERATION P SUBSTREAM))))))) (SETQ NORMALP T)) (AND SUBSTREAM (NOT NORMALP) (CLOSE SUBSTREAM :ABORT T))))) (DEFUN CRYPT-STREAM-HANDLE (OPERATION PATHNAME STREAM) (ECASE OPERATION (:INFO (LET ((I (SEND STREAM :INFO))) (AND I (CONS (SEND (CAR I) :NEW-PATHNAME :HOST (SEND PATHNAME :HOST)) (CDR I))))) (:TRUENAME (SEND (SEND STREAM :TRUENAME) :NEW-PATHNAME :HOST (SEND PATHNAME :HOST))) (:PATHNAME (SEND (SEND STREAM :PATHNAME) :NEW-PATHNAME :HOST (SEND PATHNAME :HOST))) (:GENERIC-PATHNAME (SEND (SEND STREAM :GENERIC-PATHNAME) :NEW-PATHNAME :HOST (SEND PATHNAME :HOST))))) (COMPILE-FLAVOR-METHODS CRYPT-HOST CRYPT-PATHNAME CRYPT-PROBE-STREAM) (DEFUN ADD-CRYPT-HOST (PHYSICAL-HOST &OPTIONAL CRYPT-NAME) (LET* ((PH (SI:PARSE-HOST PHYSICAL-HOST)) (NAME (OR CRYPT-NAME (STRING-APPEND "CRYPT-" (SEND PH :SHORT-NAME))))) (LET ((CH (MAKE-INSTANCE 'CRYPT-HOST :PHYSICAL-HOST PH :NAME NAME))) (SETQ FS:*PATHNAME-HOST-LIST* (DELQ (CAR (MEM #'(LAMBDA (NAME HOST) (AND (TYPEP HOST 'CRYPT-HOST) (STRING-EQUAL (SEND HOST :NAME) NAME))) NAME FS:*PATHNAME-HOST-LIST*)) FS:*PATHNAME-HOST-LIST*)) (PUSH CH FS:*PATHNAME-HOST-LIST*) CH)))