Openpgp security update (V2) (#31)
* Change keyring unlock functionalities * Add keyring#Lock, keyring#CheckIntegrity, tests * Update helpers, fix bugs * Update go.mod with ProtonMail/crypto commit * Change key management system * Clear keys from memory + tests * Create SessionKey with direct encryption for datapackets. Move symmetrickey to password. * Fix upstream dependencies * Update module to V2, documentation * Add linter * Add v2 folder to .gitignore * Minor changes to KeyID getters * Remove old changelog * Improve docs, remove compilation script
This commit is contained in:
parent
136c0a5495
commit
54f45d0471
46 changed files with 2588 additions and 1770 deletions
|
|
@ -10,9 +10,9 @@ import (
|
|||
"regexp"
|
||||
"runtime"
|
||||
|
||||
"github.com/ProtonMail/gopenpgp/armor"
|
||||
"github.com/ProtonMail/gopenpgp/constants"
|
||||
"github.com/ProtonMail/gopenpgp/internal"
|
||||
"github.com/ProtonMail/gopenpgp/v2/armor"
|
||||
"github.com/ProtonMail/gopenpgp/v2/constants"
|
||||
"github.com/ProtonMail/gopenpgp/v2/internal"
|
||||
|
||||
"golang.org/x/crypto/openpgp/clearsign"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
|
|
@ -51,7 +51,7 @@ type PGPSplitMessage struct {
|
|||
// A Cleartext message is a signed PGP message, that is not encrypted,
|
||||
// i.e. the ones beginning with -----BEGIN PGP SIGNED MESSAGE-----
|
||||
type ClearTextMessage struct {
|
||||
Data []byte
|
||||
Data []byte
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ func NewPGPSignatureFromArmored(armored string) (*PGPSignature, error) {
|
|||
// NewClearTextMessage generates a new ClearTextMessage from data and signature
|
||||
func NewClearTextMessage(data []byte, signature []byte) *ClearTextMessage {
|
||||
return &ClearTextMessage{
|
||||
Data: data,
|
||||
Data: data,
|
||||
Signature: signature,
|
||||
}
|
||||
}
|
||||
|
|
@ -183,7 +183,7 @@ func (msg *PlainMessage) GetBase64() string {
|
|||
return base64.StdEncoding.EncodeToString(msg.Data)
|
||||
}
|
||||
|
||||
// NewReader returns a New io.Reader for the bianry data of the message
|
||||
// NewReader returns a New io.Reader for the binary data of the message
|
||||
func (msg *PlainMessage) NewReader() io.Reader {
|
||||
return bytes.NewReader(msg.GetBinary())
|
||||
}
|
||||
|
|
@ -203,7 +203,7 @@ func (msg *PGPMessage) GetBinary() []byte {
|
|||
return msg.Data
|
||||
}
|
||||
|
||||
// NewReader returns a New io.Reader for the unarmored bianry data of the message
|
||||
// NewReader returns a New io.Reader for the unarmored binary data of the message
|
||||
func (msg *PGPMessage) NewReader() io.Reader {
|
||||
return bytes.NewReader(msg.GetBinary())
|
||||
}
|
||||
|
|
@ -225,7 +225,7 @@ func (msg *PGPSplitMessage) GetBinaryKeyPacket() []byte {
|
|||
|
||||
// GetBinary returns the unarmored binary joined packets as a []byte
|
||||
func (msg *PGPSplitMessage) GetBinary() []byte {
|
||||
return append(msg.KeyPacket , msg.DataPacket...)
|
||||
return append(msg.KeyPacket, msg.DataPacket...)
|
||||
}
|
||||
|
||||
// GetArmored returns the armored message as a string, with joined data and key packets
|
||||
|
|
@ -233,6 +233,11 @@ func (msg *PGPSplitMessage) GetArmored() (string, error) {
|
|||
return armor.ArmorWithType(msg.GetBinary(), constants.PGPMessageHeader)
|
||||
}
|
||||
|
||||
// GetPGPMessage joins asymmetric session key packet with the symmetric data packet to obtain a PGP message
|
||||
func (msg *PGPSplitMessage) GetPGPMessage() *PGPMessage {
|
||||
return NewPGPMessage(append(msg.KeyPacket, msg.DataPacket...))
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -244,7 +249,6 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
|
|||
|
||||
// Store encrypted key and symmetrically encrypted packet separately
|
||||
var encryptedKey *packet.EncryptedKey
|
||||
var decryptErr error
|
||||
for {
|
||||
var p packet.Packet
|
||||
if p, err = packets.Next(); err == io.EOF {
|
||||
|
|
@ -259,7 +263,7 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
|
|||
encryptedKey = p
|
||||
|
||||
case *packet.SymmetricallyEncrypted:
|
||||
// FIXME: add support for multiple keypackets
|
||||
// TODO: add support for multiple keypackets
|
||||
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.
|
||||
|
|
@ -267,8 +271,14 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
|
|||
// in low-memory environments
|
||||
b.Grow(1<<16 + estimatedLength)
|
||||
// empty encoded length + start byte
|
||||
b.Write(make([]byte, 6))
|
||||
b.WriteByte(byte(1))
|
||||
if _, err := b.Write(make([]byte, 6)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := b.WriteByte(byte(1)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actualLength := 1
|
||||
block := make([]byte, 128)
|
||||
for {
|
||||
|
|
@ -276,7 +286,9 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
|
|||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
b.Write(block[:n])
|
||||
if _, err := b.Write(block[:n]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
actualLength += n
|
||||
gcCounter += n
|
||||
if gcCounter > garbageCollector && garbageCollector > 0 {
|
||||
|
|
@ -287,17 +299,18 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
|
|||
|
||||
// quick encoding
|
||||
symEncryptedData := b.Bytes()
|
||||
if actualLength < 192 {
|
||||
switch {
|
||||
case actualLength < 192:
|
||||
symEncryptedData[4] = byte(210)
|
||||
symEncryptedData[5] = byte(actualLength)
|
||||
symEncryptedData = symEncryptedData[4:]
|
||||
} else if actualLength < 8384 {
|
||||
actualLength = actualLength - 192
|
||||
case actualLength < 8384:
|
||||
actualLength -= 192
|
||||
symEncryptedData[3] = byte(210)
|
||||
symEncryptedData[4] = 192 + byte(actualLength>>8)
|
||||
symEncryptedData[5] = byte(actualLength)
|
||||
symEncryptedData = symEncryptedData[3:]
|
||||
} else {
|
||||
default:
|
||||
symEncryptedData[0] = byte(210)
|
||||
symEncryptedData[1] = byte(255)
|
||||
symEncryptedData[2] = byte(actualLength >> 24)
|
||||
|
|
@ -305,13 +318,9 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
|
|||
symEncryptedData[4] = byte(actualLength >> 8)
|
||||
symEncryptedData[5] = byte(actualLength)
|
||||
}
|
||||
|
||||
outSplit.DataPacket = symEncryptedData
|
||||
}
|
||||
}
|
||||
if decryptErr != nil {
|
||||
return nil, fmt.Errorf("gopenpgp: cannot decrypt encrypted key packet: %v", decryptErr)
|
||||
}
|
||||
if encryptedKey == nil {
|
||||
return nil, errors.New("gopenpgp: packets don't include an encrypted key packet")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue