Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I dynamically change the keys that Crypt uses in Laravel?

I have been researching how to use Laravel Encryption as building a homestead encryption platform is frowned upon and rightfully so.

Illuminate\Support\Facades\Crypt::encryptString('This is a secret message from user 1 to user 2');

Take the above example, this is using my APP_KEY which derives from my .env file, generation previously by php artisan key:generate. The issue is that user 1 is never issued two sets of keys to communicate only to user 2. User 3, 4 and so on could still read this message using the Illuminate\Support\Facades\Crypt::decryptString method.

Currently, my database is set up to have a chat header. This contains information about what is communicating. All participants will use these keys for encryption and decryption - thus any outside users not being able to decrypt the messages.

public function up()
{
    Schema::create('chat_headers', function(Blueprint $table) {
        $table->increments('id');

        $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
        $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));

        $table->string('private_key')->unique();
        $table->string('public_key')->unique();
    });
}

I also have a chat participants, this contains information about who is communicating:

public function up()
{
    Schema::create('chat_participants', function(Blueprint $table) {
        $table->increments('id');

        $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
        $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));

        $table->integer('user_id')->unsigned();

        # TODO: Build RBAC

        $table->index(['user_id']);
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
}

Finally, I have a table for message logs. This contains the encrypted message followed by what chat room they're associating with.

public function up()
{
    Schema::create('chat_messages', function(Blueprint $table) {
        $table->increments('id');

        $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
        $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));

        $table->integer('chat_id')->unsigned();
        $table->string('message');

        $table->index(['chat_id']);
        $table->foreign('chat_id')->references('id')->on('chat_headers')->onDelete('cascade');
    });
}

How can I dynamically assign new keys to the Illuminate\Support\Facades\Crypt to use in order to encrypt messages between a chat party?

If this is not possible, how can I secure the messages between the participants within a chat using these two keys? I feel like using Crypt for this is 'encrypting for the sake of it' and not actually hiding the content of anything between users.

like image 564
Jaquarh Avatar asked Jan 29 '19 16:01

Jaquarh


1 Answers

I would recommend against using the Crypt facade directly and would instead recommend using the Laravel Illuminate\Encryption\Encrypter which is the class that is used for the Crypt facade (I'm on Laravel 5.6).

Here is a little code snippet that I hope will help:

use Illuminate\Encryption\Encrypter;

//Keys and cipher used by encrypter(s)
$fromKey = base64_decode("from_key_as_a_base_64_encoded_string");
$toKey = base64_decode("to_key_as_a_base_64_encoded_string");
$cipher = "AES-256-CBC"; //or AES-128-CBC if you prefer

//Create two encrypters using different keys for each
$encrypterFrom = new Encrypter($fromKey, $cipher);
$encrypterTo = new Encrypter($toKey, $cipher);

//Decrypt a string that was encrypted using the "from" key
$decryptedFromString = $encrypterFrom->decryptString("gobbledygook=that=is=a=from=key=encrypted=string==");

//Now encrypt the decrypted string using the "to" key
$encryptedToString = $encrypterTo->encryptString($decryptedFromString);

If you would like to see the facade loading code it is in vendor\laravel\framework\src\Illuminate\Encryption\EncryptionServiceProvider.

like image 144
pwyg Avatar answered Oct 25 '22 02:10

pwyg