Subject: 23.2; smime feature requests

From: Arik Mitschang <[email-masked]>
Date: Mon, 11 Apr 2011 12:55:34 +1000

I have two feature requests for the smime package included in gnus
shipped with emacs. The first is trivial and simply adds the AES
encryption standard to that which is supported by emacs smime (openssl
supports these, if there are many versions which don't perhaps adding a
note the the doc string to check before changing would be appropriate in
addition to the change). This change is implemented in the first
attached patch.

The second is somewhat less trivial, some folks will have there RSA
private key not encrypted for whatever reason and it can be fairly
annoying to have to enter a password for such keys each time (and in
cases where it would not be appropriate to change the password cache
time, one would have to). Since I found no real easy way to determine if
a key is encrypted other than to open the file and check every time, I
added another bit to the smime-keys variable allowing the user to
specify if that key is clear or not, and added optional args to the
signing and decryption functions along with a helper function that will
determine if the key (by email) needs a password or not. This is
implemented in the second attached patch.

Thanks,
-Arik

--- smime.el
+++ smime.el
@@ -204,6 +204,9 @@
   :version "22.1"
   :type '(choice (const :tag "Triple DES" "-des3")
 		 (const :tag "DES"  "-des")
+		 (const :tag "AES 256 bits" "-aes256")
+		 (const :tag "AES 192 bits" "-aes192")
+		 (const :tag "AES 128 bits" "-aes128")
 		 (const :tag "RC2 40 bits" "-rc2-40")
 		 (const :tag "RC2 64 bits" "-rc2-64")
 		 (const :tag "RC2 128 bits" "-rc2-128"))

--- smime.el
+++ smime.el
@@ -152,9 +152,10 @@
 The file is assumed to be in PEM format. You can also associate additional
 certificates to be sent with every message to each address."
   :type '(repeat (list (string :tag "Mail address")
+			   (boolean :tag "Private key encrypted" :value t)
 		       (file :tag "File name")
 		       (repeat :tag "Additional certificate files"
-			       (file :tag "File name"))))
+					   (file :tag "File name"))))
   :group 'smime)
 
 (defcustom smime-CA-directory nil
@@ -292,7 +296,7 @@
 
 ;; Sign+encrypt region
 
-(defun smime-sign-region (b e keyfile)
+(defun smime-sign-region (b e keyfile &optional clearkey)
   "Sign region with certified key in KEYFILE.
 If signing fails, the buffer is not modified.  Region is assumed to
 have proper MIME tags.  KEYFILE is expected to contain a PEM encoded
@@ -304,7 +308,8 @@
   (let* ((certfiles (and (cdr-safe keyfile) (cadr keyfile)))
 	 (keyfile (or (car-safe keyfile) keyfile))
 	 (buffer (generate-new-buffer " *smime*"))
-	 (passphrase (smime-ask-passphrase (expand-file-name keyfile)))
+	 (passphrase (if clearkey nil
+				   (smime-ask-passphrase (expand-file-name keyfile))))
 	 (tmpfile (smime-make-temp-file "smime")))
     (if passphrase
 	(setenv "GNUS_SMIME_PASSPHRASE" passphrase))
@@ -332,7 +337,7 @@
 	(insert-buffer-substring buffer))
       (kill-buffer buffer))))
 
