PHP Classes

File: src/EncryptedField.php

Recommend this page to a friend!
  Classes of Scott Arciszewski   Cipher Sweet   src/EncryptedField.php   Download  
File: src/EncryptedField.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Cipher Sweet
Encrypt data in away that can be searched
Author: By
Last change:
Date: 5 years ago
Size: 7,115 bytes
 

Contents

Class file image Download
<?php
namespace ParagonIE\CipherSweet;

use
ParagonIE\CipherSweet\Backend\Key\SymmetricKey;
use
ParagonIE\CipherSweet\Exception\BlindIndexNameCollisionException;
use
ParagonIE\CipherSweet\Exception\BlindIndexNotFoundException;
use
ParagonIE\CipherSweet\Exception\CryptoOperationException;
use
ParagonIE\ConstantTime\Hex;

/**
 * Class EncryptedField
 * @package ParagonIE\CipherSweet
 */
class EncryptedField
{
   
/**
     * @var array<string, BlindIndex> $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<int, string|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<string, string|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<string, string>
     */
   
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;
    }
}