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")
|
return nil, errors.New("cannot encrypt attachment: no attachment key available")
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, att.unencryptedKey.CipherFunc, att.unencryptedKey.Key, config)
|
// TODO: sign and store signature in att.Signature
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
hints := &openpgp.FileHints{
|
||||||
|
IsBinary: true,
|
||||||
|
FileName: att.Name,
|
||||||
}
|
}
|
||||||
|
return symetricallyEncrypt(ciphertext, att.unencryptedKey, nil, hints, config)
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (att *Attachment) Read(ciphertext io.Reader, keyring openpgp.KeyRing, prompt openpgp.PromptFunction) (*openpgp.MessageDetails, error) {
|
func (att *Attachment) Read(ciphertext io.Reader, keyring openpgp.KeyRing, prompt openpgp.PromptFunction) (*openpgp.MessageDetails, error) {
|
||||||
|
|
|
@ -2,6 +2,8 @@ package protonmail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"crypto"
|
||||||
|
"hash"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/openpgp"
|
"golang.org/x/crypto/openpgp"
|
||||||
|
@ -103,3 +105,103 @@ func generateUnencryptedKey(cipher packet.CipherFunction, config *packet.Config)
|
||||||
Key: symKey,
|
Key: symKey,
|
||||||
}, nil
|
}, 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
|
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 MessagePackage struct {
|
||||||
Type MessagePackageType
|
Type MessagePackageType
|
||||||
|
@ -328,7 +328,7 @@ type MessagePackageSet struct {
|
||||||
Type MessagePackageType // OR of each Type
|
Type MessagePackageType // OR of each Type
|
||||||
Addresses map[string]*MessagePackage
|
Addresses map[string]*MessagePackage
|
||||||
MIMEType string
|
MIMEType string
|
||||||
Body string // Body data packet
|
Body string // Encrypted body data packet
|
||||||
|
|
||||||
// Only if cleartext is sent
|
// Only if cleartext is sent
|
||||||
BodyKey string
|
BodyKey string
|
||||||
|
@ -336,6 +336,7 @@ type MessagePackageSet struct {
|
||||||
|
|
||||||
bodyKey *packet.EncryptedKey
|
bodyKey *packet.EncryptedKey
|
||||||
attachmentKeys map[string]*packet.EncryptedKey
|
attachmentKeys map[string]*packet.EncryptedKey
|
||||||
|
signature int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessagePackageSet(attachmentKeys map[string]*packet.EncryptedKey) *MessagePackageSet {
|
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
|
// Encrypt encrypts the data that will be written to the returned
|
||||||
// io.WriteCloser.
|
// io.WriteCloser, and optionally signs it.
|
||||||
//
|
|
||||||
// The signed parameter is ignored for now.
|
|
||||||
func (set *MessagePackageSet) Encrypt(mimeType string, signed *openpgp.Entity) (io.WriteCloser, error) {
|
func (set *MessagePackageSet) Encrypt(mimeType string, signed *openpgp.Entity) (io.WriteCloser, error) {
|
||||||
set.MIMEType = mimeType
|
set.MIMEType = mimeType
|
||||||
|
|
||||||
|
@ -383,31 +382,43 @@ func (set *MessagePackageSet) Encrypt(mimeType string, signed *openpgp.Entity) (
|
||||||
}
|
}
|
||||||
set.bodyKey = key
|
set.bodyKey = key
|
||||||
|
|
||||||
var encoded bytes.Buffer
|
var signer *packet.PrivateKey
|
||||||
ciphertext := base64.NewEncoder(base64.StdEncoding, &encoded)
|
if signed != nil {
|
||||||
|
signKey, ok := signingKey(signed, config.Now())
|
||||||
encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, set.bodyKey.CipherFunc, set.bodyKey.Key, config)
|
if !ok {
|
||||||
if err != nil {
|
return nil, errors.New("no valid signing keys")
|
||||||
return nil, err
|
}
|
||||||
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &outgoingMessageWriter{
|
return &outgoingMessageWriter{
|
||||||
cleartext: literalData,
|
cleartext: cleartext,
|
||||||
ciphertext: ciphertext,
|
ciphertext: ciphertext,
|
||||||
encoded: &encoded,
|
encoded: encoded,
|
||||||
set: set,
|
set: set,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (set *MessagePackageSet) AddCleartext(addr string) error {
|
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
|
set.Type |= MessagePackageCleartext
|
||||||
|
|
||||||
if set.BodyKey == "" || set.AttachmentKeys == nil {
|
if set.BodyKey == "" || set.AttachmentKeys == nil {
|
||||||
|
@ -463,6 +474,7 @@ func (set *MessagePackageSet) AddInternal(addr string, pub *openpgp.Entity) erro
|
||||||
Type: MessagePackageInternal,
|
Type: MessagePackageInternal,
|
||||||
BodyKeyPacket: bodyKey,
|
BodyKeyPacket: bodyKey,
|
||||||
AttachmentKeyPackets: attachmentKeys,
|
AttachmentKeyPackets: attachmentKeys,
|
||||||
|
Signature: set.signature,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue