Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undisclosed v3 breaking change: KeyRing.Decrypt was removed #313

Closed
hpurmann opened this issue Nov 11, 2024 · 16 comments
Closed

Undisclosed v3 breaking change: KeyRing.Decrypt was removed #313

hpurmann opened this issue Nov 11, 2024 · 16 comments
Labels
v3 Targeting GopenPGP v3

Comments

@hpurmann
Copy link

Hey all!

We are currently using v2 and make use of the KeyRing.Decrypt function. This function has disappeared in v3, but it's not mentioned in the changelog.

I'm wondering if this was a mistake or deliberate. And if deliberate, how can we adapt our implementation to fit v3?

@lubux
Copy link
Member

lubux commented Nov 11, 2024

Hi 👋 All OpenPGP operations can now only be executed via the new API.
Reasoning:

GopenPGP v3 introduces a new unified API for high level OpenPGP operations. In comparison to GopenPGP v2, where similar functions were dispersed across different types and required varying implementations for the same operations, GopenPGP v3 consolidates these functions into a consistent interface. Now, operations such as Sign, Verify, Encrypt, Decrypt, and Key generation are each accessible through a unified, builder like API, simplifying integration and enhancing code readability across cryptographic workflows.

So for KeyRing.Decrypt it would be:

keyRing := ...
pgp := PGP()
decHandle, err := pgp.
	Decryption().
	DecryptionKeys(keyRing).
	VerificationKeys(...). // optional if signatures should be verified 
	VerifyTime(...). // optional if the verification time should be something else than the local time
	New()
if err != nil {
	panic(err)
}
decrypted, err := decHandle.Decrypt([]byte(armoredMessage), crypto.Armor)
if err != nil {
	panic(err)
}
fmt.Println(decrypted.String())

@lubux lubux added the v3 Targeting GopenPGP v3 label Nov 11, 2024
@hpurmann
Copy link
Author

Thank you @lubux, that worked. I see that your quote is from the releases page. My bad, I only looked at the Changelog file.

@hpurmann
Copy link
Author

hpurmann commented Nov 15, 2024

Hey @lubux! The code change worked in CI (unit tests are decrypting a local file with a local key/passphrase) but it crashed on production with

gopenpgp: decrypting message with private keys failed: openpgp: incorrect key

I'm wondering where the difference in behavior might be. Have you seen any regression between v2 and v3 related to that?

With v2 we're using the library like this:

pgpMessage, err := crypto.NewPGPMessageFromArmored(string(bytes))
if err != nil {
	return nil, err
}

message, err := keyring.Decrypt(pgpMessage, nil, 0)
if err != nil {
	return nil, err
}
keyring.ClearPrivateParams()

return message.Data, nil

and in v3 we're doing

pgp := crypto.PGP()
decHandle, err := pgp.Decryption().DecryptionKeys(keyring).New()
if err != nil {
	return nil, err
}

message, err := decHandle.Decrypt(bytes, crypto.Armor)
if err != nil {
	return nil, err
}
keyring.ClearPrivateParams()

return message.Bytes(), nil

@hpurmann hpurmann reopened this Nov 15, 2024
@JasonQuinn
Copy link
Contributor

@hpurmann I am also seeing the same when testing this, some files work ok and some others using the same key return the openpgp: incorrect key error

@lubux
Copy link
Member

lubux commented Nov 18, 2024

Hi 👋 This error indicates that there is no matching valid key available for decrypting the message.
GopenPGP v3 introduces a new go-crypto fork API that improves interoperability, but it also modifies the core logic.

In version 3, decryption now involves checking the decryption keys for validity, if they are not valid they are not considered. Consequently, some subkeys might have invalid or outdated signatures or use a blocked hash functions.
Do you have an example public key of a decryption key that is failing?

@JasonQuinn
Copy link
Contributor

JasonQuinn commented Nov 19, 2024

@lubux So they key is able to decrypt some of the files but not others using v3 but gpg on the cmd line can decrypt them all so they key seems fine to me.
V2 is failing some files with "openpgp: invalid data: tag byte does not have MSB set" which works ok in V3, but other files which fail in V3 with "openpgp: incorrect key" work ok in V2.
Unfortunately the only examples I have of it breaking are for production data so i can't share the key/files.

@JasonQuinn
Copy link
Contributor

I figured out what the difference was. For the files which worked in V2 but failed in V3 the file was encrypted using the primary key instead of the sub key so i guess that was allowed to be decrypted in v2 but changed for v3?

@lubux
Copy link
Member

lubux commented Nov 20, 2024

Thanks for checking this. GopenPGP v3 does allow to decrypt with the primary key if it is marked as encryption capable. However, if it fails it means the primary key is most likely marked as signing key only. We are considering adding a flag to allow decryption with signing keys (ProtonMail/go-crypto#251), if the client accepts the security risk. Using the same key for encryption and signing reduces security.

@JasonQuinn
Copy link
Contributor

That makes sense, thank you

@lubux
Copy link
Member

lubux commented Nov 25, 2024

Added the option with: #316

@JasonQuinn
Copy link
Contributor

JasonQuinn commented Nov 25, 2024 via email

@hpurmann
Copy link
Author

Thank you @lubux for the quick reaction, it works for me too 👍

@jamesapc
Copy link

jamesapc commented Dec 3, 2024

Hi @JasonQuinn and @hpurmann can you show the point if code to resolved this issue ? not for all only issue point. still not work for me 🙏🏻

@JasonQuinn
Copy link
Contributor

@jamesapc I needed to add .InsecureAllowDecryptionWithSigningKeys() to the DecryptionHandleBuilder so it would allow decrypting with the signing key like v2 allowed

decHandle, err := pgp.Decryption().InsecureAllowDecryptionWithSigningKeys().DecryptionKey(privateKey).New()

@hpurmann
Copy link
Author

hpurmann commented Dec 3, 2024

@jamesapc exactly as @JasonQuinn wrote, you disable the validation by invoking the InsecureAllowDecryptionWithSigningKeys() function in the builder chain.

@jamesapc
Copy link

jamesapc commented Dec 6, 2024

Thank you 🙇🏻‍♂️ @JasonQuinn @hpurmann

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v3 Targeting GopenPGP v3
Projects
None yet
Development

No branches or pull requests

4 participants