passforios-gopenpgp/crypto/sessionkey_streaming.go
marinthiercelin c46ed8ed9e
Add a streaming api to KeyRing and SessionKey (#131)
* barebone streaming functionality

* encryption needs to return a writecloser

* added eof check

* workaround for reader problem with copies

* separate mobile wrappers from main api

* add a clone in the read result to avoid memory corruption

* refactor to reuse code, and fix verification

* have to give the verify key at the start of the decryption

* enfore readAll before signature verification

* streaming api for SessionKey

* add split message stream apis

* name interface params

* fix streaming api so it's supported by go-mobile

* hide internal writeCloser

* fix nil access

* added detached sigs methods

* started unit testing

* unit testing and fixed a bug where key and data packets where inverted

* remove unecessary error wrapping

* figured out closing order and error handling

* add GC calls to mobile writer and reader

* remove debugging values and arrays

* writer with builtin sha256

* unit testing the mobile helpers

* comments and linting

* Typo in error

Co-authored-by: wussler <aron@wussler.it>

* Add GetKeyPacket doc

Co-authored-by: wussler <aron@wussler.it>

* Add rfc reference in comments

Co-authored-by: wussler <aron@wussler.it>

* small improvements

* add compatibility tests with normal methods

* remove unecessary copies in the tests

* update go-crypto to the merged changes commit

* update comments of core internal functions

* remove unused nolint comment

* group message metadata in a struct

* fix comments

* change default values for metadata

* change the mobile reader wrapper to fit the behavior of java

* remove gc calls in the wrappers to avoid performance penalties

* bring back the former Go2MobileReader to be used for ios

* Update crypto/keyring_streaming.go

Co-authored-by: wussler <aron@wussler.it>

* return an error when verifying an embedded sig with no keyring

* Update crypto/sessionkey_streaming.go

Co-authored-by: wussler <aron@wussler.it>

* linter error

* update changelog

* update changelog

Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00

105 lines
2.6 KiB
Go

package crypto
import (
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/packet"
"github.com/pkg/errors"
)
type signAndEncryptWriteCloser struct {
signWriter WriteCloser
encryptWriter WriteCloser
}
func (w *signAndEncryptWriteCloser) Write(b []byte) (int, error) {
return w.signWriter.Write(b)
}
func (w *signAndEncryptWriteCloser) Close() error {
if err := w.signWriter.Close(); err != nil {
return err
}
return w.encryptWriter.Close()
}
// EncryptStream is used to encrypt data as a Writer.
// It takes a writer for the encrypted data packet and returns a writer for the plaintext data.
// If signKeyRing is not nil, it is used to do an embedded signature.
func (sk *SessionKey) EncryptStream(
dataPacketWriter Writer,
plainMessageMetadata *PlainMessageMetadata,
signKeyRing *KeyRing,
) (plainMessageWriter WriteCloser, err error) {
dc, err := sk.GetCipherFunc()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt with session key")
}
config := &packet.Config{
Time: getTimeGenerator(),
DefaultCipher: dc,
}
var signEntity *openpgp.Entity
if signKeyRing != nil {
signEntity, err = signKeyRing.getSigningEntity()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to sign")
}
}
if plainMessageMetadata == nil {
// Use sensible default metadata
plainMessageMetadata = &PlainMessageMetadata{
IsBinary: true,
Filename: "",
ModTime: GetUnixTime(),
}
}
encryptWriter, signWriter, err := encryptStreamWithSessionKey(
plainMessageMetadata.IsBinary,
plainMessageMetadata.Filename,
uint32(plainMessageMetadata.ModTime),
dataPacketWriter,
sk,
signEntity,
config,
)
if err != nil {
return nil, err
}
if signWriter != nil {
plainMessageWriter = &signAndEncryptWriteCloser{signWriter, encryptWriter}
} else {
plainMessageWriter = encryptWriter
}
return plainMessageWriter, err
}
// DecryptStream is used to decrypt a data packet as a Reader.
// It takes a reader for the data packet
// and returns a PlainMessageReader for the plaintext data.
// If verifyKeyRing is not nil, PlainMessageReader.VerifySignature() will
// verify the embedded signature with the given key ring and verification time.
func (sk *SessionKey) DecryptStream(
dataPacketReader Reader,
verifyKeyRing *KeyRing,
verifyTime int64,
) (plainMessage *PlainMessageReader, err error) {
messageDetails, err := decryptStreamWithSessionKey(
sk,
dataPacketReader,
verifyKeyRing,
)
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in reading message")
}
return &PlainMessageReader{
messageDetails,
verifyKeyRing,
verifyTime,
false,
}, err
}