From 37459ffa7b94b980881088346569207f42982b47 Mon Sep 17 00:00:00 2001 From: Jakub Date: Thu, 7 Mar 2019 15:15:35 +0100 Subject: [PATCH] first key id --- Changelog.md | 13 ++++-- crypto/keyring.go | 100 +++++++++++++++++++++++----------------------- 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/Changelog.md b/Changelog.md index 5f766ba..d13af4c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,13 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) ## 2019-03-07 -* update crypto and mime -* return decrypt error from `GetSessionFromKeyPaket` -* refactor +* `master` refactor of master contains all changes from `oldMaster` + +### Added +* `FirstKeyID` into `KeyRing` object to be able match salts + +### Changed +* Comments following linter recomendations +* Update the crypto and mime dependencies +* Error handling in `GetSessionFromKeyPaket` + diff --git a/crypto/keyring.go b/crypto/keyring.go index 67c7aa1..4c3094d 100644 --- a/crypto/keyring.go +++ b/crypto/keyring.go @@ -52,6 +52,7 @@ type Signature struct { md *openpgp.MessageDetails } +// SignedString wraps string with Signature type SignedString struct { String string Signed *Signature @@ -59,15 +60,15 @@ type SignedString struct { var errKeyringNotUnlocked = errors.New("pmapi: cannot sign message, key ring is not unlocked") -// Use: not used by bridge // Err returns a non-nil error if the signature is invalid. +// Use: not used by bridge func (s *Signature) Err() error { return s.md.SignatureError } -// Use: not used by bridge // KeyRing returns the key ring that was used to produce the signature, if // available. +// Use: not used by bridge func (s *Signature) KeyRing() *KeyRing { if s.md.SignedBy == nil { return nil @@ -78,8 +79,8 @@ func (s *Signature) KeyRing() *KeyRing { } } -// Use: not used by bridge // IsBy returns true if the signature has been created by kr's owner. +// Use: not used by bridge func (s *Signature) IsBy(kr *KeyRing) bool { // Use fingerprint if possible if s.md.SignedBy != nil { @@ -99,21 +100,24 @@ func (s *Signature) IsBy(kr *KeyRing) bool { return false } -// A keyring contains multiple private and public keys. +// KeyRing contains multiple private and public keys. type KeyRing struct { // PGP entities in this keyring. entities openpgp.EntityList + + // FirstKeyID as obtained from API to match salt + FirstKeyID string } -// Returns openpgp entities contained in this KeyRing +// GetEntities returns openpgp entities contained in this KeyRing func (kr *KeyRing) GetEntities() openpgp.EntityList { return kr.entities } +// GetSigningEntity returns first private signing entity from keyring // Use: internal, but proxied to ios/android only // Use: go-pm-crypto, message.go, sign_detached.go func (kr *KeyRing) GetSigningEntity(passphrase string) *openpgp.Entity { - var signEntity *openpgp.Entity for _, e := range kr.entities { @@ -131,10 +135,10 @@ func (kr *KeyRing) GetSigningEntity(passphrase string) *openpgp.Entity { return signEntity } -// Use: go-pmapi // Encrypt encrypts data to this keyring's owner. If sign is not nil, it also // signs data with it. sign must be unlock to be able to sign data, if it's not // the case an error will be returned. +// Use: go-pmapi func (kr *KeyRing) Encrypt(w io.Writer, sign *KeyRing, filename string, canonicalizeText bool) (io.WriteCloser, error) { // The API returns keys sorted by descending priority // Only encrypt to the first one @@ -163,8 +167,8 @@ func (kr *KeyRing) Encrypt(w io.Writer, sign *KeyRing, filename string, canonica return EncryptCore(w, encryptEntities, signEntity, filename, canonicalizeText, func() time.Time { return GetPmCrypto().GetTime() }) } +// EncryptCore is common encryption method for desktop and mobile clients // Use: go-pm-crypto, keyring.go -// Helper common encryption method for desktop and mobile clients func EncryptCore(w io.Writer, encryptEntities []*openpgp.Entity, signEntity *openpgp.Entity, filename string, canonicalizeText bool, timeGenerator func() time.Time) (io.WriteCloser, error) { config := &packet.Config{DefaultCipher: packet.CipherAES256, Time: timeGenerator} @@ -199,8 +203,8 @@ func (w *armorEncryptWriter) Close() (err error) { return } -// Use: go-pm-crypto, keyring.go // EncryptArmored encrypts and armors data to the keyring's owner. +// Use: go-pm-crypto, keyring.go func (kr *KeyRing) EncryptArmored(w io.Writer, sign *KeyRing) (wc io.WriteCloser, err error) { aw, err := armorUtils.ArmorWithTypeBuffered(w, armorUtils.PGP_MESSAGE_HEADER) if err != nil { @@ -217,8 +221,8 @@ func (kr *KeyRing) EncryptArmored(w io.Writer, sign *KeyRing) (wc io.WriteCloser return } -// Use go-pmapi // EncryptString encrypts and armors a string to the keyring's owner. +// Use go-pmapi func (kr *KeyRing) EncryptString(s string, sign *KeyRing) (encrypted string, err error) { var b bytes.Buffer w, err := kr.EncryptArmored(&b, sign) @@ -237,10 +241,9 @@ func (kr *KeyRing) EncryptString(s string, sign *KeyRing) (encrypted string, err return } +// EncryptSymmetric data using generated symmetric key encrypted with this KeyRing // Use: bridge -// Encrypts data using generated symmetric key encrypted with this KeyRing func (kr *KeyRing) EncryptSymmetric(textToEncrypt string, canonicalizeText bool) (outSplit *models.EncryptedSplit, err error) { - var encryptedWriter io.WriteCloser buffer := &bytes.Buffer{} @@ -260,10 +263,10 @@ func (kr *KeyRing) EncryptSymmetric(textToEncrypt string, canonicalizeText bool) return } -// Use go-pmapi // DecryptString decrypts an armored string sent to the keypair's owner. // If error is errors.ErrSignatureExpired (from golang.org/x/crypto/openpgp/errors), // contents are still provided if library clients wish to process this message further +// Use go-pmapi func (kr *KeyRing) DecryptString(encrypted string) (SignedString, error) { r, signed, err := kr.DecryptArmored(strings.NewReader(encrypted)) if err != nil && err != pgperrors.ErrSignatureExpired { @@ -279,10 +282,10 @@ func (kr *KeyRing) DecryptString(encrypted string) (SignedString, error) { return SignedString{String: s, Signed: signed}, nil } -// Use go-pmapi -// Decrypt data if has PGP MESSAGE format, if not return original data. +// DecryptStringIfNeeded data if has armored PGP message format, if not return original data. // If error is errors.ErrSignatureExpired (from golang.org/x/crypto/openpgp/errors), // contents are still provided if library clients wish to process this message further +// Use go-pmapi func (kr *KeyRing) DecryptStringIfNeeded(data string) (decrypted string, err error) { if re := regexp.MustCompile("^-----BEGIN " + armorUtils.PGP_MESSAGE_HEADER + "-----(?s:.+)-----END " + armorUtils.PGP_MESSAGE_HEADER + "-----"); re.MatchString(data) { var signed SignedString @@ -294,10 +297,9 @@ func (kr *KeyRing) DecryptStringIfNeeded(data string) (decrypted string, err err return } +// SignString sings a string message, using this KeyRing. canonicalizeText identifies if newlines are canonicalized // Use go-pmapi -// Sign a string message, using this KeyRing. canonicalizeText identifies if newlines are canonicalized func (kr *KeyRing) SignString(message string, canonicalizeText bool) (signed string, err error) { - var sig bytes.Buffer err = kr.DetachedSign(&sig, strings.NewReader(message), canonicalizeText, true) @@ -308,11 +310,11 @@ func (kr *KeyRing) SignString(message string, canonicalizeText bool) (signed str } } +// DetachedSign will sign a separate ("detached") data from toSign, writing to +// w writer. The canonicalizeText identifies if newlines are canonicalized // Use: go-pmapi // Use: go-pm-crypto, keyring.go -// Sign a separate ("detached") data from toSign, writing to w. canonicalizeText identifies if newlines are canonicalized func (kr *KeyRing) DetachedSign(w io.Writer, toSign io.Reader, canonicalizeText bool, armored bool) (err error) { - var signEntity *openpgp.Entity for _, e := range kr.entities { if e.PrivateKey != nil && !e.PrivateKey.Encrypted { @@ -347,12 +349,11 @@ func (kr *KeyRing) DetachedSign(w io.Writer, toSign io.Reader, canonicalizeText return } +// VerifyString may return errors.ErrSignatureExpired (defined in +// golang.org/x/crypto/openpgp/errors) In this case signature has been verified +// successfuly, but it is either expired or in the future. // Use: go-pmapi -// May return errors.ErrSignatureExpired (defined in golang.org/x/crypto/openpgp/errors) -// In this case signature has been verified successfuly, but it is either expired or -// in the future. func (kr *KeyRing) VerifyString(message, signature string, sign *KeyRing) (err error) { - messageReader := strings.NewReader(message) signatureReader := strings.NewReader(signature) @@ -375,13 +376,13 @@ func (kr *KeyRing) VerifyString(message, signature string, sign *KeyRing) (err e return err } -// Use: go-pmapi -// Use: go-pm-crypto, attachment.go, message.go -// Unlock unlocks as many keys as possible with the following password. Note +// Unlock tries to unlock as many keys as possible with the following password. Note // that keyrings can contain keys locked with different passwords, and thus // err == nil does not mean that all keys have been successfully decrypted. // If err != nil, the password is wrong for every key, and err is the last error // encountered. +// Use: go-pmapi +// Use: go-pm-crypto, attachment.go, message.go func (kr *KeyRing) Unlock(passphrase []byte) error { // Build a list of keys to decrypt var keys []*packet.PrivateKey @@ -421,12 +422,12 @@ func (kr *KeyRing) Unlock(passphrase []byte) error { return nil } -// Use: go-pmapi -// Use: go-pm-crypto, keyring.go // Decrypt decrypts a message sent to the keypair's owner. If the message is not // signed, signed will be nil. // If error is errors.ErrSignatureExpired (from golang.org/x/crypto/openpgp/errors), // contents are still provided if library clients wish to process this message further +// Use: go-pmapi +// Use: go-pm-crypto, keyring.go func (kr *KeyRing) Decrypt(r io.Reader) (decrypted io.Reader, signed *Signature, err error) { md, err := openpgp.ReadMessage(r, kr.entities, nil, nil) if err != nil && err != pgperrors.ErrSignatureExpired { @@ -440,10 +441,10 @@ func (kr *KeyRing) Decrypt(r io.Reader) (decrypted io.Reader, signed *Signature, return } -// Use: go-pm-crypto, keyring.go // DecryptArmored decrypts an armored message sent to the keypair's owner. // If error is errors.ErrSignatureExpired (from golang.org/x/crypto/openpgp/errors), // contents are still provided if library clients wish to process this message further +// Use: go-pm-crypto, keyring.go func (kr *KeyRing) DecryptArmored(r io.Reader) (decrypted io.Reader, signed *Signature, err error) { block, err := armor.Decode(r) if err != nil && err != pgperrors.ErrSignatureExpired { @@ -458,8 +459,8 @@ func (kr *KeyRing) DecryptArmored(r io.Reader) (decrypted io.Reader, signed *Sig return kr.Decrypt(block.Body) } -// Use: go-pm-crypto, keyring.go // WriteArmoredPublicKey outputs armored public keys from the keyring to w. +// Use: go-pm-crypto, keyring.go func (kr *KeyRing) WriteArmoredPublicKey(w io.Writer) (err error) { aw, err := armor.Encode(w, openpgp.PublicKeyType, nil) if err != nil { @@ -477,8 +478,8 @@ func (kr *KeyRing) WriteArmoredPublicKey(w io.Writer) (err error) { return } -// Use: bridge // ArmoredPublicKeyString returns the armored public keys from this keyring. +// Use: bridge func (kr *KeyRing) ArmoredPublicKeyString() (s string, err error) { b := &bytes.Buffer{} if err = kr.WriteArmoredPublicKey(b); err != nil { @@ -531,15 +532,9 @@ func (kr *KeyRing) readFrom(r io.Reader, armored bool) error { return nil } -/*func (kr *KeyRing) AppendStringKey(key string) error { - - sr := strings.NewReader(key) - return kr.readFrom(sr, true) -}*/ - +// BuildKeyRing reads keyring from binary data // Use: ios/android only func (pm *PmCrypto) BuildKeyRing(binKeys []byte) (kr *KeyRing, err error) { - kr = &KeyRing{} entriesReader := bytes.NewReader(binKeys) err = kr.readFrom(entriesReader, false) @@ -547,16 +542,14 @@ func (pm *PmCrypto) BuildKeyRing(binKeys []byte) (kr *KeyRing, err error) { return } +// BuildKeyRingNoError does not return error on fail // Use: ios/android only func (pm *PmCrypto) BuildKeyRingNoError(binKeys []byte) (kr *KeyRing) { - - kr = &KeyRing{} - entriesReader := bytes.NewReader(binKeys) - kr.readFrom(entriesReader, false) - + kr, _ = pm.BuildKeyRing(binKeys) return } +// BuildKeyRingArmored reads armored string and returns keyring // Use: ios/android only func (pm *PmCrypto) BuildKeyRingArmored(key string) (kr *KeyRing, err error) { keyRaw, err := armorUtils.Unarmor(key) @@ -565,8 +558,9 @@ func (pm *PmCrypto) BuildKeyRingArmored(key string) (kr *KeyRing, err error) { return &KeyRing{entities: keyEntries}, err } -// Only ios/android // UnmarshalJSON implements encoding/json.Unmarshaler. +// Use: go-pmapi +// Use: ios/android func (kr *KeyRing) UnmarshalJSON(b []byte) (err error) { kr.entities = nil @@ -579,15 +573,18 @@ func (kr *KeyRing) UnmarshalJSON(b []byte) (err error) { return } - for _, ko := range keyObjs { + for i, ko := range keyObjs { + if i == 0 { + kr.FirstKeyID = ko.ID + } kr.readFrom(ko.PrivateKeyReader(), true) } return } -// Use: bridge // Identities returns the list of identities associated with this key ring. +// Use: bridge func (kr *KeyRing) Identities() []*Identity { var identities []*Identity for _, e := range kr.entities { @@ -601,8 +598,8 @@ func (kr *KeyRing) Identities() []*Identity { return identities } +// KeyIds returns array of IDs of keys in this KeyRing // Use: not used by bridge -// Return array of IDs of keys in this KeyRing func (kr *KeyRing) KeyIds() []uint64 { var res []uint64 for _, e := range kr.entities { @@ -611,25 +608,26 @@ func (kr *KeyRing) KeyIds() []uint64 { return res } +// ReadArmoredKeyRing reads an armored data into keyring. // Use: go-pmapi -// ReadArmoredKeyRing reads an armored keyring. func ReadArmoredKeyRing(r io.Reader) (kr *KeyRing, err error) { kr = &KeyRing{} err = kr.readFrom(r, true) return } +// ReadKeyRing reads an binary data into keyring. // Use: bridge -// ReadArmoredKeyRing reads an armored keyring. func ReadKeyRing(r io.Reader) (kr *KeyRing, err error) { kr = &KeyRing{} err = kr.readFrom(r, false) return } +// FilterExpiredKeys takes a given KeyRing list and it returns only those +// KeyRings which contain at least, one unexpired Key. It returns only unexpired +// parts of these KeyRings // Use: bridge -// Take a given KeyRing list and return only those KeyRings which contain at least, one unexpired Key -// Returns only unexpired parts of these KeyRings func FilterExpiredKeys(contactKeys []*KeyRing) (filteredKeys []*KeyRing, err error) { now := time.Now() hasExpiredEntity := false