Gnus development mailing list
 help / color / mirror / Atom feed
* EasyPG support for mml2015.el
@ 2006-07-10  3:54 Daiki Ueno
  2006-07-10  9:04 ` Daiki Ueno
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Daiki Ueno @ 2006-07-10  3:54 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 360 bytes --]

Hi,

2 weeks ago, we had CodeFest Akihabara 2006 (a 24-hour hacking marathon
in Japan).  There I wrote a patch which allows to use EasyPG directly
from Gnus.

Can you install this patch into Gnus?  Though it has not yet been tested
thoroughly, it should not break existing mml2015.el feature.

To use: just set (setq mml2015-use 'epg)

Regards,
-- 
Daiki Ueno

[-- Attachment #2: mml2015.el.diff --]
[-- Type: application/octet-stream, Size: 12411 bytes --]

Index: lisp/mml2015.el
===================================================================
RCS file: /usr/local/cvsroot/gnus/lisp/mml2015.el,v
retrieving revision 7.15
diff -u -r7.15 mml2015.el
--- lisp/mml2015.el	28 Apr 2006 05:17:40 -0000	7.15
+++ lisp/mml2015.el	10 Jul 2006 03:53:59 -0000
@@ -34,6 +34,7 @@
 (require 'mm-decode)
 (require 'mm-util)
 (require 'mml)
+(require 'password)
 
 (defvar mc-pgp-always-sign)
 
@@ -79,7 +80,13 @@
        mml2015-pgg-verify
        mml2015-pgg-decrypt
        mml2015-pgg-clear-verify
-       mml2015-pgg-clear-decrypt))
+       mml2015-pgg-clear-decrypt)
+  (epg mml2015-epg-sign
+       mml2015-epg-encrypt
+       mml2015-epg-verify
+       mml2015-epg-decrypt
+       mml2015-epg-clear-verify
+       mml2015-epg-clear-decrypt))
   "Alist of PGP/MIME functions.")
 
 (defvar mml2015-result-buffer nil)
@@ -96,6 +103,23 @@
   :type '(repeat (cons (regexp :tag "GnuPG output regexp")
 		       (boolean :tag "Trust key"))))
 
+(defcustom mml2015-verbose nil
+  "If non-nil, ask the user about the current operation more verbosely."
+  :group 'mime-security
+  :type 'boolean)
+
+(defcustom mml2015-cache-passphrase t
+  "If t, cache passphrase."
+  :group 'mime-security
+  :type 'boolean)
+
+(defcustom mml2015-passphrase-cache-expiry 16
+  "How many seconds the passphrase is cached.
+Whether the passphrase is cached at all is controlled by
+`mml2015-cache-passphrase'."
+  :group 'mime-security
+  :type 'integer)
+
 ;;; mailcrypt wrapper
 
 (eval-and-compile
@@ -871,6 +895,295 @@
     (insert (format "--%s\n" boundary))
     (insert "Content-Type: application/octet-stream\n\n")
     (insert-buffer-substring pgg-output-buffer)
+    (goto-char (point-max))
+    (insert (format "--%s--\n" boundary))
+    (goto-char (point-max))))
+
+;;; epg wrapper
+
+(eval-and-compile
+  (autoload 'epg-make-context "epg")
+  (autoload 'epa-select-keys "epa"))
+
+(eval-when-compile
+  (defvar epg-user-id-alist)
+  (defvar epg-digest-algorithm-alist)
+  (defvar inhibit-redisplay)
+  (autoload 'epg-context-set-armor "epg")
+  (autoload 'epg-context-set-textmode "epg")
+  (autoload 'epg-context-set-signers "epg")
+  (autoload 'epg-context-result-for "epg")
+  (autoload 'epg-new-signature-digest-algorithm "epg")
+  (autoload 'epg-verify-result-to-string "epg")
+  (autoload 'epg-list-keys "epg")
+  (autoload 'epg-decrypt-string "epg")
+  (autoload 'epg-verify-string "epg")
+  (autoload 'epg-sign-string "epg")
+  (autoload 'epg-encrypt-string "epg")
+  (autoload 'epg-passphrase-callback-function "epg")
+  (autoload 'epg-context-set-passphrase-callback "epg"))
+
+(defvar mml2015-epg-secret-key-id-list nil)
+
+(defun mml2015-epg-passphrase-callback (context key-id ignore)
+  (if (eq key-id 'SYM)
+      (epg-passphrase-callback-function context key-id nil)
+    (let* ((entry (assoc key-id epg-user-id-alist))
+	   (passphrase
+	    (password-read
+	     (format "GnuPG passphrase for %s: "
+		     (if entry
+			 (cdr entry)
+		       key-id))
+	     (if (eq key-id 'PIN)
+		 "PIN"
+	       key-id))))
+      (when passphrase
+	(let ((password-cache-expiry mml2015-passphrase-cache-expiry))
+	  (password-cache-add key-id passphrase))
+	(setq mml2015-epg-secret-key-id-list
+	      (cons key-id mml2015-epg-secret-key-id-list))
+	(copy-sequence passphrase)))))
+
+(defun mml2015-epg-decrypt (handle ctl)
+  (catch 'error
+    (let ((inhibit-redisplay t)
+	  context plain child handles result decrypt-status)
+      (unless (setq child (mm-find-part-by-type
+			   (cdr handle)
+			   "application/octet-stream" nil t))
+	(mm-set-handle-multipart-parameter
+	 mm-security-handle 'gnus-info "Corrupted")
+	(throw 'error handle))
+      (setq context (epg-make-context))
+      (epg-context-set-passphrase-callback
+       context
+       #'mml2015-epg-passphrase-callback)
+      (condition-case error
+	  (setq plain (epg-decrypt-string context (mm-get-part child))
+		mml2015-epg-secret-key-id-list nil)
+	(error
+	 (while mml2015-epg-secret-key-id-list
+	   (password-cache-remove (car mml2015-epg-secret-key-id-list))
+	   (setq mml2015-epg-secret-key-id-list
+		 (cdr mml2015-epg-secret-key-id-list)))
+	 (mm-set-handle-multipart-parameter
+	  mm-security-handle 'gnus-info "Failed")
+	 (if (eq (car error) 'quit)
+	     (mm-set-handle-multipart-parameter
+	      mm-security-handle 'gnus-details "Quit.")
+	   (mm-set-handle-multipart-parameter
+	    mm-security-handle 'gnus-details (mml2015-format-error error)))
+	 (throw 'error handle)))
+      (with-temp-buffer
+	(insert plain)
+	(goto-char (point-min))
+	(while (search-forward "\r\n" nil t)
+	  (replace-match "\n" t t))
+	(setq handles (mm-dissect-buffer t))
+	(mm-destroy-parts handle)
+	(if (epg-context-result-for context 'verify)
+	    (mm-set-handle-multipart-parameter
+	     mm-security-handle 'gnus-info
+	     (concat "OK\n"
+		     (epg-verify-result-to-string
+		      (epg-context-result-for context 'verify))))
+	  (mm-set-handle-multipart-parameter
+	   mm-security-handle 'gnus-info "OK"))
+	(if (stringp (car handles))
+	    (mm-set-handle-multipart-parameter
+	     mm-security-handle 'gnus-details
+	     (mm-handle-multipart-ctl-parameter handles 'gnus-details))))
+	(if (listp (car handles))
+	    handles
+	  (list handles)))))
+
+(defun mml2015-epg-clear-decrypt ()
+  (let ((inhibit-redisplay t)
+	(context (epg-make-context))
+	plain)
+    (epg-context-set-passphrase-callback
+     context
+     #'mml2015-epg-passphrase-callback)
+    (condition-case error
+	(setq plain (epg-decrypt-string context (buffer-string))
+	      mml2015-epg-secret-key-id-list nil)
+      (error
+       (while mml2015-epg-secret-key-id-list
+	 (password-cache-remove (car mml2015-epg-secret-key-id-list))
+	 (setq mml2015-epg-secret-key-id-list
+	       (cdr mml2015-epg-secret-key-id-list)))
+       (mm-set-handle-multipart-parameter
+	mm-security-handle 'gnus-info "Failed")
+       (if (eq (car error) 'quit)
+	   (mm-set-handle-multipart-parameter
+	    mm-security-handle 'gnus-details "Quit.")
+	 (mm-set-handle-multipart-parameter
+	  mm-security-handle 'gnus-details (mml2015-format-error error)))))
+    (when plain
+      (erase-buffer)
+      ;; Treat data which epg returns as a unibyte string.
+      (mm-disable-multibyte)
+      (insert plain)
+      (goto-char (point-min))
+      (while (search-forward "\r\n" nil t)
+	(replace-match "\n" t t))
+      (if (epg-context-result-for context 'verify)
+	  (mm-set-handle-multipart-parameter
+	   mm-security-handle 'gnus-info
+	   (concat "OK\n"
+		   (epg-verify-result-to-string
+		    (epg-context-result-for context 'verify))))
+	(mm-set-handle-multipart-parameter
+	 mm-security-handle 'gnus-info "OK")))))
+
+(defun mml2015-epg-verify (handle ctl)
+  (catch 'error
+    (let ((inhibit-redisplay t)
+	  context plain signature-file part signature)
+      (when (or (null (setq part (mm-find-raw-part-by-type
+				  ctl (or (mm-handle-multipart-ctl-parameter
+					   ctl 'protocol)
+					  "application/pgp-signature")
+				  t)))
+		(null (setq signature (mm-find-part-by-type
+				       (cdr handle) "application/pgp-signature"
+				       nil t))))
+	(mm-set-handle-multipart-parameter
+	 mm-security-handle 'gnus-info "Corrupted")
+	(throw 'error handle))
+      (setq context (epg-make-context))
+      (condition-case error
+	  (setq plain (epg-verify-string context (mm-get-part signature) part))
+	(error
+	 (mm-set-handle-multipart-parameter
+	  mm-security-handle 'gnus-info "Failed")
+	 (if (eq (car error) 'quit)
+	     (mm-set-handle-multipart-parameter
+	      mm-security-handle 'gnus-details "Quit.")
+	   (mm-set-handle-multipart-parameter
+	    mm-security-handle 'gnus-details (mml2015-format-error error)))
+	 (throw 'error handle)))
+      (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info
+       (epg-verify-result-to-string (epg-context-result-for context 'verify)))
+      handle)))
+
+(defun mml2015-epg-clear-verify ()
+  (let ((inhibit-redisplay t)
+	(context (epg-make-context))
+	(signature (encode-coding-string (buffer-string)
+					 buffer-file-coding-system))
+	plain)
+    (condition-case error
+	(setq plain (epg-verify-string context signature))
+      (error
+       (mm-set-handle-multipart-parameter
+	mm-security-handle 'gnus-info "Failed")
+       (if (eq (car error) 'quit)
+	   (mm-set-handle-multipart-parameter
+	    mm-security-handle 'gnus-details "Quit.")
+	 (mm-set-handle-multipart-parameter
+	  mm-security-handle 'gnus-details (mml2015-format-error error)))))
+    (if plain
+	(mm-set-handle-multipart-parameter
+	 mm-security-handle 'gnus-info
+	 (epg-verify-result-to-string
+	  (epg-context-result-for context 'verify))))))
+
+(defun mml2015-epg-sign (cont)
+  (let ((inhibit-redisplay t)
+	(context (epg-make-context))
+	(boundary (mml-compute-boundary cont))
+	signers	signature micalg)
+    (if mml2015-verbose
+	(setq signers (epa-select-keys context "Select keys for signing.
+If no one is selected, default secret key is used.  "
+				       nil t))
+      (setq signers (list (car (epg-list-keys
+				context
+				(message-options-get 'mml-sender) t)))))
+    (epg-context-set-armor context t)
+    (epg-context-set-textmode context t)
+    (epg-context-set-signers context signers)
+    (epg-context-set-passphrase-callback
+     context
+     #'mml2015-epg-passphrase-callback)
+    (condition-case error
+	(setq signature (epg-sign-string context (buffer-string) t)
+	      mml2015-epg-secret-key-id-list nil)
+      (error
+       (while mml2015-epg-secret-key-id-list
+	 (password-cache-remove (car mml2015-epg-secret-key-id-list))
+	 (setq mml2015-epg-secret-key-id-list
+	       (cdr mml2015-epg-secret-key-id-list)))
+       (signal (car error) (cdr error))))
+    (if (epg-context-result-for context 'sign)
+	(setq micalg (epg-new-signature-digest-algorithm
+		      (car (epg-context-result-for context 'sign)))))
+    (goto-char (point-min))
+    (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
+		    boundary))
+    (if micalg
+	(insert (format "\tmicalg=%s; "
+			(downcase
+			 (cdr (assq micalg
+				    epg-digest-algorithm-alist))))))
+    (insert "protocol=\"application/pgp-signature\"\n")
+    (insert (format "\n--%s\n" boundary))
+    (goto-char (point-max))
+    (insert (format "\n--%s\n" boundary))
+    (insert "Content-Type: application/pgp-signature\n\n")
+    (insert signature)
+    (goto-char (point-max))
+    (insert (format "--%s--\n" boundary))
+    (goto-char (point-max))))
+
+(defun mml2015-epg-encrypt (cont &optional sign)
+  (let ((inhibit-redisplay t)
+	(context (epg-make-context))
+	recipients cipher
+	(boundary (mml-compute-boundary cont)))
+    (if (or mml2015-verbose
+	    (null (message-options-get 'message-recipients)))
+	(setq recipients
+	      (epa-select-keys context "Select recipients for encryption.
+If no one is selected, symmetric encryption will be performed.  "
+			       (if (message-options-get 'message-recipients)
+				   (split-string
+				    (message-options-get 'message-recipients)
+				    "[ \f\t\n\r\v,]+"))))
+      (setq recipients
+	    (epg-list-keys context
+			   (split-string
+			    (message-options-get 'message-recipients)
+			    "[ \f\t\n\r\v,]+"))))
+    (epg-context-set-armor context t)
+    (epg-context-set-textmode context t)
+    (epg-context-set-passphrase-callback
+     context
+     #'mml2015-epg-passphrase-callback)
+    (condition-case error
+	(setq cipher
+	      (epg-encrypt-string context (buffer-string) recipients sign)
+	      mml2015-epg-secret-key-id-list nil)
+      (error
+       (while mml2015-epg-secret-key-id-list
+	 (password-cache-remove (car mml2015-epg-secret-key-id-list))
+	 (setq mml2015-epg-secret-key-id-list
+	       (cdr mml2015-epg-secret-key-id-list)))
+       (signal (car error) (cdr error))))
+    (delete-region (point-min) (point-max))
+    (goto-char (point-min))
+    (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
+		    boundary))
+    (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/pgp-encrypted\n\n")
+    (insert "Version: 1\n\n")
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/octet-stream\n\n")
+    (insert cipher)
     (goto-char (point-max))
     (insert (format "--%s--\n" boundary))
     (goto-char (point-max))))

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2006-07-25  5:23 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-07-10  3:54 EasyPG support for mml2015.el Daiki Ueno
2006-07-10  9:04 ` Daiki Ueno
2006-07-10 10:08   ` Simon Josefsson
2006-07-10 10:36     ` Daiki Ueno
2006-07-10 10:53       ` Simon Josefsson
2006-07-11  8:28         ` Daiki Ueno
2006-07-25  5:23           ` Daiki Ueno
2006-07-10 10:03 ` Simon Josefsson
2006-07-12  7:38 ` EasyPG hangs Max Froumentin
2006-07-12  8:16   ` Daiki Ueno
2006-07-12  9:16     ` Max Froumentin
2006-07-13  4:02       ` Daiki Ueno

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).