-(defun smime-encrypt-region (b e certfiles)
+(defun smime-encrypt-region (b e certfiles &optional clearkey)
   "Encrypt region for recipients specified in CERTFILES.
 If encryption fails, the buffer is not modified.  Region is assumed to
 have proper MIME tags.  CERTFILES is a list of filenames, each file
@@ -365,19 +370,24 @@
   "S/MIME sign BUFFER with key in KEYFILE.
 KEYFILE should contain a PEM encoded key and certificate."
   (interactive)
-  (with-current-buffer (or buffer (current-buffer))
-    (unless (smime-sign-region
-	     (point-min) (point-max)
-	     (if keyfile
-		 keyfile
-	       (smime-get-key-with-certs-by-email
-		(completing-read
-		 (concat "Sign using key"
-			 (if smime-keys
-			     (concat " (default " (caar smime-keys) "): ")
-			   ": "))
-		 smime-keys nil nil (car-safe (car-safe smime-keys))))))
-      (error "Signing failed"))))
+  (let (keycerts email)
+	(if keyfile
+		(setq keycerts keyfile)
+	  (setq email
+			(completing-read
+			 (concat "Sign using key"
+					 (if smime-keys
+						 (concat " (default " (caar smime-keys) "): ")
+					   ": "))
+			 smime-keys nil nil (car-safe (car-safe smime-keys))))
+	  (setq keycerts (smime-get-key-with-certs-by-email email)))
+	(with-current-buffer (or buffer (current-buffer))
+	  (unless (smime-sign-region
+			   (point-min) (point-max)
+			   keycerts
+			   (unless keyfile
+				 (smime-get-key-is-clear-by-email email)))
+      (error "Signing failed")))))
 
 (defun smime-encrypt-buffer (&optional certfiles buffer)
   "S/MIME encrypt BUFFER for recipients specified in CERTFILES.
@@ -431,14 +441,15 @@
 
 (defvar from)
 
-(defun smime-decrypt-region (b e keyfile)
+(defun smime-decrypt-region (b e keyfile &optional clearkey)
   "Decrypt S/MIME message in region between B and E with key in KEYFILE.
 On success, replaces region with decrypted data and return non-nil.
 Any details (stderr on success, stdout and stderr on error) are left
 in the buffer specified by `smime-details-buffer'."
   (smime-new-details-buffer)
   (let ((buffer (generate-new-buffer " *smime*"))
-	CAs (passphrase (smime-ask-passphrase (expand-file-name keyfile)))
+	CAs (passphrase (if clearkey nil
+					  (smime-ask-passphrase (expand-file-name keyfile))))
 	(tmpfile (smime-make-temp-file "smime")))
     (if passphrase
 	(setenv "GNUS_SMIME_PASSPHRASE" passphrase))
@@ -496,18 +507,24 @@
 Any details (stderr on success, stdout and stderr on error) are left
 in the buffer specified by `smime-details-buffer'."
   (interactive)
-  (with-current-buffer (or buffer (current-buffer))
-    (smime-decrypt-region
-     (point-min) (point-max)
-     (expand-file-name
-      (or keyfile
-	  (smime-get-key-by-email
-	   (completing-read
-	    (concat "Decipher using key"
-		    (if smime-keys (concat " (default " (caar smime-keys) "): ")
-		      ": "))
-	    smime-keys nil nil (car-safe (car-safe smime-keys)))))))))
-
+  (let (key email)
+	(if keyfile
+		(setq key keyfile)
+	  (setq email
+			(completing-read
+			 (concat "Decipher using key"
+					 (if smime-keys
+						 (concat " (default " (caar smime-keys) "): ")
+					   ": "))
+			 smime-keys nil nil (car-safe (car-safe smime-keys))))
+	  (setq key (smime-get-key-by-email email)))
+	(with-current-buffer (or buffer (current-buffer))
+	  (smime-decrypt-region
+	   (point-min) (point-max)
+	   key
+	   (unless keyfile
+		 (smime-get-key-is-clear-by-email email))))))
+	   
 ;; Various operations
 
 (defun smime-new-details-buffer ()
@@ -722,10 +739,13 @@
 ;; Other functions
 
 (defun smime-get-key-by-email (email)
-  (cadr (assoc email smime-keys)))
+  (nth 2 (assoc email smime-keys)))
 
 (defun smime-get-key-with-certs-by-email (email)
-  (cdr (assoc email smime-keys)))
+  (cddr (assoc email smime-keys)))
+
+(defun smime-get-key-is-clear-by-email (email)
+  (not (cadr (assoc email smime-keys))))
 
 (provide 'smime)