Skip to content

Commit a791b80

Browse files
committed
Migrate from gopenpgp/v2 to gopenpgp/v3
gopenpgp v3 drops the helper package and replaces KeyRing methods (Encrypt/Decrypt/Sign/Verify/EncryptSessionKey/DecryptSessionKey) with a handle-builder API. PlainMessage and PGPSignature value types are gone, replaced by raw []byte and *PGPMessage. Notable call-site changes: - helper.GenerateKey replaced with a local generateLockedKey wrapper around pgp.KeyGeneration() + pgp.LockKey() + Armor(). - addrKR.SignDetachedEncrypted is not exposed in v3; we sign with pgp.Sign().Detached() then encrypt the signature bytes separately. - sessionKey.Decrypt / Encrypt go through pgp.Decryption().SessionKey() / pgp.Encryption().SessionKey() handles. - addrKR.VerifyDetachedEncrypted maps to pgp.Decryption() with PlainDetachedSignature() + DecryptDetached(). - CountDecryptionEntities() now takes a unix-time argument. Pulls in the matching go-proton-api commit b4908c1, which makes the same migration in the underlying library so the KeyRing types match across the package boundary.
1 parent ecd7d61 commit a791b80

12 files changed

Lines changed: 171 additions & 75 deletions

File tree

cache.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"context"
55
"sync"
66

7-
"github.com/ProtonMail/gopenpgp/v2/crypto"
7+
"github.com/ProtonMail/gopenpgp/v3/crypto"
88
"github.com/rclone/Proton-API-Bridge/common"
99
"github.com/rclone/go-proton-api"
1010
)

common/keyring.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package common
33
import (
44
"context"
55

6-
"github.com/ProtonMail/gopenpgp/v2/crypto"
6+
"github.com/ProtonMail/gopenpgp/v3/crypto"
77
"github.com/rclone/go-proton-api"
88
)
99

