diff --git a/asymcrypt.go b/asymcrypt.go index 3f520a5..9175365 100644 --- a/asymcrypt.go +++ b/asymcrypt.go @@ -6,6 +6,7 @@ import ( "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/helper" + "github.com/pkg/errors" "github.com/rs/zerolog/log" ) @@ -49,7 +50,33 @@ func (Kp *KeyPair) GetCryptoKeyObject() *crypto.Key { return key } -func Encrypt(PublicKey string, data []byte) ([]byte, error) { +func AsymEncrypt(publicKey string, data []byte) ([]byte, error) { + pub, err := base64.StdEncoding.DecodeString(publicKey) + if err != nil { + log.Error().Msg("Message encryption b64 failed") + } + ciphertext, err := encryptMessage(string(pub), crypto.NewPlainMessage(data)) + if err != nil { + log.Error().Msg("Message encryption failed") + return nil, err + } + + return ciphertext.GetBinary(), err +} + +func AsymDecrypt(PrivateKey string, data []byte) ([]byte, error) { + priv, err := base64.StdEncoding.DecodeString(PrivateKey) + if err != nil { + log.Error().Msg("Message decryption b64 failed") + } + decrypted, err := decryptMessage(string(priv), nil, crypto.NewPGPMessage(data)) + if err != nil { + log.Error().Msg("Message decryption failed") + } + return decrypted.GetBinary(), err +} + +func AsymEncryptArmored(PublicKey string, data []byte) ([]byte, error) { pub, err := base64.StdEncoding.DecodeString(PublicKey) if err != nil { log.Error().Msg("Message encryption b64 failed") @@ -61,7 +88,7 @@ func Encrypt(PublicKey string, data []byte) ([]byte, error) { return []byte(armor), err } -func Decrypt(PrivateKey string, data []byte) ([]byte, error) { +func AsymDecryptArmored(PrivateKey string, data []byte) ([]byte, error) { priv, err := base64.StdEncoding.DecodeString(PrivateKey) if err != nil { log.Error().Msg("Message decryption b64 failed") @@ -73,7 +100,7 @@ func Decrypt(PrivateKey string, data []byte) ([]byte, error) { return []byte(decrypted), err } -func EncryptAndSign(PublicEncryptionKey string, PrivateSignatureKey string, data []byte) ([]byte, []byte, error) { +func AsymEncryptAndSign(PublicEncryptionKey string, PrivateSignatureKey string, data []byte) ([]byte, []byte, error) { pub, err := base64.StdEncoding.DecodeString(PublicEncryptionKey) if err != nil { log.Error().Msg("Message encryption and sign b64 failed") @@ -89,7 +116,7 @@ func EncryptAndSign(PublicEncryptionKey string, PrivateSignatureKey string, data return []byte(encrypted), []byte(signature), err } -func DecryptAndCheck(MyPrivateEncryptionKey string, MyContactPublicKey string, data []byte, Signature []byte) (DecryptedMessage []byte, err error) { +func AsymDecryptAndCheck(MyPrivateEncryptionKey string, MyContactPublicKey string, data []byte, Signature []byte) (DecryptedMessage []byte, err error) { pub, err := base64.StdEncoding.DecodeString(MyPrivateEncryptionKey) if err != nil { log.Error().Msg("Message decryption and sign b64 failed") @@ -104,3 +131,64 @@ func DecryptAndCheck(MyPrivateEncryptionKey string, MyContactPublicKey string, d } return DecryptedMessage, err } + +func encryptMessage(key string, message *crypto.PlainMessage) (*crypto.PGPMessage, error) { + publicKeyRing, err := createPublicKeyRing(key) + if err != nil { + return nil, err + } + + ciphertext, err := publicKeyRing.Encrypt(message, nil) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to encrypt message") + } + + return ciphertext, nil +} + +func decryptMessage(privateKey string, passphrase []byte, ciphertext *crypto.PGPMessage) (*crypto.PlainMessage, error) { + privateKeyObj, err := crypto.NewKeyFromArmored(privateKey) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to parse the private key") + } + + privateKeyUnlocked, err := privateKeyObj.Unlock(passphrase) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to unlock key") + } + + defer privateKeyUnlocked.ClearPrivateParams() + + privateKeyRing, err := crypto.NewKeyRing(privateKeyUnlocked) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to create the private key ring") + } + + message, err := privateKeyRing.Decrypt(ciphertext, nil, 0) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to decrypt message") + } + + return message, nil +} + +func createPublicKeyRing(publicKey string) (*crypto.KeyRing, error) { + publicKeyObj, err := crypto.NewKeyFromArmored(publicKey) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to parse public key") + } + + if publicKeyObj.IsPrivate() { + publicKeyObj, err = publicKeyObj.ToPublic() + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to extract public key from private key") + } + } + + publicKeyRing, err := crypto.NewKeyRing(publicKeyObj) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to create new keyring") + } + + return publicKeyRing, nil +} diff --git a/asymcrypt_test.go b/asymcrypt_test.go index d2c00f9..167389c 100644 --- a/asymcrypt_test.go +++ b/asymcrypt_test.go @@ -29,28 +29,29 @@ func TestGetKey(t *testing.T) { //} } -func TestEncryptDecrypt(t *testing.T) { +func TestAsymEncryptDecrypt(t *testing.T) { kp := NewKeyPair() - foo := "totoaimelesfrites!" - encMess, err := Encrypt(kp.Public, []byte(foo)) + foo := []byte("!#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~") + encMess, err := AsymEncrypt(kp.Public, foo) if err != nil { log.Println(err.Error()) } - decMess, err2 := Decrypt(kp.Private, encMess) + println("len enc:", len(encMess)) + decMess, err2 := AsymDecrypt(kp.Private, encMess) if err2 != nil { log.Println(err2.Error()) } assert.Equal(t, foo, decMess, "The two messages should be the same.") } -func TestEncryptDecryptSigned(t *testing.T) { +func TestAsymEncryptDecryptSigned(t *testing.T) { kp := NewKeyPair() - foo := "totoaimelesfrites!" - encMess, sign, err := EncryptAndSign(kp.Public, kp.Private, []byte(foo)) + foo := "!#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~" + encMess, sign, err := AsymEncryptAndSign(kp.Public, kp.Private, []byte(foo)) if err != nil { log.Println(err.Error()) } - decMess, err2 := DecryptAndCheck(kp.Private, kp.Public, encMess, sign) + decMess, err2 := AsymDecryptAndCheck(kp.Private, kp.Public, encMess, sign) if err2 != nil { log.Println(err2.Error()) } diff --git a/client/peer.go b/client/peer.go index 0bdf142..c5a71ed 100644 --- a/client/peer.go +++ b/client/peer.go @@ -55,18 +55,17 @@ func (pl *PeerList) GetFromName(name string) *Peer { // AsymEncryptMessage prepares a message to send to a specific peer contact func (p *Peer) AsymEncryptMessage(Message []byte) (EncryptedMessage []byte, Signature []byte, Servers []*meowlib.Server, err error) { - EncryptedMessage, Signature, err = meowlib.EncryptAndSign(p.Contact.EncryptionPublicKey, p.Me.Private, Message) + EncryptedMessage, Signature, err = meowlib.AsymEncryptAndSign(p.Contact.EncryptionPublicKey, p.Me.Private, Message) if err != nil { fmt.Println(err.Error()) return nil, nil, nil, err } - return EncryptedMessage, Signature, p.Contact.PullServers, err } // AsymDecryptMessage reads a message from a specific peer contact func (p *Peer) AsymDecryptMessage(Message []byte, Signature []byte) (DecryptedMessage []byte, err error) { - DecryptedMessage, err = meowlib.DecryptAndCheck(p.Me.Private, p.Contact.ContactPublicKey, Message, Signature) + DecryptedMessage, err = meowlib.AsymDecryptAndCheck(p.Me.Private, p.Contact.ContactPublicKey, Message, Signature) if err != nil { fmt.Println(err.Error()) return nil, err @@ -101,6 +100,6 @@ func (p *Peer) LoadLastMessages(qty int) { } -func (p *Peer) GetLastMessageUid(msg []byte) { +func (p *Peer) GetLastMessageUuid(msg []byte) { } diff --git a/client/server.go b/client/server.go index ed945a0..e4b34d1 100644 --- a/client/server.go +++ b/client/server.go @@ -37,7 +37,7 @@ func (sl *InternalServerList) AddUrls(urls []string) { // AsymEncryptMessage prepares a message to send to a specific internal server func (ints *InternalServer) AsymEncryptMessage(Message []byte) (EncryptedMessage []byte, Signature []byte, err error) { - EncryptedMessage, Signature, err = meowlib.EncryptAndSign(ints.ServerData.PublicKey, ints.Me.Private, Message) + EncryptedMessage, Signature, err = meowlib.AsymEncryptAndSign(ints.ServerData.PublicKey, ints.Me.Private, Message) if err != nil { fmt.Println(err.Error()) return nil, nil, err @@ -47,7 +47,7 @@ func (ints *InternalServer) AsymEncryptMessage(Message []byte) (EncryptedMessage // AsymDecryptMessage reads a message from a specific internal server func (ints *InternalServer) AsymDecryptMessage(Message []byte, Signature []byte) (DecryptedMessage []byte, err error) { - DecryptedMessage, err = meowlib.DecryptAndCheck(ints.Me.Private, ints.ServerData.PublicKey, Message, Signature) + DecryptedMessage, err = meowlib.AsymDecryptAndCheck(ints.Me.Private, ints.ServerData.PublicKey, Message, Signature) if err != nil { fmt.Println(err.Error()) return nil, err diff --git a/go.mod b/go.mod index 39a1026..66bc9ca 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.16 require ( github.com/ProtonMail/gopenpgp/v2 v2.2.4 github.com/makiuchi-d/gozxing v0.1.1 + github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.25.0 github.com/stretchr/testify v1.4.0 google.golang.org/protobuf v1.28.1 diff --git a/server/identity.go b/server/identity.go index ba7ebe5..22cb531 100644 --- a/server/identity.go +++ b/server/identity.go @@ -53,7 +53,7 @@ func (id *Identity) Save(file string) error { // AsymEncryptMessage prepares a message to send to a specific client contact func (id *Identity) AsymEncryptMessage(ClientPublicKey string, Message []byte) (EncryptedMsg []byte, Signature []byte, err error) { - EncryptedMsg, Signature, err = meowlib.EncryptAndSign(ClientPublicKey, id.ServerKp.Private, Message) + EncryptedMsg, Signature, err = meowlib.AsymEncryptAndSign(ClientPublicKey, id.ServerKp.Private, Message) if err != nil { fmt.Println(err.Error()) return nil, nil, err @@ -63,7 +63,7 @@ func (id *Identity) AsymEncryptMessage(ClientPublicKey string, Message []byte) ( // AsymDecryptMessage reads a message from a specific client contact func (id *Identity) AsymDecryptMessage(ClientPublicKey string, Message []byte, Signature []byte) (DecryptedMsg []byte, err error) { - DecryptedMsg, err = meowlib.DecryptAndCheck(id.ServerKp.Private, ClientPublicKey, Message, Signature) + DecryptedMsg, err = meowlib.AsymDecryptAndCheck(id.ServerKp.Private, ClientPublicKey, Message, Signature) if err != nil { fmt.Println(err.Error()) return nil, err diff --git a/server/server.go b/server/server.go index da6290b..2c8dc47 100644 --- a/server/server.go +++ b/server/server.go @@ -36,7 +36,7 @@ func (sl *InternalServerList) AddUrls(urls []string) { // AsymEncryptMessage prepares a message to send to a specific internal server func (ints *InternalServer) AsymEncryptMessage(Message []byte) (EncryptedMsg []byte, Signature []byte, err error) { - EncryptedMsg, Signature, err = meowlib.EncryptAndSign(ints.ServerData.PublicKey, ints.Me.Private, Message) + EncryptedMsg, Signature, err = meowlib.AsymEncryptAndSign(ints.ServerData.PublicKey, ints.Me.Private, Message) if err != nil { fmt.Println(err.Error()) return nil, nil, err @@ -46,7 +46,7 @@ func (ints *InternalServer) AsymEncryptMessage(Message []byte) (EncryptedMsg []b // AsymDecryptMessage reads a message from a specific internal server func (ints *InternalServer) AsymDecryptMessage(Message []byte, Signature []byte) (DecryptedMsg []byte, err error) { - DecryptedMsg, err = meowlib.DecryptAndCheck(ints.Me.Private, ints.ServerData.PublicKey, Message, Signature) + DecryptedMsg, err = meowlib.AsymDecryptAndCheck(ints.Me.Private, ints.ServerData.PublicKey, Message, Signature) if err != nil { fmt.Println(err.Error()) return nil, err diff --git a/symcrypt.go b/symcrypt.go new file mode 100644 index 0000000..d8d9505 --- /dev/null +++ b/symcrypt.go @@ -0,0 +1,67 @@ +package meowlib + +import ( + "encoding/base64" + + "github.com/ProtonMail/gopenpgp/v2/crypto" + "github.com/ProtonMail/gopenpgp/v2/helper" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" +) + +func SymEncrypt(password string, data []byte) ([]byte, error) { + var pgpMessage *crypto.PGPMessage + var err error + var message = crypto.NewPlainMessage(data) + + pgpMessage, err = crypto.EncryptMessageWithPassword(message, []byte(password)) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to encrypt message with password") + } + return pgpMessage.GetBinary(), nil +} + +func SymDecrypt(password string, data []byte) ([]byte, error) { + var message *crypto.PlainMessage + var pgpMessage *crypto.PGPMessage + var err error + + pgpMessage = crypto.NewPGPMessage(data) + message, err = crypto.DecryptMessageWithPassword(pgpMessage, []byte(password)) + if err != nil { + return nil, errors.Wrap(err, "gopenpgp: unable to decrypt message with password") + } + return message.GetBinary(), nil +} + +func SymEncryptAndSign(PublicEncryptionKey string, PrivateSignatureKey string, data []byte) ([]byte, []byte, error) { + pub, err := base64.StdEncoding.DecodeString(PublicEncryptionKey) + if err != nil { + log.Error().Msg("Message encryption and sign b64 failed") + } + priv, err := base64.StdEncoding.DecodeString(PrivateSignatureKey) + if err != nil { + log.Error().Msg("Message encryption and sign b64 failed") + } + encrypted, signature, err := helper.EncryptSignBinaryDetached(string(pub), string(priv), nil, data) + if err != nil { + log.Error().Msg("Message encryption and sign failed") + } + return []byte(encrypted), []byte(signature), err +} + +func SymDecryptAndCheck(MyPrivateEncryptionKey string, MyContactPublicKey string, data []byte, Signature []byte) (DecryptedMessage []byte, err error) { + pub, err := base64.StdEncoding.DecodeString(MyPrivateEncryptionKey) + if err != nil { + log.Error().Msg("Message decryption and sign b64 failed") + } + priv, err := base64.StdEncoding.DecodeString(MyContactPublicKey) + if err != nil { + log.Error().Msg("Message decryption and sign b64 failed") + } + DecryptedMessage, err = helper.DecryptVerifyBinaryDetached(string(pub), string(priv), nil, data, string(Signature)) + if err != nil { + log.Error().Msg("Message decryption and sign failed") + } + return DecryptedMessage, err +} diff --git a/symcrypt_test.go b/symcrypt_test.go new file mode 100644 index 0000000..0dba90c --- /dev/null +++ b/symcrypt_test.go @@ -0,0 +1,21 @@ +package meowlib + +import ( + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSymEncryptDecrypt(t *testing.T) { + foo := []byte("!#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~") + encMess, err := SymEncrypt("mysecretpassword", foo) + if err != nil { + log.Println(err.Error()) + } + decMess, err2 := SymDecrypt("mysecretpassword", encMess) + if err2 != nil { + log.Println(err2.Error()) + } + assert.Equal(t, foo, decMess, "The two messages should be the same.") +}