302 lines
9.5 KiB
Go
302 lines
9.5 KiB
Go
package meowlib
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"time"
|
|
|
|
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
|
"github.com/ProtonMail/gopenpgp/v2/helper"
|
|
"github.com/pkg/errors"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
type KeyPair struct {
|
|
Public string `json:"public,omitempty"`
|
|
Private string `json:"private,omitempty"`
|
|
Generated time.Time `json:"generated,omitempty"`
|
|
}
|
|
|
|
type KeysArray []KeyPair
|
|
|
|
func NewKeyPair() KeyPair {
|
|
var kp KeyPair
|
|
keys, err := crypto.GenerateKey("name", "mail", "x25519", 0)
|
|
if err != nil {
|
|
log.Error().Msg("Key generation failed")
|
|
}
|
|
kp.Generated = time.Now()
|
|
pub, err := keys.GetArmoredPublicKey()
|
|
if err != nil {
|
|
log.Error().Msg("Public key extraction failed")
|
|
}
|
|
kp.Public = base64.StdEncoding.EncodeToString([]byte(pub))
|
|
priv, err := keys.Armor()
|
|
if err != nil {
|
|
log.Error().Msg("Private key extraction failed")
|
|
}
|
|
kp.Private = base64.StdEncoding.EncodeToString([]byte(priv))
|
|
return kp
|
|
}
|
|
|
|
func (Kp *KeyPair) GetCryptoKeyObject() *crypto.Key {
|
|
priv, err := base64.StdEncoding.DecodeString(Kp.Private)
|
|
if err != nil {
|
|
log.Error().Msg("Create key from armoured b64 failed")
|
|
}
|
|
key, err := crypto.NewKeyFromArmored(string(priv))
|
|
if err != nil {
|
|
log.Error().Msg("Create key from armoured failed")
|
|
}
|
|
return key
|
|
}
|
|
|
|
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")
|
|
}
|
|
armor, err := helper.EncryptBinaryMessageArmored(string(pub), data)
|
|
if err != nil {
|
|
log.Error().Msg("Message encryption failed")
|
|
}
|
|
return []byte(armor), err
|
|
}
|
|
|
|
func AsymDecryptArmored(PrivateKey string, data []byte) ([]byte, error) {
|
|
priv, err := base64.StdEncoding.DecodeString(PrivateKey)
|
|
if err != nil {
|
|
log.Error().Msg("Message decryption b64 failed")
|
|
}
|
|
decrypted, err := helper.DecryptBinaryMessageArmored(string(priv), nil, string(data))
|
|
if err != nil {
|
|
log.Error().Msg("Message decryption failed")
|
|
}
|
|
return []byte(decrypted), err
|
|
}
|
|
|
|
func AsymEncryptAndSign_helpers(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 AsymDecryptAndCheck_helpers(MyPrivateEncryptionKey string, MyContactPublicKey string, data []byte, Signature []byte) (DecryptedMessage []byte, err error) {
|
|
priv, err := base64.StdEncoding.DecodeString(MyPrivateEncryptionKey)
|
|
if err != nil {
|
|
log.Error().Msg("Message decryption and sign b64 failed")
|
|
}
|
|
pub, 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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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")
|
|
}
|
|
priv, err := base64.StdEncoding.DecodeString(PrivateSignatureKey)
|
|
if err != nil {
|
|
log.Error().Msg("Message encryption and sign b64 failed")
|
|
}
|
|
ciphertext, signature, err := encryptAndSignMessage(string(pub), string(priv), crypto.NewPlainMessage(data))
|
|
if err != nil {
|
|
log.Error().Msg("Message encryption failed")
|
|
return nil, nil, err
|
|
}
|
|
return ciphertext.GetBinary(), signature, err
|
|
}
|
|
|
|
func AsymDecryptAndCheck(MyPrivateEncryptionKey string, MyContactPublicKey string, data []byte, Signature []byte) (DecryptedMessage []byte, err error) {
|
|
priv, err := base64.StdEncoding.DecodeString(MyPrivateEncryptionKey)
|
|
if err != nil {
|
|
log.Error().Msg("Message decryption and sign b64 failed")
|
|
}
|
|
pub, err := base64.StdEncoding.DecodeString(MyContactPublicKey)
|
|
if err != nil {
|
|
log.Error().Msg("Message decryption and sign b64 failed")
|
|
}
|
|
DecryptedMessage, err = decryptAndCheckMessage(string(pub), string(priv), crypto.NewPGPMessage(data), crypto.NewPGPSignature(Signature))
|
|
if err != nil {
|
|
log.Error().Msg("Message decryption and sign failed")
|
|
}
|
|
return DecryptedMessage, err
|
|
}
|
|
|
|
func encryptAndSignMessage(pub string, priv string, message *crypto.PlainMessage) (*crypto.PGPMessage, []byte, error) {
|
|
var privateKeyObj, unlockedKeyObj *crypto.Key
|
|
var privateKeyRing *crypto.KeyRing
|
|
publicKeyRing, err := createPublicKeyRing(pub)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, nil, errors.Wrap(err, "gopenpgp: unable to encrypt message")
|
|
}
|
|
|
|
if privateKeyObj, err = crypto.NewKeyFromArmored(priv); err != nil {
|
|
return nil, nil, errors.Wrap(err, "gopenpgp: unable to parse private key")
|
|
}
|
|
|
|
if unlockedKeyObj, err = privateKeyObj.Unlock(nil); err != nil {
|
|
return nil, nil, errors.Wrap(err, "gopenpgp: unable to unlock key")
|
|
}
|
|
defer unlockedKeyObj.ClearPrivateParams()
|
|
|
|
if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil {
|
|
return nil, nil, errors.Wrap(err, "gopenpgp: unable to create private keyring")
|
|
}
|
|
|
|
ciphertext, err := publicKeyRing.Encrypt(message, nil)
|
|
if err != nil {
|
|
return nil, nil, errors.Wrap(err, "gopenpgp: unable to encrypt message")
|
|
}
|
|
|
|
signature, err := privateKeyRing.SignDetached(message)
|
|
if err != nil {
|
|
return nil, nil, errors.Wrap(err, "gopenpgp: unable to encrypt message")
|
|
}
|
|
return ciphertext, signature.GetBinary(), nil
|
|
}
|
|
|
|
func decryptAndCheckMessage(pub string, priv string, message *crypto.PGPMessage, signature *crypto.PGPSignature) ([]byte, error) {
|
|
var privateKeyObj, unlockedKeyObj *crypto.Key
|
|
var privateKeyRing *crypto.KeyRing
|
|
publicKeyRing, err := createPublicKeyRing(pub)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt message")
|
|
}
|
|
|
|
if privateKeyObj, err = crypto.NewKeyFromArmored(priv); err != nil {
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to parse private key")
|
|
}
|
|
|
|
if unlockedKeyObj, err = privateKeyObj.Unlock(nil); err != nil {
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to unlock key")
|
|
}
|
|
defer unlockedKeyObj.ClearPrivateParams()
|
|
|
|
if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil {
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to create private keyring")
|
|
}
|
|
|
|
plainmessage, err := privateKeyRing.Decrypt(message, nil, 0)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to decrypt message")
|
|
}
|
|
|
|
err = publicKeyRing.VerifyDetached(plainmessage, signature, crypto.GetUnixTime())
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to check message signature")
|
|
}
|
|
return plainmessage.GetBinary(), nil
|
|
}
|