$blindIndexes */ protected $blindIndexes = []; /** * @var CipherSweet $engine */ protected $engine; /** * @var SymmetricKey $key */ protected $key; /** * @var string $fieldName */ protected $fieldName = ''; /** * @var string $tableName */ protected $tableName = ''; /** * EncryptedField constructor. * * @param CipherSweet $engine * @param string $tableName * @param string $fieldName * * @throws CryptoOperationException */ public function __construct(CipherSweet $engine, $tableName = '', $fieldName = '') { $this->engine = $engine; $this->tableName = $tableName; $this->fieldName = $fieldName; $this->key = $this->engine->getFieldSymmetricKey( $this->tableName, $this->fieldName ); } /** * Encrypt a value and calculate all of its blind indices in one go. * * @param string $plaintext * @return array * * @throws BlindIndexNotFoundException * @throws CryptoOperationException */ public function prepareForStorage($plaintext) { return [ $this->encryptValue($plaintext), $this->getAllBlindIndexes($plaintext) ]; } /** * Encrypt a single value, using the per-field symmetric key. * * @param string $plaintext * @return string */ public function encryptValue($plaintext) { return $this ->engine ->getBackend() ->encrypt( $plaintext, $this->key ); } /** * Decrypt a single value, using the per-field symmetric key. * * @param string $ciphertext * @return string */ public function decryptValue($ciphertext) { return $this ->engine ->getBackend() ->decrypt( $ciphertext, $this->key ); } /** * Get all blind index values for a given plaintext. * * @param string $plaintext * @return array * * @throws BlindIndexNotFoundException * @throws CryptoOperationException */ public function getAllBlindIndexes($plaintext) { $output = []; $key = $this->engine->getBlindIndexRootKey( $this->tableName, $this->fieldName ); /** @var BlindIndex $index */ foreach ($this->blindIndexes as $name => $index) { $k = $this->engine->getIndexTypeColumn( $this->tableName, $this->fieldName, $name ); $output[$name] = [ 'type' => $k, 'value' => Hex::encode( $this->getBlindIndexRaw( $plaintext, $name, $key ) ) ]; } return $output; } /** * Get a particular blind index of a given plaintext. * * @param string $plaintext * @param string $name * @return array * * @throws BlindIndexNotFoundException * @throws CryptoOperationException */ public function getBlindIndex($plaintext, $name) { $key = $this->engine->getBlindIndexRootKey( $this->tableName, $this->fieldName ); $k = $this->engine->getIndexTypeColumn( $this->tableName, $this->fieldName, $name ); return [ 'type' => $k, 'value' => Hex::encode( $this->getBlindIndexRaw( $plaintext, $name, $key ) ) ]; } /** * Internal: Get the raw blind index. Returns a raw binary string. * * @param string $plaintext * @param string $name * @param SymmetricKey|null $key * @return string * * @throws BlindIndexNotFoundException * @throws CryptoOperationException */ protected function getBlindIndexRaw( $plaintext, $name, SymmetricKey $key = null ) { if (!isset($this->blindIndexes[$name])) { throw new BlindIndexNotFoundException( 'Blind index ' . $name . ' not found' ); } if (!$key) { $key = $this->engine->getBlindIndexRootKey( $this->tableName, $this->fieldName ); } $backend = $this->engine->getBackend(); $subKey = new SymmetricKey( $backend, \hash_hmac( 'sha256', Util::pack([$this->tableName, $this->fieldName, $name]), $key->getRawKey(), true ) ); /** @var BlindIndex $index */ $index = $this->blindIndexes[$name]; if ($index->getFastHash()) { return $backend->blindIndexFast( $plaintext, $subKey, $index->getFilterBitLength() ); } return $backend->blindIndexSlow( $plaintext, $subKey, $index->getFilterBitLength(), $index->getHashConfig() ); } /** * Get a list of all the blind index "type"s, corresponding with their * index names. * * @return array */ public function getBlindIndexTypes() { $typeArray = []; foreach (\array_keys($this->blindIndexes) as $name) { $typeArray[$name] = $this->engine->getIndexTypeColumn( $this->tableName, $this->fieldName, $name ); } return $typeArray; } /** * Add a blind index to this encrypted field. * * @param BlindIndex $index * @param string|null $name * @return self * @throws BlindIndexNameCollisionException */ public function addBlindIndex(BlindIndex $index, $name = null) { if (\is_null($name)) { $name = $index->getName(); } if (isset($this->blindIndexes[$name])) { throw new BlindIndexNameCollisionException( 'Index ' . $name . ' already defined' ); } $this->blindIndexes[$name] = $index; return $this; } }