<?php
namespace ParagonIE\CipherSweet\Tests;
use ParagonIE\CipherSweet\Backend\FIPSCrypto;
use ParagonIE\CipherSweet\Backend\ModernCrypto;
use ParagonIE\CipherSweet\BlindIndex;
use ParagonIE\CipherSweet\CipherSweet;
use ParagonIE\CipherSweet\EncryptedRow;
use ParagonIE\CipherSweet\Exception\ArrayKeyException;
use ParagonIE\CipherSweet\Exception\CryptoOperationException;
use ParagonIE\CipherSweet\KeyProvider\StringProvider;
use ParagonIE\CipherSweet\Transformation\LastFourDigits;
use ParagonIE\ConstantTime\Binary;
use ParagonIE\ConstantTime\Hex;
use PHPUnit\Framework\TestCase;
/**
* Class EncryptedRowTest
* @package ParagonIE\CipherSweet\Tests
*/
class EncryptedRowTest extends TestCase
{
/**
* @var CipherSweet $fipsEngine
*/
protected $fipsEngine;
/**
* @var CipherSweet $naclEngine
*/
protected $naclEngine;
/**
* @var CipherSweet $fipsRandom
*/
protected $fipsRandom;
/**
* @var CipherSweet $naclRandom
*/
protected $naclRandom;
/**
* @throws CryptoOperationException
*/
public function setUp()
{
$fips = new FIPSCrypto();
$nacl = new ModernCrypto();
$this->fipsEngine = new CipherSweet(
new StringProvider(
$fips,
Hex::decode(
'4e1c44f87b4cdf21808762970b356891db180a9dd9850e7baf2a79ff3ab8a2fc'
)
)
);
$this->naclEngine = new CipherSweet(
new StringProvider(
$nacl,
Hex::decode(
'4e1c44f87b4cdf21808762970b356891db180a9dd9850e7baf2a79ff3ab8a2fc'
)
)
);
$this->fipsRandom = new CipherSweet(
new StringProvider(
$fips,
\random_bytes(32)
)
);
$this->naclRandom = new CipherSweet(
new StringProvider(
$nacl,
\random_bytes(32)
)
);
}
/**
* @throws ArrayKeyException
* @throws CryptoOperationException
* @throws \SodiumException
*/
public function testSimpleEncrypt()
{
$eF = (new EncryptedRow($this->fipsRandom, 'contacts'));
$eM = (new EncryptedRow($this->naclRandom, 'contacts'));
$eF->addTextField('message');
$eM->addTextField('message');
$message = 'This is a test message: ' . \random_bytes(16);
$row = [
'message' => $message
];
$fCipher = $eF->encryptRow($row);
$mCipher = $eM->encryptRow($row);
$this->assertSame(
FIPSCrypto::MAGIC_HEADER,
Binary::safeSubstr($fCipher['message'], 0, 5)
);
$this->assertSame(
ModernCrypto::MAGIC_HEADER,
Binary::safeSubstr($mCipher['message'], 0, 5)
);
$this->assertSame($row, $eF->decryptRow($fCipher));
$this->assertSame($row, $eM->decryptRow($mCipher));
}
/**
* @throws CryptoOperationException
* @throws ArrayKeyException
* @throws \SodiumException
*/
public function testGetAllIndexes()
{
$row = [
'extraneous' => 'this is unecnrypted',
'ssn' => '123-45-6789',
'hivstatus' => true
];
$eF = $this->getExampleRow($this->fipsEngine, true);
$indexes = $eF->getAllBlindIndexes($row);
$this->assertEquals('a88e74ada916ab9b', $indexes['contact_ssn_last_four']['value']);
$this->assertEquals('9c3d53214ab71d7f', $indexes['contact_ssnlast4_hivstatus']['value']);
}
/**
* @throws ArrayKeyException
* @throws CryptoOperationException
* @throws \SodiumException
*/
public function testEncrypt()
{
$row = [
'extraneous' => 'this is unecnrypted',
'ssn' => '123-45-6789',
'hivstatus' => true
];
$eF = $this->getExampleRow($this->fipsRandom, true);
$eM = $this->getExampleRow($this->naclRandom, true);
/** @var EncryptedRow $engine */
foreach ([$eM, $eF] as $engine) {
$store = $engine->encryptRow($row);
$this->assertSame($store['extraneous'], $row['extraneous']);
$this->assertNotSame($store['ssn'], $row['ssn']);
$this->assertNotSame($store['hivstatus'], $row['hivstatus']);
}
}
/**
* @throws CryptoOperationException
* @throws \ParagonIE\CipherSweet\Exception\ArrayKeyException
* @throws \SodiumException
*/
public function testPrepareForStorage()
{
$eF = $this->getExampleRow($this->fipsRandom, true);
$rows = [
[
'ssn' => '111-11-1111',
'hivstatus' => false
],
[
'ssn' => '123-45-6789',
'hivstatus' => false
],
[
'ssn' => '999-99-6789',
'hivstatus' => false
],
[
'ssn' => '123-45-1111',
'hivstatus' => true
],
[
'ssn' => '999-99-1111',
'hivstatus' => true
],
[
'ssn' => '123-45-6789',
'hivstatus' => true
]
];
foreach ($rows as $row) {
list($store, $indexes) = $eF->prepareRowForStorage($row);
$this->assertTrue(\is_array($store));
$this->assertTrue(\is_string($store['ssn']));
$this->assertTrue(\is_string($store['hivstatus']));
$this->assertNotSame($row['ssn'], $store['ssn']);
$this->assertNotSame($row['hivstatus'], $store['hivstatus']);
$this->assertTrue(\is_array($indexes));
}
}
/**
* @param CipherSweet $backend
* @param bool $longer
* @param bool $fast
*
* @return EncryptedRow
* @throws BlindIndexNameCollisionException
*/
public function getExampleRow(
CipherSweet $backend,
$longer = false,
$fast = false
) {
$row = (new EncryptedRow($backend, 'contacts'))
->addTextField('ssn')
->addBooleanField('hivstatus');
$row->addBlindIndex(
'ssn',
new BlindIndex(
// Name (used in key splitting):
'contact_ssn_last_four',
// List of Transforms:
[new LastFourDigits()],
// Output length (bytes)
$longer ? 64 : 16,
$fast
)
);
$row->createCompoundIndex(
'contact_ssnlast4_hivstatus',
['ssn', 'hivstatus'],
$longer ? 64 : 16,
$fast
);
return $row;
}
}
|