Refactor api (#6)

* Refactor library, remove duplicates

* Rebuild structure to use Messages and Signature models

* Use PGPSplitMessage

* Remove signature model

* Various fixes

* Add helpers with tests

* Fixes, add some docs, add tests

* Add attachment helpers

* Add helpers Symmetric encryption

* Edit docs + examples

* Rename kr to keyRing

* Various fixes for documentation

* Edit JSON handling functions, add decrypt keyring via token

* Add proposal changes doc

* Fix CI

* Drop *Message functions, join CleartextMessage and BinaryMessage

* Change canonicalization and trimming only to text signatures

* Add cleartextsignature, detach signature from message model, move helpers

* Documentation, remove optional parameters

* Move verification to separate model

* Don't return message in VerifyDetached

* Update table of contents in readme

* Appease golint

* Run go fmt

* Rename Encrypt/DecryptMessageWithPassword to ..WithToken

These functions shouldn't be used with user-provided passwords,
as they don't do any key-stretching.

* Change key generation usernames
This commit is contained in:
wussler 2019-06-03 17:00:01 +02:00 committed by GitHub
parent 82d49bf235
commit e65ed17b41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 2573 additions and 1478 deletions

View file

@ -2,15 +2,11 @@ package crypto
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"runtime"
"sync"
armorUtils "github.com/ProtonMail/gopenpgp/armor"
"github.com/ProtonMail/gopenpgp/constants"
"github.com/ProtonMail/gopenpgp/models"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/packet"
)
@ -21,7 +17,7 @@ type AttachmentProcessor struct {
w *io.WriteCloser
pipe *io.PipeWriter
done sync.WaitGroup
split *models.EncryptedSplit
split *PGPSplitMessage
garbageCollector int
err error
}
@ -34,7 +30,7 @@ func (ap *AttachmentProcessor) Process(plainData []byte) {
}
// Finish closes the attachment and returns the encrypted data
func (ap *AttachmentProcessor) Finish() (*models.EncryptedSplit, error) {
func (ap *AttachmentProcessor) Finish() (*PGPSplitMessage, error) {
if ap.err != nil {
return nil, ap.err
}
@ -47,10 +43,10 @@ func (ap *AttachmentProcessor) Finish() (*models.EncryptedSplit, error) {
return ap.split, nil
}
// encryptAttachment creates an AttachmentProcessor which can be used to encrypt
// newAttachmentProcessor creates an AttachmentProcessor which can be used to encrypt
// a file. It takes an estimatedSize and fileName as hints about the file.
func (pgp *GopenPGP) encryptAttachment(
estimatedSize int, fileName string, publicKey *KeyRing, garbageCollector int,
func (keyRing *KeyRing) newAttachmentProcessor(
estimatedSize int, fileName string, garbageCollector int,
) (*AttachmentProcessor, error) {
attachmentProc := &AttachmentProcessor{}
// You could also add these one at a time if needed.
@ -70,17 +66,18 @@ func (pgp *GopenPGP) encryptAttachment(
go func() {
defer attachmentProc.done.Done()
split, splitError := SeparateKeyAndData(nil, reader, estimatedSize, garbageCollector)
ciphertext, _ := ioutil.ReadAll(reader)
message := NewPGPMessage(ciphertext)
split, splitError := message.SeparateKeyAndData(estimatedSize, garbageCollector)
if attachmentProc.err != nil {
attachmentProc.err = splitError
}
split.Algo = constants.AES256
attachmentProc.split = split
}()
var ew io.WriteCloser
var encryptErr error
ew, encryptErr = openpgp.Encrypt(writer, publicKey.entities, nil, hints, config)
ew, encryptErr = openpgp.Encrypt(writer, keyRing.entities, nil, hints, config)
if encryptErr != nil {
return nil, encryptErr
}
@ -90,15 +87,14 @@ func (pgp *GopenPGP) encryptAttachment(
return attachmentProc, nil
}
// EncryptAttachment encrypts a file. fileName
func (pgp *GopenPGP) EncryptAttachment(
plainData []byte, fileName string, publicKey *KeyRing,
) (*models.EncryptedSplit, error) {
ap, err := pgp.encryptAttachment(len(plainData), fileName, publicKey, -1)
// EncryptAttachment encrypts a file given a PlainMessage and a fileName.
// Returns a PGPSplitMessage containing a session key packet and symmetrically encrypted data
func (keyRing *KeyRing) EncryptAttachment(message *PlainMessage, fileName string) (*PGPSplitMessage, error) {
ap, err := keyRing.newAttachmentProcessor(len(message.GetBinary()), fileName, -1)
if err != nil {
return nil, err
}
ap.Process(plainData)
ap.Process(message.GetBinary())
split, err := ap.Finish()
if err != nil {
return nil, err
@ -106,47 +102,23 @@ func (pgp *GopenPGP) EncryptAttachment(
return split, nil
}
// EncryptAttachmentLowMemory creates an AttachmentProcessor which can be used
// NewLowMemoryAttachmentProcessor creates an AttachmentProcessor which can be used
// to encrypt a file. It takes an estimatedSize and fileName as hints about the
// file. It is optimized for low-memory environments and collects garbage every
// megabyte.
func (pgp *GopenPGP) EncryptAttachmentLowMemory(
estimatedSize int, fileName string, publicKey *KeyRing,
func (keyRing *KeyRing) NewLowMemoryAttachmentProcessor(
estimatedSize int, fileName string,
) (*AttachmentProcessor, error) {
return pgp.encryptAttachment(estimatedSize, fileName, publicKey, 1<<20)
return keyRing.newAttachmentProcessor(estimatedSize, fileName, 1<<20)
}
// SplitArmor is a helper method which splits an armored message into its
// session key packet and symmetrically encrypted data packet.
func SplitArmor(encrypted string) (*models.EncryptedSplit, error) {
var err error
// DecryptAttachment takes a PGPSplitMessage, containing a session key packet and symmetrically encrypted data
// and returns a decrypted PlainMessage
func (keyRing *KeyRing) DecryptAttachment(message *PGPSplitMessage) (*PlainMessage, error) {
privKeyEntries := keyRing.entities
encryptedRaw, err := armorUtils.Unarmor(encrypted)
if err != nil {
return nil, err
}
encryptedReader := bytes.NewReader(encryptedRaw)
return SeparateKeyAndData(nil, encryptedReader, len(encrypted), -1)
}
// DecryptAttachment takes a session key packet and symmetrically encrypted data
// packet. privateKeys is a KeyRing that can contain multiple keys. The
// passphrase is used to unlock keys in privateKeys.
func (pgp *GopenPGP) DecryptAttachment(
keyPacket, dataPacket []byte,
kr *KeyRing, passphrase string,
) ([]byte, error) {
privKeyEntries := kr.entities
if err := kr.Unlock([]byte(passphrase)); err != nil {
err = fmt.Errorf("gopenpgp: cannot decrypt attachment: %v", err)
return nil, err
}
keyReader := bytes.NewReader(keyPacket)
dataReader := bytes.NewReader(dataPacket)
keyReader := bytes.NewReader(message.GetKeyPacket())
dataReader := bytes.NewReader(message.GetDataPacket())
encryptedReader := io.MultiReader(keyReader, dataReader)
@ -163,5 +135,5 @@ func (pgp *GopenPGP) DecryptAttachment(
return nil, err
}
return b, nil
return NewPlainMessage(b), nil
}