<?php 
namespace ParagonIE\CipherSweet; 
 
use ParagonIE\CipherSweet\Backend\FIPSCrypto; 
use ParagonIE\CipherSweet\Backend\Key\SymmetricKey; 
use ParagonIE\CipherSweet\Backend\ModernCrypto; 
use ParagonIE\CipherSweet\Contract\BackendInterface; 
use ParagonIE\CipherSweet\Contract\KeyProviderInterface; 
use ParagonIE\CipherSweet\Exception\CryptoOperationException; 
use ParagonIE_Sodium_Compat as SodiumCompat; 
 
/** 
 * Class CipherSweet 
 * @package ParagonIE\CipherSweet 
 */ 
final class CipherSweet 
{ 
    /* 
     * These domain separation constants has a hamming distance of 4 from each 
     * other, for each byte. 
     */ 
    const DS_BIDX = "\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E\x7E"; 
    const DS_FENC = "\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4\xB4"; 
 
    /** 
     * @var BackendInterface $backend 
     */ 
    private $backend; 
 
    /** 
     * @var KeyProviderInterface $keyProvider 
     */ 
    private $keyProvider; 
 
    /** 
     * CipherSweet constructor. 
     * 
     * @param KeyProviderInterface $keyProvider 
     * @param BackendInterface|null $backend 
     */ 
    public function __construct( 
        KeyProviderInterface $keyProvider, 
        BackendInterface $backend = null 
    ) { 
        $this->keyProvider = $keyProvider; 
        if (\is_null($backend)) { 
            $backend = $this->keyProvider->getBackend(); 
        } 
        $this->backend = $backend; 
    } 
 
    /** 
     * @return BackendInterface 
     */ 
    public function getBackend() 
    { 
        return $this->backend; 
    } 
 
    /** 
     * @param string $tableName 
     * @param string $fieldName 
     * @param string $indexName 
     * @return string 
     */ 
    public function getIndexTypeColumn( 
        $tableName, 
        $fieldName, 
        $indexName 
    ) { 
        return $this->backend->getIndexTypeColumn( 
            $tableName, 
            $fieldName, 
            $indexName 
        ); 
    } 
 
    /** 
     * Get the root key for calculating blind index keys for a given 
     * EncryptedField instance. 
     * 
     * Uses a 32 byte prefix for the HKDF "info" parameter, for domain 
     * separation. 
     * 
     * @param string $tableName 
     * @param string $fieldName 
     * 
     * @return SymmetricKey 
     * @throws CryptoOperationException 
     */ 
    public function getBlindIndexRootKey($tableName, $fieldName) 
    { 
        return new SymmetricKey( 
            $this->backend, 
            Util::HKDF( 
                $this->keyProvider->getSymmetricKey(), 
                $tableName, 
                self::DS_BIDX . $fieldName 
            ) 
        ); 
    } 
 
    /** 
     * Get the per-field encryption key. 
     * 
     * Uses a 32 byte prefix for the HKDF "info" parameter, for domain 
     * separation. 
     * 
     * @param string $tableName 
     * @param string $fieldName 
     * 
     * @return SymmetricKey 
     * @throws CryptoOperationException 
     */ 
    public function getFieldSymmetricKey($tableName, $fieldName) 
    { 
        return new SymmetricKey( 
            $this->backend, 
            Util::HKDF( 
                $this->keyProvider->getSymmetricKey(), 
                $tableName, 
                self::DS_FENC . $fieldName 
            ) 
        ); 
    } 
 
    /** 
     * Return the default backend for a given environment. Note that the 
     * stability of the result of this static method should not be depended on. 
     * 
     * @return BackendInterface 
     */ 
    public static function getDefaultBackend() 
    { 
        if (SodiumCompat::crypto_pwhash_is_available()) { 
            if (PHP_VERSION_ID >= 70000 && \extension_loaded('sodium')) { 
                return new ModernCrypto(); 
            } 
            if (PHP_VERSION_ID >= 70000 && \extension_loaded('libsodium')) { 
                // This is a little weird but OK 
                return new ModernCrypto(); 
            } 
            if (PHP_VERSION_ID < 70000 && \extension_loaded('libsodium')) { 
                return new ModernCrypto(); 
            } 
        } 
        // FIPS mode will always work... but it only uses FIPS algorithms. 
        return new FIPSCrypto(); 
    } 
} 
 
 |