# HG changeset patch # User Ken Manheimer # Date 1292018997 18000 # Node ID a348c631aeb8b694184807922b76120f31034381 # Parent f2d8b7a80f044335ee548bbedf4d1b2d8ea2a87c - replace pgg with epg/epa - working version, with no calls to pgg. - remove passphrase verifier and hinting. (allout-passphrase-verifier-handling), (allout-passphrase-hint-handling): No longer used, delete. (allout-epg-protocol): Never used and unnecessary, delete. (allout-mode): Adjust docstring to describe changed encryption provisions. (allout-toggle-current-subtree-encryption): Adjust docstring to describe changed encryption provisions. Change fetch-pass to keymode-cue, for simpler universal argument interpretation. (allout-toggle-subtree-encryption): Adjust docstring to describe changed encryption provisions. Change fetch-pass to keymode-cue, for simpler universal argument interpretation. Remove provisions for handling key type and identity - they'll all be within allout-encrypt-string or epg/epg or even contained all the way in gpg. (allout-encrypt-string): Include keypair-mode argument, for requesting keypair encryption. Require epa, for recipients handling. Change how regexp filtering elements are named. (allout-obtain-passphrase), (allout-epg-passphrase-callback-function), (allout-make-passphrase-state), (allout-passphrase-state-passphrase): Remove, we're not providing passphrase verification and hinting because: - gpg v1 is required for epg passphrase callback operation, on which verification and hinting depends - doing that handling exposes the passphrase to emacs code, which is much much less secure than leaving all passphrase handling in gpg - leaving all passphrase handling to gpg removes a lot of complexity from allout code - gpg v2 connection to gpg-agent requires no user provisions, so is simpler and provides some convenience that makes up for the lack of hinting and verification (allout-encrypted-key-info), (allout-update-passphrase-mnemonic-aids), (allout-get-encryption-passphrase-verifier), (allout-verify-passphrase): Obsolete. diff -r f2d8b7a80f04 -r a348c631aeb8 lisp/allout.el --- a/lisp/allout.el Wed Dec 08 14:57:06 2010 -0500 +++ b/lisp/allout.el Fri Dec 10 17:09:57 2010 -0500 @@ -85,6 +85,7 @@ (eval-when-compile ;; Most of the requires here are for stuff covered by autoloads, which ;; byte-compiling doesn't trigger. + (require 'epg) (require 'epa) (require 'overlay) ;; `cl' is required for `assert'. `assert' is not covered by a standard @@ -812,32 +813,6 @@ :type '(choice (const nil) string) :version "22.1" :group 'allout-encryption) -;;;_ = allout-passphrase-verifier-handling -(defcustom allout-passphrase-verifier-handling t - "Enable use of symmetric encryption passphrase verifier if non-nil. - -See the docstring for the `allout-enable-file-variable-adjustment' -variable for details about allout ajustment of file variables." - :type 'boolean - :version "22.1" - :group 'allout-encryption) -(make-variable-buffer-local 'allout-passphrase-verifier-handling) -;;;_ = allout-passphrase-hint-handling -(defcustom allout-passphrase-hint-handling 'always - "Dictate outline encryption passphrase reminder handling: - - always -- always show reminder when prompting - needed -- show reminder on passphrase entry failure - disabled -- never present or adjust reminder - -See the docstring for the `allout-enable-file-variable-adjustment' -variable for details about allout ajustment of file variables." - :type '(choice (const always) - (const needed) - (const disabled)) - :version "22.1" - :group 'allout-encryption) -(make-variable-buffer-local 'allout-passphrase-hint-handling) ;;;_ = allout-encrypt-unencrypted-on-saves (defcustom allout-encrypt-unencrypted-on-saves t "When saving, should topics pending encryption be encrypted? @@ -1533,12 +1508,6 @@ "Horrible hack used to prevent invalid multiple triggering of outline mode from prop-line file-var activation. Used by `allout-mode' function to track repeats.") -;;;_ = allout-epg-protocol -(defvar allout-epg-protocol 'OpenPGP - "*The default protocol. -The value can be either 'OpenPGP or 'CMS. - -You should bind this variable with `let', but do not set it globally.") ;;;_ = allout-passphrase-verifier-string (defvar allout-passphrase-verifier-string nil "Setting used to test solicited encryption passphrases against the one @@ -1554,6 +1523,8 @@ the Emacs buffer state, if file variable adjustments are enabled. See `allout-enable-file-variable-adjustment' for details about that.") (make-variable-buffer-local 'allout-passphrase-verifier-string) +(make-obsolete 'allout-passphrase-verifier-string + 'allout-passphrase-verifier-string "23.3") ;;;###autoload (put 'allout-passphrase-verifier-string 'safe-local-variable 'stringp) ;;;_ = allout-passphrase-hint-string @@ -1568,6 +1539,8 @@ `allout-enable-file-variable-adjustment' for details about that.") (make-variable-buffer-local 'allout-passphrase-hint-string) (setq-default allout-passphrase-hint-string "") +(make-obsolete 'allout-passphrase-hint-string + 'allout-passphrase-hint-string "23.3") ;;;###autoload (put 'allout-passphrase-hint-string 'safe-local-variable 'stringp) ;;;_ = allout-after-save-decrypt @@ -1937,19 +1910,14 @@ Topic Encryption Outline mode supports gpg encryption of topics, with support for -symmetric and key-pair modes, passphrase timeout, passphrase -consistency checking, user-provided hinting for symmetric key -mode, and auto-encryption of topics pending encryption on save. +symmetric and key-pair modes, and auto-encryption of topics +pending encryption on save. Topics pending encryption are, by default, automatically -encrypted during file saves. If the contents of the topic -containing the cursor was encrypted for a save, it is -automatically decrypted for continued editing. - -The aim of these measures is reliable topic privacy while -preventing accidents like neglected encryption before saves, -forgetting which passphrase was used, and other practical -pitfalls. +encrypted during file saves, including checkpoint saves, to avoid +exposing the plain text of encrypted topics in the file system. +If the content of the topic containing the cursor was encrypted +for a save, it is automatically decrypted for continued editing. See `allout-toggle-current-subtree-encryption' function docstring and `allout-encrypt-unencrypted-on-saves' customization variable @@ -5999,29 +5967,27 @@ (goto-char start-pt))) ;;;_ #8 Encryption -;;;_ > allout-toggle-current-subtree-encryption (&optional fetch-pass) -(defun allout-toggle-current-subtree-encryption (&optional fetch-pass) - "Encrypt clear or decrypt encoded text of visibly-containing topic's contents. - -Optional FETCH-PASS universal argument provokes key-pair encryption with -single universal argument. With doubled universal argument (value = 16), -it forces prompting for the passphrase regardless of availability from the -passphrase cache. With no universal argument, the appropriate passphrase -is obtained from the cache, if available, else from the user. - -Allout uses emacs 'epg' libary to perform encryption. Allout -encrypts with ascii armoring. - -Both symmetric-key and key-pair encryption is implemented. Symmetric is -the default, use a single (x4) universal argument for keypair mode. - -Encrypted topic's bullet is set to a `~' to signal that the contents of the -topic (body and subtopics, but not heading) is pending encryption or -encrypted. `*' asterisk immediately after the bullet signals that the body -is encrypted, its' absence means the topic is meant to be encrypted but is -not. When a file with topics pending encryption is saved, topics pending -encryption are encrypted. See allout-encrypt-unencrypted-on-saves for -auto-encryption specifics. +;;;_ > allout-toggle-current-subtree-encryption (&optional keymode-cue) +(defun allout-toggle-current-subtree-encryption (&optional keymode-cue) + "Encrypt clear or decrypt encoded topic text. + +Allout uses emacs 'epg' libary to perform encryption. Symmetric +and keypair encryption are supported. All encryption is ascii +armored. + +When encrypting, optional KEYMODE-CUE universal argument greater +than 1 causes prompting for recipients for public-key keypair +encryption. Otherwise a symmetric mode is assumed for +encryption. + +Encrypted topic's bullets are set to a `~' to signal that the +contents of the topic (body and subtopics, but not heading) is +pending encryption or encrypted. `*' asterisk immediately after +the bullet signals that the body is encrypted, its absence means +the topic is meant to be encrypted but is not currently. When a +file with topics pending encryption is saved, topics pending +encryption are encrypted. See allout-encrypt-unencrypted-on-saves +for auto-encryption specifics. \*NOTE WELL* that automatic encryption that happens during saves will default to symmetric encryption -- you must deliberately (re)encrypt key-pair @@ -6029,55 +5995,22 @@ Level-one topics, with prefix consisting solely of an `*' asterisk, cannot be encrypted. If you want to encrypt the contents of a top-level topic, use -\\[allout-shift-in] to increase its depth. - - Passphrase Caching - -The encryption passphrase is solicited if not currently available in the -passphrase cache from a recent encryption action. - - Symmetric Passphrase Hinting and Verification - -If the file previously had no associated passphrase, or had a different -passphrase than specified, the user is prompted to repeat the new one for -corroboration. A random string encrypted by the new passphrase is set on -the buffer-specific variable `allout-passphrase-verifier-string', for -confirmation of the passphrase when next obtained, before encrypting or -decrypting anything with it. This helps avoid mistakenly shifting between -keys. - -If allout customization var `allout-passphrase-verifier-handling' is -non-nil, an entry for `allout-passphrase-verifier-string' and its value is -added to an Emacs 'local variables' section at the end of the file, which -is created if necessary. That setting is for retention of the passphrase -verifier across Emacs sessions. - -Similarly, `allout-passphrase-hint-string' stores a user-provided reminder -about their passphrase, and `allout-passphrase-hint-handling' specifies -when the hint is presented, or if passphrase hints are disabled. If -enabled (see the `allout-passphrase-hint-handling' docstring for details), -the hint string is stored in the local-variables section of the file, and -solicited whenever the passphrase is changed." +\\[allout-shift-in] to increase its depth." (interactive "P") (save-excursion (allout-back-to-current-heading) - (allout-toggle-subtree-encryption fetch-pass) - ) - ) -;;;_ > allout-toggle-subtree-encryption (&optional fetch-pass) -(defun allout-toggle-subtree-encryption (&optional fetch-pass) + (allout-toggle-subtree-encryption keymode-cue))) +;;;_ > allout-toggle-subtree-encryption (&optional keymode-cue) +(defun allout-toggle-subtree-encryption (&optional keymode-cue) "Encrypt clear text or decrypt encoded topic contents (body and subtopics.) -Optional FETCH-PASS universal argument provokes key-pair encryption with -single universal argument. With doubled universal argument (value = 16), -it forces prompting for the passphrase regardless of availability from the -passphrase cache. With no universal argument, the appropriate passphrase -is obtained from the cache, if available, else from the user. - -Currently only GnuPG encryption is supported, and integration -with gpg-agent is not yet implemented. - -NOTE that the encrypted text will be ascii-armored. +When encrypting, optional KEYMODE-CUE universal argument greater than +1 provokes prompting for recipients for public-key keypair +encryption, otherwise a symmetric-mode passphrase is solicited. + +Encryption depends on the emacs epg library. + +Encrypted text will be ascii-armored. See `allout-toggle-current-subtree-encryption' for more details." @@ -6097,6 +6030,7 @@ (progn (if (= (point-max) after-bullet-pos) (error "no body to encrypt")) (allout-encrypted-topic-p))) + (keypair-mode (> (prefix-numeric-value keymode-cue) 1)) (was-collapsed (if (not (search-forward "\n" nil t)) nil (backward-char 1) @@ -6115,17 +6049,6 @@ (if was-encrypted "de" "en")) nil)) ;; Assess key parameters: - ;;PGG rework key-info! - (key-info (or - ;; detect the type by which it is already encrypted - (and was-encrypted - (allout-encrypted-key-info subject-text)) - (and (member fetch-pass '(4 (4))) - '(keypair nil)) - '(symmetric nil))) - (for-key-type (car key-info)) - (for-key-identity (cadr key-info)) - (fetch-pass (and fetch-pass (member fetch-pass '(16 (16))))) (was-coding-system buffer-file-coding-system)) (when (not was-encrypted) @@ -6151,9 +6074,7 @@ (setq result-text (allout-encrypt-string subject-text was-encrypted - (current-buffer) - for-key-type for-key-identity - )) + (current-buffer) keypair-mode)) ;; Replace the subtree with the processed product. (allout-unprotected @@ -6184,8 +6105,10 @@ (insert "*")))) (run-hook-with-args 'allout-structure-added-hook bullet-pos subtree-end)))) -;;;_ > allout-encrypt-string (text decrypt allout-buffer) -(defun allout-encrypt-string (text decrypt allout-buffer &optional rejected) +;;;_ > allout-encrypt-string (text decrypt allout-buffer keypair-mode +;;; &optional rejected) +(defun allout-encrypt-string (text decrypt allout-buffer keypair-mode + &optional rejected) "Encrypt or decrypt message TEXT. Returns the resulting string, or nil if the transformation fails. @@ -6194,31 +6117,40 @@ ALLOUT-BUFFER identifies the buffer containing the text. -Optional REJECTED is for internal use -- conveys the number of +If KEYPAIR-MODE is non-nil, encryption involves prompting for +keypair recipients. + +Optional REJECTED is for internal use, to convey the number of rejections due to matches against `allout-encryption-ciphertext-rejection-regexps', as limited by -`allout-encryption-ciphertext-rejection-ceiling'. -" +`allout-encryption-ciphertext-rejection-ceiling'." (require 'epg) - - (let* ((epg-context (epg-make-context epa-protocol t)) + (require 'epa) + + (let* ((epg-context (epg-make-context nil t)) (encoding (with-current-buffer allout-buffer buffer-file-coding-system)) (multibyte (with-current-buffer allout-buffer enable-multibyte-characters)) - (strip-plaintext-regexps - (if (not decrypt) - (allout-get-configvar-values - 'allout-encryption-plaintext-sanitization-regexps))) - (reject-ciphertext-regexps - (if (not decrypt) - (allout-get-configvar-values - 'allout-encryption-ciphertext-rejection-regexps))) + ;; "sanitization" avoids encryption results that are outline structure. + (sani-regexps 'allout-encryption-plaintext-sanitization-regexps) + (strip-plaintext-regexps (if (not decrypt) + (allout-get-configvar-values + sani-regexps))) + (rejection-regexps 'allout-encryption-ciphertext-rejection-regexps) + (reject-ciphertext-regexps (if (not decrypt) + (allout-get-configvar-values + rejection-regexps))) (rejected (or rejected 0)) (rejections-left (- allout-encryption-ciphertext-rejection-ceiling rejected)) - massaged-text result-text + (keypair-message (concat "Select encryption recipients.\n Not" + " selecting any causes" + " symmetric encryption. ")) + recipients + massaged-text + result-text ) ;; Massage the subject text for encoding and filtering. @@ -6243,284 +6175,49 @@ (setq massaged-text (buffer-substring-no-properties (point-min) (point-max)))) (setq result-text - (if decrypt - (epg-decrypt-string epg-context (encode-coding-string massaged-text (or encoding 'utf-8))) - - (if (equal key-type 'symmetric) - ;; establish the passphrase callback. it will only be used - ;; with gpgv1, but then it will handle hinting and verification. - (allout-set-epg-passphrase-callback epg-context allout-buffer)) - (epg-encrypt-string epg-context (encode-coding-string massaged-text (or encoding 'utf-8)) - nil))) + (and keypair-mode + (epa-select-keys epg-context + keypair-message))))) ;; validate result -- non-empty - (if (not result-text) - (error "%scryption failed." (if decrypt "De" "En")) - - ;; Retry (within limit) if ciphertext contains rejections: - ((and (not decrypt) - ;; Check for disqualification of this ciphertext: - (let ((regexps reject-ciphertext-regexps) - reject-it) - (while (and regexps (not reject-it)) - (setq reject-it (string-match (car regexps) result-text)) - (pop regexps)) - reject-it)) - (setq rejections-left (1- rejections-left)) - (if (<= rejections-left 0) - (error (concat "Ciphertext rejected too many times" - " (%s), per `%s'") - allout-encryption-ciphertext-rejection-ceiling - 'allout-encryption-ciphertext-rejection-regexps) - ;; try again: - ;; XXX alas, we depend on external caching for the passphrase. - (allout-encrypt-string text decrypt allout-buffer - (1+ rejected)))) - - ;; Barf if encryption yields extraordinary control chars: - ((and (not decrypt) - (string-match "[\C-a\C-k\C-o-\C-z\C-@]" - result-text)) - (error (concat "Encryption produced non-armored text, which" - "conflicts with allout mode -- reconfigure!"))) - - (t result-text) - ) - ) - ) -;;;_ . epg passphrase callback handling (epg uses only for GnuPG v1) -;;;_ > allout-epg-passphrase-callback-function (context key-id state) -(defun allout-epg-passphrase-callback-function (context key-id state) - "Handle allout passphrase prompting when used with the emacs epg library. - -Note that epg's passphrase callback provision only works when -operating with GnuPG v1. Check your GnuPG version using 'gpg ---version' from the command line. - -CONTEXT is an epg context object, per 'epg-make-context'. - -KEY-ID is apparently either 'SYM, for symmetric passphrase, or -something else for a key pair, per 'epg-passphrase-callback-function'. - -STATE is an allout passphrase state construct, per -'allout-make-passphrase-state'." - (message "allout-passphrase-callback-function: in")(sit-for 1) - (let* ((allout-buffer (allout-passphrase-state-buffer state)) - (provided (allout-passphrase-state-buffer state))) - (if (eq key-id 'SYM) - (if provided - provided - (let* - ((hint-string - (with-current-buffer allout-buffer - (if (and (not (string= allout-passphrase-hint-string - "")) - (or (equal allout-passphrase-hint-handling 'always) - (and (equal allout-passphrase-hint-handling - 'needed) - retried))) - (format " [%s]" allout-passphrase-hint-string) - ""))) - (verifier-string (allout-get-encryption-passphrase-verifier)) - (passphrase (read-passwd - (format "Passphrase for %s symmetric encryption%s: " - (buffer-name allout-buffer) hint-string)))) - (if allout-passphrase-verifier-handling - (if verifier-string - ;; try verifying against existing verifier. - ;; - successful: return the passphrase. - ;; - unsuccessful: offer to change the verifier - ;; - if change accepted, change verifier and continue - ;; - if change refused, raise an encryption error. - (if (condition-case err - (epg-decrypt-string - (allout-context-epg-passphrase-callback - epg-context allout-buffer passphrase) - verifier-string) - (error nil)) - ;;(allout-update-passphrase-mnemonic-aids for-key passphrase - ;; allout-buffer) - - ) - (read-passwd - (if (eq key-id 'PIN) - "Passphrase for PIN: " - (let ((entry (assoc key-id epg-user-id-alist))) - (if entry - (format "Passphrase for %s %s: " key-id (cdr entry)) - (format "Passphrase for %s: " key-id))))))) -;;;_ > allout-context-epg-passphrase-callback (epg-context buffer -;;; &optional passphrase) -(defun allout-context-epg-passphrase-callback (epg-context buffer - &optional passphrase) - "Return an epg-context which uses allout's passphrase callback with state. - -NOTE that epg's passphrase callback provision only works when -operating with GnuPG v1. Check your GnuPG version using 'gpg ---version' from the command line. - -A deep copy of the specified EPG-CONTEXT, per 'epg-make-context', -is used as a template. - -BUFFER is the allout outline buffer containing the target text. - -Optional PASSPHRASE is an already obtained passphrase to be used for -multiple decryptions, eg when verifying symmetric passphrases." - (let ((new-epg-context (copy-tree epg-context))) - (epg-context-set-passphrase-callback - new-epg-context - (cons #'allout-epg-passphrase-callback-function - (allout-make-passphrase-state buffer passphrase))) - new-epg-context)) -;;;_ > allout-make-passphrase-state (buffer &optional passphrase) -(defun allout-make-passphrase-state (buffer &optional passphrase) - "Return an allout passphrase state construct. - -BUFFER is the allout outline buffer. - -Optional PASSPHRASE is used when decrypting to convey an already -obtained passphrase for doing multiple decryptions, eg when doing -verification as part of symmetric passphrse decryption." - (cons buffer passphrase)) -;;;_ > allout-passphrase-state-buffer (state) -(defun allout-passphrase-state-buffer (state) - "Given an allout passphrase STATE construct, return the buffer." - (car state)) -;;;_ > allout-passphrase-state-passphrase (state) -(defun allout-passphrase-state-passphrase (state) - "Given an allout passphrase STATE construct, return the passphrase or nil." - (cdr state)) -;;;_ > ;;PGG allout-obtain-passphrase (for-key ;;PGG cache-id -;;; prompt-id key-type allout-buffer retried -;;; ;;PGG fetch-pass) -(defun allout-obtain-passphrase (for-key ;;PGG cache-id - prompt-id key-type allout-buffer retried - ;;fetch-pass - ) - "Obtain passphrase for a key from the user. - -When obtaining from the user, symmetric-cipher passphrases are verified -against either, if available and enabled, a random string that was -encrypted against the passphrase, or else against repeated entry by the -user for corroboration. - -FOR-KEY is the key for which the passphrase is being obtained. - -;;PGG CACHE-ID is the cache id of the key for the passphrase. - -PROMPT-ID is the id for use when prompting the user. - -KEY-TYPE is either `symmetric' or `keypair'. - -ALLOUT-BUFFER is the buffer containing the entry being en/decrypted. - -RETRIED is the number of this attempt to obtain this passphrase. - -;;PGG FETCH-PASS causes the passphrase to be solicited from the user, regardless -;;PGG of the availability of a cached copy. -" - - (if (not (equal key-type 'symmetric)) - ;; do regular passphrase read on non-symmetric passphrase: - (pgg-read-passphrase (format "%s passphrase%s: " - (upcase (format "%s" (or pgg-scheme - pgg-default-scheme - "GPG"))) - (if prompt-id - (format " for %s" prompt-id) - "")) - for-key ;;PGG cache-id - t) - - ;; Symmetric hereon: - - (with-current-buffer allout-buffer - (let* ((hint (if (and (not (string= allout-passphrase-hint-string "")) - (or (equal allout-passphrase-hint-handling 'always) - (and (equal allout-passphrase-hint-handling - 'needed) - retried))) - (format " [%s]" allout-passphrase-hint-string) - "")) - (retry-message (if retried (format " (%s retry)" retried) "")) - (prompt-sans-hint (format "'%s' symmetric passphrase%s: " - prompt-id retry-message)) - (full-prompt (format "'%s' symmetric passphrase%s%s: " - prompt-id hint retry-message)) - (prompt full-prompt) - (verifier-string (allout-get-encryption-passphrase-verifier)) - - ;;PGG (cached (and (not fetch-pass) - ;;PGG (pgg-read-passphrase-from-cache cache-id t))) - (got-pass ;;PGG (or cached - (pgg-read-passphrase full-prompt ;;PGG cache-id - for-key t)) - ;;PGG ) - confirmation) - - (if (not got-pass) - nil - - ;; Duplicate our handle on the passphrase so it's not clobbered by - ;; deactivate-passwd memory clearing: - (setq got-pass (copy-sequence got-pass)) - - (cond (verifier-string - (save-window-excursion - (if (allout-encrypt-string verifier-string 'decrypt - allout-buffer 'symmetric for-key - ;;PGG nil - 0 0 'verifying - (copy-sequence got-pass)) - (setq confirmation (format "%s" got-pass)))) - - (if (and (not confirmation) - (if (yes-or-no-p - (concat "Passphrase differs from established" - " -- use new one instead? ")) - ;; deactivate password for subsequent - ;; confirmation: - (progn - ;;PGG (pgg-remove-passphrase-from-cache cache-id t) - (setq prompt prompt-sans-hint) - nil) - t)) - ;;PGG (progn (pgg-remove-passphrase-from-cache cache-id t) - (error "Wrong passphrase"))) - ;;PGG) - ;; No verifier string -- force confirmation by repetition of - ;; (new) passphrase: - ;;PGG ((or fetch-pass (not cached)) - ;;PGG (pgg-remove-passphrase-from-cache cache-id t))) - ) - ;; confirmation vs new input -- doing pgg-read-passphrase will do the - ;; right thing, in either case: - (if (not confirmation) - (setq confirmation - (pgg-read-passphrase (concat prompt - " ... confirm spelling: ") - ;;PGG cache-id - for-key t))) - (prog1 - (if (equal got-pass confirmation) - confirmation - (if (yes-or-no-p (concat "spelling of original and" - " confirmation differ -- retry? ")) - (progn (setq retried (if retried (1+ retried) 1)) - ;;PGG (pgg-remove-passphrase-from-cache cache-id - for-key t) - ;; recurse to this routine: - (pgg-read-passphrase prompt-sans-hint ;;PGG cache-id - for-key t)) - ;;PGG (pgg-remove-passphrase-from-cache cache-id t) - (error "Confirmation failed")))))))) + (cond + ((not result-text) + (error "%scryption failed." (if decrypt "De" "En"))) + + ;; Retry (within limit) if ciphertext contains rejections: + ((and (not decrypt) + ;; Check for disqualification of this ciphertext: + (let ((regexps reject-ciphertext-regexps) + reject-it) + (while (and regexps (not reject-it)) + (setq reject-it (string-match (car regexps) result-text)) + (pop regexps)) + reject-it)) + (setq rejections-left (1- rejections-left)) + (if (<= rejections-left 0) + (error (concat "Ciphertext rejected too many times" + " (%s), per `%s'") + allout-encryption-ciphertext-rejection-ceiling + 'allout-encryption-ciphertext-rejection-regexps) + ;; try again (gpg-agent may have the key cached): + (allout-encrypt-string text decrypt allout-buffer keypair-mode + (1+ rejected)))) + + ;; Barf if encryption yields extraordinary control chars: + ((and (not decrypt) + (string-match "[\C-a\C-k\C-o-\C-z\C-@]" + result-text)) + (error (concat "Encryption produced non-armored text, which" + "conflicts with allout mode -- reconfigure!"))) + + (t result-text)))) ;;;_ > allout-encrypted-topic-p () (defun allout-encrypted-topic-p () "True if the current topic is encryptable and encrypted." @@ -6531,130 +6228,6 @@ (save-match-data (looking-at "\\*"))) ) ) -;;;_ > ;;PGG allout-encrypted-key-info (text) -;; XXX gpg-specific, alas -(defun allout-encrypted-key-info (text) - "Return a pair of the key type and identity of a recipient's secret key. - -The key type is one of `symmetric' or `keypair'. - -If `keypair', and some of the user's secret keys are among those for which -the message was encoded, return the identity of the first. Otherwise, -return nil for the second item of the pair. - -An error is raised if the text is not encrypted." - (require 'pgg-parse) - (save-excursion - (with-temp-buffer - (insert text) - (let* ((parsed-armor (pgg-parse-armor-region (point-min) (point-max))) - (type (if (assq 'symmetric-key-algorithm (car (cdr parsed-armor))) - 'symmetric - 'keypair)) - secret-keys first-secret-key for-key-owner) - (if (equal type 'keypair) - (setq secret-keys (pgg-gpg-lookup-all-secret-keys) - first-secret-key (pgg-gpg-select-matching-key parsed-armor - secret-keys) - for-key-owner (and first-secret-key - (pgg-gpg-lookup-key-owner - first-secret-key)))) - (list type (pgg-gpg-key-id-from-key-owner for-key-owner)) - ) - ) - ) - ) -;;;_ > allout-create-encryption-passphrase-verifier (passphrase) -(defun allout-create-encryption-passphrase-verifier (passphrase) - "Encrypt random message for later validation of symmetric key's passphrase." - ;; use 20 random ascii characters, across the entire ascii range. - (random t) - (let ((spew (make-string 20 ?\0))) - (dotimes (i (length spew)) - (aset spew i (1+ (random 254)))) - (allout-encrypt-string spew nil (current-buffer) 'symmetric nil - ;;PGG nil - nil 0 0 passphrase)) - ) -;;;_ > allout-update-passphrase-mnemonic-aids (for-key passphrase -;;; outline-buffer) -(defun allout-update-passphrase-mnemonic-aids (for-key passphrase - outline-buffer) - "Update passphrase verifier and hint strings if necessary. - -See `allout-passphrase-verifier-string' and `allout-passphrase-hint-string' -settings. - -PASSPHRASE is the passphrase being mnemonicized. - -OUTLINE-BUFFER is the buffer of the outline being adjusted. - -These are used to help the user keep track of the passphrase they use for -symmetric encryption in the file. - -Behavior is governed by `allout-passphrase-verifier-handling', -`allout-passphrase-hint-handling', and also, controlling whether the values -are preserved on Emacs local file variables, -`allout-enable-file-variable-adjustment'." - - ;; If passphrase doesn't agree with current verifier: - ;; - adjust the verifier - ;; - if passphrase hint handling is enabled, adjust the passphrase hint - ;; - if file var settings are enabled, adjust the file vars - - (let* ((new-verifier-needed (not (allout-verify-passphrase - for-key passphrase outline-buffer))) - (new-verifier-string - (if new-verifier-needed - ;; Collapse to a single line and enclose in string quotes: - (subst-char-in-string - ?\n ?\C-a (allout-create-encryption-passphrase-verifier - passphrase)))) - new-hint) - (when new-verifier-string - ;; do the passphrase hint first, since it's interactive - (when (and allout-passphrase-hint-handling - (not (equal allout-passphrase-hint-handling 'disabled))) - (setq new-hint - (read-from-minibuffer "Passphrase hint to jog your memory: " - allout-passphrase-hint-string)) - (when (not (string= new-hint allout-passphrase-hint-string)) - (setq allout-passphrase-hint-string new-hint) - (allout-adjust-file-variable "allout-passphrase-hint-string" - allout-passphrase-hint-string))) - (when allout-passphrase-verifier-handling - (setq allout-passphrase-verifier-string new-verifier-string) - (allout-adjust-file-variable "allout-passphrase-verifier-string" - allout-passphrase-verifier-string)) - ) - ) - ) -;;;_ > allout-get-encryption-passphrase-verifier () -(defun allout-get-encryption-passphrase-verifier () - "Return text of the encrypt passphrase verifier, unmassaged, or nil if none. - -Derived from value of `allout-passphrase-verifier-string'." - - (let ((verifier-string (and (boundp 'allout-passphrase-verifier-string) - allout-passphrase-verifier-string))) - (if verifier-string - ;; Return it uncollapsed - (subst-char-in-string ?\C-a ?\n verifier-string)) - ) - ) -;;;_ > allout-verify-passphrase (key passphrase allout-buffer) -(defun allout-verify-passphrase (key passphrase allout-buffer) - "True if passphrase successfully decrypts verifier, nil otherwise. - -\"Otherwise\" includes absence of passphrase verifier." - (with-current-buffer allout-buffer - (and (boundp 'allout-passphrase-verifier-string) - allout-passphrase-verifier-string - (allout-encrypt-string (allout-get-encryption-passphrase-verifier) - 'decrypt allout-buffer 'symmetric key - ;;PGG nil - 0 0 'verifying passphrase) - t))) ;;;_ > allout-next-topic-pending-encryption (&optional except-mark) (defun allout-next-topic-pending-encryption (&optional except-mark) "Return the point of the next topic pending encryption, or nil if none.