feat(helper): Add hardware token ECDH decryption support#356
feat(helper): Add hardware token ECDH decryption support#35683noit wants to merge 2 commits intoProtonMail:v2from
Conversation
Add two new helper functions for integrating OpenPGP hardware tokens (YubiKey, smartcards) with gopenpgp: GetEncryptedKeyFieldsFromMessage extracts the key ID, algorithm, and raw encrypted MPI fields from the first PKESK packet in a PGP message. This allows callers to send the ephemeral point (MPI1) to a hardware token for the ECDH Decaps operation. DecryptMessageWithECDHSharedSecret completes ECDH decryption given a pre-computed shared secret from an external Decaps operation. It performs the KDF (RFC 6637 §8) and AES key unwrap (RFC 3394) to recover the session key, then decrypts the message. The private key is never needed. Depends on go-crypto additions: EncryptedKey.GetEncryptedMPI1/2, PublicKey.GetECDHOid, and ecdh.DecryptWithSharedSecret. Relates to ProtonMail#174.
Adds a gomobile-compatible wrapper around GetEncryptedKeyFieldsFromMessage that returns only the first MPI field. gomobile cannot bind functions with more than 2 return values, so this single-purpose wrapper is needed for iOS integration.
|
Note on v2 vs v3: This PR targets |
|
Note: This PR depends on ProtonMail/go-crypto#307, which has been reworked based on reviewer feedback to use an interface-based approach ( Once the go-crypto PR is merged, I'll rework this PR to match the new design — the gopenpgp surface will be simpler since the library now handles KDF/unwrap internally. Please hold off on reviewing until then. |
Summary
Adds helper functions to support ECDH decryption when the private key
operation (Decaps) is performed by an external hardware token such as a
YubiKey or OpenPGP smartcard.
GetEncryptedKeyFieldsFromMessage— extracts key ID, algorithm, andraw MPI fields from the first PKESK packet, so the ephemeral point
can be sent to a hardware token
GetEncryptedMPI1FromMessage— gomobile-compatible wrapper returningonly the ephemeral point (gomobile cannot bind functions with more
than 2 return values)
DecryptMessageWithECDHSharedSecret— completes ECDH decryptiongiven a pre-computed shared secret from an external Decaps operation,
performing KDF (RFC 6637 §8) and AES key unwrap (RFC 3394) to
recover the session key
No existing behaviour is changed. All new functions are additive.
Motivation
OpenPGP smartcards support ECDH via PSO:DECIPHER, which takes the
ephemeral point and returns the raw shared secret without exposing
the private scalar. The current gopenpgp API requires a full private
key for decryption.
These helpers enable the split workflow:
GetEncryptedKeyFieldsFromMessage/GetEncryptedMPI1FromMessage)DecryptMessageWithECDHSharedSecret)This follows the existing helper pattern of composing lower-level
go-crypto operations into gomobile-compatible convenience functions.
Depends on ProtonMail/go-crypto#307 adding
GetEncryptedMPI1/2,GetECDHOid, andecdh.DecryptWithSharedSecret.Relates to #174.
Test plan
TestGetEncryptedKeyFieldsFromMessage— RSA message field extractionTestDecryptMessageWithECDHSharedSecret— full ECDH roundtrip:encrypt → extract MPI1 → manual Decaps → DecryptMessageWithECDHSharedSecret
go test ./...)