1 ;;; liece-crypt.el --- Encryption/Decryption facility for conversation.
2 ;; Copyright (C) 1998-2000 Daiki Ueno
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
7 ;; Keywords: IRC, liece
9 ;; This file is part of Liece.
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
33 (require 'liece-inlines)
34 (require 'liece-misc))
36 (autoload 'crc32-string "crc32")
38 (defgroup liece-crypt nil
39 "Crypt customization group"
44 (defcustom liece-crypt-decryption-keys nil
45 "String list containing decryption keys. e.g. '(\"foo\" \"bar\")."
46 :type '(repeat (string :tag "Key"))
49 (defcustom liece-crypt-encryption-keys nil
50 "List containing pairs of addresses and associated default keys."
51 :type '(repeat (cons (string :tag "Channel")
55 (defcustom liece-crypt-timestamp-tolerance 300
56 "Allow incoming messages to have N seconds old timestamp."
60 (defcustom liece-crypt-default-cipher-algorithm 'idea
64 (defcustom liece-crypt-default-hash-function
65 (function liece-crypt-hash-crc32-string)
70 (defconst liece-crypt-encrypt-message-format "|*E*|%s|%s|%s|%s|")
72 (defvar liece-crypt-mode-active nil
73 "If t, liece encrypts all messages it has a default key for.")
75 (defun liece-crypt-encrypted-message-p (message)
76 (string-match "^|\\*E\\*|[^|]*|[0-9][0-9]*\\.[0-9][0-9]*|[^|]*|[^|]*|$"
79 (defun liece-crypt-hash-crc32-string (string)
80 (let ((r (make-string 9 0)) (s (make-string 9 0)))
82 (aset r 7 (logand (nth 0 string) 255))
83 (aset r 6 (logand (lsh (nth 0 string) -8) 255))
84 (aset r 5 (logand (nth 1 string) 255))
85 (aset r 4 (logand (lsh (nth 1 string) -8) 255))
86 (aset r 3 (logand (nth 2 string) 255))
87 (aset r 2 (logand (lsh (nth 2 string) -8) 255))
88 (aset r 1 (logand (nth 3 string) 255))
89 (aset r 0 (logand (lsh (nth 3 string) -8) 255))
91 (aset s 7 (logand (nth 4 string) 255))
92 (aset s 6 (logand (lsh (nth 4 string) -8) 255))
93 (aset s 5 (logand (nth 5 string) 255))
94 (aset s 4 (logand (lsh (nth 5 string) -8) 255))
95 (aset s 3 (logand (nth 6 string) 255))
96 (aset s 2 (logand (lsh (nth 6 string) -8) 255))
97 (aset s 1 (logand (nth 7 string) 255))
98 (aset s 0 (logand (lsh (nth 7 string) -8) 255))
99 (setq s (concat (crc32-string (concat r s)) s))
100 (setq r (concat (crc32-string (concat s r)) r))
101 (substring (crc32-string r) 0 6)
102 (substring (crc32-string s) 0 6)))
104 (defun liece-crypt-key-fingerprint (key &optional algorithm)
105 (let* ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
106 (func (intern (concat (symbol-name algorithm)
107 "-key-fingerprint"))))
109 (funcall (symbol-function func) key)
110 (funcall liece-crypt-default-hash-function key))))
112 (defun liece-crypt-algorithm-major-version (&optional algorithm)
113 (let ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
114 (major (intern (concat (symbol-name algorithm) "-major-version"))))
116 (symbol-value major))))
118 (defun liece-crypt-algorithm-minor-version (&optional algorithm)
119 (let ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
120 (minor (intern (concat (symbol-name algorithm) "-minor-version"))))
122 (symbol-value minor))))
124 (defun liece-crypt-build-decryption-key (key &optional algorithm)
125 (let* ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
126 (func (symbol-function
127 (intern (concat (symbol-name algorithm)
128 "-build-decryption-key")))))
131 (defun liece-crypt-build-encryption-key (key &optional algorithm)
132 (let* ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
133 (func (symbol-function
134 (intern (concat (symbol-name algorithm)
135 "-build-encryption-key")))))
138 (defun liece-crypt-decrypt-string (string key &optional algorithm mode)
139 (let* ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
140 (mode (or mode "cbc"))
141 (func (intern (format "%s-%s-decrypt-string"
142 (symbol-name algorithm)
145 (funcall (symbol-function func) string key)
146 (error (_ "Mode `%s' is not available.") (upcase mode)))))
148 (defun liece-crypt-encrypt-string (string key &optional algorithm mode)
149 (let* ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
150 (mode (or mode "cbc"))
151 (func (intern (format "%s-%s-encrypt-string"
152 (symbol-name algorithm)
155 (funcall (symbol-function func) string key)
156 (error (_ "Mode `%s' is not available.") (upcase mode)))))
158 (defun liece-crypt-valid-version-p (algorithm major-version minor-version)
160 (setq major (liece-crypt-algorithm-major-version algorithm)
161 minor (liece-crypt-algorithm-minor-version algorithm))
164 (and (= (symbol-value major) major-version)
165 (>= (symbol-value minor) minor-version)))
168 (defun liece-crypt-import-cipher-algorithm (algorithm &optional no-error)
169 (let ((algorithm (symbol-name algorithm)))
170 (or (eval `(featurep ',(intern algorithm)))
173 (error (_ "Unknown algorithm `%s'") (upcase algorithm))))))
175 (defun liece-crypt-initialize ()
176 "Initialize crypt variables."
177 (let ((keys (copy-sequence liece-crypt-decryption-keys)))
178 (setq liece-crypt-decryption-keys nil)
180 (liece-command-add-decryption-key key)))
181 (let ((keys (copy-sequence liece-crypt-encryption-keys)))
182 (setq liece-crypt-encryption-keys nil)
184 (liece-command-set-encryption-key (car key) (cdr key))))
185 (liece-crypt-reset-variables))
187 (defmacro liece-crypt-reset-variables ()
188 '(setq liece-message-encrypted-p nil
189 liece-message-suspicious-p nil
190 liece-message-garbled-p nil
191 liece-message-fingerprint nil
192 liece-message-timestamp nil))
196 (defun liece-set-crypt-indicator ()
197 "Set crypt mode indicator."
198 (setq liece-crypt-indicator
199 (cond ((and liece-crypt-mode-active
200 (eq liece-command-buffer-mode 'channel)
201 liece-current-channel
202 liece-crypt-encryption-keys
203 (string-assoc-ignore-case liece-current-channel
204 liece-crypt-encryption-keys))
206 ((and liece-crypt-mode-active
207 (eq liece-command-buffer-mode 'chat)
208 liece-current-chat-partner
209 liece-crypt-encryption-keys
210 (string-assoc-ignore-case liece-current-chat-partner
211 liece-crypt-encryption-keys))
213 (liece-crypt-mode-active "c")
217 (defun liece-command-add-decryption-key (key-var &optional algorithm)
218 "Add new KEY to known decryption keys list."
220 (let ((passwd-echo ?*))
221 (list (read-passwd "Add passphrase: "))))
222 (let ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
224 (liece-crypt-import-cipher-algorithm algorithm)
225 (setq key (if (stringp key-var)
226 (liece-crypt-build-decryption-key key-var)
228 fingerprint (liece-crypt-key-fingerprint key))
229 (set-alist 'liece-crypt-decryption-keys fingerprint key)
230 (when (interactive-p)
231 (liece-message (_ "Added new decryption key (%s).") fingerprint))))
234 (defun liece-command-delete-decryption-key (key-var &optional algorithm)
235 "Delete a KEY from known decryption keys list."
237 (let ((passwd-echo ?*))
238 (list (read-passwd (_ "Delete passphrase: ")))))
239 (let ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
241 (liece-crypt-import-cipher-algorithm algorithm)
242 (setq fingerprint (liece-crypt-key-fingerprint key-var))
243 (remove-alist 'liece-crypt-decryption-keys fingerprint)
244 (when (interactive-p)
245 (liece-message (_ "Removed decryption key (%s).") fingerprint))))
248 (defun liece-command-set-encryption-key
249 (addr-var pass-var &optional algorithm)
250 "Set a default key for ADDRESS (channel/nick) to be KEY."
253 (liece-minibuffer-completing-default-read
254 (_ "Default key for channel/user: ")
255 (append liece-nick-alist liece-channel-alist)
256 nil nil liece-privmsg-partner))
258 (let ((passwd-echo ?*))
259 (setq pass-var (read-passwd (_ "Passphrase: "))))
260 (when (string-equal pass-var "")
262 (list addr-var pass-var)))
263 (let ((algorithm (or algorithm liece-crypt-default-cipher-algorithm))
264 (addr-var (upcase addr-var)) ek dk fingerprint)
265 (liece-crypt-import-cipher-algorithm algorithm)
268 (remove-alist 'liece-crypt-encryption-keys addr-var)
269 (liece-message (_ "Removed a default key from \"%s\".")
272 (setq ek (liece-crypt-build-encryption-key pass-var)
273 dk (liece-crypt-build-decryption-key pass-var)
274 fingerprint (liece-crypt-key-fingerprint dk))
275 (liece-command-add-decryption-key dk)
276 (set-alist 'liece-crypt-encryption-keys
277 addr-var (list fingerprint ek dk))
278 (when (interactive-p)
279 (liece-message (_ "Added a default key for \"%s\".") addr-var))
280 (liece-set-crypt-indicator)))))
282 (defun liece-make-encrypted-message (message key &optional algorithm)
283 "Build an encrypted message from MESSAGE with KEY."
284 (let ((algorithm (or algorithm liece-crypt-default-cipher-algorithm)))
285 (format liece-crypt-encrypt-message-format
286 (upcase (symbol-name algorithm))
287 (let ((major (liece-crypt-algorithm-major-version algorithm))
288 (minor (liece-crypt-algorithm-minor-version algorithm)))
291 (format "%d.%d" major minor))
293 (liece-crypt-key-fingerprint key)
294 (liece-crypt-encrypt-string message key algorithm))))
296 (defun liece-encrypt-message (message address &optional no-clear-text)
297 "Encrypt MESSAGE to ADDRESS. NO-CLEAR-TEXT prohibits cleartext output."
302 (string-match (concat "^" (upcase item) "$") (upcase ,address)))
303 liece-crypt-encryption-keys)))
304 (message (liece-coding-encode-charset-string message)))
306 ((and no-clear-text (null key))
307 (error (_ "No default key associated with \"%s\".") address))
310 (liece-make-encrypted-message
311 (format "%s\001%s\001%s"
312 (liece-current-nickname)
313 (liece-generate-hex-timestamp)
317 (defmacro liece-crypt-decrypt-fail (&optional value)
318 `(throw 'failed ,value))
320 (defun liece-decrypt-message (message)
322 (if (string-match "^|\\*E\\*|\\([^|]*\\)|\\([0-9][0-9]*\\)\\.\\([0-9][0-9]*\\)|\\([^|]*\\)|\\([^|]*\\)|$" message)
323 (let ((algorithm (intern (downcase (substring message
326 (version-major (string-to-number (match-string 2 message)))
327 (version-minor (string-to-number (match-string 3 message)))
328 (fingerprint (match-string 4 message))
329 (msg (match-string 5 message))
332 (or (liece-crypt-import-cipher-algorithm algorithm 'no-error)
333 (liece-crypt-decrypt-fail
334 (list 'error nil nil (_ "Unknown algorithm")
336 (or (liece-crypt-valid-version-p
337 algorithm version-major version-minor)
338 (liece-crypt-decrypt-fail
339 (list 'error nil nil (_ "Unknown version")
341 (or (setq key (cdr (assoc fingerprint liece-crypt-decryption-keys)))
342 (liece-crypt-decrypt-fail
343 (list 'error nil nil (_ "No key")
345 (or (setq r (liece-crypt-decrypt-string msg key))
346 (liece-crypt-decrypt-fail
347 (list 'error nil nil (_ "Decryption failed")
349 (or (string-match "^\\([^\001][^\001]*\\)\001\\([^\001][^\001]*\\)\001\\(.*\\)$" r)
350 (liece-crypt-decrypt-fail
351 (list 'error nil nil (_ "Invalid cleartext format")
356 (liece-coding-decode-charset-string (match-string 3 r))
358 (list 'error nil nil (_ "Invalid message!") nil)))
360 (defun liece-crypt-maybe-decrypt-message (message sender)
361 (let (head tail clear stat nick time msg fprint warn)
362 (when (string-match "^\\([^ ]+\\) :\\(.*\\)" message)
363 (setq head (match-string 1 message)
364 tail (match-string 2 message))
365 (when (liece-crypt-encrypted-message-p tail)
366 (setq clear (liece-decrypt-message tail)
367 stat (nth 0 clear) ;; 'success or 'error
368 nick (nth 1 clear) ;; sender's nick
369 time (nth 2 clear) ;; timestamp
370 msg (nth 3 clear) ;; cleartext msg
371 fprint (nth 4 clear) ;; fingerprint
373 liece-message-encrypted-p t
374 liece-message-fingerprint fprint
375 liece-message-timestamp time)
376 ;; Check timestamp and nick here
378 ((equal 'success stat)
379 (setq liece-message-suspicious-p t)
380 (or (liece-hex-timestamp-valid
381 time liece-crypt-timestamp-tolerance)
382 (setq warn (concat warn " [Invalid timestamp!]")))
383 (or (liece-nick-equal nick sender)
385 "%s [Invalid sender \"%s\" != \"%s\"]"
388 (setq liece-message-garbled-p t)
389 (liece-insert liece-C-buffer
390 (format "<%s -> %s> %s [%s]\n"
391 sender head tail msg))))
392 (setq message (format "%s :%s%s" head msg warn))))
395 (defun liece-crypt-maybe-encrypt-message (message addr arg key)
396 "Encrypt MESSAGE when `liece-crypt-mode' is active."
397 (if (or (and arg addr) key)
398 (setq liece-message-encrypted-p t
399 message (liece-encrypt-message message addr t))
400 (setq liece-message-encrypted-p nil))
403 (defmacro with-liece-decryption (args &rest body)
404 `(let (liece-message-encrypted-p
405 liece-message-suspicious-p
406 liece-message-garbled-p
407 liece-message-fingerprint
408 liece-message-timestamp)
410 (funcall #'liece-crypt-maybe-decrypt-message ,@args))
413 (defmacro with-liece-encryption (args &rest body)
414 `(let (liece-message-encrypted-p
415 liece-message-suspicious-p
416 liece-message-garbled-p
417 liece-message-fingerprint
418 liece-message-timestamp)
420 (funcall #'liece-crypt-maybe-encrypt-message ,@args))
423 (put 'with-liece-decryption 'lisp-indent-function 1)
424 (put 'with-liece-encryption 'lisp-indent-function 1)
426 (provide 'liece-crypt)
428 ;;; liece-crypt.el ends here