115 lines
3 KiB
Go
115 lines
3 KiB
Go
package internal
|
|
|
|
import (
|
|
"bytes"
|
|
"golang.org/x/crypto/openpgp/packet"
|
|
"gitlab.com/ProtonMail/go-pm-crypto/models"
|
|
"io"
|
|
"runtime"
|
|
)
|
|
|
|
func SplitPackets(encryptedReader io.Reader, estimatedLength int, garbageCollector int) (*models.EncryptedSplit, error){
|
|
var err error
|
|
|
|
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
|
|
//kr *KeyRing, r io.Reader) (key *SymmetricKey, symEncryptedData []byte,
|
|
packets := packet.NewReader(encryptedReader)
|
|
|
|
outSplit := &models.EncryptedSplit{}
|
|
gcCounter := 0
|
|
|
|
// Save encrypted key and signature apart
|
|
var ek *packet.EncryptedKey
|
|
// var decryptErr error
|
|
for {
|
|
var p packet.Packet
|
|
if p, err = packets.Next(); err == io.EOF {
|
|
err = nil
|
|
break
|
|
}
|
|
switch p := p.(type) {
|
|
case *packet.EncryptedKey:
|
|
// We got an encrypted key. Try to decrypt it with each available key
|
|
if ek != nil && ek.Key != nil {
|
|
break
|
|
}
|
|
ek = p
|
|
break
|
|
case *packet.SymmetricallyEncrypted:
|
|
// The code below is optimized to not
|
|
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
|
|
b.Write(make([]byte, 6))
|
|
b.WriteByte(byte(1))
|
|
actualLength := 1
|
|
block := make([]byte, 128)
|
|
for {
|
|
n, err := p.Contents.Read(block)
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
b.Write(block[:n])
|
|
actualLength += n
|
|
gcCounter += n
|
|
if gcCounter > garbageCollector && garbageCollector > 0 {
|
|
runtime.GC()
|
|
gcCounter = 0
|
|
}
|
|
}
|
|
|
|
// quick encoding
|
|
symEncryptedData := b.Bytes()
|
|
if actualLength < 192 {
|
|
symEncryptedData[4] = byte(210)
|
|
symEncryptedData[5] = byte(actualLength)
|
|
symEncryptedData = symEncryptedData[4:]
|
|
} else if actualLength < 8384 {
|
|
actualLength = actualLength - 192
|
|
symEncryptedData[3] = byte(210)
|
|
symEncryptedData[4] = 192+byte(actualLength>>8)
|
|
symEncryptedData[5] = byte(actualLength)
|
|
symEncryptedData = symEncryptedData[3:]
|
|
} else {
|
|
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
|
|
break
|
|
|
|
}
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
ek.Serialize(&buf)
|
|
outSplit.KeyPacket = buf.Bytes()
|
|
|
|
return outSplit, err
|
|
}
|
|
|
|
//encode length based on 4.2.2. in the RFC
|
|
func encodedLength(length int) (b []byte) {
|
|
if length < 192 {
|
|
b = append(b, byte(length))
|
|
} else if length < 8384 {
|
|
length = length - 192
|
|
b = append(b, 192+byte(length>>8))
|
|
b = append(b, byte(length))
|
|
} else {
|
|
b = append(b, byte(255))
|
|
b = append(b, byte(length>>24))
|
|
b = append(b, byte(length>>16))
|
|
b = append(b, byte(length>>8))
|
|
b = append(b, byte(length))
|
|
}
|
|
return
|
|
}
|