@@ -60,7 +60,7 @@ func getAccountKRs(ctx context.Context, c *proton.Client, keyPass, saltedKeyPass
6060
if err != nil {
6161
return nil, nil, nil, nil, err
6262

63-
} else if userKR.CountDecryptionEntities() == 0 {
63+
} else if userKR.CountDecryptionEntities(0) == 0 {
6464
if err != nil {
6565
return nil, nil, nil, nil, ErrFailedToUnlockUserKeys
6666
}

common/user.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"encoding/json"
77
"os"
88

9-
"github.com/ProtonMail/gopenpgp/v2/crypto"
9+
"github.com/ProtonMail/gopenpgp/v3/crypto"
1010
"github.com/rclone/Proton-API-Bridge/utility"
1111
"github.com/rclone/go-proton-api"
1212
)

crypto.go

Lines changed: 98 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package proton_api_bridge
22

33
import (
4+
"bytes"
45
"crypto/sha256"
56
"encoding/base64"
67
"io"
78

8-
"github.com/ProtonMail/gopenpgp/v2/crypto"
9-
"github.com/ProtonMail/gopenpgp/v2/helper"
9+
"github.com/ProtonMail/gopenpgp/v3/armor"
10+
"github.com/ProtonMail/gopenpgp/v3/crypto"
1011
)
1112

1213
func generatePassphrase() (string, error) {
@@ -19,44 +20,72 @@ func generatePassphrase() (string, error) {
1920
return tokenBase64, nil
2021
}
2122

23+
// generateLockedKey is the v3-equivalent of v2 helper.GenerateKey: it generates
24+
// a new curve25519 key with the given identity, locks it with the passphrase,
25+
// and returns the armored locked key.
26+
func generateLockedKey(name, email string, passphrase []byte) (string, error) {
27+
pgp := crypto.PGP()
28+
key, err := pgp.KeyGeneration().AddUserId(name, email).New().GenerateKey()
29+
if err != nil {
30+
return "", err
31+
}
32+
defer key.ClearPrivateParams()
33+
34+
locked, err := pgp.LockKey(key, passphrase)
35+
if err != nil {
36+
return "", err
37+
}
38+
return locked.Armor()
39+
}
40+
2241
func generateCryptoKey() (string, string, error) {
2342
passphrase, err := generatePassphrase()
2443
if err != nil {
2544
return "", "", err
2645
}
2746

28-
// all hardcoded values from iOS drive
29-
key, err := helper.GenerateKey("Drive key", "noreply@protonmail.com", []byte(passphrase), "x25519", 0)
47+
// "Drive key" / "noreply@protonmail.com" are the hardcoded identity used by
48+
// the iOS Drive client; v3's default profile produces a curve25519 key,
49+
// which is what the v2 helper produced for keyType "x25519".
50+
key, err := generateLockedKey("Drive key", "noreply@protonmail.com", []byte(passphrase))
3051
if err != nil {
3152
return "", "", err
3253
}
3354

3455
return passphrase, key, nil
3556
}
3657

37-
// taken from Proton Go API Backend
58+
// encryptWithSignature encrypts b to kr and signs it with addrKR, returning the
59+
// armored ciphertext and armored detached signature.
3860
func encryptWithSignature(kr, addrKR *crypto.KeyRing, b []byte) (string, string, error) {
39-
enc, err := kr.Encrypt(crypto.NewPlainMessage(b), nil)
61+
pgp := crypto.PGP()
62+
63+
encHandle, err := pgp.Encryption().Recipients(kr).New()
64+
if err != nil {
65+
return "", "", err
66+
}
67+
68+
enc, err := encHandle.Encrypt(b)
4069
if err != nil {
4170
return "", "", err
4271
}
4372

44-
encArm, err := enc.GetArmored()
73+
encArm, err := enc.Armor()
4574
if err != nil {
4675
return "", "", err
4776
}
4877

49-
sig, err := addrKR.SignDetached(crypto.NewPlainMessage(b))
78+
signHandle, err := pgp.Sign().SigningKeys(addrKR).Detached().New()
5079
if err != nil {
5180
return "", "", err
5281
}
5382

54-
sigArm, err := sig.GetArmored()
83+
sigArm, err := signHandle.Sign(b, crypto.Armor)
5584
if err != nil {
5685
return "", "", err
5786
}
5887

59-
return encArm, sigArm, nil
88+
return encArm, string(sigArm), nil
6089
}
6190

6291
func generateNodeKeys(kr, addrKR *crypto.KeyRing) (string, string, string, error) {
@@ -74,52 +103,79 @@ func generateNodeKeys(kr, addrKR *crypto.KeyRing) (string, string, string, error
74103
}
75104

76105
func reencryptKeyPacket(srcKR, dstKR, addrKR *crypto.KeyRing, passphrase string) (string, error) {
77-
oldSplitMessage, err := crypto.NewPGPSplitMessageFromArmored(passphrase)
106+
pgp := crypto.PGP()
107+
108+
oldMessage, err := crypto.NewPGPMessageFromArmored(passphrase)
78109
if err != nil {
79110
return "", err
80111
}
81112

82-
sessionKey, err := srcKR.DecryptSessionKey(oldSplitMessage.KeyPacket)
113+
srcDec, err := pgp.Decryption().DecryptionKeys(srcKR).New()
83114
if err != nil {
84115
return "", err
85116
}
86117

87-
newKeyPacket, err := dstKR.EncryptSessionKey(sessionKey)
118+
sessionKey, err := srcDec.DecryptSessionKey(oldMessage.BinaryKeyPacket())
88119
if err != nil {
89120
return "", err
90121
}
91122

92-
newSplitMessage := crypto.NewPGPSplitMessage(newKeyPacket, oldSplitMessage.DataPacket)
123+
dstEnc, err := pgp.Encryption().Recipients(dstKR).New()
124+
if err != nil {
125+
return "", err
126+
}
127+
128+
newKeyPacket, err := dstEnc.EncryptSessionKey(sessionKey)
129+
if err != nil {
130+
return "", err
131+
}
93132

94-
return newSplitMessage.GetArmored()
133+
newSplitMessage := crypto.NewPGPSplitMessage(newKeyPacket, oldMessage.BinaryDataPacket())
134+
return newSplitMessage.Armor()
95135
}
96136

97137
func getKeyRing(kr, addrKR *crypto.KeyRing, key, passphrase, passphraseSignature string) (*crypto.KeyRing, error) {
138+
pgp := crypto.PGP()
139+
98140
enc, err := crypto.NewPGPMessageFromArmored(passphrase)
99141
if err != nil {
100142
return nil, err
101143
}
102144

103-
dec, err := kr.Decrypt(enc, nil, crypto.GetUnixTime())
145+
decHandle, err := pgp.Decryption().DecryptionKeys(kr).New()
104146
if err != nil {
105147
return nil, err
106148
}
107149

108-
sig, err := crypto.NewPGPSignatureFromArmored(passphraseSignature)
150+
decResult, err := decHandle.Decrypt(enc.Bytes(), crypto.Bytes)
109151
if err != nil {
110152
return nil, err
111153
}
154+
dec := decResult.Bytes()
112155

113-
if err := addrKR.VerifyDetached(dec, sig, crypto.GetUnixTime()); err != nil {
156+
sig, err := armor.Unarmor(passphraseSignature)
157+
if err != nil {
114158
return nil, err
115159
}
116160

161+
verifyHandle, err := pgp.Verify().VerificationKeys(addrKR).New()
162+
if err != nil {
163+
return nil, err
164+
}
165+
verifyResult, err := verifyHandle.VerifyDetached(dec, sig, crypto.Bytes)
166+
if err != nil {
167+
return nil, err
168+
}
169+
if sigErr := verifyResult.SignatureError(); sigErr != nil {
170+
return nil, sigErr
171+
}
172+
117173
lockedKey, err := crypto.NewKeyFromArmored(key)
118174
if err != nil {
119175
return nil, err
120176
}
121177

122-
unlockedKey, err := lockedKey.Unlock(dec.GetBinary())
178+
unlockedKey, err := lockedKey.Unlock(dec)
123179
if err != nil {
124180
return nil, err
125181
}
@@ -133,33 +189,48 @@ func decryptBlockIntoBuffer(sessionKey *crypto.SessionKey, addrKR, nodeKR *crypt
133189
return err
134190
}
135191

136-
plainMessage, err := sessionKey.Decrypt(data)
192+
skDec, err := crypto.PGP().Decryption().SessionKey(sessionKey).New()
137193
if err != nil {
138194
return err
139195
}
140-
141-
encSignatureArm, err := crypto.NewPGPMessageFromArmored(encSignature)
196+
skResult, err := skDec.Decrypt(data, crypto.Bytes)
142197
if err != nil {
143198
return err
144199
}
200+
plain := skResult.Bytes()
145201

146-
err = addrKR.VerifyDetachedEncrypted(plainMessage, encSignatureArm, nodeKR, crypto.GetUnixTime())
202+
encSignatureMsg, err := crypto.NewPGPMessageFromArmored(encSignature)
147203
if err != nil {
148204
return err
149205
}
150206

151-
_, err = buffer.ReadFrom(plainMessage.NewReader())
207+
// v2 used addrKR.VerifyDetachedEncrypted, where the signature itself is
208+
// encrypted to nodeKR. v3 expresses this through a Decryption handle with
209+
// PlainDetachedSignature() + DecryptDetached().
210+
decHandle, err := crypto.PGP().Decryption().
211+
DecryptionKeys(nodeKR).
212+
VerificationKeys(addrKR).
213+
PlainDetachedSignature().
214+
New()
152215
if err != nil {
153216
return err
154217
}
218+
verifyResult, err := decHandle.DecryptDetached(plain, encSignatureMsg.Bytes(), crypto.Bytes)
219+
if err != nil {
220+
return err
221+
}
222+
if sigErr := verifyResult.SignatureError(); sigErr != nil {
223+
return sigErr
224+
}
225+
226+
if _, err := buffer.ReadFrom(bytes.NewReader(plain)); err != nil {
227+
return err
228+
}
155229

156230
h := sha256.New()
157231
h.Write(data)
158232
hash := h.Sum(nil)
159233
base64Hash := base64.StdEncoding.EncodeToString(hash)
160-
if err != nil {
161-
return err
162-
}
163234
if base64Hash != originalHash {
164235
return ErrDownloadedBlockHashVerificationFailed
165236
}

drive.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"github.com/rclone/Proton-API-Bridge/common"
77
"golang.org/x/sync/semaphore"
88

9-
"github.com/ProtonMail/gopenpgp/v2/crypto"
9+
"github.com/ProtonMail/gopenpgp/v3/crypto"
1010
"github.com/rclone/go-proton-api"
1111
)
1212

file_download.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"context"
66
"io"
77

8-
"github.com/ProtonMail/gopenpgp/v2/crypto"
8+
"github.com/ProtonMail/gopenpgp/v3/crypto"
99
"github.com/rclone/Proton-API-Bridge/utility"
1010
"github.com/rclone/go-proton-api"
1111
)

file_upload.go

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
"path/filepath"
1515
"time"
1616

17-
"github.com/ProtonMail/gopenpgp/v2/crypto"
17+
"github.com/ProtonMail/gopenpgp/v3/crypto"
1818
"github.com/rclone/Proton-API-Bridge/utility"
1919
"github.com/rclone/go-proton-api"
2020
)
@@ -342,17 +342,38 @@ func (protonDrive *ProtonDrive) uploadAndCollectBlockData(ctx context.Context, n
342342
Encryption: current link's session key
343343
Signature: share's signature address keys
344344
*/
345-
dataPlainMessage := crypto.NewPlainMessage(data)
346-
encData, err := newSessionKey.Encrypt(dataPlainMessage)
345+
pgp := crypto.PGP()
346+
347+
sessionEnc, err := pgp.Encryption().SessionKey(newSessionKey).New()
348+
if err != nil {
349+
return nil, 0, nil, "", err
350+
}
351+
encMsg, err := sessionEnc.Encrypt(data)
347352
if err != nil {
348353
return nil, 0, nil, "", err
349354
}
355+
encData := encMsg.Bytes()
350356

351-
encSignature, err := protonDrive.DefaultAddrKR.SignDetachedEncrypted(dataPlainMessage, newNodeKR)
357+
// v2's SignDetachedEncrypted: sign the data with addrKR, then encrypt
358+
// the signature to newNodeKR. v3 does not expose a one-shot helper, so
359+
// we sign first and encrypt the signature bytes separately.
360+
signHandle, err := pgp.Sign().SigningKeys(protonDrive.DefaultAddrKR).Detached().New()
361+
if err != nil {
362+
return nil, 0, nil, "", err
363+
}
364+
rawSig, err := signHandle.Sign(data, crypto.Bytes)
365+
if err != nil {
366+
return nil, 0, nil, "", err
367+
}
368+
sigEncHandle, err := pgp.Encryption().Recipients(newNodeKR).New()
369+
if err != nil {
370+
return nil, 0, nil, "", err
371+
}
372+
encSignature, err := sigEncHandle.Encrypt(rawSig)
352373
if err != nil {
353374
return nil, 0, nil, "", err
354375
}
355-
encSignatureStr, err := encSignature.GetArmored()
376+
encSignatureStr, err := encSignature.Armor()
356377
if err != nil {
357378
return nil, 0, nil, "", err
358379
}
@@ -387,14 +408,15 @@ func (protonDrive *ProtonDrive) uploadAndCollectBlockData(ctx context.Context, n
387408
}
388409

389410
func (protonDrive *ProtonDrive) commitNewRevision(ctx context.Context, nodeKR *crypto.KeyRing, xAttrCommon *proton.RevisionXAttrCommon, manifestSignatureData []byte, linkID, revisionID string) error {
390-
manifestSignature, err := protonDrive.DefaultAddrKR.SignDetached(crypto.NewPlainMessage(manifestSignatureData))
411+
signHandle, err := crypto.PGP().Sign().SigningKeys(protonDrive.DefaultAddrKR).Detached().New()
391412
if err != nil {
392413
return err
393414
}
394-
manifestSignatureString, err := manifestSignature.GetArmored()
415+
manifestSig, err := signHandle.Sign(manifestSignatureData, crypto.Armor)
395416
if err != nil {
396417
return err
397418
}
419+
manifestSignatureString := string(manifestSig)
398420

399421
commitRevisionReq := proton.CommitRevisionReq{
400422
ManifestSignature: manifestSignatureString,

folder_recursive.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"io"
66
"os"
77

8-
"github.com/ProtonMail/gopenpgp/v2/crypto"
8+
"github.com/ProtonMail/gopenpgp/v3/crypto"
99
"github.com/rclone/go-proton-api"
1010
)
1111

0 commit comments

Comments
 (0)