Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random RuntimeException: The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key length

Tags:

I have same problem with Laravel 5.3 (on windows server). I did all possible attempts: checked .env file, config, artisan new key generation, cache: clear, config: clear, composer update, but the problem randomly persists.

Note that the same code with exactly same version of apache, mysql, php, doesn't generate this problem on Mac OS.

I found that the key (first parameter of Encrypter constractor) arrives "sometimes" empty and of course it fails. Most of the times the key is correct, but randomly the key arrives empty from EncryptionServiceProvider that in turns asks it to the app config.

So the only solution that worked for me was to add an if ($key) in EncryptionServiceProvider so that the Encryption constructor doesn't get called with empty key.

Of course is not a "clean" solution nor it explains the problem, but at least avoids to find the log file filled with the error:

RuntimeException: The only supported ciphers are AES-128-CBC and AES-256-CBC and pages are displayed correctly.

If this is a Laravel bug I don't know, but of course if someone could explain this I will be more then happy to know.

Below is my modified class: I just added the if ($key) line before new Encrypter:

class EncryptionServiceProvider extends ServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('encrypter', function ($app) {
            $config = $app->make('config')->get('app');

            // If the key starts with "base64:", we will need to decode the key before handing
            // it off to the encrypter. Keys may be base-64 encoded for presentation and we
            // want to make sure to convert them back to the raw bytes before encrypting.
            if (Str::startsWith($key = $config['key'], 'base64:')) {
                $key = base64_decode(substr($key, 7));
            }
        if ($key)
            return new Encrypter($key, $config['cipher']);
        });
    }
}

Further details and backtrace log:

Of course, as I wrote I checked, .env file, config, artisan new key generation, cache: clear, config: clear, composer update. This stuff is ok since it works 99% of the time but randomly I get the error.

Here the back trace:

[2017-01-09 10:25:40] test.ERROR: RuntimeException: The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths. in C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Encryption\Encrypter.php:43

Stack trace:

#0 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Encryption\EncryptionServiceProvider.php(27): Illuminate\Encryption\Encrypter->__construct('', 'AES-256-CBC')
#1 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(746): Illuminate\Encryption\EncryptionServiceProvider->Illuminate\Encryption\{closure}(Object(Illuminate\Foundation\Application), Array)
#2 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(644): Illuminate\Container\Container->build(Object(Closure), Array)
#3 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Application.php(709): Illuminate\Container\Container->make('encrypter', Array)
#4 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(864): Illuminate\Foundation\Application->make('encrypter')
#5 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(819): Illuminate\Container\Container->resolveClass(Object(ReflectionParameter))
#6 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(788): Illuminate\Container\Container->getDependencies(Array, Array)
#7 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(644): Illuminate\Container\Container->build('App\\Http\\Middle...', Array)
#8 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Application.php(709): Illuminate\Container\Container->make('App\\Http\\Middle...', Array)
#9 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(127): Illuminate\Foundation\Application->make('App\\Http\\Middle...')
#10 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#11 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\View\Middleware\ShareErrorsFromSession.php(49): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#12 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(137): Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#13 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#14 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Session\Middleware\StartSession.php(64): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#15 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(137): Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#16 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#17 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse.php(37): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#18 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(137): Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#19 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#20 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(104): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#21 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Router.php(655): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#22 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Router.php(629): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#23 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Router.php(607): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#24 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(268): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#25 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}(Object(Illuminate\Http\Request))
#26 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode.php(46): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#27 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(137): Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure))
#28 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#29 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(104): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#30 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(150): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#31 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(117): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#32 C:\Apache24\htdocs\sph\public\index.php(53): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#33 {main}  
like image 308
Raul Avatar asked Jan 09 '17 15:01

Raul


People also ask

What is AES 128 CBC encryption?

AES-128 uses a 128-bit key length to encrypt and decrypt a block of messages. AES-192 uses a 192-bit key length to encrypt and decrypt a block of messages. AES-256 uses a 256-bit key length to encrypt and decrypt a block of messages.

What is AES CBC 256?

What is 256-bit AES encryption? 256-bit AES encryption refers to the process of concealing plaintext data using the AES algorithm and an AES key length of 256 bits. In addition, 256 bits is the largest AES key length size, as well as its most mathematically complex. It is also the most difficult to crack.

Is AES 256 CBC secure?

We are using aes-256-cbc for encryption in our PA. From a cryptographic perspective, though, both AES-CBC and AES-GCM are highly secure. GCM provides authentication, removing the need for an HMAC SHA hashing function.


1 Answers

The issue occurs when using thread-safe versions of PHP on multi-threaded web servers, instead of multi-process web servers. You can read about the issue a little more on the Github issue here, Github issue here, and a PHP bug report here. There are a few more links, but they are just branched off from those few I posted.

The basic gist is that with the multi-threaded web server, you have a single process that handles multiple threads. However, the putenv()/getenv() methods are not thread safe, and change environment variables at the process level, so all threads under that process are affected.

So, you end up with something like this: (as described in this issue):

Request 1: {starts --- loads env --- work --- finishes}
Request 2:                             {starts ----- loads env --- work --- finishes}

So, request 1 comes in, loads the environment fine, and gets to work. While request 1 is working, request 2 comes in and starts on another thread. Before request 2 reads the environment variables, request 1 finishes and PHP clears out all variables set by putenv(). Now, request 2 attempts to read the environment, but gets null because the variables were cleared when request 1 finished.

This issue can be mitigated in two ways:

  1. Don't use a .env file in production. Set the environment variables directly, and disable phpdotenv. This is also suggested by the package itself:

    phpdotenv is made for development environments, and generally should not be used in production. In production, the actual environment variables should be set so that there is no overhead of loading the .env file on each request.

  2. Never use the env() method outside of config files, and make sure you cache your config files. By using this method, the environment is read once: when you create the config file cache. Every actual web request will read the data from the cache, and the environment variables will never be touched again.

like image 56
patricus Avatar answered Oct 19 '22 13:10

patricus