Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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

```
Expand Down
7 changes: 7 additions & 0 deletions src/Exception/EncryptionKeyNotFound.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace DevJack\EncryptedContentEncoding\Exception;

class EncryptionKeyNotFound extends \Exception {

}
4 changes: 2 additions & 2 deletions src/RFC8188.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'
));
}
Expand Down Expand Up @@ -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()
));
}
Expand Down
19 changes: 19 additions & 0 deletions test/Mock/MockKeyLookupProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
namespace DevJack\EncryptedContentEncoding\Test\Mock;

use DevJack\EncryptedContentEncoding\Exception\EncryptionKeyNotFound;

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.");
}
}
28 changes: 28 additions & 0 deletions test/RFC8188Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
*/
Expand Down