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>
This commit is contained in:
marinthiercelin 2021-06-30 16:49:30 +02:00 committed by GitHub
parent 7380f7391f
commit c46ed8ed9e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1718 additions and 97 deletions

View file

@ -119,7 +119,7 @@ func (keyRing *KeyRing) VerifyDetachedEncrypted(message *PlainMessage, encrypted
// ------ INTERNAL FUNCTIONS -------
// Core for encryption+signature functions.
// Core for encryption+signature (non-streaming) functions.
func asymmetricEncrypt(
plainMessage *PlainMessage,
publicKey, privateKey *KeyRing,
@ -127,30 +127,17 @@ func asymmetricEncrypt(
) ([]byte, error) {
var outBuf bytes.Buffer
var encryptWriter io.WriteCloser
var signEntity *openpgp.Entity
var err error
if privateKey != nil && len(privateKey.entities) > 0 {
var err error
signEntity, err = privateKey.getSigningEntity()
if err != nil {
return nil, err
}
}
hints := &openpgp.FileHints{
IsBinary: plainMessage.IsBinary(),
FileName: plainMessage.Filename,
ModTime: plainMessage.getFormattedTime(),
}
if plainMessage.IsBinary() {
encryptWriter, err = openpgp.Encrypt(&outBuf, publicKey.entities, signEntity, hints, config)
} else {
encryptWriter, err = openpgp.EncryptText(&outBuf, publicKey.entities, signEntity, hints, config)
}
encryptWriter, err = asymmetricEncryptStream(hints, &outBuf, &outBuf, publicKey, privateKey, config)
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in encrypting asymmetrically")
return nil, err
}
_, err = encryptWriter.Write(plainMessage.GetBinary())
@ -166,26 +153,46 @@ func asymmetricEncrypt(
return outBuf.Bytes(), nil
}
// Core for decryption+verification functions.
// Core for encryption+signature (all) functions.
func asymmetricEncryptStream(
hints *openpgp.FileHints,
keyPacketWriter io.Writer,
dataPacketWriter io.Writer,
publicKey, privateKey *KeyRing,
config *packet.Config,
) (encryptWriter io.WriteCloser, err error) {
var signEntity *openpgp.Entity
if privateKey != nil && len(privateKey.entities) > 0 {
var err error
signEntity, err = privateKey.getSigningEntity()
if err != nil {
return nil, err
}
}
if hints.IsBinary {
encryptWriter, err = openpgp.EncryptSplit(keyPacketWriter, dataPacketWriter, publicKey.entities, signEntity, hints, config)
} else {
encryptWriter, err = openpgp.EncryptTextSplit(keyPacketWriter, dataPacketWriter, publicKey.entities, signEntity, hints, config)
}
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in encrypting asymmetrically")
}
return encryptWriter, nil
}
// Core for decryption+verification (non streaming) functions.
func asymmetricDecrypt(
encryptedIO io.Reader, privateKey *KeyRing, verifyKey *KeyRing, verifyTime int64,
) (message *PlainMessage, err error) {
privKeyEntries := privateKey.entities
var additionalEntries openpgp.EntityList
if verifyKey != nil {
additionalEntries = verifyKey.entities
}
if additionalEntries != nil {
privKeyEntries = append(privKeyEntries, additionalEntries...)
}
config := &packet.Config{Time: getTimeGenerator()}
messageDetails, err := openpgp.ReadMessage(encryptedIO, privKeyEntries, nil, config)
messageDetails, err := asymmetricDecryptStream(
encryptedIO,
privateKey,
verifyKey,
)
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in reading message")
return nil, err
}
body, err := ioutil.ReadAll(messageDetails.UnverifiedBody)
@ -205,3 +212,27 @@ func asymmetricDecrypt(
Time: messageDetails.LiteralData.Time,
}, err
}
// Core for decryption+verification (all) functions.
func asymmetricDecryptStream(
encryptedIO io.Reader, privateKey *KeyRing, verifyKey *KeyRing,
) (messageDetails *openpgp.MessageDetails, err error) {
privKeyEntries := privateKey.entities
var additionalEntries openpgp.EntityList
if verifyKey != nil {
additionalEntries = verifyKey.entities
}
if additionalEntries != nil {
privKeyEntries = append(privKeyEntries, additionalEntries...)
}
config := &packet.Config{Time: getTimeGenerator()}
messageDetails, err = openpgp.ReadMessage(encryptedIO, privKeyEntries, nil, config)
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in reading message")
}
return messageDetails, err
}