Merge branch 'master' into imap
This commit is contained in:
commit
60b4122c1d
|
@ -82,19 +82,13 @@ func (att *Attachment) Encrypt(ciphertext io.Writer, signed *openpgp.Entity) (cl
|
|||
return nil, errors.New("cannot encrypt attachment: no attachment key available")
|
||||
}
|
||||
|
||||
encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, att.unencryptedKey.CipherFunc, att.unencryptedKey.Key, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// TODO: sign and store signature in att.Signature
|
||||
|
||||
hints := &openpgp.FileHints{
|
||||
IsBinary: true,
|
||||
FileName: att.Name,
|
||||
}
|
||||
|
||||
// TODO: sign, see https://github.com/golang/crypto/blob/master/openpgp/write.go#L287
|
||||
|
||||
literalData, err := packet.SerializeLiteral(encryptedData, true, att.Name, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return literalData, nil
|
||||
return symetricallyEncrypt(ciphertext, att.unencryptedKey, nil, hints, config)
|
||||
}
|
||||
|
||||
func (att *Attachment) Read(ciphertext io.Reader, keyring openpgp.KeyRing, prompt openpgp.PromptFunction) (*openpgp.MessageDetails, error) {
|
||||
|
|
|
@ -2,6 +2,8 @@ package protonmail
|
|||
|
||||
import (
|
||||
"io"
|
||||
"crypto"
|
||||
"hash"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/openpgp"
|
||||
|
@ -103,3 +105,103 @@ func generateUnencryptedKey(cipher packet.CipherFunction, config *packet.Config)
|
|||
Key: symKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func symetricallyEncrypt(ciphertext io.Writer, symKey *packet.EncryptedKey, signer *packet.PrivateKey, hints *openpgp.FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
|
||||
// From https://github.com/golang/crypto/blob/master/openpgp/write.go#L172
|
||||
|
||||
encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, symKey.CipherFunc, symKey.Key, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hash := crypto.SHA256
|
||||
|
||||
if signer != nil {
|
||||
ops := &packet.OnePassSignature{
|
||||
SigType: packet.SigTypeBinary,
|
||||
Hash: hash,
|
||||
PubKeyAlgo: signer.PubKeyAlgo,
|
||||
KeyId: signer.KeyId,
|
||||
IsLast: true,
|
||||
}
|
||||
if err := ops.Serialize(encryptedData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if hints == nil {
|
||||
hints = &openpgp.FileHints{}
|
||||
}
|
||||
|
||||
w := encryptedData
|
||||
if signer != nil {
|
||||
// If we need to write a signature packet after the literal
|
||||
// data then we need to stop literalData from closing
|
||||
// encryptedData.
|
||||
w = noOpCloser{encryptedData}
|
||||
}
|
||||
var epochSeconds uint32
|
||||
if !hints.ModTime.IsZero() {
|
||||
epochSeconds = uint32(hints.ModTime.Unix())
|
||||
}
|
||||
literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if signer != nil {
|
||||
return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil
|
||||
}
|
||||
return literalData, nil
|
||||
}
|
||||
|
||||
// signatureWriter hashes the contents of a message while passing it along to
|
||||
// literalData. When closed, it closes literalData, writes a signature packet
|
||||
// to encryptedData and then also closes encryptedData.
|
||||
type signatureWriter struct {
|
||||
encryptedData io.WriteCloser
|
||||
literalData io.WriteCloser
|
||||
hashType crypto.Hash
|
||||
h hash.Hash
|
||||
signer *packet.PrivateKey
|
||||
config *packet.Config
|
||||
}
|
||||
|
||||
func (s signatureWriter) Write(data []byte) (int, error) {
|
||||
s.h.Write(data)
|
||||
return s.literalData.Write(data)
|
||||
}
|
||||
|
||||
func (s signatureWriter) Close() error {
|
||||
sig := &packet.Signature{
|
||||
SigType: packet.SigTypeBinary,
|
||||
PubKeyAlgo: s.signer.PubKeyAlgo,
|
||||
Hash: s.hashType,
|
||||
CreationTime: s.config.Now(),
|
||||
IssuerKeyId: &s.signer.KeyId,
|
||||
}
|
||||
|
||||
if err := sig.Sign(s.h, s.signer, s.config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.literalData.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sig.Serialize(s.encryptedData); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.encryptedData.Close()
|
||||
}
|
||||
|
||||
// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
|
||||
type noOpCloser struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (c noOpCloser) Write(data []byte) (n int, err error) {
|
||||
return c.w.Write(data)
|
||||
}
|
||||
|
||||
func (c noOpCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -308,7 +308,7 @@ const (
|
|||
MessagePackageMIME = 32
|
||||
)
|
||||
|
||||
// From https://github.com/ProtonMail/Angular/blob/v3/src/app/composer/controllers/composeMessage.js#L656
|
||||
// From https://github.com/ProtonMail/WebClient/blob/public/src/app/composer/services/encryptMessage.js
|
||||
|
||||
type MessagePackage struct {
|
||||
Type MessagePackageType
|
||||
|
@ -328,7 +328,7 @@ type MessagePackageSet struct {
|
|||
Type MessagePackageType // OR of each Type
|
||||
Addresses map[string]*MessagePackage
|
||||
MIMEType string
|
||||
Body string // Body data packet
|
||||
Body string // Encrypted body data packet
|
||||
|
||||
// Only if cleartext is sent
|
||||
BodyKey string
|
||||
|
@ -336,6 +336,7 @@ type MessagePackageSet struct {
|
|||
|
||||
bodyKey *packet.EncryptedKey
|
||||
attachmentKeys map[string]*packet.EncryptedKey
|
||||
signature int
|
||||
}
|
||||
|
||||
func NewMessagePackageSet(attachmentKeys map[string]*packet.EncryptedKey) *MessagePackageSet {
|
||||
|
@ -369,9 +370,7 @@ func (w *outgoingMessageWriter) Close() error {
|
|||
}
|
||||
|
||||
// Encrypt encrypts the data that will be written to the returned
|
||||
// io.WriteCloser.
|
||||
//
|
||||
// The signed parameter is ignored for now.
|
||||
// io.WriteCloser, and optionally signs it.
|
||||
func (set *MessagePackageSet) Encrypt(mimeType string, signed *openpgp.Entity) (io.WriteCloser, error) {
|
||||
set.MIMEType = mimeType
|
||||
|
||||
|
@ -383,31 +382,43 @@ func (set *MessagePackageSet) Encrypt(mimeType string, signed *openpgp.Entity) (
|
|||
}
|
||||
set.bodyKey = key
|
||||
|
||||
var encoded bytes.Buffer
|
||||
ciphertext := base64.NewEncoder(base64.StdEncoding, &encoded)
|
||||
|
||||
encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, set.bodyKey.CipherFunc, set.bodyKey.Key, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var signer *packet.PrivateKey
|
||||
if signed != nil {
|
||||
signKey, ok := signingKey(signed, config.Now())
|
||||
if !ok {
|
||||
return nil, errors.New("no valid signing keys")
|
||||
}
|
||||
signer = signKey.PrivateKey
|
||||
if signer == nil {
|
||||
return nil, errors.New("no private key in signing key")
|
||||
}
|
||||
if signer.Encrypted {
|
||||
return nil, errors.New("signing key must be decrypted")
|
||||
}
|
||||
set.signature = 1
|
||||
}
|
||||
|
||||
// TODO: sign, see https://github.com/golang/crypto/blob/master/openpgp/write.go#L287
|
||||
encoded := new(bytes.Buffer)
|
||||
ciphertext := base64.NewEncoder(base64.StdEncoding, encoded)
|
||||
|
||||
literalData, err := packet.SerializeLiteral(encryptedData, false, "", 0)
|
||||
cleartext, err := symetricallyEncrypt(ciphertext, key, signer, nil, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &outgoingMessageWriter{
|
||||
cleartext: literalData,
|
||||
cleartext: cleartext,
|
||||
ciphertext: ciphertext,
|
||||
encoded: &encoded,
|
||||
encoded: encoded,
|
||||
set: set,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (set *MessagePackageSet) AddCleartext(addr string) error {
|
||||
set.Addresses[addr] = &MessagePackage{Type: MessagePackageCleartext}
|
||||
set.Addresses[addr] = &MessagePackage{
|
||||
Type: MessagePackageCleartext,
|
||||
Signature: set.signature,
|
||||
}
|
||||
set.Type |= MessagePackageCleartext
|
||||
|
||||
if set.BodyKey == "" || set.AttachmentKeys == nil {
|
||||
|
@ -463,6 +474,7 @@ func (set *MessagePackageSet) AddInternal(addr string, pub *openpgp.Entity) erro
|
|||
Type: MessagePackageInternal,
|
||||
BodyKeyPacket: bodyKey,
|
||||
AttachmentKeyPackets: attachmentKeys,
|
||||
Signature: set.signature,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue