home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.eterna.com.au
/
2014.06.ftp.eterna.com.au.tar
/
ftp.eterna.com.au
/
lisp
/
zenirc-secure-beta.el
< prev
Wrap
Lisp/Scheme
|
1998-04-14
|
9KB
|
277 lines
;;; zenirc-secure.el -- cryptographically secure privmsgs
;; Copyright (C) 1998 anyone but me.
;; Author: not me.
;; Keywords: zenirc, secure, IDEA, oink, fuck the NSA
;; Created: 98-04-14
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, you can either send email to this
;; program's maintainer or write to: The Free Software Foundation,
;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
;;; Commentary:
;; usage: /secure [nick]
;; /encrypt [nick] [string]
;;; Code:
(require 'zenirc)
(require 'idea)
(defvar zenirc-command-secure-hook '(zenirc-secure-initiate))
(defvar zenirc-command-encrypt-hook '(zenirc-secure-encrypt))
(defvar zenirc-ctcp-query-SECURE1-hook '(zenirc-ctcp-query-SECURE1))
(defvar zenirc-ctcp-query-SECURE2-hook '(zenirc-ctcp-query-SECURE2))
(defvar zenirc-ctcp-query-ENCRYPTED-hook '(zenirc-ctcp-query-ENCRYPTED))
(defvar zenirc-secure-keys nil
"assoc list of nick,key")
(defvar zenirc-secure-pending nil
"secure connections waiting for reply from other end,
assoc of nick,half-key")
(defun zenirc-secure-install-message-catalogs ()
(zenirc-lang-define-catalog 'english
'((secure-usage . "[info] usage: /secure nick\n")
(secure-already . "[info] there is already a secure channel to %s.\n")
(secure-pending . "[info] already trying to establish a secure channel to %s.\n")
(secure-list-start . "[info] current secure channels:\n")
(secure-pending-start . "[info] pending secure channels:\n")
(secure-list . "[info] %s\n")
(secure-end-list . "[info] (end of list)\n")
(secure-established . "[inf] secure connection established with %s.\n")
(secure-not-pending . "[inf] %s trying to complete unasked for secure channel.\n")
(secure-sent . "[inf] encrypted message sent to %s.\n")
(secure-message . "ENC|%s|ENC %s\n")
(secure-bogus-message . "[inf] bogus message from %s.\n")
(secure-no-channel . "[inf] no encrypted channel to %s.\n")
)))
(defun zenirc-secure-initiate (proc parsedcmd)
"initiate a secure channel with someone"
(let ((lst (zenirc-parse-words (cdr parsedcmd))))
(cond ((null lst) (zenirc-secure-display-channels proc))
((= (length lst) 1)
(let ((nick (car lst)))
(cond ((assoc nick zenirc-secure-keys)
(zenirc-message proc 'secure-already nick))
((assoc nick zenirc-secure-pending)
(zenirc-message proc 'secure-pending nick))
(t (let ((half-key (zenirc-secure-make-half-key)))
(setq zenirc-secure-pending
(cons (cons nick half-key) zenirc-secure-pending))
(process-send-string
proc
(concat "PRIVMSG "
nick
" :\C-a"
"SECURE1 "
(format "%s" half-key)
"\C-a\n")))))))
(t (zenirc-message proc 'secure-usage)))))
(defun zenirc-secure-display-channels (proc)
"show the current established and pending secure channels."
(zenirc-message proc 'secure-list-start)
(let ((lst zenirc-secure-keys))
(while lst
(zenirc-message proc 'secure-list (caar lst))
(setq lst (cdr lst))))
(zenirc-message proc 'secure-end-list)
(zenirc-message proc 'secure-pending-start)
(let ((lst zenirc-secure-pending))
(while lst
(zenirc-message proc 'secure-list (caar lst))
(setq lst (cdr lst))))
(zenirc-message proc 'secure-end-list))
(defun zenirc-secure-make-half-key ()
"make half a key"
;; lamely, for now.
(vector (logand ?\xffff (random))
(logand ?\xffff (random))
(logand ?\xffff (random))
(logand ?\xffff (random))
(logand ?\xffff (random))
(logand ?\xffff (random))
(logand ?\xffff (random))
(logand ?\xffff (random))))
(defun zenirc-ctcp-query-SECURE1 (proc parsedctcp from to)
(if (zenirc-names-equal-p to zenirc-nick)
(let ((half-key (read (cdr parsedctcp)))
(nick (zenirc-extract-nick from))
(other-half (zenirc-secure-make-half-key)))
(process-send-string proc
(concat "PRIVMSG "
nick
" :\C-a"
"SECURE2 "
(format "%s" other-half)
"\C-a\n"))
(setq zenirc-secure-keys
(cons (cons nick
(zenirc-secure-combine-keys half-key
other-half))
zenirc-secure-keys))
(zenirc-message proc 'secure-established nick))))
(defun zenirc-ctcp-query-SECURE2 (proc parsedctcp from to)
(if (zenirc-names-equal-p to zenirc-nick)
(let* ((half-key (read (cdr parsedctcp)))
(nick (zenirc-extract-nick from))
(pending (assoc nick zenirc-secure-pending)))
(if (not pending)
(zenirc-message proc 'secure-not-pending nick)
(progn
(setq zenirc-secure-pending
(delq pending zenirc-secure-pending))
(setq zenirc-secure-keys
(cons (cons nick
(zenirc-secure-combine-keys half-key
(cdr pending)))
zenirc-secure-keys))
(zenirc-message proc 'secure-established nick))))))
(defun zenirc-secure-combine-keys (key1 key2)
(let ((combined (copy-sequence key1))
(idx 0)
(len (length key1)))
(while (< idx len)
(aset combined idx (logxor (aref key1 idx)
(aref key2 idx)))
(setq idx (1+ idx)))
(let ((subkeys (idea-encrypt-subkeys combined)))
(cons subkeys (idea-decrypt-subkeys subkeys)))))
(defun zenirc-secure-encrypt (proc parsedcmd)
(let* ((pair (zenirc-parse-firstword (cdr parsedcmd)))
(nick (car pair))
(subkeys (cadr (assoc nick zenirc-secure-keys)))
(encrypted (and subkeys
(zenirc-idea-encrypt subkeys (cdr pair)))))
(if encrypted
(progn
(process-send-string proc
(concat "PRIVMSG "
nick
" :\C-a"
"ENCRYPTED "
encrypted
"\C-a\n"))
(zenirc-message proc 'secure-sent nick))
(zenirc-message proc 'secure-no-channel nick))))
(defun zenirc-ctcp-query-ENCRYPTED (proc parsedctcp from to)
(if (zenirc-names-equal-p to zenirc-nick)
(let* ((nick (zenirc-extract-nick from))
(subkeys (cddr (assoc nick zenirc-secure-keys)))
(decrypted (and subkeys
(zenirc-idea-decrypt subkeys (cdr parsedctcp)))))
(if (not decrypted)
(zenirc-message proc 'secure-bogus-message nick)
(zenirc-message proc 'secure-message
nick
decrypted)))))
(defun zenirc-idea-encrypt (subkeys message)
;; seed the message with a random block and the length
(let* ((len (length message))
(temp (list len
(logand ?\xffff (random))
(logand ?\xffff (random))
(logand ?\xffff (random))))
(store nil)
(idx 0)
(num-blocks 0)
;; pad to a multiple of 4 blocks, 2 chars per block
(total-blocks (* 4 (/ (+ (/ len 2) 3) 4))))
(while (< num-blocks total-blocks)
(let ((this-char (if (< idx len)
(aref message idx)
0)))
(if store
(progn
(setq temp (cons (+ store this-char)
temp))
(setq num-blocks (1+ num-blocks))
(setq store nil))
(setq store (ash this-char 8)))
(setq idx (1+ idx))))
(let* ((vec (apply #'vector (nreverse temp))))
(zenirc-secure-idea-run vec subkeys 'forward)
;; output as an elisp readable vector
(format "%s" vec))))
(defun zenirc-secure-idea-run (vec subkeys direction)
(let ((len (length vec))
(idx 0)
feedback)
(while (< idx len)
(let* ((t1 (vector (aref vec (+ 0 idx))
(aref vec (+ 1 idx))
(aref vec (+ 2 idx))
(aref vec (+ 3 idx))))
(t2 (idea-cipher-block t1 subkeys)))
(let ((i 0))
(while (< i 4)
;; feedback is nil the first time through, even
;; when running backward.
(aset vec (+ i idx) (if feedback
(logxor (aref t2 i)
(aref feedback i))
(aref t2 i)))
(setq i (1+ i))))
(setq idx (+ idx 4))
(if (eq direction 'backward)
;; store off ciphertext for later undoing of feedback
(setq feedback t1)
;; feedback in forward direction:
;; cipher(n+1) = cipher(cipher(n) xor plain(n+1))
(if (< idx len)
(let ((i 0))
(while (< i 4)
(aset vec (+ i idx) (logxor (aref vec (+ i idx))
(aref vec (+ i idx -4))))
(setq i (1+ i))))))))))
(defun zenirc-idea-decrypt (subkeys message)
(let ((vec (read message)))
(zenirc-secure-idea-run vec subkeys 'backward)
(let ((len (aref vec 3)))
(substring (mapconcat #'(lambda (x)
(concat (char-to-string (ash x -8))
(char-to-string (logand ?\xff x))))
vec
"")
8 (+ len 8)))))
(provide 'zenirc-secure)
(zenirc-secure-install-message-catalogs)