From 118dd9624b84921814be20728bbbe3739cddbf0a Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Wed, 19 Mar 2025 14:40:16 +0100 Subject: [PATCH] store userprivatekey in clients as crypto.key instead of armor --- api/auth.go | 9 +-------- api/client.go | 28 ++++++++-------------------- api/encryption.go | 43 +++++++++++-------------------------------- api/verify.go | 8 +------- 4 files changed, 21 insertions(+), 67 deletions(-) diff --git a/api/auth.go b/api/auth.go index 93e7732..19da61b 100644 --- a/api/auth.go +++ b/api/auth.go @@ -30,14 +30,7 @@ func (c *Client) CheckSession(ctx context.Context) bool { func (c *Client) Login(ctx context.Context) error { c.csrfToken = http.Cookie{} - privateKey, err := c.getPrivateKey(c.userPrivateKey, c.userPassword) - if err != nil { - return fmt.Errorf("Parsing User Private Key: %w", err) - } - - defer privateKey.ClearPrivateParams() - - data := Login{&GPGAuth{KeyID: privateKey.GetFingerprint()}} + data := Login{&GPGAuth{KeyID: c.userPrivateKey.GetFingerprint()}} res, _, err := c.DoCustomRequestAndReturnRawResponse(ctx, "POST", "/auth/login.json", "v2", data, nil) if err != nil && !strings.Contains(err.Error(), "Error API JSON Response Status: Message: The authentication failed.") { diff --git a/api/client.go b/api/client.go index e97a134..3acf427 100644 --- a/api/client.go +++ b/api/client.go @@ -26,8 +26,7 @@ type Client struct { // userPublicKey has been removed since it can be gotten from the private userPrivateKey - userPassword []byte - userPrivateKey string + userPrivateKey *crypto.Key userID string // Server Settings Determining which Resource Types we can use @@ -71,23 +70,13 @@ func NewClient(httpClient *http.Client, UserAgent, BaseURL, UserPrivateKey, User pgp := crypto.PGP() - // Verify that the Given Privatekey and Password are valid and work Together if we were provieded one + var unlockedKey *crypto.Key = nil if UserPrivateKey != "" { - privateKeyObj, err := crypto.NewKeyFromArmored(UserPrivateKey) + key, err := GetPrivateKeyFromArmor(UserPrivateKey, []byte(UserPassword)) if err != nil { - return nil, fmt.Errorf("Unable to Create Key From UserPrivateKey string: %w", err) + return nil, fmt.Errorf("Get Private Key: %w", err) } - unlockedKeyObj, err := privateKeyObj.Unlock([]byte(UserPassword)) - if err != nil { - return nil, fmt.Errorf("Unable to Unlock UserPrivateKey using UserPassword: %w", err) - } - privateKeyRing, err := crypto.NewKeyRing(unlockedKeyObj) - if err != nil { - return nil, fmt.Errorf("Unable to Create a new Key Ring using the unlocked UserPrivateKey: %w", err) - } - - // Cleanup Secrets - privateKeyRing.ClearPrivateParams() + unlockedKey = key } // Create Client Object @@ -95,8 +84,7 @@ func NewClient(httpClient *http.Client, UserAgent, BaseURL, UserPrivateKey, User httpClient: httpClient, baseURL: u, userAgent: UserAgent, - userPassword: []byte(UserPassword), - userPrivateKey: UserPrivateKey, + userPrivateKey: unlockedKey, pgp: pgp, } return c, err @@ -207,11 +195,11 @@ func (c *Client) GetPublicKey(ctx context.Context) (string, string, error) { } // Lets get the actual Fingerprint instead of trusting the Server - privateKeyObj, err := crypto.NewKeyFromArmored(c.userPrivateKey) + serverKey, err := crypto.NewKeyFromArmored(body.Keydata) if err != nil { return "", "", fmt.Errorf("Parsing Server Key: %w", err) } - return body.Keydata, privateKeyObj.GetFingerprint(), nil + return body.Keydata, serverKey.GetFingerprint(), nil } // setMetadataTypeSettings Gets and configures the Client to use the Types the Server wants us to use diff --git a/api/encryption.go b/api/encryption.go index 3186f0d..1ce2c8f 100644 --- a/api/encryption.go +++ b/api/encryption.go @@ -8,14 +8,7 @@ import ( // EncryptMessage encrypts a message using the users public key and then signes the message using the users private key func (c *Client) EncryptMessage(message string) (string, error) { - key, err := c.getPrivateKey(c.userPrivateKey, c.userPassword) - if err != nil { - return "", fmt.Errorf("Get Private Key: %w", err) - } - - defer key.ClearPrivateParams() - - encHandle, err := c.pgp.Encryption().SigningKey(key).Recipient(key).New() + encHandle, err := c.pgp.Encryption().SigningKey(c.userPrivateKey).Recipient(c.userPrivateKey).New() if err != nil { return "", fmt.Errorf("New Encryptor: %w", err) } @@ -36,19 +29,12 @@ func (c *Client) EncryptMessage(message string) (string, error) { // EncryptMessageWithPublicKey encrypts a message using the provided public key and then signes the message using the users private key func (c *Client) EncryptMessageWithPublicKey(publickey, message string) (string, error) { - key, err := c.getPrivateKey(c.userPrivateKey, c.userPassword) - if err != nil { - return "", fmt.Errorf("Get Private Key: %w", err) - } - - defer key.ClearPrivateParams() - publicKey, err := crypto.NewKeyFromArmored(publickey) if err != nil { return "", fmt.Errorf("Get Public Key: %w", err) } - encHandle, err := c.pgp.Encryption().SigningKey(key).Recipient(publicKey).New() + encHandle, err := c.pgp.Encryption().SigningKey(c.userPrivateKey).Recipient(publicKey).New() if err != nil { return "", fmt.Errorf("New Encryptor: %w", err) } @@ -68,29 +54,26 @@ func (c *Client) EncryptMessageWithPublicKey(publickey, message string) (string, } // DecryptMessage decrypts a message using the users Private Key -func (c *Client) DecryptMessage(message string) (string, error) { - message, _, err := c.DecryptMessageWithPrivateKeyAndReturnSessionKey(c.userPrivateKey, c.userPassword, message) +func (c *Client) DecryptMessage(armoredCiphertext string) (string, error) { + message, _, err := c.DecryptMessageWithPrivateKeyAndReturnSessionKey(c.userPrivateKey, armoredCiphertext) return message, err } // DecryptMessageWithPrivateKey Decrypts a Message using the Provided Private Key // Returns the Session key so that it can be saved in a cache -func (c *Client) DecryptMessageWithPrivateKeyAndReturnSessionKey(privateKey string, passphrase []byte, ciphertextArmored string) (string, *crypto.SessionKey, error) { - key, err := c.getPrivateKey(privateKey, passphrase) - if err != nil { - return "", nil, fmt.Errorf("Get Private Key: %w", err) - } +func (c *Client) DecryptMessageWithPrivateKeyAndReturnSessionKey(privateKey *crypto.Key, armoredCiphertext string) (string, *crypto.SessionKey, error) { - defer key.ClearPrivateParams() - - decHandle, err := c.pgp.Decryption().DecryptionKey(key).RetrieveSessionKey().New() + decHandle, err := c.pgp.Decryption(). + DecryptionKey(privateKey). + RetrieveSessionKey(). + New() if err != nil { return "", nil, fmt.Errorf("New Decryptor: %w", err) } defer decHandle.ClearPrivateParams() - res, err := decHandle.Decrypt([]byte(ciphertextArmored), crypto.Armor) + res, err := decHandle.Decrypt([]byte(armoredCiphertext), crypto.Armor) if err != nil { return "", nil, fmt.Errorf("Decrypt: %w", err) } @@ -98,11 +81,7 @@ func (c *Client) DecryptMessageWithPrivateKeyAndReturnSessionKey(privateKey stri return res.String(), res.SessionKey(), nil } -func (c *Client) getPrivateKey(privateKey string, passphrase []byte) (*crypto.Key, error) { - if c.userPrivateKey == "" { - return nil, fmt.Errorf("Client has no Private Key") - } - +func GetPrivateKeyFromArmor(privateKey string, passphrase []byte) (*crypto.Key, error) { key, err := crypto.NewKeyFromArmored(privateKey) if err != nil { return nil, fmt.Errorf("Key From Armored: %w", err) diff --git a/api/verify.go b/api/verify.go index 74e35b6..8ed16e2 100644 --- a/api/verify.go +++ b/api/verify.go @@ -5,7 +5,6 @@ import ( "fmt" "strings" - "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/google/uuid" ) @@ -44,15 +43,10 @@ func (c *Client) SetupServerVerification(ctx context.Context) (string, string, e // VerifyServer verifys that the Server is still the same one as during the Setup, Only works before login func (c *Client) VerifyServer(ctx context.Context, token, encToken string) error { - privateKeyObj, err := crypto.NewKeyFromArmored(c.userPrivateKey) - if err != nil { - return fmt.Errorf("Parsing User Private Key: %w", err) - } - data := GPGVerifyContainer{ Req: GPGVerify{ Token: encToken, - KeyID: privateKeyObj.GetFingerprint(), + KeyID: c.userPrivateKey.GetFingerprint(), }, } raw, _, err := c.DoCustomRequestAndReturnRawResponse(ctx, "POST", "/auth/verify.json", "v2", data, nil)