From d64087884ab9e3144635ef07be20ecb5ed41faaf Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 16 Jan 2019 08:44:51 +0800 Subject: [PATCH 1/3] adds a new EncryptionKeyNotFound exception for a MockKeyLookupProvider with new tests --- src/Exception/EncryptionKeyNotFound.php | 7 +++++++ test/Mock/MockKeyLookupProvider.php | 19 +++++++++++++++++ test/RFC8188Test.php | 28 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/Exception/EncryptionKeyNotFound.php create mode 100644 test/Mock/MockKeyLookupProvider.php diff --git a/src/Exception/EncryptionKeyNotFound.php b/src/Exception/EncryptionKeyNotFound.php new file mode 100644 index 0000000..33dee93 --- /dev/null +++ b/src/Exception/EncryptionKeyNotFound.php @@ -0,0 +1,7 @@ +keys[$keyid] = $key; + } + public function __invoke($keyid) { + if (in_array($keyid, array_keys($this->keys))) { + return $this->keys[$keyid]; + } + throw new EncryptionKeyNotFound("Encryption key not found."); + } +} \ No newline at end of file diff --git a/test/RFC8188Test.php b/test/RFC8188Test.php index b1de58d..d632f73 100644 --- a/test/RFC8188Test.php +++ b/test/RFC8188Test.php @@ -4,6 +4,8 @@ use PHPUnit\Framework\TestCase; use DevJack\EncryptedContentEncoding\RFC8188; +use DevJack\EncryptedContentEncoding\Test\Mock\MockKeyLookupProvider; +use DevJack\EncryptedContentEncoding\Exception\EncryptionKeyNotFound; use Base64Url\Base64Url as b64; final class RFC8188Test extends TestCase @@ -76,6 +78,32 @@ function($keyid ) use ($key) { return $key; } $this->assertEquals($message, $decoded); } + public function testCanInvokeCallableClassAsKeyProvider() { + $encoded = b64::decode("uNCkWiNYzKTnBN9ji3-qWAAAABkCYTHOG8chz_gnvgOqdGYovxyjuqRyJFjEDyoF1Fvkj6hQPdPHI51OEUKEpgz3SsLWIqS_uA"); + $keyProvider = new MockKeyLookupProvider(); + $keyProvider->addKey(b64::decode("BO3ZVPxUlnLORbVGMpbT1Q"), 'a1'); + $decoded = RFC8188::rfc8188_decode( + $encoded, // data to decode + $keyProvider + ); + + $this->assertEquals("I am the walrus", $decoded); + } + + public function testMockLookupProviderThrowsKeyNotFoundException() { + $encoded = b64::decode("uNCkWiNYzKTnBN9ji3-qWAAAABkCYTHOG8chz_gnvgOqdGYovxyjuqRyJFjEDyoF1Fvkj6hQPdPHI51OEUKEpgz3SsLWIqS_uA"); + + $keyProvider = new MockKeyLookupProvider(); + $keyProvider->addKey(b64::decode("BO3ZVPxUlnLORbVGMpbT1Q"), ''); // intentionally set keyid NOT to 'a1' + + $this->expectException(EncryptionKeyNotFound::class); + + $decoded = RFC8188::rfc8188_decode( + $encoded, // data to decode + $keyProvider + ); + } + /** * @requires PHP 5.6 */ From 72cd060b038ccd2609c9deecf79c6faaba38b9f3 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 16 Jan 2019 08:49:58 +0800 Subject: [PATCH 2/3] documents the use of an invocable class for key lookup --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index 15ff13a..b5426fd 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ > Note: RFC8188 relies heavily on base64 URL encoding. +### Simple callback function for encryption key lookup + ```php require_once "vendor/autoload.php"; @@ -35,8 +37,41 @@ $decoded = RFC8188::rfc8188_decode( $this->assertEquals($message, $decoded); ``` +### Invocable class for key lookup +In this example we use a simple incovable class to provide key lookup. This may be more useful in complex framework integrations such as providing middleware that looks up keys from a database. This sample does not cover service injection to the key lookup class. + +```php +use DevJack\EncryptedContentEncoding\RFC8188; +use DevJack\EncryptedContentEncoding\Exception\EncryptionKeyNotFound; +use Base64Url\Base64Url as b64; + +class MockKeyLookupProvider { + + protected $keys = []; + + public function addKey($key, $keyid='') { + $this->keys[$keyid] = $key; + } + public function __invoke($keyid) { + if (in_array($keyid, array_keys($this->keys))) { + return $this->keys[$keyid]; + } + throw new EncryptionKeyNotFound("Encryption key not found."); + } +} +$encoded = b64::decode("uNCkWiNYzKTnBN9ji3-qWAAAABkCYTHOG8chz_gnvgOqdGYovxyjuqRyJFjEDyoF1Fvkj6hQPdPHI51OEUKEpgz3SsLWIqS_uA"); + +$keyProvider = new MockKeyLookupProvider(); +$keyProvider->addKey(b64::decode("BO3ZVPxUlnLORbVGMpbT1Q"), 'a1'); + +$decoded = RFC8188::rfc8188_decode( + $encoded, // data to decode + $keyProvider +); +``` + ## Installation ``` From 1bd40f1f672e31c9b28072b38ed1811f7b4baa32 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 16 Jan 2019 09:03:07 +0800 Subject: [PATCH 3/3] fixes \Exception class references. --- src/RFC8188.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RFC8188.php b/src/RFC8188.php index 14c40aa..ba1f703 100644 --- a/src/RFC8188.php +++ b/src/RFC8188.php @@ -25,7 +25,7 @@ protected static function hkdf($salt, $ikm, $sequence=0) public static function rfc8188_decode($payload, $key_lookup) { if (!is_callable($key_lookup)) { - throw new Exception(sprintf( + throw new \Exception(sprintf( '$key_lookup must be invocable' )); } @@ -124,7 +124,7 @@ public static function rfc8188_encode($payload, $key, $keyid=null, $rs=25) $encrypted = openssl_encrypt($plaintext_record, "aes-128-gcm", $hkdf['cek'], OPENSSL_RAW_DATA, $hkdf['nonce'], $tag); $block = $encrypted.$tag; if (false === $encrypted) { - throw new Exception(sprintf( + throw new \Exception(sprintf( "OpenSSL error: %s", openssl_error_string() )); }