merlyn@intelob.intel.com (Randal L. Schwartz @ Stonehenge) (05/04/89)
Some time ago, Carsten Wiethoff <cnwietho@immd4.informatik.uni-erlangen.de> published the algorithm for the Postscript "undocumented" eexec operator in comp.lang.postscript. This operator apparently takes trivially encrypted text on the indicated file (the top of stack parameter), and decrypts it and then executes it. I took his algorithm description and wrote the attached GNU Emacs elisp code to play with it. With the code, you can take an arbitrary chunk of Postscript, 'eexec-encode' it, and feed the ugly-looking result into a LaserWriter(tm) or any Postscript(tm) implementation that supports eexec. You can even send it to your friend, and he/she won't be able to tell what it does until it comes out of the printer. But, since this message is going out to thousands of machines worldwide, don't count on secrecy for long... because the reverse is supported... take a file that has been encrypted, and decrypt it with 'eexec-decode'. The 'seed' value apparently doesn't matter. It worked for any of the values I tried on a standard LaserWriter, but your mileage may vary. I'd be interested to hear about bugs, feature enhancements, or whatever. Yeah, I know it is slow decoding... elisp has no fast hex number manipulators. Enjoy. (This code is copyleft according to the GNU 'COPYING' file.) /=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095===\ { on contract to BiiN, Hillsboro, Oregon, USA, until 30 May 1989 } { <merlyn@intelob.intel.com> ...!uunet!tektronix!biin!merlyn } { or try <merlyn@agora.hf.intel.com> after 30 May 1989 } \=Cute quote: "Welcome to Oregon... home of the California Raisins!"=/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cut here ;;;;;;;;;; ;;; Postscript eexec support routines ;;; LastEditDate "Wed May 3 10:22:06 1989" ;;; Copyright (c) 1989 by Randal L. Schwartz. All Rights Reserved. ;;; This code may be freely distributed according to the GNU Public License (defun hex-string-to-int (str) "Convert STRING to an integer by parsing it as a hexadecimal number." (let ((result 0) ch) (while (string-match "^[0-9a-fA-F]" str) (setq ch (string-to-char (substring str 0 1)) str (substring str 1) result (+ (* 16 result) (cond ((>= ch ?a) (+ (- ch ?a) 10)) ((>= ch ?A) (+ (- ch ?A) 10)) (t (- ch ?0)))))) result)) (defun byte-to-hex-string (byte) "Convert BYTE to a string by printing it in hexadecimal." ;; quick and dirty (concat (char-to-string (aref "0123456789abcdef" (logand 15 (lsh byte -4)))) (char-to-string (aref "0123456789abcdef" (logand 15 byte))))) (defconst eexec-const-init (hex-string-to-int "d971")) (defconst eexec-const-mult (hex-string-to-int "ce6d")) (defconst eexec-const-add (hex-string-to-int "58bf")) (defconst eexec-const-seed (mapconcat (function (lambda (x) (char-to-string (hex-string-to-int x)))) '("17" "ec" "9c" "f3") "")) (defun eexec-decode () "Decode the first eexec string in the current (possibly narrowed) buffer. Result is displayed in a temp buffer." (interactive) (with-output-to-temp-buffer "*eexec-decode-output*" (goto-char (point-min)) (search-forward "eexec") (let ((str "") newstr) (while (re-search-forward "[ \t\n]*\\([0-9a-fA-F][0-9a-fA-F]\\)" nil t) (setq str (concat str (char-to-string (hex-string-to-int (buffer-substring (match-beginning 1) (match-end 1))))))) (setq newstr (eexec-endecode str)) (princ "Seed: ") (princ (byte-to-hex-string (aref newstr 0))) (princ (byte-to-hex-string (aref newstr 1))) (princ (byte-to-hex-string (aref newstr 2))) (princ (byte-to-hex-string (aref newstr 3))) (princ "\nText:\n") (princ (substring newstr 4))))) (defun eexec-encode (start end &optional seed) "Encode text from START to END (region if interactive). Result is displayed in a temp buffer. If optional SEED is passed as a four-character string, use it for initial state, else use the known string from the uartpatch.ps file '17ec9cf3'." (interactive "r") (with-output-to-temp-buffer "*eexec-encode-output*" (let ((i 0)) (princ "currentfile eexec\n") (mapcar (function (lambda (ch) (princ (byte-to-hex-string ch)) (if (< (setq i (1+ i)) 32) nil (princ "\n") (setq i 0)))) (eexec-endecode (concat (or (and (stringp seed) (= (length seed) 4) seed) eexec-const-seed) (buffer-substring start end)) t)) (if (> i 0) (princ "\n"))))) (defun eexec-endecode (str &optional encode) "Decode STR (or encode if optional ENCODE is non-nil), returning result. If decoding, you will probably want to toss the first four bytes, but they are returned anyway so that you may reencode a decoded string for verification." (let ((state eexec-const-init) outbyte) (concat (mapcar (function (lambda (inbyte) (setq outbyte (logxor inbyte (logand (lsh state -8))) state (logand 65535 (+ state (if encode outbyte inbyte))) state (logand 65535 (* state eexec-const-mult)) state (logand 65535 (+ state eexec-const-add))) outbyte)) str)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cut here
rbj@dsys.icst.nbs.GOV (Root Boy Jim) (05/05/89)
? Reply-To: "Randal L. Schwartz @ Stonehenge" <merlyn@intelob.intel.com> ? (defun byte-to-hex-string (byte) ? "Convert BYTE to a string by printing it in hexadecimal." ? ;; quick and dirty ? (concat (char-to-string (aref "0123456789abcdef" (logand 15 (lsh byte -4)))) ? (char-to-string (aref "0123456789abcdef" (logand 15 byte))))) The above function can be written as: (defun byte-to-hex-string (byte) "mumble" (format "%x" byte)) Unfortunately, the reverse is not true. String-to-int should also take an optional base argument. Having said that, I will now quibble with your input scanner: (defun hex-string-to-int (str) "Convert STRING to an integer by parsing it as a hexadecimal number." (let ((result 0) ch) (while (string-match "^[0-9a-fA-F]" str) (setq ch (string-to-char (substring str 0 1)) str (substring str 1) result (+ (* 16 result) (cond ((>= ch ?a) (+ (- ch ?a) 10)) ((>= ch ?A) (+ (- ch ?A) 10)) (t (- ch ?0)))))) result)) Replace (string-to-char (substring str 0 1)) with (aref str 0). A string is really a vector of characters; you used this fact later. You can always replace (* 16 result) with (lsh result 4). Since you have already verified that the digits match [0-9a-fA-F], you can replace the cond statement with: (logand 15 (+ ch (if (> ch ?9) 9 0))) Finally, towards the end you wrote ... (concat (mapcar ... )) ... I'm not sure, but this looks awful similar to ... (mapconcat ...) ... BTW, to the author of SIP (scroll-in-place): you wrote a function whose point was to determine if two numbers were of same sign. The definition looked something like: (defun same-sign (x y) "Return t is X and Y are same sign, else nil" (if (< x 0) (< y 0) (<= 0 y))) How bout: (defun same-sign (x y) (<= 0 (logxor x y))) instead? You could also use `natnump' instead of `<='. If the function was different-sign, then replace `<=' with `>'. Don't y'all just hate smart alecks :-? Root Boy Jim is what I am Are you what you are or what?