2018-09-11 11:09:28 +02:00
|
|
|
package crypto
|
2018-06-04 16:05:14 -07:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
2019-06-03 17:00:01 +02:00
|
|
|
"encoding/base64"
|
2019-05-14 16:48:39 +02:00
|
|
|
"errors"
|
2019-05-13 12:42:29 +00:00
|
|
|
"fmt"
|
2018-11-22 10:53:14 +01:00
|
|
|
"io"
|
2018-06-04 16:05:14 -07:00
|
|
|
"io/ioutil"
|
2019-06-03 17:00:01 +02:00
|
|
|
"regexp"
|
|
|
|
|
"runtime"
|
2020-10-12 21:24:33 +02:00
|
|
|
"strings"
|
2020-10-14 18:28:12 +02:00
|
|
|
"time"
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2019-12-27 19:35:43 +01:00
|
|
|
"github.com/ProtonMail/gopenpgp/v2/armor"
|
|
|
|
|
"github.com/ProtonMail/gopenpgp/v2/constants"
|
|
|
|
|
"github.com/ProtonMail/gopenpgp/v2/internal"
|
2019-06-03 17:00:01 +02:00
|
|
|
|
2019-07-02 07:36:02 -07:00
|
|
|
"golang.org/x/crypto/openpgp/clearsign"
|
2019-06-03 17:00:01 +02:00
|
|
|
"golang.org/x/crypto/openpgp/packet"
|
2018-09-11 11:09:28 +02:00
|
|
|
)
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// ---- MODELS -----
|
2018-11-09 02:03:19 +01:00
|
|
|
|
2019-08-29 17:45:13 +02:00
|
|
|
// PlainMessage stores a plain text / unencrypted message.
|
2019-06-03 17:00:01 +02:00
|
|
|
type PlainMessage struct {
|
|
|
|
|
// The content of the message
|
|
|
|
|
Data []byte
|
2020-10-12 18:45:57 +02:00
|
|
|
// If the content is text or binary
|
2019-06-03 17:00:01 +02:00
|
|
|
TextType bool
|
2020-10-12 18:45:57 +02:00
|
|
|
// The file's latest modification time
|
2020-10-13 13:14:09 +02:00
|
|
|
Time uint32
|
2020-10-12 18:45:57 +02:00
|
|
|
// The encrypted message's filename
|
2020-10-13 13:14:09 +02:00
|
|
|
Filename string
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// PGPMessage stores a PGP-encrypted message.
|
|
|
|
|
type PGPMessage struct {
|
|
|
|
|
// The content of the message
|
|
|
|
|
Data []byte
|
|
|
|
|
}
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// PGPSignature stores a PGP-encoded detached signature.
|
|
|
|
|
type PGPSignature struct {
|
|
|
|
|
// The content of the signature
|
|
|
|
|
Data []byte
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// PGPSplitMessage contains a separate session key packet and symmetrically
|
|
|
|
|
// encrypted data packet.
|
|
|
|
|
type PGPSplitMessage struct {
|
|
|
|
|
DataPacket []byte
|
|
|
|
|
KeyPacket []byte
|
|
|
|
|
}
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// A ClearTextMessage is a signed but not encrypted PGP message,
|
2020-05-06 18:50:18 +02:00
|
|
|
// i.e. the ones beginning with -----BEGIN PGP SIGNED MESSAGE-----.
|
2019-07-02 07:36:02 -07:00
|
|
|
type ClearTextMessage struct {
|
2019-12-27 19:35:43 +01:00
|
|
|
Data []byte
|
2019-07-02 07:36:02 -07:00
|
|
|
Signature []byte
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// ---- GENERATORS -----
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// NewPlainMessage generates a new binary PlainMessage ready for encryption,
|
|
|
|
|
// signature, or verification from the unencrypted binary data.
|
|
|
|
|
func NewPlainMessage(data []byte) *PlainMessage {
|
|
|
|
|
return &PlainMessage{
|
2020-04-08 11:11:16 +02:00
|
|
|
Data: clone(data),
|
2019-06-03 17:00:01 +02:00
|
|
|
TextType: false,
|
2020-10-13 13:14:09 +02:00
|
|
|
Time: uint32(GetUnixTime()),
|
2020-10-12 18:45:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPlainMessageFromFile generates a new binary PlainMessage ready for encryption,
|
|
|
|
|
// signature, or verification from the unencrypted binary data.
|
|
|
|
|
// It assigns a filename and a modification time.
|
|
|
|
|
func NewPlainMessageFromFile(data []byte, filename string, time uint32) *PlainMessage {
|
|
|
|
|
return &PlainMessage{
|
|
|
|
|
Data: clone(data),
|
|
|
|
|
TextType: false,
|
2020-10-13 13:14:09 +02:00
|
|
|
Filename: filename,
|
|
|
|
|
Time: time,
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
2019-06-03 17:00:01 +02:00
|
|
|
}
|
2018-11-05 22:55:45 +01:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// NewPlainMessageFromString generates a new text PlainMessage,
|
|
|
|
|
// ready for encryption, signature, or verification from an unencrypted string.
|
|
|
|
|
func NewPlainMessageFromString(text string) *PlainMessage {
|
|
|
|
|
return &PlainMessage{
|
2020-10-12 21:24:33 +02:00
|
|
|
Data: []byte(strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n")),
|
2019-06-03 17:00:01 +02:00
|
|
|
TextType: true,
|
2020-10-13 13:14:09 +02:00
|
|
|
Time: uint32(GetUnixTime()),
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// NewPGPMessage generates a new PGPMessage from the unarmored binary data.
|
|
|
|
|
func NewPGPMessage(data []byte) *PGPMessage {
|
|
|
|
|
return &PGPMessage{
|
2020-04-08 11:11:16 +02:00
|
|
|
Data: clone(data),
|
2019-06-03 17:00:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-05-14 14:42:38 +00:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// NewPGPMessageFromArmored generates a new PGPMessage from an armored string ready for decryption.
|
|
|
|
|
func NewPGPMessageFromArmored(armored string) (*PGPMessage, error) {
|
|
|
|
|
encryptedIO, err := internal.Unarmor(armored)
|
2019-05-14 14:42:38 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
message, err := ioutil.ReadAll(encryptedIO.Body)
|
2018-06-04 16:05:14 -07:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
return &PGPMessage{
|
|
|
|
|
Data: message,
|
|
|
|
|
}, nil
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// NewPGPSplitMessage generates a new PGPSplitMessage from the binary unarmored keypacket,
|
|
|
|
|
// datapacket, and encryption algorithm.
|
|
|
|
|
func NewPGPSplitMessage(keyPacket []byte, dataPacket []byte) *PGPSplitMessage {
|
|
|
|
|
return &PGPSplitMessage{
|
2020-04-08 11:11:16 +02:00
|
|
|
KeyPacket: clone(keyPacket),
|
|
|
|
|
DataPacket: clone(dataPacket),
|
2018-07-31 01:00:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// NewPGPSplitMessageFromArmored generates a new PGPSplitMessage by splitting an armored message into its
|
|
|
|
|
// session key packet and symmetrically encrypted data packet.
|
|
|
|
|
func NewPGPSplitMessageFromArmored(encrypted string) (*PGPSplitMessage, error) {
|
|
|
|
|
message, err := NewPGPMessageFromArmored(encrypted)
|
2018-11-09 02:03:19 +01:00
|
|
|
if err != nil {
|
2019-06-03 17:00:01 +02:00
|
|
|
return nil, err
|
2018-11-09 02:03:19 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
return message.SeparateKeyAndData(len(encrypted), -1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPGPSignature generates a new PGPSignature from the unarmored binary data.
|
|
|
|
|
func NewPGPSignature(data []byte) *PGPSignature {
|
|
|
|
|
return &PGPSignature{
|
2020-04-08 11:11:16 +02:00
|
|
|
Data: clone(data),
|
2018-11-09 02:03:19 +01:00
|
|
|
}
|
2019-06-03 17:00:01 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// NewPGPSignatureFromArmored generates a new PGPSignature from the armored
|
|
|
|
|
// string ready for verification.
|
2019-06-03 17:00:01 +02:00
|
|
|
func NewPGPSignatureFromArmored(armored string) (*PGPSignature, error) {
|
|
|
|
|
encryptedIO, err := internal.Unarmor(armored)
|
2018-06-04 16:05:14 -07:00
|
|
|
if err != nil {
|
2019-06-03 17:00:01 +02:00
|
|
|
return nil, err
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
2019-06-03 17:00:01 +02:00
|
|
|
|
|
|
|
|
signature, err := ioutil.ReadAll(encryptedIO.Body)
|
2018-11-09 02:03:19 +01:00
|
|
|
if err != nil {
|
2019-06-03 17:00:01 +02:00
|
|
|
return nil, err
|
2018-11-09 02:03:19 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
return &PGPSignature{
|
|
|
|
|
Data: signature,
|
|
|
|
|
}, nil
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// NewClearTextMessage generates a new ClearTextMessage from data and
|
|
|
|
|
// signature.
|
2019-07-02 07:36:02 -07:00
|
|
|
func NewClearTextMessage(data []byte, signature []byte) *ClearTextMessage {
|
|
|
|
|
return &ClearTextMessage{
|
2020-04-08 11:11:16 +02:00
|
|
|
Data: clone(data),
|
|
|
|
|
Signature: clone(signature),
|
2019-07-02 07:36:02 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// NewClearTextMessageFromArmored returns the message body and unarmored
|
|
|
|
|
// signature from a clearsigned message.
|
2019-07-02 07:36:02 -07:00
|
|
|
func NewClearTextMessageFromArmored(signedMessage string) (*ClearTextMessage, error) {
|
|
|
|
|
modulusBlock, rest := clearsign.Decode([]byte(signedMessage))
|
|
|
|
|
if len(rest) != 0 {
|
2019-08-29 17:45:13 +02:00
|
|
|
return nil, errors.New("gopenpgp: extra data after modulus")
|
2019-07-02 07:36:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signature, err := ioutil.ReadAll(modulusBlock.ArmoredSignature.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NewClearTextMessage(modulusBlock.Bytes, signature), nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// ---- MODEL METHODS -----
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBinary returns the binary content of the message as a []byte.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PlainMessage) GetBinary() []byte {
|
|
|
|
|
return msg.Data
|
|
|
|
|
}
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetString returns the content of the message as a string.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PlainMessage) GetString() string {
|
2020-10-12 21:24:33 +02:00
|
|
|
return strings.ReplaceAll(string(msg.Data), "\r\n", "\n")
|
2019-06-03 17:00:01 +02:00
|
|
|
}
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBase64 returns the base-64 encoded binary content of the message as a
|
|
|
|
|
// string.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PlainMessage) GetBase64() string {
|
|
|
|
|
return base64.StdEncoding.EncodeToString(msg.Data)
|
|
|
|
|
}
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// NewReader returns a New io.Reader for the binary data of the message.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PlainMessage) NewReader() io.Reader {
|
|
|
|
|
return bytes.NewReader(msg.GetBinary())
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// IsText returns whether the message is a text message.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PlainMessage) IsText() bool {
|
|
|
|
|
return msg.TextType
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// IsBinary returns whether the message is a binary message.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PlainMessage) IsBinary() bool {
|
|
|
|
|
return !msg.TextType
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-14 18:28:12 +02:00
|
|
|
// getFormattedTime returns the message (latest modification) Time as time.Time.
|
|
|
|
|
func (msg *PlainMessage) getFormattedTime() time.Time {
|
|
|
|
|
return time.Unix(int64(msg.Time), 0)
|
2020-10-12 18:45:57 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBinary returns the unarmored binary content of the message as a []byte.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PGPMessage) GetBinary() []byte {
|
|
|
|
|
return msg.Data
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// NewReader returns a New io.Reader for the unarmored binary data of the
|
|
|
|
|
// message.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PGPMessage) NewReader() io.Reader {
|
|
|
|
|
return bytes.NewReader(msg.GetBinary())
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetArmored returns the armored message as a string.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PGPMessage) GetArmored() (string, error) {
|
|
|
|
|
return armor.ArmorWithType(msg.Data, constants.PGPMessageHeader)
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 18:50:18 +02:00
|
|
|
// GetArmoredWithCustomHeaders returns the armored message as a string, with
|
|
|
|
|
// the given headers. Empty parameters are omitted from the headers.
|
|
|
|
|
func (msg *PGPMessage) GetArmoredWithCustomHeaders(comment, version string) (string, error) {
|
|
|
|
|
return armor.ArmorWithTypeAndCustomHeaders(msg.Data, constants.PGPMessageHeader, version, comment)
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-01 10:02:13 +02:00
|
|
|
// GetEncryptionKeyIDs Returns the key IDs of the keys to which the session key is encrypted.
|
|
|
|
|
func (msg *PGPMessage) GetEncryptionKeyIDs() ([]uint64, bool) {
|
2020-07-02 15:55:11 +07:00
|
|
|
packets := packet.NewReader(bytes.NewReader(msg.Data))
|
|
|
|
|
var err error
|
|
|
|
|
var ids []uint64
|
2020-08-26 19:05:06 +03:00
|
|
|
var encryptedKey *packet.EncryptedKey
|
|
|
|
|
Loop:
|
2020-07-02 15:55:11 +07:00
|
|
|
for {
|
|
|
|
|
var p packet.Packet
|
|
|
|
|
if p, err = packets.Next(); err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
2020-08-26 19:05:06 +03:00
|
|
|
switch p := p.(type) {
|
|
|
|
|
case *packet.EncryptedKey:
|
|
|
|
|
encryptedKey = p
|
|
|
|
|
ids = append(ids, encryptedKey.KeyId)
|
|
|
|
|
case *packet.SymmetricallyEncrypted,
|
|
|
|
|
*packet.AEADEncrypted,
|
|
|
|
|
*packet.Compressed,
|
|
|
|
|
*packet.LiteralData:
|
|
|
|
|
break Loop
|
2020-07-02 15:55:11 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if len(ids) > 0 {
|
|
|
|
|
return ids, true
|
|
|
|
|
}
|
|
|
|
|
return ids, false
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-01 10:02:13 +02:00
|
|
|
// GetHexEncryptionKeyIDs Returns the key IDs of the keys to which the session key is encrypted.
|
|
|
|
|
func (msg *PGPMessage) GetHexEncryptionKeyIDs() ([]string, bool) {
|
|
|
|
|
return getHexKeyIDs(msg.GetEncryptionKeyIDs())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetSignatureKeyIDs Returns the key IDs of the keys to which the (readable) signature packets are encrypted to.
|
|
|
|
|
func (msg *PGPMessage) GetSignatureKeyIDs() ([]uint64, bool) {
|
|
|
|
|
return getSignatureKeyIDs(msg.Data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetHexSignatureKeyIDs Returns the key IDs of the keys to which the session key is encrypted.
|
|
|
|
|
func (msg *PGPMessage) GetHexSignatureKeyIDs() ([]string, bool) {
|
|
|
|
|
return getHexKeyIDs(msg.GetSignatureKeyIDs())
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBinaryDataPacket returns the unarmored binary datapacket as a []byte.
|
2019-08-19 12:06:30 +02:00
|
|
|
func (msg *PGPSplitMessage) GetBinaryDataPacket() []byte {
|
2019-06-03 17:00:01 +02:00
|
|
|
return msg.DataPacket
|
|
|
|
|
}
|
2018-11-21 23:44:33 +01:00
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBinaryKeyPacket returns the unarmored binary keypacket as a []byte.
|
2019-08-19 12:06:30 +02:00
|
|
|
func (msg *PGPSplitMessage) GetBinaryKeyPacket() []byte {
|
2019-06-03 17:00:01 +02:00
|
|
|
return msg.KeyPacket
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBinary returns the unarmored binary joined packets as a []byte.
|
2019-08-29 17:45:13 +02:00
|
|
|
func (msg *PGPSplitMessage) GetBinary() []byte {
|
2019-12-27 19:35:43 +01:00
|
|
|
return append(msg.KeyPacket, msg.DataPacket...)
|
2019-08-29 17:45:13 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetArmored returns the armored message as a string, with joined data and key
|
|
|
|
|
// packets.
|
2019-08-29 17:45:13 +02:00
|
|
|
func (msg *PGPSplitMessage) GetArmored() (string, error) {
|
|
|
|
|
return armor.ArmorWithType(msg.GetBinary(), constants.PGPMessageHeader)
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetPGPMessage joins asymmetric session key packet with the symmetric data
|
|
|
|
|
// packet to obtain a PGP message.
|
2019-12-27 19:35:43 +01:00
|
|
|
func (msg *PGPSplitMessage) GetPGPMessage() *PGPMessage {
|
|
|
|
|
return NewPGPMessage(append(msg.KeyPacket, msg.DataPacket...))
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// SeparateKeyAndData returns the first keypacket and the (hopefully unique)
|
|
|
|
|
// dataPacket (not verified).
|
|
|
|
|
// * estimatedLength is the estimate length of the message.
|
|
|
|
|
// * garbageCollector > 0 activates the garbage collector.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int) (outSplit *PGPSplitMessage, err error) {
|
|
|
|
|
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
|
|
|
|
|
packets := packet.NewReader(bytes.NewReader(msg.Data))
|
|
|
|
|
outSplit = &PGPSplitMessage{}
|
|
|
|
|
gcCounter := 0
|
|
|
|
|
|
|
|
|
|
// Store encrypted key and symmetrically encrypted packet separately
|
|
|
|
|
var encryptedKey *packet.EncryptedKey
|
|
|
|
|
for {
|
|
|
|
|
var p packet.Packet
|
|
|
|
|
if p, err = packets.Next(); err == io.EOF {
|
|
|
|
|
err = nil
|
|
|
|
|
break
|
2019-05-14 13:34:42 +00:00
|
|
|
}
|
2019-06-03 17:00:01 +02:00
|
|
|
switch p := p.(type) {
|
|
|
|
|
case *packet.EncryptedKey:
|
|
|
|
|
if encryptedKey != nil && encryptedKey.Key != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
encryptedKey = p
|
|
|
|
|
|
|
|
|
|
case *packet.SymmetricallyEncrypted:
|
2019-12-27 19:35:43 +01:00
|
|
|
// TODO: add support for multiple keypackets
|
2019-06-03 17:00:01 +02:00
|
|
|
var b bytes.Buffer
|
|
|
|
|
// 2^16 is an estimation of the size difference between input and output, the size difference is most probably
|
|
|
|
|
// 16 bytes at a maximum though.
|
|
|
|
|
// We need to avoid triggering a grow from the system as this will allocate too much memory causing problems
|
|
|
|
|
// in low-memory environments
|
|
|
|
|
b.Grow(1<<16 + estimatedLength)
|
|
|
|
|
// empty encoded length + start byte
|
2019-12-27 19:35:43 +01:00
|
|
|
if _, err := b.Write(make([]byte, 6)); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := b.WriteByte(byte(1)); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
actualLength := 1
|
|
|
|
|
block := make([]byte, 128)
|
|
|
|
|
for {
|
|
|
|
|
n, err := p.Contents.Read(block)
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
2019-12-27 19:35:43 +01:00
|
|
|
if _, err := b.Write(block[:n]); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2019-06-03 17:00:01 +02:00
|
|
|
actualLength += n
|
|
|
|
|
gcCounter += n
|
|
|
|
|
if gcCounter > garbageCollector && garbageCollector > 0 {
|
|
|
|
|
runtime.GC()
|
|
|
|
|
gcCounter = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-21 23:44:33 +01:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// quick encoding
|
|
|
|
|
symEncryptedData := b.Bytes()
|
2019-12-27 19:35:43 +01:00
|
|
|
switch {
|
|
|
|
|
case actualLength < 192:
|
2019-06-03 17:00:01 +02:00
|
|
|
symEncryptedData[4] = byte(210)
|
|
|
|
|
symEncryptedData[5] = byte(actualLength)
|
|
|
|
|
symEncryptedData = symEncryptedData[4:]
|
2019-12-27 19:35:43 +01:00
|
|
|
case actualLength < 8384:
|
|
|
|
|
actualLength -= 192
|
2019-06-03 17:00:01 +02:00
|
|
|
symEncryptedData[3] = byte(210)
|
|
|
|
|
symEncryptedData[4] = 192 + byte(actualLength>>8)
|
|
|
|
|
symEncryptedData[5] = byte(actualLength)
|
|
|
|
|
symEncryptedData = symEncryptedData[3:]
|
2019-12-27 19:35:43 +01:00
|
|
|
default:
|
2019-06-03 17:00:01 +02:00
|
|
|
symEncryptedData[0] = byte(210)
|
|
|
|
|
symEncryptedData[1] = byte(255)
|
|
|
|
|
symEncryptedData[2] = byte(actualLength >> 24)
|
|
|
|
|
symEncryptedData[3] = byte(actualLength >> 16)
|
|
|
|
|
symEncryptedData[4] = byte(actualLength >> 8)
|
|
|
|
|
symEncryptedData[5] = byte(actualLength)
|
|
|
|
|
}
|
|
|
|
|
outSplit.DataPacket = symEncryptedData
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if encryptedKey == nil {
|
|
|
|
|
return nil, errors.New("gopenpgp: packets don't include an encrypted key packet")
|
2018-11-21 23:44:33 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := encryptedKey.Serialize(&buf); err != nil {
|
|
|
|
|
return nil, fmt.Errorf("gopenpgp: cannot serialize encrypted key: %v", err)
|
2018-11-21 23:44:33 +01:00
|
|
|
}
|
2019-06-03 17:00:01 +02:00
|
|
|
outSplit.KeyPacket = buf.Bytes()
|
|
|
|
|
|
|
|
|
|
return outSplit, nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBinary returns the unarmored binary content of the signature as a []byte.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PGPSignature) GetBinary() []byte {
|
|
|
|
|
return msg.Data
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetArmored returns the armored signature as a string.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (msg *PGPSignature) GetArmored() (string, error) {
|
|
|
|
|
return armor.ArmorWithType(msg.Data, constants.PGPSignatureHeader)
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-01 10:02:13 +02:00
|
|
|
// GetSignatureKeyIDs Returns the key IDs of the keys to which the (readable) signature packets are encrypted to.
|
|
|
|
|
func (msg *PGPSignature) GetSignatureKeyIDs() ([]uint64, bool) {
|
|
|
|
|
return getSignatureKeyIDs(msg.Data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetHexSignatureKeyIDs Returns the key IDs of the keys to which the session key is encrypted.
|
|
|
|
|
func (msg *PGPSignature) GetHexSignatureKeyIDs() ([]string, bool) {
|
|
|
|
|
return getHexKeyIDs(msg.GetSignatureKeyIDs())
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBinary returns the unarmored signed data as a []byte.
|
2019-07-02 07:36:02 -07:00
|
|
|
func (msg *ClearTextMessage) GetBinary() []byte {
|
|
|
|
|
return msg.Data
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetString returns the unarmored signed data as a string.
|
2019-07-02 07:36:02 -07:00
|
|
|
func (msg *ClearTextMessage) GetString() string {
|
|
|
|
|
return string(msg.Data)
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetBinarySignature returns the unarmored binary signature as a []byte.
|
2019-08-19 12:06:30 +02:00
|
|
|
func (msg *ClearTextMessage) GetBinarySignature() []byte {
|
2019-07-02 07:36:02 -07:00
|
|
|
return msg.Signature
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 13:55:36 +02:00
|
|
|
// GetArmored armors plaintext and signature with the PGP SIGNED MESSAGE
|
|
|
|
|
// armoring.
|
2019-07-02 07:36:02 -07:00
|
|
|
func (msg *ClearTextMessage) GetArmored() (string, error) {
|
2019-08-19 12:06:30 +02:00
|
|
|
armSignature, err := armor.ArmorWithType(msg.GetBinarySignature(), constants.PGPSignatureHeader)
|
2019-07-02 07:36:02 -07:00
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 21:01:23 +02:00
|
|
|
str := "-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: SHA512\r\n\r\n"
|
2019-07-02 07:36:02 -07:00
|
|
|
str += msg.GetString()
|
|
|
|
|
str += "\r\n"
|
|
|
|
|
str += armSignature
|
|
|
|
|
|
|
|
|
|
return str, nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// ---- UTILS -----
|
2018-11-21 23:44:33 +01:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// IsPGPMessage checks if data if has armored PGP message format.
|
2019-10-22 18:44:45 +02:00
|
|
|
func IsPGPMessage(data string) bool {
|
2019-06-03 17:00:01 +02:00
|
|
|
re := regexp.MustCompile("^-----BEGIN " + constants.PGPMessageHeader + "-----(?s:.+)-----END " +
|
|
|
|
|
constants.PGPMessageHeader + "-----")
|
|
|
|
|
return re.MatchString(data)
|
2018-11-21 23:44:33 +01:00
|
|
|
}
|
2020-09-01 10:02:13 +02:00
|
|
|
|
|
|
|
|
func getSignatureKeyIDs(data []byte) ([]uint64, bool) {
|
|
|
|
|
packets := packet.NewReader(bytes.NewReader(data))
|
|
|
|
|
var err error
|
|
|
|
|
var ids []uint64
|
|
|
|
|
var onePassSignaturePacket *packet.OnePassSignature
|
|
|
|
|
var signaturePacket *packet.Signature
|
|
|
|
|
|
|
|
|
|
Loop:
|
|
|
|
|
for {
|
|
|
|
|
var p packet.Packet
|
|
|
|
|
if p, err = packets.Next(); err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
switch p := p.(type) {
|
|
|
|
|
case *packet.OnePassSignature:
|
|
|
|
|
onePassSignaturePacket = p
|
|
|
|
|
ids = append(ids, onePassSignaturePacket.KeyId)
|
|
|
|
|
case *packet.Signature:
|
|
|
|
|
signaturePacket = p
|
|
|
|
|
if signaturePacket.IssuerKeyId != nil {
|
|
|
|
|
ids = append(ids, *signaturePacket.IssuerKeyId)
|
|
|
|
|
}
|
|
|
|
|
case *packet.SymmetricallyEncrypted,
|
|
|
|
|
*packet.AEADEncrypted,
|
|
|
|
|
*packet.Compressed,
|
|
|
|
|
*packet.LiteralData:
|
|
|
|
|
break Loop
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if len(ids) > 0 {
|
|
|
|
|
return ids, true
|
|
|
|
|
}
|
|
|
|
|
return ids, false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getHexKeyIDs(keyIDs []uint64, ok bool) ([]string, bool) {
|
|
|
|
|
hexIDs := make([]string, len(keyIDs))
|
|
|
|
|
|
|
|
|
|
for i, id := range keyIDs {
|
|
|
|
|
hexIDs[i] = keyIDToHex(id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hexIDs, ok
|
|
|
|
|
}
|