If you want to encrypt and decrypt a string (only if the data is not leaving the current machine), you can use example below. The encrypted data will always be dynamic so the result will always be different for given string. It uses Sodium on a PHP 7.2+ machine. Note: Read comments in the code.


Class


You might need to add "ext-sodium": "*" to your composer.json file. Also read what exactly the relevant function does here.


/**
* Use only if the data is not leaving the current machine.
*
* Use bin2hex() on encrypted data before storing.
* Use hex2bin() on encrypted data before decrypting.
*
* You have to use same "key" and "nonce" to decrypt encrypted data.
*/
class Encryptor
{
public function encrypt(string $plainData, string $key, string $nonce): string
{
return sodium_crypto_secretbox($plainData, $nonce, $key);
}

public function decrypt(string $encryptedData, string $key, string $nonce): string
{
$plainData = sodium_crypto_secretbox_open($encryptedData, $nonce, $key);
if (false === $plainData) {
sodium_memzero($key);

throw new RuntimeException('Bad data!');
}

return $plainData;
}
}

Test


class EncryptorTest extends TestCase
{
public function testEncrypt(): void
{
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

$result = (new Encryptor())->encrypt('inanzzz', $key, $nonce);

$this->assertIsString($result);

echo PHP_EOL.$result.PHP_EOL;
}

public function testDecryptFailsOnWrongKey(): void
{
// Sender
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

$encryptedData = (new Encryptor())->encrypt('inanzzz', $key, $nonce);

// Receiver
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Bad data!');

$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);

(new Encryptor())->decrypt($encryptedData, $key, $nonce);
}

public function testDecryptFailsOnWrongNonce(): void
{
// Sender
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

$encryptedData = (new Encryptor())->encrypt('inanzzz', $key, $nonce);

// Receiver
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Bad data!');

$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

(new Encryptor())->decrypt($encryptedData, $key, $nonce);
}

public function testDecryptSucceeds(): void
{
// Sender
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

$encryptedData = (new Encryptor())->encrypt('inanzzz', $key, $nonce);

// Receiver
$result = (new Encryptor())->decrypt($encryptedData, $key, $nonce);

$this->assertSame('inanzzz', $result);
}
}