diff --git a/Changelog.md b/Changelog.md index d13af4c..028581b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,7 +9,9 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) * `FirstKeyID` into `KeyRing` object to be able match salts ### Changed -* Comments following linter recomendations +* If statement re-factor following linter recommendations +* Constants rename following linter recomendations +* Comments following linter recomendations (not complete) * Update the crypto and mime dependencies * Error handling in `GetSessionFromKeyPaket` diff --git a/armor/armor.go b/armor/armor.go index 3b88acf..ed8b430 100644 --- a/armor/armor.go +++ b/armor/armor.go @@ -4,6 +4,7 @@ package armor import ( "bytes" "errors" + "github.com/ProtonMail/go-pm-crypto/constants" "github.com/ProtonMail/go-pm-crypto/internal" "golang.org/x/crypto/openpgp/armor" "golang.org/x/crypto/openpgp/clearsign" @@ -11,20 +12,20 @@ import ( "io/ioutil" ) -// Use: ios/android only // ArmorKey make bytes input key to armor format +// Use: ios/android only func ArmorKey(input []byte) (string, error) { - return ArmorWithType(input, PUBLIC_KEY_HEADER) + return ArmorWithType(input, constants.PublicKeyHeader) } -// Use: go-pm-crypto, keyring.go // ArmorWithTypeBuffered take input from io.Writer and returns io.WriteCloser which can be read for armored code +// Use: go-pm-crypto, keyring.go func ArmorWithTypeBuffered(w io.Writer, armorType string) (io.WriteCloser, error) { return armor.Encode(w, armorType, nil) } -// Use: go-pm-crypto // ArmorWithType make bytes input to armor format +// Use: go-pm-crypto func ArmorWithType(input []byte, armorType string) (string, error) { var b bytes.Buffer @@ -41,8 +42,8 @@ func ArmorWithType(input []byte, armorType string) (string, error) { return b.String(), nil } -// Use: go-pm-crypto, attachment.go, keyring.go, session.go, message.go // Unarmor an armored key to bytes key +// Use: go-pm-crypto, attachment.go, keyring.go, session.go, message.go func Unarmor(input string) ([]byte, error) { b, err := internal.Unarmor(input) if err != nil { @@ -51,8 +52,8 @@ func Unarmor(input string) ([]byte, error) { return ioutil.ReadAll(b.Body) } -// Use: ios/android only //ReadClearSignedMessage read clear message from a clearsign package (package containing cleartext and signature) +// Use: ios/android only func ReadClearSignedMessage(signedMessage string) (string, error) { modulusBlock, rest := clearsign.Decode([]byte(signedMessage)) if len(rest) != 0 { diff --git a/armor/constants.go b/armor/constants.go deleted file mode 100644 index ae342fd..0000000 --- a/armor/constants.go +++ /dev/null @@ -1,13 +0,0 @@ -package armor - -import ( - "github.com/ProtonMail/go-pm-crypto/internal" -) - -const ( - ARMOR_HEADER_VERSION = internal.ARMOR_HEADER_VERSION - ARMOR_HEADER_COMMENT = internal.ARMOR_HEADER_COMMENT - PGP_MESSAGE_HEADER string = "PGP MESSAGE" - PUBLIC_KEY_HEADER string = "PGP PUBLIC KEY BLOCK" - PRIVATE_KEY_HEADER string = "PGP PRIVATE KEY BLOCK" -) diff --git a/constants/armor.go b/constants/armor.go new file mode 100644 index 0000000..3b6d358 --- /dev/null +++ b/constants/armor.go @@ -0,0 +1,10 @@ +package constants + +// Definitions for armored data +const ( + ArmorHeaderVersion = "Pmcrypto Golang 0.0.1 (" + Version + ")" + ArmorHeaderComment = "https://protonmail.com" + PGPMessageHeader = "PGP MESSAGE" + PublicKeyHeader = "PGP PUBLIC KEY BLOCK" + PrivateKeyHeader = "PGP PRIVATE KEY BLOCK" +) diff --git a/constants/version.go b/constants/version.go index 066d937..e6b57ce 100644 --- a/constants/version.go +++ b/constants/version.go @@ -1,3 +1,3 @@ package constants -const VERSION = "ddacebe0" \ No newline at end of file +const Version = "ddacebe0" diff --git a/crypto/key.go b/crypto/key.go index 7e23d58..ce12cb7 100644 --- a/crypto/key.go +++ b/crypto/key.go @@ -7,22 +7,21 @@ import ( "encoding/hex" "errors" "fmt" - "github.com/ProtonMail/go-pm-crypto/armor" "io" "math/big" - "time" - // "net/http" - // "net/url" "runtime" "strings" + "time" - //"github.com/ProtonMail/go-pm-crypto/armor" + "github.com/ProtonMail/go-pm-crypto/armor" + "github.com/ProtonMail/go-pm-crypto/constants" "github.com/ProtonMail/go-pm-crypto/models" + "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/packet" ) -// A decrypted session key. +// SymmetricKey stores a decrypted session key. type SymmetricKey struct { // The clear base64-encoded key. //Key string @@ -31,7 +30,7 @@ type SymmetricKey struct { Algo string } -//18 with the 2 highest order bits set to 1 +// SymmetricallyEncryptedTag is 18 with the 2 highest order bits set to 1 const SymmetricallyEncryptedTag = 210 var symKeyAlgos = map[string]packet.CipherFunction{ @@ -43,8 +42,8 @@ var symKeyAlgos = map[string]packet.CipherFunction{ "aes256": packet.CipherAES256, } +// GetCipherFunc returns functin corresponding to an algorithm used in this SymmetricKey // Use: go-pm-crypto, key.go, session.go -// Get cipher function corresponding to an algorithm used in this SymmetricKey func (sk *SymmetricKey) GetCipherFunc() packet.CipherFunction { cf, ok := symKeyAlgos[sk.Algo] if ok { @@ -54,8 +53,8 @@ func (sk *SymmetricKey) GetCipherFunc() packet.CipherFunction { panic("pmapi: unsupported cipher function: " + sk.Algo) } +// GetBase64Key returns a key as base64 encoded string // Use: bridge -// Returns a key as base64 encoded string func (sk *SymmetricKey) GetBase64Key() string { return base64.StdEncoding.EncodeToString(sk.Key) } @@ -246,8 +245,8 @@ func encodedLength(length int) (b []byte) { return } -// Use: bridge // SetKey encrypts the provided key. +// Use: bridge func SetKey(kr *KeyRing, symKey *SymmetricKey) (packets string, err error) { b := &bytes.Buffer{} w := base64.NewEncoder(base64.StdEncoding, b) @@ -305,8 +304,8 @@ func SetKey(kr *KeyRing, symKey *SymmetricKey) (packets string, err error) { return } +// IsKeyExpiredBin checks if the given key is expired. Input in binary format //Use: ios/android only -//Check if the given key is expired. Input in binary format func (pm *PmCrypto) IsKeyExpiredBin(publicKey []byte) (bool, error) { now := pm.getNow() pubKeyReader := bytes.NewReader(publicKey) @@ -365,8 +364,8 @@ const ( failed = 3 ) -//Use: ios/android only -//Check if the given key is expired. Input in armored form +// IsKeyExpired checks if the given key is expired. Input in armored format +// Use: ios/android only func (pm *PmCrypto) IsKeyExpired(publicKey string) (bool, error) { rawPubKey, err := armor.Unarmor(publicKey) if err != nil { @@ -444,29 +443,34 @@ func (pm *PmCrypto) generateKey(userName string, domain string, passphrase strin return "", err } serialized := w.Bytes() - return armor.ArmorWithType(serialized, armor.PRIVATE_KEY_HEADER) + return armor.ArmorWithType(serialized, constants.PrivateKeyHeader) } -func (pm *PmCrypto) GenerateRSAKeyWithPrimes(userName string, domain string, passphrase string, bits int, - primeone []byte, primetwo []byte, primethree []byte, primefour []byte) (string, error) { +// GenerateRSAKeyWithPrimes generates RSA key with given primes. +// Use: TODO +func (pm *PmCrypto) GenerateRSAKeyWithPrimes( + userName, domain, passphrase string, + bits int, + primeone, primetwo, primethree, primefour []byte, +) (string, error) { return pm.generateKey(userName, domain, passphrase, "rsa", bits, primeone, primetwo, primethree, primefour) } -// Use: ios/android only // GenerateKey ... +// TODO: is it really disabled // disabled now, will enable later // #generat new key with email address. Fix the UserID issue in protonmail system. on Feb 28, 17 // #static generate_key_with_email(email : string, passphrase : string, bits : i32) : open_pgp_key; // # generate new key // #static generate_new_key(user_id : string, email : string, passphrase : string, bits : i32) : open_pgp_key; +// Use: ios/android only func (pm *PmCrypto) GenerateKey(userName string, domain string, passphrase string, keyType string, bits int) (string, error) { return pm.generateKey(userName, domain, passphrase, keyType, bits, nil, nil, nil, nil) } +// UpdatePrivateKeyPassphrase decrypts the given private key with oldPhrase and reencrypt with the newPassphrase // Use ios/android only -// Decrypt given private key with oldPhrase and reencrypt with newPassphrase func (pm *PmCrypto) UpdatePrivateKeyPassphrase(privateKey string, oldPassphrase string, newPassphrase string) (string, error) { - privKey := strings.NewReader(privateKey) privKeyEntries, err := openpgp.ReadArmoredKeyRing(privKey) if err != nil { @@ -506,11 +510,11 @@ func (pm *PmCrypto) UpdatePrivateKeyPassphrase(privateKey string, oldPassphrase } serialized := w.Bytes() - return armor.ArmorWithType(serialized, armor.PRIVATE_KEY_HEADER) + return armor.ArmorWithType(serialized, constants.PrivateKeyHeader) } -// Use: ios/android only // CheckKey print out the key and subkey fingerprint +// Use: ios/android only func (pm *PmCrypto) CheckKey(pubKey string) (string, error) { pubKeyReader := strings.NewReader(pubKey) entries, err := openpgp.ReadArmoredKeyRing(pubKeyReader) diff --git a/crypto/keyring.go b/crypto/keyring.go index 4c3094d..8cea700 100644 --- a/crypto/keyring.go +++ b/crypto/keyring.go @@ -12,13 +12,14 @@ import ( "strings" "time" - "github.com/ProtonMail/go-pm-crypto/models" "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/armor" pgperrors "golang.org/x/crypto/openpgp/errors" "golang.org/x/crypto/openpgp/packet" armorUtils "github.com/ProtonMail/go-pm-crypto/armor" + "github.com/ProtonMail/go-pm-crypto/constants" + "github.com/ProtonMail/go-pm-crypto/models" ) // A keypair contains a private key and a public key. @@ -178,9 +179,8 @@ func EncryptCore(w io.Writer, encryptEntities []*openpgp.Entity, signEntity *ope } if canonicalizeText { return openpgp.EncryptText(w, encryptEntities, signEntity, hints, config) - } else { - return openpgp.Encrypt(w, encryptEntities, signEntity, hints, config) } + return openpgp.Encrypt(w, encryptEntities, signEntity, hints, config) } // An io.WriteCloser that both encrypts and armors data. @@ -206,7 +206,7 @@ func (w *armorEncryptWriter) Close() (err error) { // 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) + aw, err := armorUtils.ArmorWithTypeBuffered(w, constants.PGPMessageHeader) if err != nil { return } @@ -287,7 +287,7 @@ func (kr *KeyRing) DecryptString(encrypted string) (SignedString, error) { // 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) { + if re := regexp.MustCompile("^-----BEGIN " + constants.PGPMessageHeader + "-----(?s:.+)-----END " + constants.PGPMessageHeader + "-----"); re.MatchString(data) { var signed SignedString signed, err = kr.DecryptString(data) decrypted = signed.String @@ -305,9 +305,8 @@ func (kr *KeyRing) SignString(message string, canonicalizeText bool) (signed str if err != nil { return "", err - } else { - return sig.String(), nil } + return sig.String(), nil } // DetachedSign will sign a separate ("detached") data from toSign, writing to @@ -451,7 +450,7 @@ func (kr *KeyRing) DecryptArmored(r io.Reader) (decrypted io.Reader, signed *Sig return } - if block.Type != armorUtils.PGP_MESSAGE_HEADER { + if block.Type != constants.PGPMessageHeader { err = errors.New("pmapi: not an armored PGP message") return } diff --git a/crypto/message.go b/crypto/message.go index de6e443..3fce8ca 100644 --- a/crypto/message.go +++ b/crypto/message.go @@ -5,23 +5,25 @@ import ( "errors" "io" "io/ioutil" + "math" "time" - armorUtils "github.com/ProtonMail/go-pm-crypto/armor" - "github.com/ProtonMail/go-pm-crypto/internal" - "github.com/ProtonMail/go-pm-crypto/models" "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/armor" - errors2 "golang.org/x/crypto/openpgp/errors" + pgpErrors "golang.org/x/crypto/openpgp/errors" "golang.org/x/crypto/openpgp/packet" - "math" + + armorUtils "github.com/ProtonMail/go-pm-crypto/armor" + "github.com/ProtonMail/go-pm-crypto/constants" + "github.com/ProtonMail/go-pm-crypto/internal" + "github.com/ProtonMail/go-pm-crypto/models" ) -// Use: ios/android only -// DecryptMessage decrypt encrypted message use private key (string ) +// DecryptMessageStringKey decrypt encrypted message use private key (string ) // encryptedText : string armored encrypted // privateKey : armored private use to decrypt message // passphrase : match with private key to decrypt message +// Use: ios/android only func (pm *PmCrypto) DecryptMessageStringKey(encryptedText string, privateKey string, passphrase string) (string, error) { privKeyRaw, err := armorUtils.Unarmor(privateKey) if err != nil { @@ -36,13 +38,12 @@ func (pm *PmCrypto) DecryptMessageStringKey(encryptedText string, privateKey str return pm.DecryptMessage(encryptedText, &KeyRing{entities: privKeyEntries}, passphrase) } -// Use ios/android only -// DecryptMessageBinKey decrypt encrypted message use private key (bytes ) +// DecryptMessage decrypts encrypted string using keyring // encryptedText : string armored encrypted -// privateKey : unarmored private use to decrypt message could be mutiple keys +// privateKey : keyring with private key to decrypt message, could be mutiple keys // passphrase : match with private key to decrypt message +// Use ios/android only func (pm *PmCrypto) DecryptMessage(encryptedText string, privateKey *KeyRing, passphrase string) (string, error) { - md, err := decryptCore(encryptedText, nil, privateKey, passphrase, pm.getTimeGenerator()) if err != nil { return "", err @@ -59,7 +60,6 @@ func (pm *PmCrypto) DecryptMessage(encryptedText string, privateKey *KeyRing, pa } func decryptCore(encryptedText string, additionalEntries openpgp.EntityList, privKey *KeyRing, passphrase string, timeFunc func() time.Time) (*openpgp.MessageDetails, error) { - rawPwd := []byte(passphrase) privKey.Unlock(rawPwd) @@ -136,7 +136,7 @@ func (pm *PmCrypto) DecryptMessageVerify(encryptedText string, verifierKey *KeyR // Handle signature time verification manually, so we can add a margin to the creationTime check. func processSignatureExpiration(md *openpgp.MessageDetails, verifyTime int64) { - if md.SignatureError == errors2.ErrSignatureExpired { + if md.SignatureError == pgpErrors.ErrSignatureExpired { if verifyTime > 0 { created := md.Signature.CreationTime.Unix() expires := int64(math.MaxInt64) @@ -160,7 +160,7 @@ func processSignatureExpiration(md *openpgp.MessageDetails, verifyTime int64) { func (pm *PmCrypto) EncryptMessageWithPassword(plainText string, password string) (string, error) { var outBuf bytes.Buffer - w, err := armor.Encode(&outBuf, armorUtils.PGP_MESSAGE_HEADER, internal.ArmorHeaders) + w, err := armor.Encode(&outBuf, constants.PGPMessageHeader, internal.ArmorHeaders) if err != nil { return "", err } @@ -196,7 +196,7 @@ func (pm *PmCrypto) EncryptMessage(plainText string, publicKey *KeyRing, private plainText = internal.TrimNewlines(plainText) } var outBuf bytes.Buffer - w, err := armor.Encode(&outBuf, armorUtils.PGP_MESSAGE_HEADER, internal.ArmorHeaders) + w, err := armor.Encode(&outBuf, constants.PGPMessageHeader, internal.ArmorHeaders) if err != nil { return "", err } diff --git a/crypto/signature_collector.go b/crypto/signature_collector.go index e568351..d4ea0da 100644 --- a/crypto/signature_collector.go +++ b/crypto/signature_collector.go @@ -34,9 +34,7 @@ func (sc *SignatureCollector) Accept(part io.Reader, header textproto.MIMEHeader newPart, rawBody := pmmime.GetRawMimePart(part, "--"+params["boundary"]) var multiparts []io.Reader var multipartHeaders []textproto.MIMEHeader - if multiparts, multipartHeaders, err = pmmime.GetMultipartParts(newPart, params); err != nil { - return - } else { + if multiparts, multipartHeaders, err = pmmime.GetMultipartParts(newPart, params); err == nil { hasPlainChild := false for _, header := range multipartHeaders { mediaType, _, _ := mime.ParseMediaType(header.Get("Content-Type")) diff --git a/internal/common.go b/internal/common.go index 1b33c33..198bc08 100644 --- a/internal/common.go +++ b/internal/common.go @@ -16,13 +16,8 @@ func TrimNewlines(input string) string { // ProtonMail Email Parser const CreationTimeOffset = int64(60 * 60 * 24 * 2) -const ( - armorHeaderVersion = "Pmcrypto Golang 0.0.1 (" + constants.VERSION + ")" - armorHeaderComment = "https://protonmail.com" -) - // ArmorHeaders from golang pm-crypto var ArmorHeaders = map[string]string{ - "Version": armorHeaderVersion, - "Comment": armorHeaderComment, + "Version": constants.ArmorHeaderVersion, + "Comment": constants.ArmorHeaderComment, } diff --git a/key/key.go b/key/key.go index 950a806..280c332 100644 --- a/key/key.go +++ b/key/key.go @@ -5,6 +5,7 @@ import ( "bytes" "fmt" "github.com/ProtonMail/go-pm-crypto/armor" + "github.com/ProtonMail/go-pm-crypto/constants" "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/packet" "strings" @@ -55,7 +56,7 @@ func PublicKey(privateKey string) (string, error) { e.Serialize(&outBuf) } - outString, err := armor.ArmorWithType(outBuf.Bytes(), armor.PUBLIC_KEY_HEADER) + outString, err := armor.ArmorWithType(outBuf.Bytes(), constants.PublicKeyHeader) if err != nil { return "", nil }