From 7c5110c362e57b9c424829070f8e13274bbe0cfd Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Wed, 16 Dec 2020 15:29:43 -0800 Subject: [PATCH] (dev/core#2258) CryptoToken - Don't build registry if we only read plaintext Example: You have a basic site that has not enabled encrypted fields, but the integration with settings/APIs causes one to use CryptoToken::decrypt() --- Civi/Core/Container.php | 6 ++--- Civi/Crypto/CryptoToken.php | 23 +++++++++---------- tests/phpunit/Civi/Crypto/CryptoTokenTest.php | 8 +++++++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index fb3f0b9d79..67f5319585 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -221,10 +221,8 @@ class Container { $container->setDefinition('crypto.registry', new Definition('Civi\Crypto\CryptoService')) ->setFactory(__CLASS__ . '::createCryptoRegistry')->setPublic(TRUE); - $container->setDefinition('crypto.token', new Definition( - 'Civi\Crypto\CryptoToken', - [new Reference('crypto.registry')] - ))->setPublic(TRUE); + $container->setDefinition('crypto.token', new Definition('Civi\Crypto\CryptoToken', [])) + ->setPublic(TRUE); if (empty(\Civi::$statics[__CLASS__]['boot'])) { throw new \RuntimeException('Cannot initialize container. Boot services are undefined.'); diff --git a/Civi/Crypto/CryptoToken.php b/Civi/Crypto/CryptoToken.php index a14ef8c548..93fe284fc8 100644 --- a/Civi/Crypto/CryptoToken.php +++ b/Civi/Crypto/CryptoToken.php @@ -45,20 +45,13 @@ class CryptoToken { const VERSION_1 = 'CTK0'; - /** - * @var CryptoRegistry - */ - protected $registry; - protected $delim; /** * CryptoToken constructor. - * @param \Civi\Crypto\CryptoRegistry $registry */ - public function __construct(\Civi\Crypto\CryptoRegistry $registry) { + public function __construct() { $this->delim = chr(2); - $this->registry = $registry; } /** @@ -83,7 +76,10 @@ class CryptoToken { * @throws \Civi\Crypto\Exception\CryptoException */ public function encrypt($plainText, $keyIdOrTag) { - $key = $this->registry->findKey($keyIdOrTag); + /** @var CryptoRegistry $registry */ + $registry = \Civi::service('crypto.registry'); + + $key = $registry->findKey($keyIdOrTag); if ($key['suite'] === 'plain') { if (!$this->isPlainText($plainText)) { throw new CryptoException("Cannot use plaintext encoding for data with reserved delimiter."); @@ -92,7 +88,7 @@ class CryptoToken { } /** @var \Civi\Crypto\CipherSuiteInterface $cipherSuite */ - $cipherSuite = $this->registry->findSuite($key['suite']); + $cipherSuite = $registry->findSuite($key['suite']); $cipherText = $cipherSuite->encrypt($plainText, $key); return $this->delim . self::VERSION_1 . $this->delim . $key['id'] . $this->delim . base64_encode($cipherText); } @@ -119,6 +115,9 @@ class CryptoToken { } } + /** @var CryptoRegistry $registry */ + $registry = \Civi::service('crypto.registry'); + $parts = explode($this->delim, $token); if ($parts[1] !== self::VERSION_1) { throw new CryptoException("Unrecognized encoding"); @@ -126,13 +125,13 @@ class CryptoToken { $keyId = $parts[2]; $cipherText = base64_decode($parts[3]); - $key = $this->registry->findKey($keyId); + $key = $registry->findKey($keyId); if (!in_array('*', $keyIdOrTag) && !in_array($keyId, $keyIdOrTag) && empty(array_intersect($keyIdOrTag, $key['tags']))) { throw new CryptoException("Cannot decrypt token. Unexpected key: $keyId"); } /** @var \Civi\Crypto\CipherSuiteInterface $cipherSuite */ - $cipherSuite = $this->registry->findSuite($key['suite']); + $cipherSuite = $registry->findSuite($key['suite']); $plainText = $cipherSuite->decrypt($cipherText, $key); return $plainText; } diff --git a/tests/phpunit/Civi/Crypto/CryptoTokenTest.php b/tests/phpunit/Civi/Crypto/CryptoTokenTest.php index 961166a89a..64d3e310a9 100644 --- a/tests/phpunit/Civi/Crypto/CryptoTokenTest.php +++ b/tests/phpunit/Civi/Crypto/CryptoTokenTest.php @@ -66,4 +66,12 @@ class CryptoTokenTest extends \CiviUnitTestCase { $this->assertEquals($inputText, $actualText); } + public function testReadPlainTextWithoutRegistry() { + // This is performance optimization - don't initialize crypto.registry unless + // you actually need it. + $this->assertFalse(\Civi::container()->initialized('crypto.registry')); + $this->assertEquals("Hello world", \Civi::service('crypto.token')->decrypt("Hello world")); + $this->assertFalse(\Civi::container()->initialized('crypto.registry')); + } + } -- 2.25.1