diff --git a/CHANGELOG.md b/CHANGELOG.md index 76a4327..04d70b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### Unreleased + +### Added +- `SessionKey.Decrypt() and SessionKey.DecryptAndVerify`, now suport the decryption of AEAD encrypted +data packets (packet type 20). + ## [2.4.7] 2022-04-27 ### Changed diff --git a/crypto/keyring_message_test.go b/crypto/keyring_message_test.go new file mode 100644 index 0000000..c577339 --- /dev/null +++ b/crypto/keyring_message_test.go @@ -0,0 +1,38 @@ +package crypto + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAEADKeyRingDecryption(t *testing.T) { + pgpMessageData, err := ioutil.ReadFile("testdata/gpg2.3-aead-pgp-message.pgp") + if err != nil { + t.Fatal("Expected no error when reading message data, got:", err) + } + pgpMessage := NewPGPMessage(pgpMessageData) + + aeadKey, err := NewKeyFromArmored(readTestFile("gpg2.3-aead-test-key.asc", false)) + if err != nil { + t.Fatal("Expected no error when unarmoring key, got:", err) + } + + aeadKeyUnlocked, err := aeadKey.Unlock([]byte("test")) + if err != nil { + t.Fatal("Expected no error when unlocking, got:", err) + } + kR, err := NewKeyRing(aeadKeyUnlocked) + if err != nil { + t.Fatal("Expected no error when creating the keyring, got:", err) + } + defer kR.ClearPrivateParams() + + decrypted, err := kR.Decrypt(pgpMessage, nil, 0) + if err != nil { + t.Fatal("Expected no error when decrypting, got:", err) + } + + assert.Exactly(t, "hello world\n", decrypted.GetString()) +} diff --git a/crypto/sessionkey.go b/crypto/sessionkey.go index 481e505..9750544 100644 --- a/crypto/sessionkey.go +++ b/crypto/sessionkey.go @@ -327,17 +327,19 @@ func decryptStreamWithSessionKey(sk *SessionKey, messageReader io.Reader, verify // Decrypt data packet switch p := p.(type) { - case *packet.SymmetricallyEncrypted: + case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted: dc, err := sk.GetCipherFunc() if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt with session key") } - - decrypted, err = p.Decrypt(dc, sk.Key) + encryptedDataPacket, isDataPacket := p.(packet.EncryptedDataPacket) + if !isDataPacket { + return nil, errors.Wrap(err, "gopenpgp: unknown data packet") + } + decrypted, err = encryptedDataPacket.Decrypt(dc, sk.Key) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt symmetric packet") } - default: return nil, errors.New("gopenpgp: invalid packet type") } diff --git a/crypto/sessionkey_test.go b/crypto/sessionkey_test.go index 1724681..905bc22 100644 --- a/crypto/sessionkey_test.go +++ b/crypto/sessionkey_test.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/hex" "errors" + "io/ioutil" "testing" "github.com/ProtonMail/gopenpgp/v2/constants" @@ -344,3 +345,42 @@ func TestAsymmetricKeyPacketDecryptionFailure(t *testing.T) { _, err = ukr.DecryptSessionKey(keyPacket) assert.Error(t, err, "gopenpgp: unable to decrypt session key") } + +func TestAEADDataPacketDecryption(t *testing.T) { + pgpMessageData, err := ioutil.ReadFile("testdata/gpg2.3-aead-pgp-message.pgp") + if err != nil { + t.Fatal("Expected no error when reading message data, got:", err) + } + pgpMessage := NewPGPMessage(pgpMessageData) + + split, err := pgpMessage.SplitMessage() + if err != nil { + t.Fatal("Expected no error when splitting, got:", err) + } + + aeadKey, err := NewKeyFromArmored(readTestFile("gpg2.3-aead-test-key.asc", false)) + if err != nil { + t.Fatal("Expected no error when unarmoring key, got:", err) + } + + aeadKeyUnlocked, err := aeadKey.Unlock([]byte("test")) + if err != nil { + t.Fatal("Expected no error when unlocking, got:", err) + } + kR, err := NewKeyRing(aeadKeyUnlocked) + if err != nil { + t.Fatal("Expected no error when creating the keyring, got:", err) + } + defer kR.ClearPrivateParams() + sessionKey, err := kR.DecryptSessionKey(split.GetBinaryKeyPacket()) + if err != nil { + t.Fatal("Expected no error when decrypting session key, got:", err) + } + + decrypted, err := sessionKey.Decrypt(split.GetBinaryDataPacket()) + if err != nil { + t.Fatal("Expected no error when decrypting, got:", err) + } + + assert.Exactly(t, "hello world\n", decrypted.GetString()) +} diff --git a/crypto/testdata/gpg2.3-aead-pgp-message.pgp b/crypto/testdata/gpg2.3-aead-pgp-message.pgp new file mode 100644 index 0000000..118053a --- /dev/null +++ b/crypto/testdata/gpg2.3-aead-pgp-message.pgp @@ -0,0 +1 @@ +^Y7p}@MMRtɑݖ9 #0%;׬j4# RsRAZA"Ĩ?f/L] eѣ^ kE8^ς8&x#2nQ sAСB6ِj~j1%i6s+-I`p \ No newline at end of file diff --git a/crypto/testdata/gpg2.3-aead-test-key.asc b/crypto/testdata/gpg2.3-aead-test-key.asc new file mode 100644 index 0000000..bdd66d5 --- /dev/null +++ b/crypto/testdata/gpg2.3-aead-test-key.asc @@ -0,0 +1,17 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lIYEYqiY8xYJKwYBBAHaRw8BAQdAlnAqgX8/hgDonAw/IpekRQwfVJmRWZUbVaK9 +SpL7qbr+BwMCweVnv2EC0AD/0ZzV/9F9qVc8P9kwBXsL2PZTSMLTHPlv9Wp4ny9X +LH13AjR8+SbiX+FZxjBqYMfzQE/vMoSDgrOqEwToZM+K8Xczitox+LQ1YWVhZC1r +ZXkgKHRoaXMgaXMgYSB0ZXN0IGtleSkgPGFlYWQta2V5QHByb3Rvbi5ibGFjaz6I +kgQTFgoAOhYhBLTRCn0YEvaHOC8wd5z6DYBV4wK2BQJiqJjzAhsDBQsJCAcCAiIC +BhUKCQgLAgMWAgECHgcCF4AACgkQnPoNgFXjArYTOwEApydkVgypRciM+4hOw4e4 +JrPulK90nKTt/ETH1idPicIBANke01I2pKoTj8dmzq5imE4+sDsKGNEdiksEYMqd +Da8BnIsEYqiY8xIKKwYBBAGXVQEFAQEHQJBylc4dtR6ea1yu63TR8+tRpfGxIBR+ +58mXXJ+yfX9dAwEIB/4HAwJtMIaMnD5Nbf9BohXuc0kph8vqzqhMhKahUeBD4B+P +1Gl4nH3BqyMCBS8bWhuYS5SmFdree1nny4aRI+veEB8aCLKDwqvlinh2N/z5Kh2v +iHgEGBYKACAWIQS00Qp9GBL2hzgvMHec+g2AVeMCtgUCYqiY8wIbDAAKCRCc+g2A +VeMCti86AQDjvVtf8P/pPSpC3KrrKTEZOW+x3mCZJhhUcQkTXlxRTgEArLOPU6kj +vWc1uLyrizai9gxpkMZY9oT1BOMkp0wDdgI= +=pBZD +-----END PGP PRIVATE KEY BLOCK-----