Bruno Clermont uploaded Use prompt function to decrypt private key for review.
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.
Bruno Clermont posted comments on Use prompt function to decrypt private key.
Patch Set 1: fix https://github.com/golang/go/issues/17845
To view, visit this change. To unsubscribe, visit settings.
Ian Lance Taylor uploaded patch set #2 to openpgp: use prompt function to decrypt private key.
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.
Emmanuel Odeke posted comments on this change.
Patch set 2:
I'll tag also @agl & @hanwen who most likely are familiar with this package than I'd be
(6 comments)
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
Patch Set #2, Line 509: if err != nil {
if err := w.Close(); err != nil {
To view, visit change 32890. To unsubscribe, visit settings.
Han-Wen Nienhuys posted comments on this change.
Patch set 2:
I know nothing of PGP.
Filippo Valsorda abandoned this change.
To view, visit change 32890. To unsubscribe, or for help writing mail filters, visit settings.