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

@ -4,6 +4,133 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- Streaming API:
- New structs:
- `PlainMessageMetadata`: holds the metadata of a plain PGP message
```go
type PlainMessageMetadata struct {
IsBinary bool
Filename string
ModTime int64
}
```
- `PlainMessageReader` implements `Reader` and:
```go
func (msg *PlainMessageReader) GetMetadata() *PlainMessageMetadata
func (msg *PlainMessageReader) VerifySignature() (err error)
```
- `EncryptSplitResult` implements `WriteCloser` and:
```go
func (res *EncryptSplitResult) GetKeyPacket() (keyPacket []byte, err error)
```
- Keyring methods:
- Encrypt (and optionally sign) a message directly into a `Writer`:
```go
func (keyRing *KeyRing) EncryptStream(
pgpMessageWriter Writer,
plainMessageMetadata *PlainMessageMetadata,
signKeyRing *KeyRing,
) (plainMessageWriter WriteCloser, err error)
```
- Encrypt (and optionally sign) a message directly into a `Writer` (split keypacket and datapacket):
```go
func (keyRing *KeyRing) EncryptSplitStream(
dataPacketWriter Writer,
plainMessageMetadata *PlainMessageMetadata,
signKeyRing *KeyRing,
) (*EncryptSplitResult, error)
```
- Decrypt (and optionally verify) a message from a `Reader`:
```go
func (keyRing *KeyRing) DecryptStream(
message Reader,
verifyKeyRing *KeyRing,
verifyTime int64,
) (plainMessage *PlainMessageReader, err error)
```
N.B.: to verify the signature, you will need to call `plainMessage.VerifySignature()` after all the data has been read from `plainMessage`.
- Decrypt (and optionally verify) a split message, getting the datapacket from a `Reader`:
```go
func (keyRing *KeyRing) DecryptSplitStream(
keypacket []byte,
dataPacketReader Reader,
verifyKeyRing *KeyRing, verifyTime int64,
) (plainMessage *PlainMessageReader, err error)
```
N.B.: to verify the signature, you will need to call `plainMessage.VerifySignature()` after all the data has been read from `plainMessage`.
- Generate a detached signature from a `Reader`:
```go
func (keyRing *KeyRing) SignDetachedStream(message Reader) (*PGPSignature, error)
```
- Verify a detached signature for a `Reader`:
```go
func (keyRing *KeyRing) VerifyDetachedStream(
message Reader,
signature *PGPSignature,
verifyTime int64,
) error
```
- Generate an encrypted detached signature from a `Reader`:
```go
func (keyRing *KeyRing) SignDetachedEncryptedStream(
message Reader,
encryptionKeyRing *KeyRing,
) (encryptedSignature *PGPMessage, err error)
```
- Verify an encrypted detached signature for a `Reader`:
```go
func (keyRing *KeyRing) VerifyDetachedEncryptedStream(
message Reader,
encryptedSignature *PGPMessage,
decryptionKeyRing *KeyRing,
verifyTime int64,
) error
```
- SessionKey methods:
- Encrypt (and optionally sign) a message into a `Writer`:
```go
func (sk *SessionKey) EncryptStream(
dataPacketWriter Writer,
plainMessageMetadata *PlainMessageMetadata,
signKeyRing *KeyRing,
) (plainMessageWriter WriteCloser, err error)
```
- Decrypt (and optionally verify) a message from a `Reader`:
```go
func (sk *SessionKey) DecryptStream(
dataPacketReader Reader,
verifyKeyRing *KeyRing,
verifyTime int64,
) (plainMessage *PlainMessageReader, err error)
```
N.B.: to verify the signature, you will need to call `plainMessage.VerifySignature()` after all the data has been read from `plainMessage`.
- Mobile apps helpers for `Reader` and `Writer`:
Due to limitations of `gomobile`, mobile apps can't implement the `Reader` and `Writer` interfaces directly.
- Implementing `Reader`: Apps should implement the interface:
```go
type MobileReader interface {
Read(max int) (result *MobileReadResult, err error)
}
type MobileReadResult struct {
N int // N, The number of bytes read
IsEOF bool // IsEOF, If true, then the reader has reached the end of the data to read.
Data []byte // Data, the data that has been read
}
```
And then wrap it with `Mobile2GoReader(mobileReader)` to turn it into a `Reader`.
- Implementing `Writer`:
The apps should implement the `Writer` interface directly, but still need to wrap the writer with `Mobile2GoWriter(mobileWriter)`. We also provide the `Mobile2GoWriterWithSHA256` if you want to compute the SHA256 hash of the written data.
- Using a `Reader`: To use a reader returned by golang in mobile apps: you should wrap it with:
- Android: `Go2AndroidReader(reader)`, implements the `Reader` interface, but returns `n == -1` instead of `err == io.EOF`
- iOS: `Go2IOSReader(reader)`, implements `MobileReader`.
- Using a `Writer`: you can use a writer returned by golang directly.
## [2.1.10] 2021-06-16
### Fixed
- Removed time interpolation via monotonic clock that can cause signatures in the future