From 3fe6899fbb36058c97e8a0967c42a99e7e940a8f Mon Sep 17 00:00:00 2001 From: Jakub Lehotsky Date: Fri, 9 Nov 2018 02:03:19 +0100 Subject: [PATCH] Android stable version --- crypto/attachment.go | 93 +------------------ crypto/keyring.go | 31 +++++++ crypto/message.go | 200 +++++++++++----------------------------- crypto/mime.go | 4 +- crypto/sign_detached.go | 117 ----------------------- 5 files changed, 91 insertions(+), 354 deletions(-) diff --git a/crypto/attachment.go b/crypto/attachment.go index 2a81114..d578e52 100644 --- a/crypto/attachment.go +++ b/crypto/attachment.go @@ -14,19 +14,13 @@ import ( ) // Encrypt attachment. Takes input data and key data in binary form -func (pm *PmCrypto) EncryptAttachmentBinKey(plainData []byte, fileName string, publicKey []byte) (*models.EncryptedSplit, error) { - +func (pm *PmCrypto) EncryptAttachment(plainData []byte, fileName string, publicKey *KeyRing) (*models.EncryptedSplit, error) { var outBuf bytes.Buffer w, err := armor.Encode(&outBuf, armorUtils.PGP_MESSAGE_HEADER, internal.ArmorHeaders) if err != nil { return nil, err } - pubKeyReader := bytes.NewReader(publicKey) - pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader) - if err != nil { - return nil, err - } hints := &openpgp.FileHints{ FileName: fileName, } @@ -36,7 +30,7 @@ func (pm *PmCrypto) EncryptAttachmentBinKey(plainData []byte, fileName string, p Time: pm.getTimeGenerator(), } - ew, err := openpgp.Encrypt(w, pubKeyEntries, nil, hints, config) + ew, err := openpgp.Encrypt(w, publicKey.entities, nil, hints, config) _, _ = ew.Write(plainData) ew.Close() @@ -66,22 +60,10 @@ func SplitArmor(encrypted string) (*models.EncryptedSplit, error) { } -// Encrypt attachment. Takes input data in binary form and key in as a string -func (pm *PmCrypto) EncryptAttachment(plainData []byte, fileName string, publicKey string) (*models.EncryptedSplit, error) { - rawPubKey, err := armorUtils.Unarmor(publicKey) - if err != nil { - return nil, err - } - return pm.EncryptAttachmentBinKey(plainData, fileName, rawPubKey) -} - // Decrypt attachment. Takes input data and key data in binary form. privateKeys can contains more keys. passphrase is used to unlock keys -func (pm *PmCrypto) DecryptAttachmentBinKey(keyPacket []byte, dataPacket []byte, privateKeys []byte, passphrase string) ([]byte, error) { - privKeyRaw := bytes.NewReader(privateKeys) - privKeyEntries, err := openpgp.ReadKeyRing(privKeyRaw) - if err != nil { - return nil, err - } +func (pm *PmCrypto) DecryptAttachment(keyPacket []byte, dataPacket []byte, kr *KeyRing, passphrase string) ([]byte, error) { + + privKeyEntries := kr.entities rawPwd := []byte(passphrase) for _, e := range privKeyEntries { @@ -117,68 +99,3 @@ func (pm *PmCrypto) DecryptAttachmentBinKey(keyPacket []byte, dataPacket []byte, return b, nil } - -// Decrypt attachment. Takes input data and key data in binary form and key as an armored string. passphrase is used to unlock keys -func (pm *PmCrypto) DecryptAttachment(keyPacket []byte, dataPacket []byte, privateKey string, passphrase string) ([]byte, error) { - rawPrivKey, err := armorUtils.Unarmor(privateKey) - if err != nil { - return nil, err - } - return pm.DecryptAttachmentBinKey(keyPacket, dataPacket, rawPrivKey, passphrase) -} - -//Encrypt attachment. Use symmetrical cipher with key in password input string -func (pm *PmCrypto) EncryptAttachmentWithPassword(plainData []byte, password string) (string, error) { - - var outBuf bytes.Buffer - w, err := armor.Encode(&outBuf, armorUtils.PGP_MESSAGE_HEADER, internal.ArmorHeaders) - if err != nil { - return "", err - } - - config := &packet.Config{Time: pm.getTimeGenerator()} - - plaintext, err := openpgp.SymmetricallyEncrypt(w, []byte(password), nil, config) - if err != nil { - return "", err - } - - _, err = plaintext.Write(plainData) - if err != nil { - return "", err - } - err = plaintext.Close() - if err != nil { - return "", err - } - w.Close() - - return outBuf.String(), nil -} - -//Decrypt attachment using password locked key. -func (pm *PmCrypto) DecryptAttachmentWithPassword(keyPacket []byte, dataPacket []byte, password string) ([]byte, error) { - - encrypted := append(keyPacket, dataPacket...) - - encryptedReader := bytes.NewReader(encrypted) - - var prompt = func(keys []openpgp.Key, symmetric bool) ([]byte, error) { - return []byte(password), nil - } - - config := &packet.Config{Time: pm.getTimeGenerator()} - - md, err := openpgp.ReadMessage(encryptedReader, nil, prompt, config) - if err != nil { - return nil, err - } - - messageBuf := bytes.NewBuffer(nil) - _, err = io.Copy(messageBuf, md.UnverifiedBody) - if err != nil { - return nil, err - } - - return messageBuf.Bytes(), nil -} diff --git a/crypto/keyring.go b/crypto/keyring.go index 2e07b17..a72833b 100644 --- a/crypto/keyring.go +++ b/crypto/keyring.go @@ -473,6 +473,37 @@ 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) +}*/ + +func (pm *PmCrypto) BuildKeyRing(binKeys []byte) (kr *KeyRing, err error) { + + kr = &KeyRing{} + entriesReader := bytes.NewReader(binKeys) + err = kr.readFrom(entriesReader, false) + + return +} + +func (pm *PmCrypto) BuildKeyRingNoEror(binKeys []byte) (kr *KeyRing) { + + kr = &KeyRing{} + entriesReader := bytes.NewReader(binKeys) + kr.readFrom(entriesReader, false) + + return +} + +func (pm *PmCrypto) BuildKeyRingArmored(key string) (kr *KeyRing, err error) { + keyRaw, err := armorUtils.Unarmor(key) + keyReader := bytes.NewReader(keyRaw) + keyEntries, err := openpgp.ReadKeyRing(keyReader) + return &KeyRing{entities: keyEntries}, err +} + // UnmarshalJSON implements encoding/json.Unmarshaler. func (kr *KeyRing) UnmarshalJSON(b []byte) (err error) { kr.entities = nil diff --git a/crypto/message.go b/crypto/message.go index 5b7c5a1..6f7f6f2 100644 --- a/crypto/message.go +++ b/crypto/message.go @@ -3,9 +3,7 @@ package crypto import ( "bytes" "errors" - "io" "io/ioutil" - "strings" "time" armorUtils "github.com/ProtonMail/go-pm-crypto/armor" @@ -22,21 +20,27 @@ import ( // encryptedText : string armored encrypted // privateKey : armored private use to decrypt message // passphrase : match with private key to decrypt message -func (pm *PmCrypto) DecryptMessage(encryptedText string, privateKey string, passphrase string) (string, error) { +func (pm *PmCrypto) DecryptMessageStringKey(encryptedText string, privateKey string, passphrase string) (string, error) { privKeyRaw, err := armorUtils.Unarmor(privateKey) if err != nil { return "", err } - return pm.DecryptMessageBinKey(encryptedText, privKeyRaw, passphrase) + privKeyReader := bytes.NewReader(privKeyRaw) + privKeyEntries, err := openpgp.ReadKeyRing(privKeyReader) + if err != nil { + return "", err + } + + return pm.DecryptMessage(encryptedText, &KeyRing{entities: privKeyEntries}, passphrase) } // DecryptMessageBinKey decrypt encrypted message use private key (bytes ) // encryptedText : string armored encrypted // privateKey : unarmored private use to decrypt message could be mutiple keys // passphrase : match with private key to decrypt message -func (pm *PmCrypto) DecryptMessageBinKey(encryptedText string, privateKey []byte, passphrase string) (string, error) { +func (kr *KeyRing) DecryptMessage(encryptedText string, passphrase string) (string, error) { - md, err := pm.decryptCore(encryptedText, nil, privateKey, passphrase, pm.getTimeGenerator()) + md, err := pm.decryptCore(encryptedText, nil, kr.entities, passphrase, pm.getTimeGenerator()) if err != nil { return "", err } @@ -51,60 +55,14 @@ func (pm *PmCrypto) DecryptMessageBinKey(encryptedText string, privateKey []byte return string(b), nil } -// DecryptMessageVerifyPrivBinKeys decrypt message and verify the signature -// verifierKey string: armored verifier keys -// privateKey []byte: unarmored private key to decrypt. could be mutiple -func (pm *PmCrypto) DecryptMessageVerifyPrivBinKeys(encryptedText string, verifierKey string, privateKeys []byte, passphrase string, verifyTime int64) (*models.DecryptSignedVerify, error) { - - if len(verifierKey) > 0 { - verifierRaw, err := armorUtils.Unarmor(verifierKey) - if err != nil { - return nil, err - } - return pm.decryptMessageVerifyAllBin(encryptedText, verifierRaw, privateKeys, passphrase, verifyTime) - } - return pm.decryptMessageVerifyAllBin(encryptedText, nil, privateKeys, passphrase, verifyTime) -} - // DecryptMessageVerifyBinKeyPrivBinKeys decrypt message and verify the signature // verifierKey []byte: unarmored verifier keys // privateKey []byte: unarmored private key to decrypt. could be mutiple -func (pm *PmCrypto) DecryptMessageVerifyBinKeyPrivBinKeys(encryptedText string, verifierKey []byte, privateKeys []byte, passphrase string, verifyTime int64) (*models.DecryptSignedVerify, error) { - return pm.decryptMessageVerifyAllBin(encryptedText, verifierKey, privateKeys, passphrase, verifyTime) +func (pm *PmCrypto) DecryptMessageVerify(encryptedText string, verifierKey []byte, privateKeysRing *KeyRing, passphrase string, verifyTime int64) (*models.DecryptSignedVerify, error) { + return pm.decryptMessageVerify(encryptedText, verifierKey, privateKeysRing, passphrase, verifyTime) } -// DecryptMessageVerify decrypt message and verify the signature -// verifierKey string: armored verifier keys -// privateKey string: private to decrypt -func (pm *PmCrypto) DecryptMessageVerify(encryptedText string, verifierKey string, privateKey string, passphrase string, verifyTime int64) (*models.DecryptSignedVerify, error) { - if len(verifierKey) > 0 { - verifierRaw, err := armorUtils.Unarmor(verifierKey) - if err != nil { - return nil, err - } - return pm.DecryptMessageVerifyBinKey(encryptedText, verifierRaw, privateKey, passphrase, verifyTime) - } - return pm.DecryptMessageVerifyBinKey(encryptedText, nil, privateKey, passphrase, verifyTime) -} - -// DecryptMessageVerifyBinKey decrypt message and verify the signature -// verifierKey []byte: unarmored verifier keys -// privateKey string: private to decrypt -func (pm *PmCrypto) DecryptMessageVerifyBinKey(encryptedText string, verifierKey []byte, privateKey string, passphrase string, verifyTime int64) (*models.DecryptSignedVerify, error) { - privateKeyRaw, err := armorUtils.Unarmor(privateKey) - if err != nil { - return nil, err - } - return pm.decryptMessageVerifyAllBin(encryptedText, verifierKey, privateKeyRaw, passphrase, verifyTime) -} - -func (pm *PmCrypto) decryptCore(encryptedText string, additionalEntries openpgp.EntityList, privateKey []byte, passphrase string, timeFunc func() time.Time) (*openpgp.MessageDetails, error) { - - privKey := bytes.NewReader(privateKey) - privKeyEntries, err := openpgp.ReadKeyRing(privKey) - if err != nil { - return nil, err - } +func (pm *PmCrypto) decryptCore(encryptedText string, additionalEntries openpgp.EntityList, privKeyEntries openpgp.EntityList, passphrase string, timeFunc func() time.Time) (*openpgp.MessageDetails, error) { rawPwd := []byte(passphrase) for _, e := range privKeyEntries { @@ -137,10 +95,10 @@ func (pm *PmCrypto) decryptCore(encryptedText string, additionalEntries openpgp. return md, err } -// decryptMessageVerifyAllBin +// decryptMessageVerify // decrypt_message_verify_single_key(private_key: string, passphras: string, encrypted : string, signature : string) : decrypt_sign_verify; // decrypt_message_verify(passphras: string, encrypted : string, signature : string) : decrypt_sign_verify; -func (pm *PmCrypto) decryptMessageVerifyAllBin(encryptedText string, verifierKey []byte, privateKey []byte, passphrase string, verifyTime int64) (*models.DecryptSignedVerify, error) { +func (pm *PmCrypto) decryptMessageVerify(encryptedText string, verifierKey []byte, privateKeyRing *KeyRing, passphrase string, verifyTime int64) (*models.DecryptSignedVerify, error) { out := &models.DecryptSignedVerify{} out.Verify = failed @@ -158,7 +116,7 @@ func (pm *PmCrypto) decryptMessageVerifyAllBin(encryptedText string, verifierKey out.Verify = noVerifier } - md, err := pm.decryptCore(encryptedText, verifierEntries, privateKey, passphrase, func() time.Time { return time.Unix(0, 0) }) // TODO: I doubt this time is correct + md, err := pm.decryptCore(encryptedText, verifierEntries, privateKeyRing.entities, passphrase, func() time.Time { return time.Unix(0, 0) }) // TODO: I doubt this time is correct decrypted := md.UnverifiedBody b, err := ioutil.ReadAll(decrypted) @@ -212,76 +170,6 @@ func processSignatureExpiration(md *openpgp.MessageDetails, verifyTime int64) { } } -// EncryptMessage encrypt message with public key, if pass private key and passphrase will also sign the message -// publicKey : string armored public key -// plainText : the input -// privateKey : optional required when you want to sign -// passphrase : optional required when you pass the private key and this passphrase must could decrypt the private key -func (pm *PmCrypto) EncryptMessage(plainText string, publicKey string, privateKey string, passphrase string, trim bool) (string, error) { - rawPubKey, err := armorUtils.Unarmor(publicKey) - if err != nil { - return "", err - } - return pm.EncryptMessageBinKey(plainText, rawPubKey, privateKey, passphrase, trim) -} - -// EncryptMessageBinKey encrypt message with unarmored public key, if pass private key and passphrase will also sign the message -// publicKey : bytes unarmored public key -// plainText : the input -// privateKey : optional required when you want to sign -// passphrase : optional required when you pass the private key and this passphrase must could decrypt the private key -func (pm *PmCrypto) EncryptMessageBinKey(plainText string, publicKey []byte, privateKey string, passphrase string, trim bool) (string, error) { - - if trim { - plainText = internal.TrimNewlines(plainText) - } - var outBuf bytes.Buffer - w, err := armor.Encode(&outBuf, armorUtils.PGP_MESSAGE_HEADER, internal.ArmorHeaders) - if err != nil { - return "", err - } - - pubKeyReader := bytes.NewReader(publicKey) - pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader) - if err != nil { - return "", err - } - - var signEntity *openpgp.Entity - - if len(passphrase) > 0 && len(privateKey) > 0 { - signerReader := strings.NewReader(privateKey) - signerEntries, err := openpgp.ReadArmoredKeyRing(signerReader) - if err != nil { - return "", err - } - - for _, e := range signerEntries { - // Entity.PrivateKey must be a signing key - if e.PrivateKey != nil { - if e.PrivateKey.Encrypted { - e.PrivateKey.Decrypt([]byte(passphrase)) - } - if !e.PrivateKey.Encrypted { - signEntity = e - break - } - } - } - - if signEntity == nil { - return "", errors.New("cannot sign message, signer key is not unlocked") - } - } - - ew, err := EncryptCore(w, pubKeyEntries, signEntity, "", false, pm.getTimeGenerator()) - - _, _ = ew.Write([]byte(plainText)) - ew.Close() - w.Close() - return outBuf.String(), nil -} - //EncryptMessageWithPassword encrypt a plain text to pgp message with a password //plainText string: clear text //output string: armored pgp message @@ -312,30 +200,48 @@ func (pm *PmCrypto) EncryptMessageWithPassword(plainText string, password string return outBuf.String(), nil } -//DecryptMessageWithPassword decrypt a pgp message with a password -//encrypted string : armored pgp message -//output string : clear text -func (pm *PmCrypto) DecryptMessageWithPassword(encrypted string, password string) (string, error) { - encryptedio, err := internal.Unarmor(encrypted) +// EncryptMessageBinKey encrypt message with unarmored public key, if pass private key and passphrase will also sign the message +// publicKey : bytes unarmored public key +// plainText : the input +// privateKey : optional required when you want to sign +// passphrase : optional required when you pass the private key and this passphrase must could decrypt the private key +func (pm *PmCrypto) EncryptMessage(plainText string, publicKey *KeyRing, privateKey *KeyRing, passphrase string, trim bool) (string, error) { + + if trim { + plainText = internal.TrimNewlines(plainText) + } + var outBuf bytes.Buffer + w, err := armor.Encode(&outBuf, armorUtils.PGP_MESSAGE_HEADER, internal.ArmorHeaders) if err != nil { return "", err } - var prompt = func(keys []openpgp.Key, symmetric bool) ([]byte, error) { - return []byte(password), nil + var signEntity *openpgp.Entity + + if len(passphrase) > 0 && len(privateKey.entities) > 0 { + + for _, e := range privateKey.entities { + // Entity.PrivateKey must be a signing key + if e.PrivateKey != nil { + if e.PrivateKey.Encrypted { + e.PrivateKey.Decrypt([]byte(passphrase)) + } + if !e.PrivateKey.Encrypted { + signEntity = e + break + } + } + } + + if signEntity == nil { + return "", errors.New("cannot sign message, signer key is not unlocked") + } } - config := &packet.Config{Time: pm.getTimeGenerator()} - md, err := openpgp.ReadMessage(encryptedio.Body, nil, prompt, config) - if err != nil { - return "", err - } + ew, err := EncryptCore(w, publicKey.entities, signEntity, "", false, pm.getTimeGenerator()) - messageBuf := bytes.NewBuffer(nil) - _, err = io.Copy(messageBuf, md.UnverifiedBody) - if err != nil { - return "", err - } - - return messageBuf.String(), nil + _, _ = ew.Write([]byte(plainText)) + ew.Close() + w.Close() + return outBuf.String(), nil } diff --git a/crypto/mime.go b/crypto/mime.go index ccc4ebc..3e36334 100644 --- a/crypto/mime.go +++ b/crypto/mime.go @@ -54,9 +54,9 @@ type MIMECallbacks interface { OnError(err error) } -func (pm *PmCrypto) DecryptMIMEMessage(encryptedText string, verifierKey []byte, privateKeys []byte, +func (pm *PmCrypto) DecryptMIMEMessage(encryptedText string, verifierKey []byte, privateKeyRing *KeyRing, passphrase string, callbacks MIMECallbacks, verifyTime int64) { - decsignverify, err := pm.decryptMessageVerifyAllBin(encryptedText, verifierKey, privateKeys, passphrase, verifyTime) + decsignverify, err := pm.decryptMessageVerify(encryptedText, verifierKey, privateKeyRing, passphrase, verifyTime) if err != nil { callbacks.OnError(err) return diff --git a/crypto/sign_detached.go b/crypto/sign_detached.go index 6276003..60b4fe9 100644 --- a/crypto/sign_detached.go +++ b/crypto/sign_detached.go @@ -58,51 +58,6 @@ func (pm *PmCrypto) SignTextDetached(plainText string, privateKey string, passph return outBuf.String(), nil } -// Sign detached text using binary key data -func (pm *PmCrypto) SignTextDetachedBinKey(plainText string, privateKey []byte, passphrase string, trim bool) (string, error) { - //sign with 0x01 - var signEntity *openpgp.Entity - - if trim { - plainText = internal.TrimNewlines(plainText) - } - - signerReader := bytes.NewReader(privateKey) - signerEntries, err := openpgp.ReadKeyRing(signerReader) - if err != nil { - return "", err - } - - for _, e := range signerEntries { - // Entity.PrivateKey must be a signing key - if e.PrivateKey != nil { - if e.PrivateKey.Encrypted { - e.PrivateKey.Decrypt([]byte(passphrase)) - } - if !e.PrivateKey.Encrypted { - signEntity = e - break - } - } - } - - if signEntity == nil { - return "", errors.New("cannot sign message, singer key is not unlocked") - } - - config := &packet.Config{DefaultCipher: packet.CipherAES256, Time: pm.getTimeGenerator()} - - att := strings.NewReader(plainText) - - var outBuf bytes.Buffer - //sign text - if err = openpgp.ArmoredDetachSignText(&outBuf, signEntity, att, config); err != nil { - return "", err - } - - return outBuf.String(), nil -} - // Sign detached bin data using string key func (pm *PmCrypto) SignBinDetached(plainData []byte, privateKey string, passphrase string) (string, error) { //sign with 0x00 @@ -144,64 +99,6 @@ func (pm *PmCrypto) SignBinDetached(plainData []byte, privateKey string, passphr return outBuf.String(), nil } -// Sign detached binary data using binary key format -func (pm *PmCrypto) SignBinDetachedBinKey(plainData []byte, privateKey []byte, passphrase string) (string, error) { - //sign with 0x00 - var signEntity *openpgp.Entity - - signerReader := bytes.NewReader(privateKey) - signerEntries, err := openpgp.ReadKeyRing(signerReader) - if err != nil { - return "", err - } - - for _, e := range signerEntries { - // Entity.PrivateKey must be a signing key - if e.PrivateKey != nil { - if e.PrivateKey.Encrypted { - e.PrivateKey.Decrypt([]byte(passphrase)) - } - if !e.PrivateKey.Encrypted { - signEntity = e - break - } - } - } - - if signEntity == nil { - return "", errors.New("cannot sign message, singer key is not unlocked") - } - - config := &packet.Config{DefaultCipher: packet.CipherAES256, Time: pm.getTimeGenerator()} - - att := bytes.NewReader(plainData) - - var outBuf bytes.Buffer - //sign bin - if err = openpgp.ArmoredDetachSign(&outBuf, signEntity, att, config); err != nil { - return "", err - } - - return outBuf.String(), nil -} - -// Verify detached text - check if signature is valid using a given publicKey -func (pm *PmCrypto) VerifyTextSignDetached(signature string, plainText string, publicKey string, verifyTime int64) (bool, error) { - - pubKeyReader := strings.NewReader(publicKey) - - pubKeyEntries, err := openpgp.ReadArmoredKeyRing(pubKeyReader) - if err != nil { - return false, err - } - - plainText = internal.TrimNewlines(plainText) - - origText := bytes.NewReader(bytes.NewBufferString(plainText).Bytes()) - - return verifySignature(pubKeyEntries, origText, signature, verifyTime) -} - // Verify detached text - check if signature is valid using a given publicKey in binary format func (pm *PmCrypto) VerifyTextSignDetachedBinKey(signature string, plainText string, publicKey []byte, verifyTime int64) (bool, error) { @@ -261,20 +158,6 @@ func verifySignature(pubKeyEntries openpgp.EntityList, origText *bytes.Reader, s return true, nil } -// Verify detached text in binary format - check if signature is valid using a given publicKey in string format -func (pm *PmCrypto) VerifyBinSignDetached(signature string, plainData []byte, publicKey string, verifyTime int64) (bool, error) { - - pubKeyReader := strings.NewReader(publicKey) - - pubKeyEntries, err := openpgp.ReadArmoredKeyRing(pubKeyReader) - if err != nil { - return false, err - } - - origText := bytes.NewReader(plainData) - return verifySignature(pubKeyEntries, origText, signature, verifyTime) -} - // Verify detached text in binary format - check if signature is valid using a given publicKey in binary format func (pm *PmCrypto) VerifyBinSignDetachedBinKey(signature string, plainData []byte, publicKey []byte, verifyTime int64) (bool, error) { pubKeyReader := bytes.NewReader(publicKey)