2019-12-27 19:35:43 +01:00
|
|
|
package crypto
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"io"
|
2020-10-12 18:45:57 +02:00
|
|
|
"time"
|
2019-12-27 19:35:43 +01:00
|
|
|
|
|
|
|
|
"golang.org/x/crypto/openpgp"
|
|
|
|
|
"golang.org/x/crypto/openpgp/packet"
|
|
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
)
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// EncryptMessageWithPassword encrypts a PlainMessage to PGPMessage with a
|
|
|
|
|
// SymmetricKey.
|
|
|
|
|
// * message : The plain data as a PlainMessage.
|
|
|
|
|
// * password: A password that will be derived into an encryption key.
|
|
|
|
|
// * output : The encrypted data as PGPMessage.
|
2019-12-27 19:35:43 +01:00
|
|
|
func EncryptMessageWithPassword(message *PlainMessage, password []byte) (*PGPMessage, error) {
|
2020-10-12 18:45:57 +02:00
|
|
|
encrypted, err := passwordEncrypt(message, password)
|
2019-12-27 19:35:43 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NewPGPMessage(encrypted), nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// DecryptMessageWithPassword decrypts password protected pgp binary messages.
|
|
|
|
|
// * encrypted: The encrypted data as PGPMessage.
|
|
|
|
|
// * password: A password that will be derived into an encryption key.
|
|
|
|
|
// * output: The decrypted data as PlainMessage.
|
2019-12-27 19:35:43 +01:00
|
|
|
func DecryptMessageWithPassword(message *PGPMessage, password []byte) (*PlainMessage, error) {
|
2020-10-12 18:45:57 +02:00
|
|
|
return passwordDecrypt(message.NewReader(), password)
|
2019-12-27 19:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DecryptSessionKeyWithPassword decrypts the binary symmetrically encrypted
|
|
|
|
|
// session key packet and returns the session key.
|
|
|
|
|
func DecryptSessionKeyWithPassword(keyPacket, password []byte) (*SessionKey, error) {
|
|
|
|
|
keyReader := bytes.NewReader(keyPacket)
|
|
|
|
|
packets := packet.NewReader(keyReader)
|
|
|
|
|
|
|
|
|
|
var symKeys []*packet.SymmetricKeyEncrypted
|
|
|
|
|
for {
|
|
|
|
|
var p packet.Packet
|
|
|
|
|
var err error
|
|
|
|
|
if p, err = packets.Next(); err != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if p, ok := p.(*packet.SymmetricKeyEncrypted); ok {
|
|
|
|
|
symKeys = append(symKeys, p)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try the symmetric passphrase first
|
|
|
|
|
if len(symKeys) != 0 && password != nil {
|
|
|
|
|
for _, s := range symKeys {
|
|
|
|
|
key, cipherFunc, err := s.Decrypt(password)
|
|
|
|
|
if err == nil {
|
2020-07-20 11:43:36 +02:00
|
|
|
sk := &SessionKey{
|
2019-12-27 19:35:43 +01:00
|
|
|
Key: key,
|
|
|
|
|
Algo: getAlgo(cipherFunc),
|
2020-07-20 11:43:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = sk.checkSize(); err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to decrypt session key with password")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sk, nil
|
2019-12-27 19:35:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-29 17:23:16 +02:00
|
|
|
return nil, errors.New("gopenpgp: unable to decrypt any packet")
|
2019-12-27 19:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EncryptSessionKeyWithPassword encrypts the session key with the password and
|
|
|
|
|
// returns a binary symmetrically encrypted session key packet.
|
|
|
|
|
func EncryptSessionKeyWithPassword(sk *SessionKey, password []byte) ([]byte, error) {
|
|
|
|
|
outbuf := &bytes.Buffer{}
|
|
|
|
|
|
|
|
|
|
cf, err := sk.GetCipherFunc()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key with password")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(password) == 0 {
|
|
|
|
|
return nil, errors.New("gopenpgp: password can't be empty")
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-20 11:43:36 +02:00
|
|
|
if err = sk.checkSize(); err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key with password")
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-27 19:35:43 +01:00
|
|
|
config := &packet.Config{
|
|
|
|
|
DefaultCipher: cf,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = packet.SerializeSymmetricKeyEncryptedReuseKey(outbuf, sk.Key, password, config)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key with password")
|
|
|
|
|
}
|
|
|
|
|
return outbuf.Bytes(), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----- INTERNAL FUNCTIONS ------
|
|
|
|
|
|
2020-10-12 18:45:57 +02:00
|
|
|
func passwordEncrypt(message *PlainMessage, password []byte) ([]byte, error) {
|
2019-12-27 19:35:43 +01:00
|
|
|
var outBuf bytes.Buffer
|
|
|
|
|
|
|
|
|
|
config := &packet.Config{
|
2020-08-31 13:42:06 +03:00
|
|
|
DefaultCipher: packet.CipherAES256,
|
|
|
|
|
Time: getTimeGenerator(),
|
2019-12-27 19:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-12 18:45:57 +02:00
|
|
|
hints := &openpgp.FileHints{
|
|
|
|
|
IsBinary: message.IsBinary(),
|
|
|
|
|
FileName: message.GetFilename(),
|
|
|
|
|
ModTime: time.Unix(int64(message.GetTime()), 0),
|
|
|
|
|
}
|
2020-04-27 21:01:23 +02:00
|
|
|
|
|
|
|
|
encryptWriter, err := openpgp.SymmetricallyEncrypt(&outBuf, password, hints, config)
|
2019-12-27 19:35:43 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-10-12 18:45:57 +02:00
|
|
|
_, err = encryptWriter.Write(message.GetBinary())
|
2019-12-27 19:35:43 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = encryptWriter.Close()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return outBuf.Bytes(), nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-12 18:45:57 +02:00
|
|
|
func passwordDecrypt(encryptedIO io.Reader, password []byte) (*PlainMessage, error) {
|
2019-12-27 19:35:43 +01:00
|
|
|
firstTimeCalled := true
|
|
|
|
|
var prompt = func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
|
|
|
|
|
if firstTimeCalled {
|
|
|
|
|
firstTimeCalled = false
|
|
|
|
|
return password, nil
|
|
|
|
|
}
|
|
|
|
|
return nil, errors.New("gopenpgp: wrong password in symmetric decryption")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
config := &packet.Config{
|
|
|
|
|
Time: getTimeGenerator(),
|
|
|
|
|
}
|
2020-09-01 11:07:30 +02:00
|
|
|
|
|
|
|
|
var emptyKeyRing openpgp.EntityList
|
|
|
|
|
md, err := openpgp.ReadMessage(encryptedIO, emptyKeyRing, prompt, config)
|
2019-12-27 19:35:43 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
messageBuf := bytes.NewBuffer(nil)
|
|
|
|
|
_, err = io.Copy(messageBuf, md.UnverifiedBody)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-12 18:45:57 +02:00
|
|
|
return &PlainMessage{
|
|
|
|
|
Data: messageBuf.Bytes(),
|
|
|
|
|
TextType: !md.LiteralData.IsBinary,
|
|
|
|
|
filename: md.LiteralData.FileName,
|
|
|
|
|
time: md.LiteralData.Time,
|
|
|
|
|
}, nil
|
2019-12-27 19:35:43 +01:00
|
|
|
}
|