Skip to content

Commit b45c629

Browse files
Allow multi-tenant providers to use static blind index keys
1 parent 86d951e commit b45c629

File tree

4 files changed

+97
-3
lines changed

4 files changed

+97
-3
lines changed

src/CipherSweet.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
BackendInterface,
1111
KeyProviderInterface,
1212
MultiTenantAwareProviderInterface,
13-
MultiTenantSafeBackendInterface
13+
MultiTenantSafeBackendInterface,
14+
StaticBlindIndexKeyProviderInterface
1415
};
1516
use ParagonIE\CipherSweet\Exception\{
1617
CipherSweetException,
@@ -81,12 +82,21 @@ public function getIndexTypeColumn(
8182
*
8283
* Uses a 32 byte prefix for the HKDF "info" parameter, for domain
8384
* separation.
85+
*
86+
* @throws CipherSweetException
8487
*/
8588
public function getBlindIndexRootKey(string $tableName, string $fieldName): SymmetricKey
8689
{
90+
$key = $this->keyProvider->getSymmetricKey();
91+
if ($this->keyProvider instanceof StaticBlindIndexKeyProviderInterface) {
92+
$tenant = $this->keyProvider->getStaticBlindIndexTenant();
93+
if (!is_null($tenant)) {
94+
$key = $this->keyProvider->getTenant($tenant)->getSymmetricKey();
95+
}
96+
}
8797
return new SymmetricKey(
8898
Util::HKDF(
89-
$this->keyProvider->getSymmetricKey(),
99+
$key,
90100
$tableName,
91101
Constants::DS_BIDX . $fieldName
92102
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
declare(strict_types=1);
3+
namespace ParagonIE\CipherSweet\Contract;
4+
5+
/**
6+
* Enables Key Providers to enable/disable using a specific, static "Tenant" for deriving the root keys
7+
* for Blind Indexes and Compound Indexes.
8+
*/
9+
interface StaticBlindIndexKeyProviderInterface extends MultiTenantAwareProviderInterface
10+
{
11+
public function getStaticBlindIndexTenant(): string|int|null;
12+
public function setStaticBlindIndexTenant(string|int|null $tenant = null): void;
13+
}

tests/MultiTenant/MultiTenantTest.php

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,37 @@ class MultiTenantTest extends TestCase
2727
{
2828
/** @var CipherSweet $csBoring */
2929
private $csBoring;
30+
/** @var CipherSweet $csBoring2 */
31+
private $csBoring2;
3032
/** @var CipherSweet $csFips */
3133
private $csFips;
34+
/** @var CipherSweet $csFips2 */
35+
private $csFips2;
3236

3337
/**
3438
* @before
3539
*/
3640
public function before()
3741
{
42+
$foo = new StringProvider(random_bytes(32));
3843
$provider = new TestMultiTenantKeyProvider([
39-
'foo' => new StringProvider(random_bytes(32)),
44+
'foo' => $foo,
4045
'bar' => new StringProvider(random_bytes(32)),
4146
'baz' => new StringProvider(random_bytes(32)),
4247
]);
4348
$provider->setActiveTenant('foo');
4449
$this->csBoring = new CipherSweet($provider, new BoringCrypto());
4550
$this->csFips = new CipherSweet($provider, new FIPSCrypto());
51+
52+
$provider2 = new SBKP([
53+
'foo' => $foo,
54+
'bar' => new StringProvider(random_bytes(32)),
55+
'baz' => new StringProvider(random_bytes(32)),
56+
]);
57+
$provider2->setStaticBlindIndexTenant('foo');
58+
59+
$this->csBoring2 = new CipherSweet($provider2, new BoringCrypto());
60+
$this->csFips2 = new CipherSweet($provider2, new FIPSCrypto());
4661
}
4762

4863
/**
@@ -288,4 +303,37 @@ public function testEncryptedMultiRows()
288303
$this->assertTrue($decryptFailed, 'Swapping out tenant identifiers should fail decryption');
289304
}
290305
}
306+
307+
public function testStaticBlindIndexKey(): void
308+
{
309+
// These keys should differ
310+
/** @var CipherSweet $cs */
311+
foreach ([$this->csBoring, $this->csFips] as $cs) {
312+
$cs->setActiveTenant('bar');
313+
$k1 = $cs->getBlindIndexRootKey('a', 'b')->getRawKey();
314+
$cs->setActiveTenant('baz');
315+
$k2 = $cs->getBlindIndexRootKey('a', 'b')->getRawKey();
316+
$this->assertNotSame($k1, $k2);
317+
}
318+
319+
// These keys should be the same:
320+
/** @var CipherSweet $cs */
321+
foreach ([$this->csBoring2, $this->csFips2] as $cs) {
322+
$cs->setActiveTenant('bar');
323+
$k1 = $cs->getBlindIndexRootKey('a', 'b')->getRawKey();
324+
$cs->setActiveTenant('baz');
325+
$k2 = $cs->getBlindIndexRootKey('a', 'b')->getRawKey();
326+
$this->assertSame($k1, $k2);
327+
}
328+
329+
// These should all differ:
330+
331+
foreach ([$this->csBoring, $this->csFips, $this->csBoring2, $this->csFips2] as $cs) {
332+
$cs->setActiveTenant('bar');
333+
$k1 = $cs->getFieldSymmetricKey('a', 'b')->getRawKey();
334+
$cs->setActiveTenant('baz');
335+
$k2 = $cs->getFieldSymmetricKey('a', 'b')->getRawKey();
336+
$this->assertNotSame($k1, $k2);
337+
}
338+
}
291339
}

tests/MultiTenant/SBKP.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
namespace ParagonIE\CipherSweet\Tests\MultiTenant;
3+
4+
use ParagonIE\CipherSweet\Contract\StaticBlindIndexKeyProviderInterface;
5+
6+
/**
7+
* Class TestMultiTenantKeyProvider
8+
* @package ParagonIE\CipherSweet\Tests\MultiTenant
9+
*/
10+
class SBKP extends TestMultiTenantKeyProvider implements StaticBlindIndexKeyProviderInterface
11+
{
12+
protected string|int|null $blindIndexTenant = null;
13+
14+
public function getStaticBlindIndexTenant(): string|int|null
15+
{
16+
return $this->blindIndexTenant;
17+
}
18+
19+
public function setStaticBlindIndexTenant(int|string|null $tenant = null): void
20+
{
21+
$this->blindIndexTenant = $tenant;
22+
}
23+
}

0 commit comments

Comments
 (0)