If you want to encrypt and decrypt a string (only if the data is leaving the current machine and if the sender and receiver machines are allowed to decrypt the data coming from each other), 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.


/**
* You have to use same "keys" and "nonce" to encrypt plain data and decrypt encrypted data.
* Use if the sender and receiver machines are allowed to decrypt the data coming from each other. A <-> B
*
* Use bin2hex() on encrypted data before sending.
* Use hex2bin() on encrypted data before decrypting.
*/
class Both
{
/**
* This is what sender computer A does.
*
* @param string $plainData This is what sender computer A will send to receiver computer B
* @param string $nonce
* @param string $aSecretKey This belongs to sender computer A where the message will be sent from
* @param string $bComputersPublicKey This belongs to receiver computer B where the message will be sent to
*
* @return string
*/
public function encryptA(string $plainData, string $nonce, string $aSecretKey, string $bComputersPublicKey): string
{
return $nonce.sodium_crypto_box($plainData, $nonce, $aSecretKey.$bComputersPublicKey);
}

/**
* This is what receiver computer B does.
*
* @param string $encryptedData This comes from the sender computer A
* @param string $nonce
* @param string $bSecretKey This belongs to receiver computer B where the message will be handled
* @param string $aComputersPublicKey This belongs to sender computer A where the message comes from
*
* @return string
*/
public function decryptB(string $encryptedData, string $nonce, string $bSecretKey, string $aComputersPublicKey): string
{
return sodium_crypto_box_open($encryptedData, $nonce, $bSecretKey.$aComputersPublicKey);
}

/**
* This is what sender computer B does.
*
* @param string $plainData This is what sender computer B will send to receiver computer A
* @param string $nonce
* @param string $bSecretKey This belongs to sender computer B where the message will be sent from
* @param string $aComputersPublicKey This belongs to receiver computer A where the message will be sent to
*
* @return string
*/
public function encryptB(string $plainData, string $nonce, string $bSecretKey, string $aComputersPublicKey): string
{
return $nonce.sodium_crypto_box($plainData, $nonce, $bSecretKey.$aComputersPublicKey);
}

/**
* This is what receiver computer A does.
*
* @param string $encryptedData This comes from the sender computer B
* @param string $nonce
* @param string $aSecretKey This belongs to receiver computer A where the message will be handled
* @param string $bComputersPublicKey This belongs to sender computer B where the message comes from
*
* @return string
*/
public function decryptA(string $encryptedData, string $nonce, string $aSecretKey, string $bComputersPublicKey): string
{
return sodium_crypto_box_open($encryptedData, $nonce, $aSecretKey.$bComputersPublicKey);
}
}

Test


class BothTest extends TestCase
{
private $aComputersKeyPair;
private $aComputersSecretKey;
private $aComputersPublicKey;
private $bComputersKeyPair;
private $bComputersSecretKey;
private $bComputersPublicKey;

protected function setUp()
{
$this->aComputersKeyPair = sodium_crypto_box_keypair();
$this->aComputersSecretKey = sodium_crypto_box_secretkey($this->aComputersKeyPair);
$this->aComputersPublicKey = sodium_crypto_box_publickey($this->aComputersKeyPair);
$this->bComputersKeyPair = sodium_crypto_box_keypair();
$this->bComputersSecretKey = sodium_crypto_box_secretkey($this->bComputersKeyPair);
$this->bComputersPublicKey = sodium_crypto_box_publickey($this->bComputersKeyPair);
}

public function testEncryptA(): void
{
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

$dataToBeSent = (new Both())
->encryptA('inanzzz', $nonce, $this->aComputersSecretKey, $this->bComputersPublicKey);

$this->assertIsString($dataToBeSent);
}

public function testDecryptB(): void
{
// Sender
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

$dataReceived = (new Both())
->encryptA('inanzzz', $nonce, $this->aComputersSecretKey, $this->bComputersPublicKey);

// Receiver
$nonce = mb_substr($dataReceived, 0, 24, '8bit');
$dataReceived = mb_substr($dataReceived, 24, null, '8bit');

$result = (new Both())
->decryptB($dataReceived, $nonce, $this->bComputersSecretKey, $this->aComputersPublicKey);

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

public function testEncryptB(): void
{
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

$dataToBeSent = (new Both())
->encryptB('inanzzz', $nonce, $this->bComputersSecretKey, $this->aComputersPublicKey);

$this->assertIsString($dataToBeSent);
}

public function testDecryptA(): void
{
// Sender
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

$dataReceived = (new Both())
->encryptB('inanzzz', $nonce, $this->bComputersSecretKey, $this->aComputersPublicKey);

// Receiver
$nonce = mb_substr($dataReceived, 0, 24, '8bit');
$dataReceived = mb_substr($dataReceived, 24, null, '8bit');

$result = (new Both())
->decryptA($dataReceived, $nonce, $this->aComputersSecretKey, $this->bComputersPublicKey);

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