diff --git a/crypto/keyring_message.go b/crypto/keyring_message.go index 0a2af8f..81497e9 100644 --- a/crypto/keyring_message.go +++ b/crypto/keyring_message.go @@ -47,7 +47,7 @@ func (keyRing *KeyRing) SignDetached(message *PlainMessage) (*PGPSignature, erro config := &packet.Config{DefaultHash: crypto.SHA512, Time: getTimeGenerator()} var outBuf bytes.Buffer - //sign bin + // sign bin if err := openpgp.DetachSign(&outBuf, signEntity, message.NewReader(), config); err != nil { return nil, err } diff --git a/helper/cleartext.go b/helper/cleartext.go index c48c6ca..9d477f5 100644 --- a/helper/cleartext.go +++ b/helper/cleartext.go @@ -85,6 +85,6 @@ func VerifyCleartextMessage(keyRing *crypto.KeyRing, armored string, verifyTime // canonicalizeAndTrim alters a string canonicalizing and trimming the newlines. func canonicalizeAndTrim(text string) string { text = internal.TrimNewlines(text) - text = strings.Replace(strings.Replace(text, "\r\n", "\n", -1), "\n", "\r\n", -1) + text = strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n") return text } diff --git a/helper/helper.go b/helper/helper.go index b189b26..da13d7d 100644 --- a/helper/helper.go +++ b/helper/helper.go @@ -52,23 +52,13 @@ func EncryptMessageArmored(key, plaintext string) (string, error) { func EncryptSignMessageArmored( publicKey, privateKey string, passphrase []byte, plaintext string, ) (ciphertext string, err error) { - var publicKeyObj, privateKeyObj, unlockedKeyObj *crypto.Key + var privateKeyObj, unlockedKeyObj *crypto.Key var publicKeyRing, privateKeyRing *crypto.KeyRing var pgpMessage *crypto.PGPMessage var message = crypto.NewPlainMessageFromString(plaintext) - if publicKeyObj, err = crypto.NewKeyFromArmored(publicKey); err != nil { - return "", err - } - if publicKeyObj.IsPrivate() { - publicKeyObj, err = publicKeyObj.ToPublic() - if err != nil { - return "", err - } - } - - if publicKeyRing, err = crypto.NewKeyRing(publicKeyObj); err != nil { + if publicKeyRing, err = createPublicKeyRing(publicKey); err != nil { return "", err } @@ -116,22 +106,12 @@ func DecryptMessageArmored( func DecryptVerifyMessageArmored( publicKey, privateKey string, passphrase []byte, ciphertext string, ) (plaintext string, err error) { - var publicKeyObj, privateKeyObj, unlockedKeyObj *crypto.Key + var privateKeyObj, unlockedKeyObj *crypto.Key var publicKeyRing, privateKeyRing *crypto.KeyRing var pgpMessage *crypto.PGPMessage var message *crypto.PlainMessage - if publicKeyObj, err = crypto.NewKeyFromArmored(publicKey); err != nil { - return "", err - } - if publicKeyObj.IsPrivate() { - publicKeyObj, err = publicKeyObj.ToPublic() - if err != nil { - return "", err - } - } - - if publicKeyRing, err = crypto.NewKeyRing(publicKeyObj); err != nil { + if publicKeyRing, err = createPublicKeyRing(publicKey); err != nil { return "", err } @@ -256,20 +236,79 @@ func DecryptVerifyArmoredDetached( return message.GetBinary(), nil } -func encryptMessageArmored(key string, message *crypto.PlainMessage) (string, error) { - publicKey, err := crypto.NewKeyFromArmored(key) - if publicKey.IsPrivate() { - publicKey, err = publicKey.ToPublic() - if err != nil { - return "", err - } +// EncryptAttachmentWithKey encrypts a binary file +// Using a given armored public key. +func EncryptAttachmentWithKey( + publicKey string, + filename string, + plainData []byte, +) (message *crypto.PGPSplitMessage, err error) { + publicKeyRing, err := createPublicKeyRing(publicKey) + if err != nil { + return nil, err } + return EncryptAttachment(plainData, filename, publicKeyRing) +} + +// DecryptAttachmentWithKey decrypts a binary file +// Using a given armored private key and its passphrase. +func DecryptAttachmentWithKey( + privateKey string, + passphrase, keyPacket, dataPacket []byte, +) (attachment []byte, err error) { + message, err := decryptAttachment(privateKey, passphrase, keyPacket, dataPacket) + if err != nil { + return nil, err + } + return message.GetBinary(), nil +} + +// EncryptSessionKey encrypts a session key +// using a given armored public key. +func EncryptSessionKey( + publicKey string, + sessionKey *crypto.SessionKey, +) (encryptedSessionKey []byte, err error) { + publicKeyRing, err := createPublicKeyRing(publicKey) + if err != nil { + return nil, err + } + encryptedSessionKey, err = publicKeyRing.EncryptSessionKey(sessionKey) + return +} + +// DecryptSessionKey decrypts a session key +// using a given armored private key +// and its passphrase. +func DecryptSessionKey( + privateKey string, + passphrase, encryptedSessionKey []byte, +) (sessionKey *crypto.SessionKey, err error) { + privateKeyObj, err := crypto.NewKeyFromArmored(privateKey) if err != nil { - return "", err + return nil, err } - publicKeyRing, err := crypto.NewKeyRing(publicKey) + privateKeyUnlocked, err := privateKeyObj.Unlock(passphrase) + + if err != nil { + return nil, err + } + + defer privateKeyUnlocked.ClearPrivateParams() + + privateKeyRing, err := crypto.NewKeyRing(privateKeyUnlocked) + + if err != nil { + return nil, err + } + sessionKey, err = privateKeyRing.DecryptSessionKey(encryptedSessionKey) + return +} + +func encryptMessageArmored(key string, message *crypto.PlainMessage) (string, error) { + publicKeyRing, err := createPublicKeyRing(key) if err != nil { return "", err @@ -363,20 +402,12 @@ func signDetachedArmored(privateKey string, passphrase []byte, message *crypto.P } func verifyDetachedArmored(publicKey string, message *crypto.PlainMessage, armoredSignature string) (check bool, err error) { - var publicKeyObj *crypto.Key var publicKeyRing *crypto.KeyRing var detachedSignature *crypto.PGPSignature + // We prepare the public key for signature verification - if publicKeyObj, err = crypto.NewKeyFromArmored(publicKey); err != nil { - return false, err - } - if publicKeyObj.IsPrivate() { - publicKeyObj, err = publicKeyObj.ToPublic() - if err != nil { - return false, err - } - } - if publicKeyRing, err = crypto.NewKeyRing(publicKeyObj); err != nil { + publicKeyRing, err = createPublicKeyRing(publicKey) + if err != nil { return false, err } @@ -418,3 +449,23 @@ func decryptAttachment( return message, nil } + +func createPublicKeyRing( + publicKey string, +) (publicKeyRing *crypto.KeyRing, err error) { + publicKeyObj, err := crypto.NewKeyFromArmored(publicKey) + + if err != nil { + return nil, err + } + + if publicKeyObj.IsPrivate() { + publicKeyObj, err = publicKeyObj.ToPublic() + if err != nil { + return nil, err + } + } + + publicKeyRing, err = crypto.NewKeyRing(publicKeyObj) + return +} diff --git a/helper/helper_test.go b/helper/helper_test.go index a4146fb..1bf518e 100644 --- a/helper/helper_test.go +++ b/helper/helper_test.go @@ -216,3 +216,78 @@ func TestEncryptSignArmoredDetached(t *testing.T) { t.Fatal("Expected an error while decrypting and verifying with a wrong signature") } } + +func TestEncryptDecryptAttachmenWithKey(t *testing.T) { + plainData := []byte("Secret message") + privateKeyString := readTestFile("keyring_privateKey", false) + privateKey, err := crypto.NewKeyFromArmored(privateKeyString) + if err != nil { + t.Fatal("Error reading the test private key: ", err) + } + publicKeyString, err := privateKey.GetArmoredPublicKey() + if err != nil { + t.Fatal("Error reading the test public key: ", err) + } + pgpSplitMessage, err := EncryptAttachmentWithKey( + publicKeyString, + "test_filename", + plainData, + ) + + if err != nil { + t.Fatal("Expected no error while encrypting, got:", err) + } + + decrypted, err := DecryptAttachmentWithKey( + privateKeyString, + testMailboxPassword, + pgpSplitMessage.KeyPacket, + pgpSplitMessage.DataPacket, + ) + + if err != nil { + t.Fatal("Expected no error while decrypting, got:", err) + } + + if !bytes.Equal(decrypted, plainData) { + t.Error("Decrypted attachment is not equal to the original attachment") + } +} + +func TestEncryptDecryptSessionKey(t *testing.T) { + privateKeyString := readTestFile("keyring_privateKey", false) + privateKey, err := crypto.NewKeyFromArmored(privateKeyString) + if err != nil { + t.Fatal("Error reading the test private key: ", err) + } + publicKeyString, err := privateKey.GetArmoredPublicKey() + if err != nil { + t.Fatal("Error reading the test public key: ", err) + } + + sessionKey, err := crypto.GenerateSessionKeyAlgo("aes256") + + if err != nil { + t.Fatal("Expected no error while generating the session key, got:", err) + } + + encrypted, err := EncryptSessionKey(publicKeyString, sessionKey) + + if err != nil { + t.Fatal("Expected no error while encrypting session key, got:", err) + } + + decryptedSessionKey, err := DecryptSessionKey( + privateKeyString, + testMailboxPassword, + encrypted, + ) + + if err != nil { + t.Fatal("Expected no error while decrypting session key, got:", err) + } + + if decryptedSessionKey.GetBase64Key() != sessionKey.GetBase64Key() { + t.Error("Decrypted session key is not equal to the original session key") + } +} diff --git a/helper/mobile.go b/helper/mobile.go index ab73335..33004bb 100644 --- a/helper/mobile.go +++ b/helper/mobile.go @@ -84,8 +84,8 @@ type EncryptSignArmoredDetachedMobileResult struct { Ciphertext, Signature string } -//EncryptSignArmoredDetachedMobile wraps the EncryptSignArmoredDetached method -//to have only one return argument for mobile. +// EncryptSignArmoredDetachedMobile wraps the EncryptSignArmoredDetached method +// to have only one return argument for mobile. func EncryptSignArmoredDetachedMobile( publicKey, privateKey string, passphrase, plainData []byte,