[crypto] Use prompt function to decrypt private key

83 views
Skip to first unread message

Bruno Clermont (Gerrit)

unread,
Nov 8, 2016, 12:08:46 AM11/8/16
to Ian Lance Taylor, golang-co...@googlegroups.com

Bruno Clermont uploaded Use prompt function to decrypt private key for review.

View Change

Use prompt function to decrypt private key

Change-Id: Ia3769c37fa6bcc02753a61d69b6809f7dff1b255
---
M openpgp/read.go
M openpgp/read_test.go
2 files changed, 105 insertions(+), 13 deletions(-)

diff --git a/openpgp/read.go b/openpgp/read.go
index 6ec664f..7f9acdb 100644
--- a/openpgp/read.go
+++ b/openpgp/read.go
@@ -79,6 +79,26 @@
 	encryptedKey *packet.EncryptedKey
 }
 
+// decryptPacketPrivateKey try to decrypt an encrypted packet using a private key
+func decryptPacketPrivateKey(k Key, encryptedKey *packet.EncryptedKey, se *packet.SymmetricallyEncrypted, md *MessageDetails, config *packet.Config) (io.ReadCloser, error) {
+	if len(encryptedKey.Key) == 0 {
+		encryptedKey.Decrypt(k.PrivateKey, config)
+		// handle error ?
+	}
+	if len(encryptedKey.Key) == 0 {
+		return nil, nil
+	}
+	decrypted, err := se.Decrypt(encryptedKey.CipherFunc, encryptedKey.Key)
+	if err != nil && err != errors.ErrKeyIncorrect {
+		return nil, err
+	}
+	if decrypted != nil {
+		md.DecryptedWith = k
+		return decrypted, nil
+	}
+	return nil, errors.ErrKeyIncorrect
+}
+
 // ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
 // The given KeyRing should contain both public keys (for signature
 // verification) and, possibly encrypted, private keys for decrypting.
@@ -157,18 +177,11 @@
 				continue
 			}
 			if !pk.key.PrivateKey.Encrypted {
-				if len(pk.encryptedKey.Key) == 0 {
-					pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
-				}
-				if len(pk.encryptedKey.Key) == 0 {
-					continue
-				}
-				decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
-				if err != nil && err != errors.ErrKeyIncorrect {
-					return nil, err
-				}
-				if decrypted != nil {
-					md.DecryptedWith = pk.key
+				if decrypted, err = decryptPacketPrivateKey(pk.key, pk.encryptedKey, se, md, config); err != nil {
+					if err != errors.ErrKeyIncorrect {
+						return nil, err
+					}
+				} else {
 					break FindKey
 				}
 			} else {
@@ -194,8 +207,12 @@
 			return nil, err
 		}
 
+		if passphrase == nil {
+			continue
+		}
+
 		// Try the symmetric passphrase first
-		if len(symKeys) != 0 && passphrase != nil {
+		if len(symKeys) != 0 {
 			for _, s := range symKeys {
 				key, cipherFunc, err := s.Decrypt(passphrase)
 				if err == nil {
@@ -210,6 +227,27 @@
 
 			}
 		}
+
+		// Then try to decrypt private key and decrypt packet with it
+		if len(candidates) != 0 {
+			for _, candidate := range candidates {
+				if err = candidate.PrivateKey.Decrypt(passphrase); err != nil {
+					// can't decrypt private key, do not use it
+					continue
+				}
+				for _, pk := range pubKeys {
+					if pk.key.PrivateKey.KeyId == candidate.PrivateKey.KeyId {
+						if decrypted, err = decryptPacketPrivateKey(candidate, pk.encryptedKey, se, md, config); err != nil {
+							if err != errors.ErrKeyIncorrect {
+								return nil, err
+							}
+						} else {
+							break FindKey
+						}
+					}
+				}
+			}
+		}
 	}
 
 	md.decrypted = decrypted
diff --git a/openpgp/read_test.go b/openpgp/read_test.go
index 1fbfbac..67aed9e 100644
--- a/openpgp/read_test.go
+++ b/openpgp/read_test.go
@@ -478,6 +478,60 @@
 	return
 }
 
+func TestEncryptionCryptedPrivateKey(t *testing.T) {
+	prompt := func(keys []Key, symmetric bool) ([]byte, error) {
+		return []byte("passphrase"), nil
+	}
+	const message = "testing"
+	var encryptedPrivateKeys int
+	for i, test := range testEncryptionTests {
+		kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+		for _, entity := range kring {
+			if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
+				encryptedPrivateKeys++
+				break
+			}
+		}
+
+		buf := new(bytes.Buffer)
+		w, err := Encrypt(buf, kring[:1], nil, nil, nil)
+		if err != nil {
+			t.Errorf("#%d: error in Encrypt: %s", i, err)
+			continue
+		}
+
+		_, err = w.Write([]byte(message))
+		if err != nil {
+			t.Errorf("#%d: error writing plaintext: %s", i, err)
+			continue
+		}
+		err = w.Close()
+		if err != nil {
+			t.Errorf("#%d: error closing WriteCloser: %s", i, err)
+			continue
+		}
+
+		md, err := ReadMessage(buf, kring, prompt, nil)
+		if err != nil {
+			t.Errorf("#%d: error reading message: %s", i, err)
+			continue
+		}
+
+		plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
+		if err != nil {
+			t.Errorf("#%d: error reading encrypted contents: %s", i, err)
+			continue
+		}
+
+		if string(plaintext) != message {
+			t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message)
+		}
+	}
+	if encryptedPrivateKeys == 0 {
+		t.Error("Couldn't test any private key password protected")
+	}
+}
+
 const testKey1KeyId = 0xA34D7E18C20C31BB
 const testKey3KeyId = 0x338934250CCC0360
 const testKeyP256KeyId = 0xd44a2c495918513e

