Problem/Motivation
The current interfaces on Encryption module - and all the implementations I've seen so far - don't take in consideration public key cryptography.
"Public key cryptography, or asymmetrical cryptography, is any cryptographic system that uses pairs of keys: public keys which may be disseminated widely, and private keys which are known only to the owner." source Wikipedia.
Currently the module description page clearly states "Encrypt is a Drupal module that provides an application programming interface (API) for performing two-way data encryption", which presume we exclude asymmetrical cryptography, when the user want to use only the public key and so only encrypt the data.
To be honest currently implementing two-way encryption is not 100% safe, as the key to encrypt as well as decrypt is stored in the same instance. This can be mitigated by not storing the key anywhere in the current machine and making sure it's not cached anyway, as well as storing the key on 3rd party services.
I'm the maintainer of the Encrypt RSA, which allow users to use a Private key to encrypt/decrypt as well as just the public key to encrypt-only their data.
Proposed resolution
My suggestion is to:
- introduce a flag/method in the
EncryptionMethodInterfacei.e.::canDecrypt()to check if method can actually decrypt - Raise an exception when "encryption" service try to decrypt through a method with
::canDecrypt()FALSE. - Extend
EncryptionMethodInterface::decrypt()docblock by adding the @throw exception annotation when the method can't decrypt - Adding some test coverage
- Update the module description and documentation, flagging it supports Public-key cryptography as well and so don't assume decryption is always possible
- Advertisting a bit this change, mainly to increase the knowledge around asymmetrical cryptography
Remaining tasks
introduce a flag/method in theEncryptionMethodInterfacei.e.::canDecrypt()to check if method can actually decryptRaise an exception when "encryption" service try to decrypt through a method with::canDecrypt()FALSE.ExtendEncryptionMethodInterface::decrypt()docblock by adding the @throw exception annotation when the method can't decryptAdding some test coverageUpdate the moduleREADME.md, description and documentation, flagging it supports Public-key cryptography as well and so don't assume decryption is always possible- Getting in touch with the main contrib modules providing Encryption Methods and for the module to be listed in Encrypt project page it needs to include a small template/widget/bullet-list (TBD) where it says: Encryption Method being used, link to the method documentation, Can decrypt? Yes/No.
User interface changes
No.
API changes
A new Encryption Method property definition can_decrypt and a new EncryptionMethodInterface::canDecrypt() method have been created. They are TRUE by default.
Data model changes
No.
| Comment | File | Size | Author |
|---|---|---|---|
| #8 | 2943231-8.patch | 13.04 KB | gambry |
| #8 | interdiff-5-8.txt | 4.81 KB | gambry |
| #5 | 2943231-5.patch | 11.97 KB | gambry |
Comments
Comment #2
gambryComment #3
nerdstein@gambry, thank you for bringing this up. I agree that we can likely strengthen the module to better support asynchronous modes. We did use Encrypt within Google Summer of Code for this module, https://www.drupal.org/project/pubkey_encrypt, which seems to have at least some similar objectives as the module you proposed. Could you please explore this? Maybe the two modules could combine.
As noted, that module is making use of encrypt. But, your suggestions may actually improve both modules.
Some specifics ---
1. "introduce a flag/method to check if it can decrypt" -> this sounds like an annotation, as it's likely static
2. and 3. and 4. agreed, this should be tied to the annotation
5. yes this would be helpful and is already happening. so it's not accurate as it is now
6. suggestions?
In addition, I'd like to see us work on the usability of the module. Users should be very keenly aware that an encryption method uses one-way encryption and their info cannot be decrypted. I would love if someone could review the UI and make a suggestion.
Comment #4
gambry@nerdstein thanks for your reply. My main concern was if my request was totally crazy. It doesn't look like, so thank you again for that.
I had a look at pubkey_encrypt during my investigation, and this was my understanding:
- The module does much more than providing an encryption method, i.e. "the module generates an Encryption Profile for each role".
- The module depends on https://www.drupal.org/project/encrypt_seclib , which doesn't have any release.
- The module uses phpseclib, which although being a wonderful library, it's hard to use in the right way (I've been playing around with it a lot and I do prefer its wrapper https://github.com/paragonie/EasyRSA )
That's why I built Encryption RSA.
But let me know by any meaning how we can contribute together, I would rather have one module doing something perfectly than two or more doing roughly the same thing.
Yes, and I'd like to have your feedbacks:
Will start working on a patch for this issue soon.
Thanks again and many thanks to @Manuel Garcia for intermediating! :D
Comment #5
gambryThis is first draft of the work. I thought it would have been more disruptive, but it's not at all and it could nicely be merged in current version.
The work introduces a new Encryption Method
can_encrypt(annotation) definition. If this is FALSE the encryption service throws aDrupal\encrypt\Exception\EncryptionMethodCanNotDecryptExceptionexception ifdecrypt()is called for an encryption method wherecan_decryptis set to FALSE (or anyway itscanDecrypt()method return FALSE).Existing encryption method plugins don't need alteration, they will inherit the default
can_decryptannotation value which is TRUE.Because decryption can be invoked also by calling directly an Encryption Profile's method
$encryption_profile->getEncryptionMethod->decrypt(), Encryption Methods who can NOT decrypt should also throw the same exception on theydecrypt()method.The patch also update the readme.md file and add some test coverage.
Comment #6
gambryFixing couple of typos and adding reference to external key management tools.
Comment #7
manuel garcia commentedPatch is looking really good, some minor nitpicks:
Trailing spaces.
This should return '###encrypted###' instead. Test should be updated accordingly.
Lets return something other than the exception here (say for example 'data encrpyted'), so that the test actually verifies that it is the EncriptService the one throwing the exception.
Comment #8
gambryThanks for the review!
I fixed all the feedback.
For point 3 I opted for throwing a different exception rather then just returning dummy data. This because in a normal scenario that method should throw EncryptionMethodCanNotDecryptException exception and I wanted to make it clear if developers use it as a blueprint for their implementation. I left a - hopefully - explanatory comment.
But honestly it doesn't matter what that returns, so let me know if you want me to return dummy data.
Also although this issue add a new method to the interface I think we can live with the API break because:
Comment #9
manuel garcia commentedThanks @gambry - changes look good, and using the test encryption method as an example is a good idea.
I agree about the API break by adding a new method to the interface (we discussed this during DrupalDevDays encrypt sprint).
Ive got nothing else to complain about so RTBCing
Comment #10
gambryComment #11
cellar door commentedA few thoughts:
1. This is a great set of work that provides some very interesting possibilities for what's possible with encrypt.
2. I checked and the 3 listed encryption methods that we know of using Encrypt in D8 (Real AES, Sodium, and Encrypt KMS) all are safe from this break in the API so it's a soft break in my opinion as most everyone using the module should be using one of those (rolling your own crypto isn't really recommended).
3. Though in Alpha, and people know the risks, there really isn't any reason this module shouldn't get a full release. It's stable, it's been used in production on a number of sites without any concerns.
So I'm going to put in my vote to include this in Alpha, cut a beta and set a timeline to get a full release out asap barring anything breaking with this implementation. I'd say that if we can roll this out to beta, and if by Drupal Europe there's no major issues that have been brought up we move to a full release.
In the meantime we'll want to write some pretty serious release notes for anyone implementing this that if they aren't using any of the modules known to support Encrypt and are compatible with this they check for compatibility first.
Comment #12
manuel garcia commentedThanks @Cellar Door for doing due diligence on the API break, the approach towards release sounds reasonable to me.
Comment #13
gambryPinging this. I'm going to start the work for Encrypt RSA for v2, in order to drop support for PHP < 7.2 and make use of libsodium methods directly.
It would be good to also lock the dependency to this module to a version where Asymmetrical Encryption is officially supported.
Also I believe this is a blocker for some issues on Webform Encrypt too.
Comment #14
gisleConfirming that patch in #8 works.
It would be nice to have this committed.
Comment #15
manuel garcia commentedAdding related issue on
webform_encryptwhich is postponed on this.Comment #16
rlhawkSupport for public-key encryption is a tremendous addition to this module. Thanks for proposing it.
Comment #18
rlhawkComment #19
rlhawkComment #20
gambryAmazing! Thanks!!!