* semi-setup.el: Delete default setting of
[elisp/semi.git] / pgg.el
1 ;;; pgg.el --- glue for the various PGP implementations.
2
3 ;; Copyright (C) 1999 Daiki Ueno
4
5 ;; Author: Daiki Ueno <ueno@ueda.info.waseda.ac.jp>
6 ;; Created: 1999/10/28
7 ;; Keywords: PGP
8
9 ;; This file is part of SEMI (Secure Emacs MIME Interface).
10
11 ;; This program is free software; you can redistribute it and/or
12 ;; modify it under the terms of the GNU General Public License as
13 ;; published by the Free Software Foundation; either version 2, or (at
14 ;; your option) any later version.
15
16 ;; This program is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 ;; General Public License for more details.
20
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.
25
26 ;;; Code:
27
28 (require 'calist)
29
30 (eval-and-compile (require 'luna))
31
32 (require 'pgg-def)
33 (require 'pgg-parse)
34
35 (eval-when-compile
36   (ignore-errors 
37     (require 'w3)
38     (require 'url)))
39
40 (in-calist-package 'pgg)
41
42 (defun pgg-field-match-method-with-containment
43   (calist field-type field-value)
44   (let ((s-field (assq field-type calist)))
45     (cond ((null s-field)
46            (cons (cons field-type field-value) calist)
47            )
48           ((memq (cdr s-field) field-value)
49            calist))))
50
51 (define-calist-field-match-method 'signature-version
52   #'pgg-field-match-method-with-containment)
53
54 (define-calist-field-match-method 'cipher-algorithm
55   #'pgg-field-match-method-with-containment)
56
57 (define-calist-field-match-method 'public-key-algorithm
58   #'pgg-field-match-method-with-containment)
59
60 (define-calist-field-match-method 'hash-algorithm
61   #'pgg-field-match-method-with-containment)
62
63 (defvar pgg-verify-codition nil
64   "Condition-tree about how to display entity.")
65
66 (defvar pgg-decrypt-codition nil
67   "Condition-tree about how to display entity.")
68
69 (ctree-set-calist-strictly
70  'pgg-verify-codition
71  '((signature-version 3)(public-key-algorithm RSA)(hash-algorithm MD5)
72    (scheme . pgp)))
73
74 (ctree-set-calist-strictly
75  'pgg-decrypt-codition
76  '((public-key-algorithm RSA)(symmetric-key-algorithm IDEA)
77    (scheme . pgp)))
78
79 (ctree-set-calist-strictly
80  'pgg-verify-codition
81  '((signature-version 3 4)
82    (public-key-algorithm RSA ELG DSA)
83    (hash-algorithm MD5 SHA1 RIPEMD160)
84    (scheme . pgp5)))
85
86 (ctree-set-calist-strictly
87  'pgg-decrypt-codition
88  '((public-key-algorithm RSA ELG DSA)
89    (symmetric-key-algorithm 3DES CAST5 IDEA)
90    (scheme . pgp5)))
91
92 (ctree-set-calist-strictly
93  'pgg-verify-codition
94  '((signature-version 3 4)
95    (public-key-algorithm ELG-E DSA ELG)
96    (hash-algorithm MD5 SHA1 RIPEMD160)
97    (scheme . gpg)))
98
99 (ctree-set-calist-strictly
100  'pgg-decrypt-codition
101  '((public-key-algorithm ELG-E DSA ELG)
102    (symmetric-key-algorithm 3DES CAST5 BLOWFISH TWOFISH)
103    (scheme . gpg)))
104
105 ;;; @ definition of the implementation scheme
106 ;;;
107
108 (eval-and-compile
109   (luna-define-class pgg-scheme ())
110
111   (luna-define-internal-accessors 'pgg-scheme)
112   )
113
114 (luna-define-generic lookup-key-string (scheme string &optional type)
115   "Search keys associated with STRING")
116
117 (luna-define-generic encrypt-region (scheme start end recipients)
118   "Encrypt the current region between START and END.")
119
120 (luna-define-generic decrypt-region (scheme start end)
121   "Decrypt the current region between START and END.")
122
123 (luna-define-generic sign-region (scheme start end)
124   "Make detached signature from text between START and END.")
125
126 (luna-define-generic verify-region (scheme start end &optional signature)
127   "Verify region between START and END 
128 as the detached signature SIGNATURE.")
129
130 (luna-define-generic insert-key (scheme)
131   "Insert public key at point.")
132
133 (luna-define-generic snarf-keys-region (scheme start end)
134   "Add all public keys in region between START 
135 and END to the keyring.")
136
137 ;;; @ interface functions
138 ;;;
139
140 (defmacro pgg-make-scheme (scheme)
141   `(progn
142      (require (intern (format "pgg-%s" ,scheme)))
143      (funcall (intern (format "pgg-make-scheme-%s" 
144                               ,scheme)))))
145
146 (defun pgg-encrypt-region (start end rcpts)
147   (let ((entity (pgg-make-scheme pgg-default-scheme)))
148     (luna-send entity 'encrypt-region entity start end rcpts)))
149
150 (defun pgg-decrypt-region (start end)
151   (let* ((packets (pgg-parse-armor-region start end))
152          (scheme
153           (or pgg-scheme
154               (cdr (assq 'scheme
155                          (progn
156                            (in-calist-package 'pgg)
157                            (ctree-match-calist pgg-decrypt-codition
158                                                packets))))
159               pgg-default-scheme))
160          (entity (pgg-make-scheme scheme)))
161     (luna-send entity 'decrypt-region entity start end)))
162
163 (defun pgg-sign-region (start end)
164   (let ((entity (pgg-make-scheme pgg-default-scheme)))
165     (luna-send entity 'sign-region entity start end)))
166
167 (defun pgg-verify-region (start end &optional signature)
168   (let* ((packets 
169           (with-temp-buffer
170             (buffer-disable-undo)
171             (set-buffer-multibyte nil)
172             (insert-file-contents signature)
173             (pgg-decode-armor-region (point-min)(point-max))
174             ))
175          (scheme
176           (or pgg-scheme
177               (cdr (assq 'scheme
178                          (progn
179                            (in-calist-package 'pgg)
180                            (ctree-match-calist pgg-verify-codition
181                                                packets))))
182               pgg-default-scheme))
183          (entity (pgg-make-scheme scheme)))
184     (luna-send entity 'verify-region entity start end signature)))
185
186 (defun pgg-insert-key ()
187   (let ((entity (pgg-make-scheme (or pgg-scheme pgg-default-scheme))))
188     (luna-send entity 'insert-key entity)))
189
190 (defun pgg-snarf-keys-region (start end)
191   (let ((entity (pgg-make-scheme (or pgg-scheme pgg-default-scheme))))
192     (luna-send entity 'snarf-keys-region entity start end)))
193
194 (defun pgg-lookup-key-string (string &optional type)
195   (let ((entity (pgg-make-scheme (or pgg-scheme pgg-default-scheme))))
196     (luna-send entity 'lookup-key-string entity string type)))
197
198 (defun pgg-fetch-key (url)
199   (require 'w3)
200   (require 'url)
201   (with-current-buffer (get-buffer-create pgg-output-buffer)
202     (buffer-disable-undo)
203     (erase-buffer)
204     (let ((proto (url-type (url-generic-parse-url url)))
205           buffer-file-name)
206       (unless (memq (intern proto) '(http finger))
207         (insert (format "Protocol %s is not supported.\n" proto)))
208       (url-insert-file-contents url)
209       (if (re-search-forward "^-+BEGIN" nil 'last)
210           (progn
211             (delete-region (point-min) (match-beginning 0))
212             (when (re-search-forward "^-+END" nil t)
213               (delete-region (progn (end-of-line) (point))
214                              (point-max)))
215             (insert "\n")
216             (with-temp-buffer
217               (insert-buffer-substring pgg-output-buffer)
218               (pgg-snarf-keys-region (point-min)(point-max))))
219         (erase-buffer)
220         (insert "Cannot retrieve public key from URL (" url ")\n")))
221     ))
222
223
224 ;;; @ utility functions
225 ;;;
226
227 (defvar pgg-passphrase-cache-expiry 16)
228 (defvar pgg-passphrase-cache (make-vector 7 0))
229
230 (defvar pgg-read-passphrase nil)
231 (defun pgg-read-passphrase (prompt &optional key)
232   (if (not pgg-read-passphrase)
233       (if (functionp 'read-passwd)
234           (setq pgg-read-passphrase 'read-passwd)
235         (if (load "passwd" t)
236             (setq pgg-read-passphrase 'read-passwd)
237           (autoload 'ange-ftp-read-passwd "ange-ftp")
238           (setq pgg-read-passphrase 'ange-ftp-read-passwd))))
239   (or (and key (setq key (pgg-truncate-key-identifier key))
240            (symbol-value (intern-soft key pgg-passphrase-cache)))
241       (funcall pgg-read-passphrase prompt)))
242
243 (defun pgg-add-passphrase-cache (key passphrase)
244   (setq key (pgg-truncate-key-identifier key))
245   (set (intern key pgg-passphrase-cache)
246        passphrase)
247   (run-at-time pgg-passphrase-cache-expiry nil
248                #'pgg-remove-passphrase-cache
249                key))
250
251 (defun pgg-remove-passphrase-cache (key)
252   (unintern key pgg-passphrase-cache))
253
254 (provide 'pgg)
255
256 ;;; pgg.el ends here