magento2: M2.3 – Sodium crypto adapter errors on unexpected input
Under certain conditions – in my case resulting from a 2.2.6 -> 2.3.0 upgrade – the cryptography adapter \Magento\Framework\Encryption\Adapter\SodiumChachaIetf::decrypt does not return a string, despite the strict return type on its signature. This results in exceptions and failure to bootstrap Magento.
Preconditions (*)
- Upgraded Magento 2.2.6 -> 2.3 instance.
- Unknown conditions – possibly non-usable crypt key or corrupt encrypted system config values.
Steps to reproduce (*)
- Attempt to run
bin/magento - Observe error output similar to:
Type Error occurred when creating object: Magento\Framework\Interception\Config\Config
Expected result (*)
- The CLI tool command list should be presented.
Actual result (*)
- An error is presented.
Research
I acknowledge that this may be difficult to reproduce, given that I have yet to understand the precise conditions. What I can tell you is that this originated in a Commerce Cloud staging environment (but affects all 2.3 versions), but did not affect Cloud integration environments. So it may have been tied to my configuration differences between environments.
However, upon investigation I found that the given “Type Error” had an underlying detail in system.log:
[2018-12-05 14:29:34] report.CRITICAL: Type Error occurred when creating object: Magento\Framework\Interception\Config\Config, Return value of Magento\Framework\Encryption\Adapter\SodiumChachaIetf::decrypt() must be of the type string, boolean returned [] []
This led me to study the new cryptography library, and what I discovered was:
SodiumChachaIetf::decryptdeclares a strictstringreturn type.- The underlying polyfill
sodium_crypto_aead_chacha20poly1305_ietf_decryptannotates@return stringbut actually can return aboolean.- The actual PHP function has no documentation to describe the expected return type.
- An exception was actually thrown under certain conditions.
Given that the return type is strictly string on the decrypt method, and that no @throws annotations are presented, this should require that its implementation does whatever is necessary to ensure only a string is returned.
Based on that assumption, I’ve created a PR (#19591 ), which does just that. Also assumed, was that in the event of decryption failure, the original input string is returned. This might not be the best assumption but it works for my use.
Note on Encryptor
This is tangentially related, but I also discovered that if you pass a malformed $hash to \Magento\Framework\Encryption\Encryptor::isValidHash, it will forward the input to explodePasswordHash, which causes an input type error on explode. You can observe this with the following sample code:
$a = \Magento\Framework\App\ObjectManager::getInstance()->create(
'\Magento\Framework\Encryption\Encryptor'
);
$b = \Magento\Framework\App\ObjectManager::getInstance()->create(
'\Magento\Framework\Encryption\Encryptor'
);
var_dump($a->isValidHash('test-input', 'correct:input:format'));
var_dump($b->isValidHash('test-input', 'incorrect-input-format'));
According to the explodePasswordHash signature you should not be throwing an exception. So a more graceful handling of bad input ought to be considered.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 9
- Comments: 22 (5 by maintainers)
tl;dr - check your crypt key matches where the database came from
I had a very similar issue on Magento 2.3, both on php7.1 and php7.2. Many of the same error messages reported here such as
SodiumChachaIetf::decrypt() must be of the type string, boolean returnedandType Error occurred when creating object: Magento\Config\Model\Config\Structure\InterceptorHowever, I got a stack trace that showed part of the config string it was attempting to decrypt, and this led me to double check my crypt key… turns out it didn’t match between my local environment and the production machine. Iirc it used to fail “silently” if the crypt keys didn’t match, where it would simply return an empty string if you tried to access an encrypted config.
As @beargroup-jay mentioned, If you are upgrading from old DB, in app/etc/env.php file simply add the crypt key from your previous configurations. For me I updated and it works fine.
This work for me Modify this file : vendor/magento/framework/Encryption/Adapter/SodiumChachaIetf.php
Hello @vbuck @andykim @evagabond @tig-daanvandenbergh @syno-bvo @
Thank you for contribution and collaboration!
The corresponding internal ticket
MAGETWO-96983was fixed, delivered and closed by Magento teamPlease see details in the next commit:
I found the way to resole it in my case. In table core_config_data , find these paths and remove their value (It happens because the paypal encrypt in magento 1 cannot decrypt on magento 2).
paypal/wpp/api_usernamepaypal/wpp/api_passwordHope can help you!
I just wanted to let you guys know, I ran into this issue while running integration tests for M2.3.1. @abdulkaderptp’s comment inspired me to find out the mocked database configuration. This can be found in
/dev/tests/integration/etc/install-config-mysql.php. The fix is to include the crypt-key, like this:Yes, it is quite correct. If you have got a database from production environment you need to take a production encryption key as well. There are some values in the DB which are sensitive to encryption key. For example, PayPal credentials are encrypted this way.
Below solution work for me : Go to this file:
vendor/magento/framework/Encryption/Adapter/SodiumChachaIetf.phpAnd update below code:
Just change the function return type: From
return $plainTextto
return (string) $plainTextWe ran into this exact issue on a fresh 2.3.0 install w/ php 7.2 w/ Magento Sample data.
Resolution:
composer update upgrade re-compile.
Solved.
Maybe it will help others.
Does anyone have a quick fix for it? @hostep