1 ;;; epa.el --- the EasyPG Assistant
2 ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;; Keywords: PGP, GnuPG
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
29 (eval-when-compile (require 'wid-edit
))
33 "The EasyPG Assistant"
37 (defcustom epa-popup-info-window t
38 "If non-nil, status information from epa commands is displayed on
43 (defcustom epa-info-window-height
5
44 "Number of lines used to display status information."
48 (defcustom epa-global-minor-modes
'(epa-global-dired-mode
51 "Globally defined minor modes to hook into other modes."
52 :type
'(repeat symbol
)
55 (defgroup epa-faces nil
60 (defface epa-validity-high
61 `((((class color
) (background dark
))
62 (:foreground
"PaleTurquoise"
63 ,@(if (assq ':weight custom-face-attributes
)
67 (,@(if (assq ':weight custom-face-attributes
)
70 "Face used for displaying the high validity."
73 (defface epa-validity-medium
74 `((((class color
) (background dark
))
75 (:foreground
"PaleTurquoise"
76 ,@(if (assq ':slant custom-face-attributes
)
80 (,@(if (assq ':slant custom-face-attributes
)
83 "Face used for displaying the medium validity."
86 (defface epa-validity-low
88 (,@(if (assq ':slant custom-face-attributes
)
91 "Face used for displaying the low validity."
94 (defface epa-validity-disabled
96 (,@(if (assq ':slant custom-face-attributes
)
100 "Face used for displaying the disabled validity."
104 '((((class color
) (background dark
))
105 (:foreground
"lightyellow"))
106 (((class color
) (background light
))
107 (:foreground
"blue4")))
108 "Face used for displaying the string."
112 `((((class color
) (background dark
))
113 (:foreground
"orange"
114 ,@(if (assq ':weight custom-face-attributes
)
117 (((class color
) (background light
))
119 ,@(if (assq ':weight custom-face-attributes
)
123 (,@(if (assq ':weight custom-face-attributes
)
126 "Face used for displaying the high validity."
129 (defface epa-field-name
130 `((((class color
) (background dark
))
131 (:foreground
"PaleTurquoise"
132 ,@(if (assq ':weight custom-face-attributes
)
136 (,@(if (assq ':weight custom-face-attributes
)
139 "Face for the name of the attribute field."
142 (defface epa-field-body
143 `((((class color
) (background dark
))
144 (:foreground
"turquoise"
145 ,@(if (assq ':slant custom-face-attributes
)
149 (,@(if (assq ':slant custom-face-attributes
)
152 "Face for the body of the attribute field."
155 (defcustom epa-validity-face-alist
156 '((unknown . epa-validity-disabled
)
157 (invalid . epa-validity-disabled
)
158 (disabled . epa-validity-disabled
)
159 (revoked . epa-validity-disabled
)
160 (expired . epa-validity-disabled
)
161 (none . epa-validity-low
)
162 (undefined . epa-validity-low
)
163 (never . epa-validity-low
)
164 (marginal . epa-validity-medium
)
165 (full . epa-validity-high
)
166 (ultimate . epa-validity-high
))
167 "An alist mapping validity values to faces."
168 :type
'(repeat (cons symbol face
))
171 (defvar epa-font-lock-keywords
174 ("^\t\\([^\t:]+:\\)[ \t]*\\(.*\\)$"
176 (2 'epa-field-body
)))
177 "Default expressions to addon in epa-mode.")
179 (defconst epa-pubkey-algorithm-letter-alist
187 (defvar epa-protocol
'OpenPGP
188 "*The default protocol.
189 The value can be either OpenPGP or CMS.
191 You should bind this variable with `let', but do not set it globally.")
193 (defvar epa-armor nil
194 "*If non-nil, epa commands create ASCII armored output.
196 You should bind this variable with `let', but do not set it globally.")
198 (defvar epa-textmode nil
199 "*If non-nil, epa commands treat input files as text.
201 You should bind this variable with `let', but do not set it globally.")
203 (defvar epa-keys-buffer nil
)
204 (defvar epa-key-buffer-alist nil
)
206 (defvar epa-list-keys-arguments nil
)
207 (defvar epa-info-buffer nil
)
208 (defvar epa-last-coding-system-specified nil
)
210 (defvar epa-key-list-mode-map
211 (let ((keymap (make-sparse-keymap)))
212 (define-key keymap
"m" 'epa-mark-key
)
213 (define-key keymap
"u" 'epa-unmark-key
)
214 (define-key keymap
"d" 'epa-decrypt-file
)
215 (define-key keymap
"v" 'epa-verify-file
)
216 (define-key keymap
"s" 'epa-sign-file
)
217 (define-key keymap
"e" 'epa-encrypt-file
)
218 (define-key keymap
"r" 'epa-delete-keys
)
219 (define-key keymap
"i" 'epa-import-keys
)
220 (define-key keymap
"o" 'epa-export-keys
)
221 (define-key keymap
"g" 'revert-buffer
)
222 (define-key keymap
"n" 'next-line
)
223 (define-key keymap
"p" 'previous-line
)
224 (define-key keymap
" " 'scroll-up
)
225 (define-key keymap
[delete] 'scroll-down)
226 (define-key keymap "q" 'epa-exit-buffer)
229 (defvar epa-key-mode-map
230 (let ((keymap (make-sparse-keymap)))
231 (define-key keymap "q" 'epa-exit-buffer)
234 (defvar epa-info-mode-map
235 (let ((keymap (make-sparse-keymap)))
236 (define-key keymap "q" 'delete-window)
239 (defvar epa-menu nil)
241 (defconst epa-menu-items
242 '("Encryption/Decryption"
244 ["File" epa-decrypt-file
245 :help "Decrypt a file"]
246 ["Region" epa-decrypt-region
247 :help "Decrypt the current region"])
249 ["File" epa-verify-file
250 :help "Verify digital signature of a file"]
251 ["Region" epa-verify-region
252 :help "Verify digital signature of the current region"])
254 ["File" epa-sign-file
255 :help "Create digital signature of a file"]
256 ["Region" epa-sign-region
257 :help "Create digital signature of the current region"])
259 ["File" epa-encrypt-file
260 :help "Encrypt a file"]
261 ["Region" epa-encrypt-region
262 :help "Encrypt the current region"])
264 ["Browse keyring" epa-list-keys
265 :help "Browse your public keyring"]
267 ["File" epa-import-keys
268 :help "Import public keys from a file"]
269 ["Region" epa-import-keys-region
270 :help "Import public keys from the current region"])
272 ["To a File" epa-export-keys
273 :help "Export public keys to a file"]
274 ["To a Buffer" epa-insert-keys
275 :help "Insert public keys after the current point"])))
277 (defvar epa-exit-buffer-function #'bury-buffer)
279 (define-widget 'epa-key 'push-button
280 "Button for representing a epg-key object."
282 :button-face-get 'epa--key-widget-button-face-get
283 :value-create 'epa--key-widget-value-create
284 :action 'epa--key-widget-action
285 :help-echo 'epa--key-widget-help-echo)
287 (defun epa--key-widget-action (widget &optional event)
288 (epa--show-key (widget-get widget :value)))
290 (defun epa--key-widget-value-create (widget)
291 (let* ((key (widget-get widget :value))
292 (primary-sub-key (car (epg-key-sub-key-list key)))
293 (primary-user-id (car (epg-key-user-id-list key))))
294 (insert (format "%c "
295 (if (epg-sub-key-validity primary-sub-key)
296 (car (rassq (epg-sub-key-validity primary-sub-key)
297 epg-key-validity-alist))
299 (epg-sub-key-id primary-sub-key)
302 (if (stringp (epg-user-id-string primary-user-id))
303 (epg-user-id-string primary-user-id)
304 (epg-decode-dn (epg-user-id-string primary-user-id)))
307 (defun epa--key-widget-button-face-get (widget)
308 (let ((validity (epg-sub-key-validity (car (epg-key-sub-key-list
309 (widget-get widget :value))))))
311 (cdr (assq validity epa-validity-face-alist))
314 (defun epa--key-widget-help-echo (widget)
316 (epg-sub-key-id (car (epg-key-sub-key-list
317 (widget-get widget :value))))))
320 (if (fboundp 'encode-coding-string)
321 (defalias 'epa--encode-coding-string 'encode-coding-string)
322 (defalias 'epa--encode-coding-string 'identity)))
325 (if (fboundp 'decode-coding-string)
326 (defalias 'epa--decode-coding-string 'decode-coding-string)
327 (defalias 'epa--decode-coding-string 'identity)))
329 (defun epa-key-list-mode ()
330 "Major mode for `epa-list-keys'."
331 (kill-all-local-variables)
332 (buffer-disable-undo)
333 (setq major-mode 'epa-key-list-mode
337 (use-local-map epa-key-list-mode-map)
338 (make-local-variable 'font-lock-defaults)
339 (setq font-lock-defaults '(epa-font-lock-keywords t))
340 ;; In XEmacs, auto-initialization of font-lock is not effective
341 ;; if buffer-file-name is not set.
342 (font-lock-set-defaults)
343 (make-local-variable 'epa-exit-buffer-function)
344 (make-local-variable 'revert-buffer-function)
345 (setq revert-buffer-function 'epa--key-list-revert-buffer)
346 (run-hooks 'epa-key-list-mode-hook))
348 (defun epa-key-mode ()
349 "Major mode for a key description."
350 (kill-all-local-variables)
351 (buffer-disable-undo)
352 (setq major-mode 'epa-key-mode
356 (use-local-map epa-key-mode-map)
357 (make-local-variable 'font-lock-defaults)
358 (setq font-lock-defaults '(epa-font-lock-keywords t))
359 ;; In XEmacs, auto-initialization of font-lock is not effective
360 ;; if buffer-file-name is not set.
361 (font-lock-set-defaults)
362 (make-local-variable 'epa-exit-buffer-function)
363 (run-hooks 'epa-key-mode-hook))
365 (defun epa-info-mode ()
366 "Major mode for `epa-info-buffer'."
367 (kill-all-local-variables)
368 (buffer-disable-undo)
369 (setq major-mode 'epa-info-mode
373 (use-local-map epa-info-mode-map)
374 (run-hooks 'epa-info-mode-hook))
376 (defun epa-mark-key (&optional arg)
377 "Mark a key on the current line.
378 If ARG is non-nil, unmark the key."
380 (let ((inhibit-read-only t)
384 (unless (get-text-property (point) 'epa-key)
385 (error "No key on this line"))
386 (setq properties (text-properties-at (point)))
388 (insert (if arg " " "*"))
389 (set-text-properties (1- (point)) (point) properties)
392 (defun epa-unmark-key (&optional arg)
393 "Unmark a key on the current line.
394 If ARG is non-nil, mark the key."
396 (epa-mark-key (not arg)))
398 (defun epa-exit-buffer ()
399 "Exit the current buffer.
400 `epa-exit-buffer-function' is called if it is set."
402 (funcall epa-exit-buffer-function))
404 (defun epa--insert-keys (keys)
407 (narrow-to-region (point) (point))
412 (add-text-properties point (point)
413 (list 'epa-key (car keys)
418 (widget-create 'epa-key :value (car keys))
420 (setq keys (cdr keys))))
421 (add-text-properties (point-min) (point-max)
422 (list 'epa-list-keys t
428 (defun epa--list-keys (name secret)
429 (unless (and epa-keys-buffer
430 (buffer-live-p epa-keys-buffer))
431 (setq epa-keys-buffer (generate-new-buffer "*Keys*")))
432 (set-buffer epa-keys-buffer)
434 (let ((inhibit-read-only t)
437 (context (epg-make-context epa-protocol)))
438 (unless (get-text-property point 'epa-list-keys)
439 (setq point (next-single-property-change point 'epa-list-keys)))
442 (or (next-single-property-change point 'epa-list-keys)
445 (epa--insert-keys (epg-list-keys context name secret))
447 (set-keymap-parent (current-local-map) widget-keymap))
448 (make-local-variable 'epa-list-keys-arguments)
449 (setq epa-list-keys-arguments (list name secret))
450 (goto-char (point-min))
451 (pop-to-buffer (current-buffer)))
454 (defun epa-list-keys (&optional name)
455 "List all keys matched with NAME from the public keyring."
457 (if current-prefix-arg
458 (let ((name (read-string "Pattern: "
459 (if epa-list-keys-arguments
460 (car epa-list-keys-arguments)))))
461 (list (if (equal name "") nil name)))
463 (epa--list-keys name nil))
466 (defun epa-list-secret-keys (&optional name)
467 "List all keys matched with NAME from the private keyring."
469 (if current-prefix-arg
470 (let ((name (read-string "Pattern: "
471 (if epa-list-keys-arguments
472 (car epa-list-keys-arguments)))))
473 (list (if (equal name "") nil name)))
475 (epa--list-keys name t))
477 (defun epa--key-list-revert-buffer (&optional ignore-auto noconfirm)
478 (apply #'epa--list-keys epa-list-keys-arguments))
480 (defun epa--marked-keys ()
482 (set-buffer epa-keys-buffer)
483 (goto-char (point-min))
485 (while (re-search-forward "^\\*" nil t)
486 (if (setq key (get-text-property (match-beginning 0)
488 (setq keys (cons key keys))))
492 (let ((key (get-text-property (point) 'epa-key)))
496 (defun epa--select-keys (prompt keys)
498 (unless (and epa-keys-buffer
499 (buffer-live-p epa-keys-buffer))
500 (setq epa-keys-buffer (generate-new-buffer "*Keys*")))
501 (set-buffer epa-keys-buffer)
503 (let ((inhibit-read-only t)
507 (substitute-command-keys "\
508 - `\\[epa-mark-key]' to mark a key on the line
509 - `\\[epa-unmark-key]' to unmark a key on the line\n"))
511 :notify (lambda (&rest ignore) (abort-recursive-edit))
513 (substitute-command-keys
514 "Click here or \\[abort-recursive-edit] to cancel")
517 :notify (lambda (&rest ignore) (exit-recursive-edit))
519 (substitute-command-keys
520 "Click here or \\[exit-recursive-edit] to finish")
523 (epa--insert-keys keys)
525 (set-keymap-parent (current-local-map) widget-keymap)
526 (setq epa-exit-buffer-function #'abort-recursive-edit)
527 (goto-char (point-min))
528 (pop-to-buffer (current-buffer)))
533 (if (get-buffer-window epa-keys-buffer)
534 (delete-window (get-buffer-window epa-keys-buffer)))
535 (kill-buffer epa-keys-buffer))))
538 (defun epa-select-keys (context prompt &optional names secret)
539 "Display a user's keyring and ask him to select keys.
540 CONTEXT is an epg-context.
541 PROMPT is a string to prompt with.
542 NAMES is a list of strings to be matched with keys. If it is nil, all
544 If SECRET is non-nil, list secret keys instead of public keys."
545 (let ((keys (epg-list-keys context names secret)))
546 (if (> (length keys) 1)
547 (epa--select-keys prompt keys)
550 (defun epa--show-key (key)
551 (let* ((primary-sub-key (car (epg-key-sub-key-list key)))
552 (entry (assoc (epg-sub-key-id primary-sub-key)
553 epa-key-buffer-alist))
554 (inhibit-read-only t)
558 (setq entry (cons (epg-sub-key-id primary-sub-key) nil)
559 epa-key-buffer-alist (cons entry epa-key-buffer-alist)))
560 (unless (and (cdr entry)
561 (buffer-live-p (cdr entry)))
562 (setcdr entry (generate-new-buffer
563 (format "*Key*%s" (epg-sub-key-id primary-sub-key)))))
564 (set-buffer (cdr entry))
566 (make-local-variable 'epa-key)
569 (setq pointer (epg-key-user-id-list key))
573 (if (epg-user-id-validity (car pointer))
575 (car (rassq (epg-user-id-validity (car pointer))
576 epg-key-validity-alist)))
579 (if (stringp (epg-user-id-string (car pointer)))
580 (epg-user-id-string (car pointer))
581 (epg-decode-dn (epg-user-id-string (car pointer))))
583 (setq pointer (cdr pointer)))
584 (setq pointer (epg-key-sub-key-list key))
587 (if (epg-sub-key-validity (car pointer))
589 (car (rassq (epg-sub-key-validity (car pointer))
590 epg-key-validity-alist)))
593 (epg-sub-key-id (car pointer))
596 (epg-sub-key-length (car pointer)))
598 (cdr (assq (epg-sub-key-algorithm (car pointer))
599 epg-pubkey-algorithm-alist))
602 (format-time-string "%Y-%m-%d"
603 (epg-sub-key-creation-time (car pointer)))
604 (error "????-??-??"))
605 (if (epg-sub-key-expiration-time (car pointer))
606 (format "\n\tExpires: %s"
608 (format-time-string "%Y-%m-%d"
609 (epg-sub-key-expiration-time
611 (error "????-??-??")))
614 (mapconcat #'symbol-name
615 (epg-sub-key-capability (car pointer))
618 (epg-sub-key-fingerprint (car pointer))
620 (setq pointer (cdr pointer)))
621 (goto-char (point-min))
622 (pop-to-buffer (current-buffer))))
624 (defun epa-display-info (info)
625 (if epa-popup-info-window
626 (save-selected-window
627 (unless (and epa-info-buffer (buffer-live-p epa-info-buffer))
628 (setq epa-info-buffer (generate-new-buffer "*Info*")))
629 (if (get-buffer-window epa-info-buffer)
630 (delete-window (get-buffer-window epa-info-buffer)))
632 (set-buffer epa-info-buffer)
633 (let ((inhibit-read-only t)
638 (goto-char (point-min)))
639 (if (> (window-height)
640 epa-info-window-height)
641 (set-window-buffer (split-window nil (- (window-height)
642 epa-info-window-height))
644 (pop-to-buffer epa-info-buffer)
645 (if (> (window-height) epa-info-window-height)
646 (shrink-window (- (window-height) epa-info-window-height)))))
647 (message "%s" info)))
649 (defun epa-display-verify-result (verify-result)
650 (epa-display-info (epg-verify-result-to-string verify-result)))
651 (make-obsolete 'epa-display-verify-result 'epa-display-info)
653 (defun epa-passphrase-callback-function (context key-id handback)
655 (read-passwd "Passphrase for symmetric encryption: "
656 (eq (epg-context-operation context) 'encrypt))
659 "Passphrase for PIN: "
660 (let ((entry (assoc key-id epg-user-id-alist)))
662 (format "Passphrase for %s %s: " key-id (cdr entry))
663 (format "Passphrase for %s: " key-id)))))))
665 (defun epa-progress-callback-function (context what char current total
667 (message "%s%d%% (%d/%d)" (or handback
669 (if (> total 0) (floor (* (/ current (float total)) 100)) 0)
673 (defun epa-decrypt-file (file)
675 (interactive "fFile: ")
676 (setq file (expand-file-name file))
677 (let* ((default-name (file-name-sans-extension file))
678 (plain (expand-file-name
680 (concat "To file (default "
681 (file-name-nondirectory default-name)
683 (file-name-directory default-name)
685 (context (epg-make-context epa-protocol)))
686 (epg-context-set-passphrase-callback context
687 #'epa-passphrase-callback-function)
688 (epg-context-set-progress-callback context
690 #'epa-progress-callback-function
691 (format "Decrypting %s..."
692 (file-name-nondirectory file))))
693 (message "Decrypting %s..." (file-name-nondirectory file))
694 (epg-decrypt-file context file plain)
695 (message "Decrypting %s...wrote %s" (file-name-nondirectory file)
696 (file-name-nondirectory plain))
697 (if (epg-context-result-for context 'verify)
698 (epa-display-info (epg-verify-result-to-string
699 (epg-context-result-for context 'verify))))))
702 (defun epa-verify-file (file)
704 (interactive "fFile: ")
705 (setq file (expand-file-name file))
706 (let* ((context (epg-make-context epa-protocol))
707 (plain (if (equal (file-name-extension file) "sig")
708 (file-name-sans-extension file))))
709 (epg-context-set-progress-callback context
711 #'epa-progress-callback-function
712 (format "Verifying %s..."
713 (file-name-nondirectory file))))
714 (message "Verifying %s..." (file-name-nondirectory file))
715 (epg-verify-file context file plain)
716 (message "Verifying %s...done" (file-name-nondirectory file))
717 (if (epg-context-result-for context 'verify)
718 (epa-display-info (epg-verify-result-to-string
719 (epg-context-result-for context 'verify))))))
721 (defun epa--read-signature-type ()
724 (message "Signature type (n,c,d,?) ")
729 (setq type 'detached))
731 (with-output-to-temp-buffer "*Help*"
733 (set-buffer standard-output)
735 n - Create a normal signature
736 c - Create a cleartext signature
737 d - Create a detached signature
741 (setq type 'normal))))))
744 (defun epa-sign-file (file signers mode)
745 "Sign FILE by SIGNERS keys selected."
747 (let ((verbose current-prefix-arg))
748 (list (expand-file-name (read-file-name "File: "))
750 (epa-select-keys (epg-make-context epa-protocol)
751 "Select keys for signing.
752 If no one is selected, default secret key is used. "
755 (epa--read-signature-type)
757 (let ((signature (concat file
758 (if (eq epa-protocol 'OpenPGP)
761 '(nil t normal detached))))
763 (if (memq mode '(t detached))
766 (if (memq mode '(t detached))
769 (context (epg-make-context epa-protocol)))
770 (epg-context-set-armor context epa-armor)
771 (epg-context-set-textmode context epa-textmode)
772 (epg-context-set-signers context signers)
773 (epg-context-set-passphrase-callback context
774 #'epa-passphrase-callback-function)
775 (epg-context-set-progress-callback context
777 #'epa-progress-callback-function
778 (format "Signing %s..."
779 (file-name-nondirectory file))))
780 (message "Signing %s..." (file-name-nondirectory file))
781 (epg-sign-file context file signature mode)
782 (message "Signing %s...wrote %s" (file-name-nondirectory file)
783 (file-name-nondirectory signature))))
786 (defun epa-encrypt-file (file recipients)
787 "Encrypt FILE for RECIPIENTS."
789 (list (expand-file-name (read-file-name "File: "))
790 (epa-select-keys (epg-make-context epa-protocol)
791 "Select recipients for encryption.
792 If no one is selected, symmetric encryption will be performed. ")))
793 (let ((cipher (concat file (if (eq epa-protocol 'OpenPGP)
794 (if epa-armor ".asc" ".gpg")
796 (context (epg-make-context epa-protocol)))
797 (epg-context-set-armor context epa-armor)
798 (epg-context-set-textmode context epa-textmode)
799 (epg-context-set-passphrase-callback context
800 #'epa-passphrase-callback-function)
801 (epg-context-set-progress-callback context
803 #'epa-progress-callback-function
804 (format "Encrypting %s..."
805 (file-name-nondirectory file))))
806 (message "Encrypting %s..." (file-name-nondirectory file))
807 (epg-encrypt-file context file recipients cipher)
808 (message "Encrypting %s...wrote %s" (file-name-nondirectory file)
809 (file-name-nondirectory cipher))))
812 (defun epa-decrypt-region (start end)
813 "Decrypt the current region between START and END.
815 Don't use this command in Lisp programs!"
818 (let ((context (epg-make-context epa-protocol))
820 (epg-context-set-passphrase-callback context
821 #'epa-passphrase-callback-function)
822 (epg-context-set-progress-callback context
824 #'epa-progress-callback-function
826 (message "Decrypting...")
827 (setq plain (epg-decrypt-string context (buffer-substring start end)))
828 (message "Decrypting...done")
829 (setq plain (epa--decode-coding-string
831 (or coding-system-for-read
832 (get-text-property start 'epa-coding-system-used))))
833 (if (y-or-n-p "Replace the original text? ")
834 (let ((inhibit-read-only t)
836 (delete-region start end)
839 (with-output-to-temp-buffer "*Temp*"
840 (set-buffer standard-output)
843 (if (epg-context-result-for context 'verify)
844 (epa-display-info (epg-verify-result-to-string
845 (epg-context-result-for context 'verify)))))))
847 (defun epa--find-coding-system-for-mime-charset (mime-charset)
848 (if (featurep 'xemacs)
849 (if (fboundp 'find-coding-system)
850 (find-coding-system mime-charset))
851 (let ((pointer (coding-system-list)))
853 (eq (coding-system-get (car pointer) 'mime-charset)
855 (setq pointer (cdr pointer)))
859 (defun epa-decrypt-armor-in-region (start end)
860 "Decrypt OpenPGP armors in the current region between START and END.
862 Don't use this command in Lisp programs!"
866 (narrow-to-region start end)
868 (let (armor-start armor-end)
869 (while (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t)
870 (setq armor-start (match-beginning 0)
871 armor-end (re-search-forward "^-----END PGP MESSAGE-----$"
874 (error "No armor tail"))
875 (goto-char armor-start)
876 (let ((coding-system-for-read
877 (or coding-system-for-read
878 (if (re-search-forward "^Charset: \\(.*\\)" armor-end t)
879 (epa--find-coding-system-for-mime-charset
880 (intern (downcase (match-string 1))))))))
881 (goto-char armor-end)
882 (epa-decrypt-region armor-start armor-end)))))))
885 (defun epa-verify-region (start end)
886 "Verify the current region between START and END.
888 Don't use this command in Lisp programs!"
890 (let ((context (epg-make-context epa-protocol))
892 (epg-context-set-progress-callback context
894 #'epa-progress-callback-function
896 (message "Verifying...")
897 (setq plain (epg-verify-string
899 (epa--encode-coding-string
900 (buffer-substring start end)
901 (or coding-system-for-write
902 (get-text-property start 'epa-coding-system-used)))))
903 (message "Verifying...done")
904 (setq plain (epa--decode-coding-string
906 (or coding-system-for-read
907 (get-text-property start 'epa-coding-system-used))))
908 (if (y-or-n-p "Replace the original text? ")
909 (let ((inhibit-read-only t)
911 (delete-region start end)
914 (with-output-to-temp-buffer "*Temp*"
915 (set-buffer standard-output)
918 (if (epg-context-result-for context 'verify)
919 (epa-display-info (epg-verify-result-to-string
920 (epg-context-result-for context 'verify))))))
923 (defun epa-verify-cleartext-in-region (start end)
924 "Verify OpenPGP cleartext signed messages in the current region
925 between START and END.
927 Don't use this command in Lisp programs!"
931 (narrow-to-region start end)
933 (let (cleartext-start cleartext-end)
934 (while (re-search-forward "-----BEGIN PGP SIGNED MESSAGE-----$"
936 (setq cleartext-start (match-beginning 0))
937 (unless (re-search-forward "^-----BEGIN PGP SIGNATURE-----$"
939 (error "Invalid cleartext signed message"))
940 (setq cleartext-end (re-search-forward
941 "^-----END PGP SIGNATURE-----$"
943 (unless cleartext-end
944 (error "No cleartext tail"))
945 (epa-verify-region cleartext-start cleartext-end))))))
948 (if (fboundp 'select-safe-coding-system)
949 (defalias 'epa--select-safe-coding-system 'select-safe-coding-system)
950 (defun epa--select-safe-coding-system (from to)
951 buffer-file-coding-system)))
954 (defun epa-sign-region (start end signers mode)
955 "Sign the current region between START and END by SIGNERS keys selected.
957 Don't use this command in Lisp programs!"
959 (let ((verbose current-prefix-arg))
960 (setq epa-last-coding-system-specified
961 (or coding-system-for-write
962 (epa--select-safe-coding-system
963 (region-beginning) (region-end))))
964 (list (region-beginning) (region-end)
966 (epa-select-keys (epg-make-context epa-protocol)
967 "Select keys for signing.
968 If no one is selected, default secret key is used. "
971 (epa--read-signature-type)
974 (let ((context (epg-make-context epa-protocol))
976 ;;(epg-context-set-armor context epa-armor)
977 (epg-context-set-armor context t)
978 ;;(epg-context-set-textmode context epa-textmode)
979 (epg-context-set-textmode context t)
980 (epg-context-set-signers context signers)
981 (epg-context-set-passphrase-callback context
982 #'epa-passphrase-callback-function)
983 (epg-context-set-progress-callback context
985 #'epa-progress-callback-function
987 (message "Signing...")
988 (setq signature (epg-sign-string context
989 (epa--encode-coding-string
990 (buffer-substring start end)
991 epa-last-coding-system-specified)
993 (message "Signing...done")
994 (delete-region start end)
996 (add-text-properties (point)
998 (insert (epa--decode-coding-string
1000 (or coding-system-for-read
1001 epa-last-coding-system-specified)))
1003 (list 'epa-coding-system-used
1004 epa-last-coding-system-specified
1011 (if (fboundp 'derived-mode-p)
1012 (defalias 'epa--derived-mode-p 'derived-mode-p)
1013 (defun epa--derived-mode-p (&rest modes)
1014 "Non-nil if the current major mode is derived from one of MODES.
1015 Uses the `derived-mode-parent' property of the symbol to trace backwards."
1016 (let ((parent major-mode))
1017 (while (and (not (memq parent modes))
1018 (setq parent (get parent 'derived-mode-parent))))
1022 (defun epa-encrypt-region (start end recipients sign signers)
1023 "Encrypt the current region between START and END for RECIPIENTS.
1025 Don't use this command in Lisp programs!"
1027 (let ((verbose current-prefix-arg)
1028 (context (epg-make-context epa-protocol))
1030 (setq epa-last-coding-system-specified
1031 (or coding-system-for-write
1032 (epa--select-safe-coding-system
1033 (region-beginning) (region-end))))
1034 (list (region-beginning) (region-end)
1035 (epa-select-keys context
1036 "Select recipients for encryption.
1037 If no one is selected, symmetric encryption will be performed. ")
1038 (setq sign (if verbose (y-or-n-p "Sign? ")))
1040 (epa-select-keys context
1041 "Select keys for signing. ")))))
1043 (let ((context (epg-make-context epa-protocol))
1045 ;;(epg-context-set-armor context epa-armor)
1046 (epg-context-set-armor context t)
1047 ;;(epg-context-set-textmode context epa-textmode)
1048 (epg-context-set-textmode context t)
1050 (epg-context-set-signers context signers))
1051 (epg-context-set-passphrase-callback context
1052 #'epa-passphrase-callback-function)
1053 (epg-context-set-progress-callback context
1055 #'epa-progress-callback-function
1057 (message "Encrypting...")
1058 (setq cipher (epg-encrypt-string context
1059 (epa--encode-coding-string
1060 (buffer-substring start end)
1061 epa-last-coding-system-specified)
1064 (message "Encrypting...done")
1065 (delete-region start end)
1067 (add-text-properties (point)
1071 (list 'epa-coding-system-used
1072 epa-last-coding-system-specified
1079 (defun epa-delete-keys (keys &optional allow-secret)
1080 "Delete selected KEYS.
1082 Don't use this command in Lisp programs!"
1084 (let ((keys (epa--marked-keys)))
1086 (error "No keys selected"))
1088 (eq (nth 1 epa-list-keys-arguments) t))))
1089 (let ((context (epg-make-context epa-protocol)))
1090 (message "Deleting...")
1091 (epg-delete-keys context keys allow-secret)
1092 (message "Deleting...done")
1093 (apply #'epa-list-keys epa-list-keys-arguments)))
1096 (defun epa-import-keys (file)
1097 "Import keys from FILE.
1099 Don't use this command in Lisp programs!"
1100 (interactive "fFile: ")
1101 (setq file (expand-file-name file))
1102 (let ((context (epg-make-context epa-protocol)))
1103 (message "Importing %s..." (file-name-nondirectory file))
1106 (epg-import-keys-from-file context file)
1107 (message "Importing %s...done" (file-name-nondirectory file)))
1109 (message "Importing %s...failed" (file-name-nondirectory file))))
1110 (if (epg-context-result-for context 'import)
1111 (epa-display-info (epg-import-result-to-string
1112 (epg-context-result-for context 'import))))
1113 (if (eq major-mode 'epa-key-list-mode)
1114 (apply #'epa-list-keys epa-list-keys-arguments))))
1117 (defun epa-import-keys-region (start end)
1118 "Import keys from the region.
1120 Don't use this command in Lisp programs!"
1122 (let ((context (epg-make-context epa-protocol)))
1123 (message "Importing...")
1126 (epg-import-keys-from-string context (buffer-substring start end))
1127 (message "Importing...done"))
1129 (message "Importing...failed")))
1130 (if (epg-context-result-for context 'import)
1131 (epa-display-info (epg-import-result-to-string
1132 (epg-context-result-for context 'import))))))
1135 (defun epa-import-armor-in-region (start end)
1136 "Import keys in the OpenPGP armor format in the current region
1137 between START and END.
1139 Don't use this command in Lisp programs!"
1143 (narrow-to-region start end)
1145 (let (armor-start armor-end)
1146 (while (re-search-forward
1147 "-----BEGIN \\(PGP \\(PUBLIC\\|PRIVATE\\) KEY BLOCK\\)-----$"
1149 (setq armor-start (match-beginning 0)
1150 armor-end (re-search-forward
1151 (concat "^-----END " (match-string 1) "-----$")
1154 (error "No armor tail"))
1155 (epa-import-keys-region armor-start armor-end))))))
1158 (defun epa-export-keys (keys file)
1159 "Export selected KEYS to FILE.
1161 Don't use this command in Lisp programs!"
1163 (let ((keys (epa--marked-keys))
1166 (error "No keys selected"))
1169 (concat (epg-sub-key-id (car (epg-key-sub-key-list (car keys))))
1170 (if epa-armor ".asc" ".gpg"))
1175 (concat "To file (default "
1176 (file-name-nondirectory default-name)
1178 (file-name-directory default-name)
1180 (let ((context (epg-make-context epa-protocol)))
1181 (epg-context-set-armor context epa-armor)
1182 (message "Exporting to %s..." (file-name-nondirectory file))
1183 (epg-export-keys-to-file context keys file)
1184 (message "Exporting to %s...done" (file-name-nondirectory file))))
1187 (defun epa-insert-keys (keys)
1188 "Insert selected KEYS after the point.
1190 Don't use this command in Lisp programs!"
1192 (list (epa-select-keys (epg-make-context epa-protocol)
1193 "Select keys to export. ")))
1194 (let ((context (epg-make-context epa-protocol)))
1195 ;;(epg-context-set-armor context epa-armor)
1196 (epg-context-set-armor context t)
1197 (insert (epg-export-keys-to-string context keys))))
1199 ;; (defun epa-sign-keys (keys &optional local)
1200 ;; "Sign selected KEYS.
1201 ;; If a prefix-arg is specified, the signature is marked as non exportable.
1203 ;; Don't use this command in Lisp programs!"
1205 ;; (let ((keys (epa--marked-keys)))
1207 ;; (error "No keys selected"))
1208 ;; (list keys current-prefix-arg)))
1209 ;; (let ((context (epg-make-context epa-protocol)))
1210 ;; (epg-context-set-passphrase-callback context
1211 ;; #'epa-passphrase-callback-function)
1212 ;; (epg-context-set-progress-callback context
1214 ;; #'epa-progress-callback-function
1215 ;; "Signing keys..."))
1216 ;; (message "Signing keys...")
1217 ;; (epg-sign-keys context keys local)
1218 ;; (message "Signing keys...done")))
1219 ;; (make-obsolete 'epa-sign-keys "Do not use.")
1222 (define-minor-mode epa-mode
1223 "Minor mode to hook EasyPG into various modes.
1224 See `epa-global-minor-modes'."
1225 :global t :init-value nil :group 'epa :version "23.1"
1227 (easy-menu-define epa-menu nil "EasyPG Assistant global menu"
1229 (easy-menu-remove-item nil '("Tools") "Encryption/Decryption")
1231 (easy-menu-add-item nil '("Tools") epa-menu))
1232 (let ((modes epa-global-minor-modes)
1235 (setq symbol (car modes))
1238 (funcall symbol epa-mode)
1239 (message "`%S' not found" (car modes)))
1240 (setq modes (cdr modes)))))
1244 ;; arch-tag: 38d20ced-20d5-4137-b17a-f206335423d7
1245 ;;; epa.el ends here