To view, visit this change. To unsubscribe, visit settings.

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia3769c37fa6bcc02753a61d69b6809f7dff1b255
Gerrit-PatchSet: 1
Gerrit-Project: crypto
Gerrit-Branch: master
Gerrit-Owner: Bruno Clermont <bruno.c...@gmail.com>

Bruno Clermont (Gerrit)

unread,
Nov 8, 2016, 12:08:46 AM11/8/16
to golang-co...@googlegroups.com

Bruno Clermont posted comments on Use prompt function to decrypt private key.

View Change

Patch Set 1:

fix https://github.com/golang/go/issues/17845

    To view, visit this change. To unsubscribe, visit settings.

    Gerrit-MessageType: comment


    Gerrit-Change-Id: Ia3769c37fa6bcc02753a61d69b6809f7dff1b255
    Gerrit-PatchSet: 1
    Gerrit-Project: crypto
    Gerrit-Branch: master
    Gerrit-Owner: Bruno Clermont <bruno.c...@gmail.com>

    Gerrit-HasComments: No

    Ian Lance Taylor (Gerrit)

    unread,
    Nov 8, 2016, 12:59:09 AM11/8/16
    to Bruno Clermont, golang-co...@googlegroups.com

    Ian Lance Taylor uploaded patch set #2 to openpgp: use prompt function to decrypt private key.

    View Change

    openpgp: use prompt function to decrypt private key
    
    Fixes #17845.
    
    Change-Id: Ia3769c37fa6bcc02753a61d69b6809f7dff1b255
    ---
    M openpgp/read.go
    M openpgp/read_test.go
    2 files changed, 105 insertions(+), 13 deletions(-)
    
    

    To view, visit this change. To unsubscribe, visit settings.

    Gerrit-MessageType: newpatchset
    Gerrit-Change-Id: Ia3769c37fa6bcc02753a61d69b6809f7dff1b255
    Gerrit-PatchSet: 2

    Emmanuel Odeke (Gerrit)

    unread,
    Feb 18, 2017, 1:52:12 AM2/18/17
    to Ian Lance Taylor, Bruno Clermont, Han-Wen Nienhuys, Adam Langley, golang-co...@googlegroups.com

    Emmanuel Odeke posted comments on this change.

    View Change

    Patch set 2:

    I'll tag also @agl & @hanwen who most likely are familiar with this package than I'd be

    (6 comments)

    • File openpgp/read.go:

      • Patch Set #2, Line 82: // decryptPacketPrivateKey try to decrypt an encrypted packet using a private key

        s/try/tries/

      • Patch Set #2, Line 83: func decryptPacketPrivateKey(k Key, encryptedKey *packet.EncryptedKey, se *packet.SymmetricallyEncrypted, md *MessageDetails, config *packet.Config) (io.ReadCloser, error) {

        k Key -> key Key

        I also don't see any usage of k except below, after decryption but that looks false because we actually used encryptedKey.Key instead of k

      • Patch Set #2, Line 83: func decryptPacketPrivateKey(k Key, encryptedKey *packet.EncryptedKey, se *packet.SymmetricallyEncrypted, md *MessageDetails, config *packet.Config) (io.ReadCloser, error) {

        k Key -> key Key

        I also don't see any usage of k except below, after decryption but that looks false because we actually used encryptedKey.Key instead of k

      • Patch Set #2, Line 85: encryptedKey.Decrypt(k.PrivateKey, config)

        Am not that familiar with the code in here but perhaps this should return such an error since we should never get to this point

        if len(encryptedKey.key) == 0 {
               nil, errors.ErrKeyIncorrect
        }

        and that should handle the case below as well.

      • Patch Set #2, Line 95: if decrypted != nil {

        Let's perhaps invert this logic to make an early return, and then the rest of the code can flow normally ie:
        if decrypted == nil {
            return nil, errors.ErrKeyIncorrect
        }

        md.DecryptedWith = key return decrypted, nil

    • File openpgp/read_test.go:

    To view, visit change 32890. To unsubscribe, visit settings.

    Gerrit-Project: crypto
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: Ia3769c37fa6bcc02753a61d69b6809f7dff1b255
    Gerrit-Change-Number: 32890
    Gerrit-PatchSet: 2
    Gerrit-Owner: Bruno Clermont <bruno.c...@gmail.com>
    Gerrit-Reviewer: Adam Langley <a...@golang.org>
    Gerrit-Reviewer: Bruno Clermont <bruno.c...@gmail.com>
    Gerrit-Reviewer: Han-Wen Nienhuys <han...@google.com>
    Gerrit-CC: Emmanuel Odeke <emm....@gmail.com>
    Gerrit-Comment-Date: Sat, 18 Feb 2017 06:52:10 +0000
    Gerrit-HasComments: Yes

    Han-Wen Nienhuys (Gerrit)

    unread,
    Feb 20, 2017, 3:20:52 AM2/20/17
    to Ian Lance Taylor, Bruno Clermont, Adam Langley, Emmanuel Odeke, golang-co...@googlegroups.com

    Han-Wen Nienhuys posted comments on this change.

    View Change

    Patch set 2:

    I know nothing of PGP.

      To view, visit change 32890. To unsubscribe, visit settings.

      Gerrit-Project: crypto
      Gerrit-Branch: master
      Gerrit-MessageType: comment
      Gerrit-Change-Id: Ia3769c37fa6bcc02753a61d69b6809f7dff1b255
      Gerrit-Change-Number: 32890
      Gerrit-PatchSet: 2
      Gerrit-Owner: Bruno Clermont <bruno.c...@gmail.com>
      Gerrit-Reviewer: Adam Langley <a...@golang.org>
      Gerrit-Reviewer: Bruno Clermont <bruno.c...@gmail.com>
      Gerrit-Reviewer: Han-Wen Nienhuys <han...@google.com>
      Gerrit-CC: Emmanuel Odeke <emm....@gmail.com>
      Gerrit-Comment-Date: Mon, 20 Feb 2017 08:20:47 +0000
      Gerrit-HasComments: No

      Filippo Valsorda (Gerrit)

      unread,
      Mar 29, 2021, 6:04:57 PM3/29/21
      to Bruno Clermont, Ian Lance Taylor, goph...@pubsubhelper.golang.org, Adam Langley, Emmanuel Odeke, golang-co...@googlegroups.com

      Filippo Valsorda abandoned this change.

      View Change

      Abandoned The x/crypto/openpgp package is now frozen, so it won't accept any more non-security changes. Thank you for opening a PR and sorry for the significant lag. You might want to consider submitting this change to one of the community forks of this package instead. See https://golang.org/issues/44226 for more information about this decision.

      To view, visit change 32890. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: crypto
      Gerrit-Branch: master
      Gerrit-Change-Id: Ia3769c37fa6bcc02753a61d69b6809f7dff1b255
      Gerrit-Change-Number: 32890
      Gerrit-PatchSet: 2
      Gerrit-Owner: Bruno Clermont <bruno.c...@gmail.com>
      Gerrit-Reviewer: Adam Langley <a...@golang.org>
      Gerrit-Reviewer: Bruno Clermont <bruno.c...@gmail.com>
      Gerrit-CC: Emmanuel Odeke <emma...@orijtech.com>
      Gerrit-MessageType: abandon
      Reply all
      Reply to author
      Forward
      0 new messages