diff --git a/crypto/message.go b/crypto/message.go index 661f71c..435f3ad 100644 --- a/crypto/message.go +++ b/crypto/message.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "regexp" "runtime" + "strings" "github.com/ProtonMail/gopenpgp/v2/armor" "github.com/ProtonMail/gopenpgp/v2/constants" @@ -86,7 +87,7 @@ func NewPlainMessageFromFile(data []byte, filename string, time uint32) *PlainMe // ready for encryption, signature, or verification from an unencrypted string. func NewPlainMessageFromString(text string) *PlainMessage { return &PlainMessage{ - Data: []byte(text), + Data: []byte(strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n")), TextType: true, time: uint32(GetUnixTime()), } @@ -195,7 +196,7 @@ func (msg *PlainMessage) GetBinary() []byte { // GetString returns the content of the message as a string. func (msg *PlainMessage) GetString() string { - return string(msg.Data) + return strings.ReplaceAll(string(msg.Data), "\r\n", "\n") } // GetBase64 returns the base-64 encoded binary content of the message as a diff --git a/crypto/mime.go b/crypto/mime.go index 9210252..81c2053 100644 --- a/crypto/mime.go +++ b/crypto/mime.go @@ -33,7 +33,7 @@ func (keyRing *KeyRing) DecryptMIMEMessage( return } - body, attachments, attachmentHeaders, err := parseMIME(decryptedMessage.GetString(), verifyKey) + body, attachments, attachmentHeaders, err := parseMIME(string(decryptedMessage.GetBinary()), verifyKey) if err != nil { callbacks.OnError(err) return diff --git a/crypto/signature_test.go b/crypto/signature_test.go index c69869e..322d73f 100644 --- a/crypto/signature_test.go +++ b/crypto/signature_test.go @@ -51,7 +51,8 @@ func TestVerifyTextDetachedSigWrong(t *testing.T) { func TestSignBinDetached(t *testing.T) { var err error - binSignature, err = keyRingTestPrivate.SignDetached(NewPlainMessage([]byte(signedPlainText))) + message = NewPlainMessage([]byte(signedPlainText)) + binSignature, err = keyRingTestPrivate.SignDetached(message) if err != nil { t.Fatal("Cannot generate signature:", err) } diff --git a/helper/cleartext.go b/helper/cleartext.go index 9d477f5..6ddd945 100644 --- a/helper/cleartext.go +++ b/helper/cleartext.go @@ -1,8 +1,6 @@ package helper import ( - "strings" - "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/internal" ) @@ -50,7 +48,7 @@ func VerifyCleartextMessageArmored(publicKey, armored string, verifyTime int64) // SignCleartextMessage signs text given a private keyring, canonicalizes and // trims the newlines, and returns the PGP-compliant special armoring. func SignCleartextMessage(keyRing *crypto.KeyRing, text string) (string, error) { - text = canonicalizeAndTrim(text) + text = internal.TrimWhitespace(text) message := crypto.NewPlainMessageFromString(text) signature, err := keyRing.SignDetached(message) @@ -79,12 +77,3 @@ func VerifyCleartextMessage(keyRing *crypto.KeyRing, armored string, verifyTime return message.GetString(), nil } - -// ----- INTERNAL FUNCTIONS ----- - -// canonicalizeAndTrim alters a string canonicalizing and trimming the newlines. -func canonicalizeAndTrim(text string) string { - text = internal.TrimNewlines(text) - text = strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n") - return text -} diff --git a/helper/cleartext_test.go b/helper/cleartext_test.go index 5d8cf89..8452afb 100644 --- a/helper/cleartext_test.go +++ b/helper/cleartext_test.go @@ -2,13 +2,16 @@ package helper import ( "regexp" + "strings" "testing" "github.com/ProtonMail/gopenpgp/v2/crypto" + "github.com/ProtonMail/gopenpgp/v2/internal" "github.com/stretchr/testify/assert" ) -const signedPlainText = "Signed message\n" +const inputPlainText = " Signed message\n \n " +const signedPlainText = " Signed message\n\n" var signedMessageTest = regexp.MustCompile( "(?s)^-----BEGIN PGP SIGNED MESSAGE-----.*-----BEGIN PGP SIGNATURE-----.*-----END PGP SIGNATURE-----$") @@ -18,7 +21,7 @@ func TestSignClearText(t *testing.T) { armored, err := SignCleartextMessageArmored( readTestFile("keyring_privateKey", false), testMailboxPassword, - signedPlainText, + inputPlainText, ) if err != nil { @@ -36,11 +39,17 @@ func TestSignClearText(t *testing.T) { t.Fatal("Cannot verify message:", err) } - assert.Exactly(t, canonicalizeAndTrim(signedPlainText), verified) + assert.Exactly(t, signedPlainText, verified) + + clearTextMessage, err := crypto.NewClearTextMessageFromArmored(armored) + if err != nil { + t.Fatal("Cannot parse message:", err) + } + assert.Exactly(t, canonicalizeAndTrim(inputPlainText), string(clearTextMessage.GetBinary())) } -func TestMessageCanonicalizeAndTrim(t *testing.T) { - text := "Hi \ntest!\r\n\n" - canon := canonicalizeAndTrim(text) - assert.Exactly(t, "Hi\r\ntest!\r\n\r\n", canon) +func canonicalizeAndTrim(text string) string { + text = internal.TrimWhitespace(text) + text = strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n") + return text } diff --git a/internal/common.go b/internal/common.go index d329729..e2c69ad 100644 --- a/internal/common.go +++ b/internal/common.go @@ -7,9 +7,9 @@ import ( "github.com/ProtonMail/gopenpgp/v2/constants" ) -// TrimNewlines removes whitespace from the end of each line of the input +// TrimWhitespace removes whitespace from the end of each line of the input // string. -func TrimNewlines(input string) string { +func TrimWhitespace(input string) string { var re = regexp.MustCompile(`(?m)[ \t]*$`) return re.ReplaceAllString(input, "") }