protonmail: add crypto helpers for contacts
This commit is contained in:
parent
0447370b16
commit
16a9952616
|
@ -1,9 +1,16 @@
|
|||
package protonmail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"golang.org/x/crypto/openpgp/armor"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
type Contact struct {
|
||||
|
@ -68,6 +75,122 @@ type ContactCard struct {
|
|||
Signature string
|
||||
}
|
||||
|
||||
func NewEncryptedContactCard(r io.Reader, to []*openpgp.Entity, signer *openpgp.Entity) (*ContactCard, error) {
|
||||
// TODO: sign and encrypt at the same time
|
||||
|
||||
var msg, armored bytes.Buffer
|
||||
if signer != nil {
|
||||
// We'll sign the message later, keep a copy of it
|
||||
r = io.TeeReader(r, &msg)
|
||||
}
|
||||
|
||||
ciphertext, err := armor.Encode(&armored, "PGP MESSAGE", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cleartext, err := openpgp.Encrypt(ciphertext, to, nil, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.Copy(cleartext, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cleartext.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ciphertext.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
card := &ContactCard{
|
||||
Type: ContactCardEncrypted,
|
||||
Data: armored.String(),
|
||||
}
|
||||
|
||||
if signer != nil {
|
||||
var sig bytes.Buffer
|
||||
if err := openpgp.ArmoredDetachSignText(&sig, signer, &msg, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
card.Type = ContactCardEncryptedAndSigned
|
||||
card.Signature = sig.String()
|
||||
}
|
||||
|
||||
return card, nil
|
||||
}
|
||||
|
||||
func NewSignedContactCard(r io.Reader, signer *openpgp.Entity) (*ContactCard, error) {
|
||||
var msg, sig bytes.Buffer
|
||||
r = io.TeeReader(r, &msg)
|
||||
if err := openpgp.ArmoredDetachSignText(&sig, signer, r, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ContactCard{
|
||||
Type: ContactCardSigned,
|
||||
Data: msg.String(),
|
||||
Signature: sig.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func entityPrimaryKey(e *openpgp.Entity) *openpgp.Key {
|
||||
var selfSig *packet.Signature
|
||||
for _, ident := range e.Identities {
|
||||
if selfSig == nil {
|
||||
selfSig = ident.SelfSignature
|
||||
} else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
|
||||
selfSig = ident.SelfSignature
|
||||
break
|
||||
}
|
||||
}
|
||||
return &openpgp.Key{e, e.PrimaryKey, e.PrivateKey, selfSig}
|
||||
}
|
||||
|
||||
func (card *ContactCard) Read(keyring openpgp.KeyRing) (*openpgp.MessageDetails, error) {
|
||||
if !card.Type.Encrypted() {
|
||||
md := &openpgp.MessageDetails{
|
||||
IsEncrypted: false,
|
||||
IsSigned: false,
|
||||
UnverifiedBody: strings.NewReader(card.Data),
|
||||
}
|
||||
|
||||
if !card.Type.Signed() {
|
||||
return md, nil
|
||||
}
|
||||
|
||||
signed := strings.NewReader(card.Data)
|
||||
signature := strings.NewReader(card.Signature)
|
||||
signer, err := openpgp.CheckArmoredDetachedSignature(keyring, signed, signature)
|
||||
md.IsSigned = true
|
||||
md.SignatureError = err
|
||||
if signer != nil {
|
||||
md.SignedByKeyId = signer.PrimaryKey.KeyId
|
||||
md.SignedBy = entityPrimaryKey(signer)
|
||||
}
|
||||
return md, nil
|
||||
}
|
||||
|
||||
ciphertextBlock, err := armor.Decode(strings.NewReader(card.Data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var r io.Reader = ciphertextBlock.Body
|
||||
|
||||
if card.Type.Signed() {
|
||||
sigBlock, err := armor.Decode(strings.NewReader(card.Signature))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r = io.MultiReader(r, sigBlock.Body)
|
||||
}
|
||||
|
||||
return openpgp.ReadMessage(r, keyring, nil, nil)
|
||||
}
|
||||
|
||||
type ContactExport struct {
|
||||
ID string
|
||||
Cards []*ContactCard
|
||||
|
|
Loading…
Reference in New Issue