Search code examples
phplaravelencryptionlaravel-encryption

Laravel Encryption/Decryption issue


I am storing users credentials for a 3rd party service in my database. When storing, these are cast to encrypted as below:

protected $casts = [
    'enabled' => 'boolean',
    'token_is_valid' => 'boolean',
    'service_username' => 'encrypted',
    'service_password' => 'encrypted',
    'service_practice_pin' => 'encrypted',,
];

I then need to use the details to authenticate with the 3rd party service.

I can return the full model from my database: dd($integration), however if I try to access the propery dd($integration->service_username) I get the below error:

The payload is invalid. {"userId":12,"exception":"[object] (Illuminate\\Contracts\\Encryption\\DecryptException(code: 0): The payload is invalid. at /var/www/app/vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php:221)
[stacktrace]

The 3rd party service I am using requires the decrypted values to authenticate.

I tried adding an accessor to the model but still get the same error

public function getDecryptedServiceUsernameAttribute()
{
    return decrypt($this->attributes['service_username']);
}

How can I receive/send the decrypted value? Do I need to store it differently? current column type is varchar(191)


Solution

  • Depending on what you're encrypting, 191 can be too short. 255 is probably standard, but to make sure you never hit the limit, you would be better off changing the column to a text column. Using Crypt::encrypt with a simple string, a 200 character string has the encrypted length of 568 characters. Here is what I tested with Laravel 9:

    $str = 'a'; 
    for($i=0; $i< 200; $i++) { 
    
        $crypt = Crypt::encrypt($str);
        echo strlen($str)." - ".strlen($crypt)."\n"; 
        $str.='a';
    }
    

    And a sample of the results:

    50 - 288
    100 - 372
    200 - 568
    300 - 740