Problem/Motivation

Version 2.0 of the Defuse PHP Encryption library has been released. The Real AES module relies on the master branch of the library, which is now incompatible with the module. Breaking changes include:

The key is now required to be 256 bits, instead of 128 bits
The key passed to Crypto::encrypt is now expected to be a \Defuse\Crypto\Key object, instead of a string
The key value used to create the \Defuse\Crypto\Key object is expected to be binhex-encoded
Proposed resolution

Update the encryption method provided by the Real AES module to use version 2.0 of the Defuse PHP Encryption library. It's important to note that this module did not use version 1 of the library, so the legacyDecrypt provided in version 2 will not work to decrypt existing data that was encrypted by the module.

Comments

arknoll created an issue. See original summary.

balsama’s picture

Status: Active » Needs review
StatusFileSize
new1.21 KB

Rather than reengineer the module, we should be able to cobble together a version of defuse/php-encryption that meets our needs for now (until the module can be updated. The attached patch pulls the 1.2.1 version of the defuse/php-encryption then applies a mega-patch to bring it up to the 8f72d5852 (which @arknoll tells me is the specific commit needed).

If defuse/php-encryption is a dependency of a dependency (which it almost definitely is) the root package will also need to set the "enable-patching" flag to true (see https://github.com/cweagans/composer-patches/commit/8de7c73b2eae217f4e70... - which is also the reason this patch references dev-master of cweagans/composer-patches)

arknoll’s picture

The maintainers of defuse/php-encryption say that 1.2.1 should be compatible with what we need. See https://github.com/defuse/php-encryption/issues/268

rlhawk’s picture

I'll test with 1.2.1 to make sure data previously encrypted with dev-master can be decrypted. Different libraries are used (MCrypt vs. OpenSSL), so while the underlying cipher is AES in both, users may run into issues if they have one library available, but not the other.

rlhawk’s picture

1.2.1 is not compatible. We need to apply a patch to bring the library up to the appropriate version of dev-master. I think commit 8f72d5852 is too far, but I'm checking now.

arknoll’s picture

@rlhawk, 1.2.1 being incompatible was my finding as well.

It sounds like the defuse/php-encryption team is open to tagging a 1.2.2 release. I think that will be the best interim solution. It looks like we are running https://github.com/defuse/php-encryption/commit/522859f0b3f35fe83be5803e... in our composer.lock file and it works

rlhawk’s picture

I don't think the maintainers of Defuse PHP Encryption should tag a release that they don't feel is stable. This is security software, after all. We're the ones who made dev-master a dependency, so we need to solve that problem for ourselves. If they do tag a release, it should not be 1.2.2. There are massive changes between 1.2.1 and commit 522859f, not the least of which is a change in the PHP extension that is used—changes much bigger than what would be included in a patch release.

rlhawk’s picture

StatusFileSize
new717 bytes

Here's an alternative patch that brings Defuse PHP Encryption up to commit 522859f, which is the last one before 2.0 branch merges.

Since users will need to modify their root composer.json file anyway, I propose that we just suggest that they copy the patch info into it. Then we don't need to require dev-master of cweagans/composer-patches. We're dealing with alpha modules here; anyone who is already using Real AES 8.x will need to take extra steps to prevent it from breaking.

Once https://github.com/cweagans/composer-patches/commit/8de7c73b2eae217f4e70... is part of a tagged release, copying will no longer be necessary, but users will still need to add "enable-patching": true to their root composer.json file.

arknoll’s picture

After using the above patch it appears that they do not fully solve the problem. I believe there is an issue with cweagans/composer-patches but I'm not 100% sure.

Here's what it will do:
1. Apply the patch
2. Add:

'extra': {
  'enable-patching': true
}

to your docroot/composer.json
3. Run composer drupal-rebuild
4. Run composer update

Result:
1. defuse/php-encryption version v1.2.1 will be downloaded
2. The autoload from the 1.2.1 version of its composer.json file will be used and your vendor/composer/autoload_static.php and vendor/composer/autoload_files.php will include Crypto.php instead of waiting for the defuse/php-encryption to be patched before it's autoload is configured
3. defuse/php-encryption is patched

The codebase fails once configured because the appropriate classes cannot be found (do to the autoloader not being included correctly)

heine’s picture

StatusFileSize
new33.72 KB

I'm not sure how sustainable this is if we need to simultaneously use two versions of defuse php, one legacy, one 2.x.

Attached patch adds the version from commit 522859f0b3f35fe83be5803ede83af3f517bfd5b as a hardcoded derivative with an altered namespace in Legacy. The MIT license should allow this.

A follow-up issue can then add Defuse 2.0 via composer, though there I run into a problem with core's random_compat 1.4.x. Core appears to work fine with random_compat 2.0.1, so perhaps a core patch is all that's needed.

Thoughts?

talhaparacha’s picture

A patch to get Real AES compatible with Defuse PHP-Encryption 2 as per the original problem statement. But as pointed out in #10, the patch will not work until core gets updated with the latest version of random_compat. An issue has been filed here for this:

https://www.drupal.org/node/2763787

I think Real AES 2.x should be released with this. As already discussed, updating Real AES 1.x would simply break the decryption of already encrypted data. But a stable version of Real AES is necessary too. Because Encrypt module recommends Real AES and all other related modules (Encrypt PHPSecLib Encryption etc.) have been deprecated. In fact, I know of several D8 modules in development (Pubkey Encrypt, Encrypted Files, Google Authenticator Login) that are going to depend on Real AES.

nerdstein’s picture

It's important we consider upgrading this to support streaming.

nerdstein’s picture

Cross referencing this other conversation: https://github.com/defuse/php-encryption/issues/283

talhaparacha’s picture

Same as #11 with a typo fix.

codefolder’s picture

Fixed error in line 35:

 ParseError: syntax error, unexpected '@', expecting ')' in Composer\Autoload\includeFile() (line 41 of /var/www/host/modules/contrib/real_aes/src/Plugin/EncryptionMethod/RealAESEncryptionMethod.php).
traviscarden’s picture

The patch in #15 works for me. The change seems very logical.

nerdstein’s picture

I'm cool with merging this patch but I'm quite nervous about the upstream impact since this patch has yet to be merged - https://www.drupal.org/node/2763787

Since the patch has been RTBC'd, I'm hoping its a matter of time until this gets rolled in.

colan’s picture

Status: Needs review » Postponed
rlhawk’s picture

Version: 8.x-1.0-alpha1 » 8.x-2.x-dev

Version number changed to 8.x-2.x-dev for this issue. See #2792491: Add hard-coded version of Defuse library to module for changes to 8.x-1.x-dev version.

nerdstein’s picture

Status: Postponed » Reviewed & tested by the community

The patch was rolled into 8.3.x and cherry picked for 8.2.x.

Moving back to RTBC and accepting the patch

nerdstein’s picture

Assigned: Unassigned » nerdstein

Assigning myself to push the patch

  • nerdstein committed 86487f4 on 8.x-2.x authored by codefolder
    Issue #2727845 by talhaparacha, codefolder, rlhawk, balsama, nerdstein:...
nerdstein’s picture

Status: Reviewed & tested by the community » Fixed

Fixed, thanks so much everyone

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

armyguyinfl’s picture

Please assist with php-encrpytion defuse library with real_aes

When updating core from 8.3.x - 8.5.x and module:

  • encrypt 8.x-3.0-alpha2 to 8.x-3.0-alpha3
  • real_aes 8.x-2.0-beta1 to 8.x-2.0
  • key 8.x-1.3 to 8.x-1.7

I am getting the following error now:

TypeError: String expected for argument 1. Double given instead. in Defuse\Crypto\Crypto::encrypt() (line 24 of /mnt/www/html/env/docroot/vendor/defuse/php-encryption/src/Crypto.php).
Drush command terminated abnormally due to an unrecoverable error.

Stack Trace:

drush cron --strict=0
TypeError: String expected for argument 1. Double given instead. in Defuse\Crypto\Crypto::encrypt() (line 24 of /mnt/www/html/env/docroot/vendor/defuse/php-encryption/src/Crypto.php) #0                        [error]
/mnt/www/html/env/docroot/modules/contrib/real_aes/src/Plugin/EncryptionMethod/RealAESEncryptionMethod.php(50): Defuse\Crypto\Crypto::encrypt(1234567, Object(Defuse\Crypto\Key))
#1 /mnt/www/html/env/docroot/modules/contrib/encrypt/src/EncryptService.php(56): Drupal\real_aes\Plugin\EncryptionMethod\RealAESEncryptionMethod->encrypt(1234567, Object(Defuse\Crypto\Key))
#2 /mnt/www/html/env/docroot/modules/custom/encryption/src/Services/EncryptionService.php(39): Drupal\encrypt\EncryptService->encrypt(1234567, Object(Drupal\encrypt\Entity\EncryptionProfile))
#3 /mnt/www/html/env/docroot/modules/custom/encryption/src/Helper/EncryptionHelper.php(68): Drupal\encryption\Services\EncryptionService->encrypt_decrypt('encrypt', 1234567)
#4 /mnt/www/html/env/docroot/modules/custom/common/common.module(33):
Drupal\encryption\Helper\EncryptionHelper::encryptEnrollmentCredentialsApiKeys(Object(Drupal\credential_entity\Entity\EnrollmentCredentialEntity))
#5 [internal function]: common_entity_presave(Object(Drupal\credential_entity\Entity\EnrollmentCredentialEntity))
#6 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Extension/ModuleHandler.php(402): call_user_func_array('common_en...', Array)
#7 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Entity/EntityStorageBase.php(169): Drupal\Core\Extension\ModuleHandler->invokeAll('entity_presave', Array)
#8 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php(730): Drupal\Core\Entity\EntityStorageBase->invokeHook('presave',
Object(Drupal\credential_entity\Entity\EnrollmentCredentialEntity))
#9 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Entity/EntityStorageBase.php(435): Drupal\Core\Entity\ContentEntityStorageBase->invokeHook('presave',
Object(Drupal\credential_entity\Entity\EnrollmentCredentialEntity))
#10 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php(587):
Drupal\Core\Entity\EntityStorageBase->doPreSave(Object(Drupal\credential_entity\Entity\EnrollmentCredentialEntity))
#11 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Entity/EntityStorageBase.php(389):
Drupal\Core\Entity\ContentEntityStorageBase->doPreSave(Object(Drupal\credential_entity\Entity\EnrollmentCredentialEntity))
#12 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(820):
Drupal\Core\Entity\EntityStorageBase->save(Object(Drupal\credential_entity\Entity\EnrollmentCredentialEntity))
#13 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Entity/Entity.php(387): Drupal\Core\Entity\Sql\SqlContentEntityStorage->save(Object(Drupal\credential_entity\Entity\EnrollmentCredentialEntity))
#14 /mnt/www/html/env/docroot/modules/contrib/salesforce/modules/salesforce_mapping/src/Entity/MappedObject.php(595): Drupal\Core\Entity\Entity->save()
#15 /mnt/www/html/env/docroot/modules/contrib/salesforce/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php(254): Drupal\salesforce_mapping\Entity\MappedObject->pull()
#16 /mnt/www/html/env/docroot/modules/contrib/salesforce/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php(115):
Drupal\salesforce_pull\Plugin\QueueWorker\PullBase->createEntity(Object(Drupal\salesforce_mapping\Entity\SalesforceMapping), Object(Drupal\salesforce\SObject), false)
#17 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Cron.php(179): Drupal\salesforce_pull\Plugin\QueueWorker\PullBase->processItem(Object(Drupal\salesforce_pull\PullQueueItem))
#18 /mnt/www/html/env/docroot/core/lib/Drupal/Core/Cron.php(144): Drupal\Core\Cron->processQueues()
#19 /mnt/www/html/env/docroot/core/lib/Drupal/Core/ProxyClass/Cron.php(75): Drupal\Core\Cron->run()
#20 /mnt/www/html/env/vendor/drush/drush/commands/core/core.drush.inc(674): Drupal\Core\ProxyClass\Cron->run()
#21 /mnt/www/html/env/vendor/drush/drush/includes/command.inc(422): drush_core_cron()
#22 /mnt/www/html/env/vendor/drush/drush/includes/command.inc(231): _drush_invoke_hooks(Array, Array)
#23 /mnt/www/html/env/vendor/drush/drush/includes/command.inc(199): drush_command()
#24 /mnt/www/html/env/vendor/drush/drush/lib/Drush/Boot/BaseBoot.php(67): drush_dispatch(Array)
#25 /mnt/www/html/env/vendor/drush/drush/includes/preflight.inc(66): Drush\Boot\BaseBoot->bootstrap_and_dispatch()
#26 /mnt/www/html/env/vendor/drush/drush/drush.php(12): drush_main()
#27 {main}.
TypeError: String expected for argument 1. Double given instead. in Defuse\Crypto\Crypto::encrypt() (line 24 of /mnt/www/html/env/docroot/vendor/defuse/php-encryption/src/Crypto.php).
Drush command terminated abnormally due to an unrecoverable error.
tijsdeboeck’s picture

I had a similar issue, with a fresh install, and it was related to the latest 2.2.0 version of Defuse/php-encrypt.
I fixed it temporarily by downgrading to 2.1.0 (composer require defuse/php-encryption:2.1.0').

armyguyinfl’s picture

That's the same that we needed to do but I won't what the ultimate fix that is needed in the library for the fix, not workaround.

fenstrat’s picture

@armyguyinfl, @tijsdeboeck have a look at #2970955: Fatal error in Crypto::encrypt() with non string values for a fix for the issue you reported here.

tijsdeboeck’s picture

@fenstrat, thanks for the link, but for me the issue has been fixed with the dev version of the drd module that I was also using. It added a similar patch recently, which fixes the problem for my usecase...

fenstrat’s picture

@tijsdeboeck right, thanks. Assuming that's #2966351: Issue creating new host due to encryption defaults, that fixes the problem in drd by casing to a string on decrypt. My guess is non string values got encrypted and stored before defuse/php-encryption 2.2.0 (which added type checking).

So going forward we need to ensure only string values are encrypted here in real_aes, which is what #2970955: Fatal error in Crypto::encrypt() with non string values should do.