primo commit
This commit is contained in:
28
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A128CBCHS256.php
vendored
Normal file
28
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A128CBCHS256.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
|
||||
|
||||
final class A128CBCHS256 extends AESCBCHS
|
||||
{
|
||||
public function getCEKSize(): int
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'A128CBC-HS256';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
|
||||
protected function getMode(): string
|
||||
{
|
||||
return 'aes-128-cbc';
|
||||
}
|
||||
}
|
||||
23
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A128GCM.php
vendored
Normal file
23
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A128GCM.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
|
||||
|
||||
final class A128GCM extends AESGCM
|
||||
{
|
||||
public function getCEKSize(): int
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'A128GCM';
|
||||
}
|
||||
|
||||
protected function getMode(): string
|
||||
{
|
||||
return 'aes-128-gcm';
|
||||
}
|
||||
}
|
||||
28
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A192CBCHS384.php
vendored
Normal file
28
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A192CBCHS384.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
|
||||
|
||||
final class A192CBCHS384 extends AESCBCHS
|
||||
{
|
||||
public function getCEKSize(): int
|
||||
{
|
||||
return 384;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'A192CBC-HS384';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha384';
|
||||
}
|
||||
|
||||
protected function getMode(): string
|
||||
{
|
||||
return 'aes-192-cbc';
|
||||
}
|
||||
}
|
||||
23
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A192GCM.php
vendored
Normal file
23
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A192GCM.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
|
||||
|
||||
final class A192GCM extends AESGCM
|
||||
{
|
||||
public function getCEKSize(): int
|
||||
{
|
||||
return 192;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'A192GCM';
|
||||
}
|
||||
|
||||
protected function getMode(): string
|
||||
{
|
||||
return 'aes-192-gcm';
|
||||
}
|
||||
}
|
||||
28
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A256CBCHS512.php
vendored
Normal file
28
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A256CBCHS512.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
|
||||
|
||||
final class A256CBCHS512 extends AESCBCHS
|
||||
{
|
||||
public function getCEKSize(): int
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'A256CBC-HS512';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha512';
|
||||
}
|
||||
|
||||
protected function getMode(): string
|
||||
{
|
||||
return 'aes-256-cbc';
|
||||
}
|
||||
}
|
||||
23
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A256GCM.php
vendored
Normal file
23
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A256GCM.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
|
||||
|
||||
final class A256GCM extends AESGCM
|
||||
{
|
||||
public function getCEKSize(): int
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'A256GCM';
|
||||
}
|
||||
|
||||
protected function getMode(): string
|
||||
{
|
||||
return 'aes-256-gcm';
|
||||
}
|
||||
}
|
||||
114
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/AESCBCHS.php
vendored
Normal file
114
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/AESCBCHS.php
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
|
||||
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
|
||||
use RuntimeException;
|
||||
use function extension_loaded;
|
||||
use const OPENSSL_RAW_DATA;
|
||||
|
||||
abstract class AESCBCHS implements ContentEncryptionAlgorithm
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (! extension_loaded('openssl')) {
|
||||
throw new RuntimeException('Please install the OpenSSL extension');
|
||||
}
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return []; //Irrelevant
|
||||
}
|
||||
|
||||
public function encryptContent(
|
||||
string $data,
|
||||
string $cek,
|
||||
string $iv,
|
||||
?string $aad,
|
||||
string $encoded_protected_header,
|
||||
?string &$tag = null
|
||||
): string {
|
||||
$k = mb_substr($cek, $this->getCEKSize() / 16, null, '8bit');
|
||||
$result = openssl_encrypt($data, $this->getMode(), $k, OPENSSL_RAW_DATA, $iv);
|
||||
if ($result === false) {
|
||||
throw new RuntimeException('Unable to encrypt the content');
|
||||
}
|
||||
|
||||
$tag = $this->calculateAuthenticationTag($result, $cek, $iv, $aad, $encoded_protected_header);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function decryptContent(
|
||||
string $data,
|
||||
string $cek,
|
||||
string $iv,
|
||||
?string $aad,
|
||||
string $encoded_protected_header,
|
||||
string $tag
|
||||
): string {
|
||||
if (! $this->isTagValid($data, $cek, $iv, $aad, $encoded_protected_header, $tag)) {
|
||||
throw new RuntimeException('Unable to decrypt or to verify the tag.');
|
||||
}
|
||||
$k = mb_substr($cek, $this->getCEKSize() / 16, null, '8bit');
|
||||
|
||||
$result = openssl_decrypt($data, $this->getMode(), $k, OPENSSL_RAW_DATA, $iv);
|
||||
if ($result === false) {
|
||||
throw new RuntimeException('Unable to decrypt or to verify the tag.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getIVSize(): int
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
|
||||
protected function calculateAuthenticationTag(
|
||||
string $encrypted_data,
|
||||
string $cek,
|
||||
string $iv,
|
||||
?string $aad,
|
||||
string $encoded_header
|
||||
): string {
|
||||
$calculated_aad = $encoded_header;
|
||||
if ($aad !== null) {
|
||||
$calculated_aad .= '.' . Base64UrlSafe::encodeUnpadded($aad);
|
||||
}
|
||||
$mac_key = mb_substr($cek, 0, $this->getCEKSize() / 16, '8bit');
|
||||
$auth_data_length = mb_strlen($encoded_header, '8bit');
|
||||
|
||||
$secured_input = implode('', [
|
||||
$calculated_aad,
|
||||
$iv,
|
||||
$encrypted_data,
|
||||
pack('N2', ($auth_data_length / 2_147_483_647) * 8, ($auth_data_length % 2_147_483_647) * 8),
|
||||
]);
|
||||
$hash = hash_hmac($this->getHashAlgorithm(), $secured_input, $mac_key, true);
|
||||
|
||||
return mb_substr($hash, 0, mb_strlen($hash, '8bit') / 2, '8bit');
|
||||
}
|
||||
|
||||
protected function isTagValid(
|
||||
string $encrypted_data,
|
||||
string $cek,
|
||||
string $iv,
|
||||
?string $aad,
|
||||
string $encoded_header,
|
||||
string $authentication_tag
|
||||
): bool {
|
||||
return hash_equals(
|
||||
$authentication_tag,
|
||||
$this->calculateAuthenticationTag($encrypted_data, $cek, $iv, $aad, $encoded_header)
|
||||
);
|
||||
}
|
||||
|
||||
abstract protected function getHashAlgorithm(): string;
|
||||
|
||||
abstract protected function getMode(): string;
|
||||
}
|
||||
75
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/AESGCM.php
vendored
Normal file
75
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/AESGCM.php
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
|
||||
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
|
||||
use RuntimeException;
|
||||
use function extension_loaded;
|
||||
use const OPENSSL_RAW_DATA;
|
||||
|
||||
abstract class AESGCM implements ContentEncryptionAlgorithm
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (! extension_loaded('openssl')) {
|
||||
throw new RuntimeException('Please install the OpenSSL extension');
|
||||
}
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return []; //Irrelevant
|
||||
}
|
||||
|
||||
public function encryptContent(
|
||||
string $data,
|
||||
string $cek,
|
||||
string $iv,
|
||||
?string $aad,
|
||||
string $encoded_protected_header,
|
||||
?string &$tag = null
|
||||
): string {
|
||||
$calculated_aad = $encoded_protected_header;
|
||||
if ($aad !== null) {
|
||||
$calculated_aad .= '.' . Base64UrlSafe::encodeUnpadded($aad);
|
||||
}
|
||||
$tag = '';
|
||||
$result = openssl_encrypt($data, $this->getMode(), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad);
|
||||
if ($result === false) {
|
||||
throw new RuntimeException('Unable to encrypt the content');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function decryptContent(
|
||||
string $data,
|
||||
string $cek,
|
||||
string $iv,
|
||||
?string $aad,
|
||||
string $encoded_protected_header,
|
||||
string $tag
|
||||
): string {
|
||||
$calculated_aad = $encoded_protected_header;
|
||||
if ($aad !== null) {
|
||||
$calculated_aad .= '.' . Base64UrlSafe::encodeUnpadded($aad);
|
||||
}
|
||||
|
||||
$result = openssl_decrypt($data, $this->getMode(), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad);
|
||||
if ($result === false) {
|
||||
throw new RuntimeException('Unable to decrypt the content');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getIVSize(): int
|
||||
{
|
||||
return 96;
|
||||
}
|
||||
|
||||
abstract protected function getMode(): string;
|
||||
}
|
||||
59
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryptionAlgorithm.php
vendored
Normal file
59
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/ContentEncryptionAlgorithm.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm;
|
||||
|
||||
use Jose\Component\Core\Algorithm;
|
||||
|
||||
interface ContentEncryptionAlgorithm extends Algorithm
|
||||
{
|
||||
/**
|
||||
* This method encrypts the data using the given CEK, IV, AAD and protected header. The variable $tag is populated
|
||||
* on success.
|
||||
*
|
||||
* @param string $data The data to encrypt
|
||||
* @param string $cek The content encryption key
|
||||
* @param string $iv The Initialization Vector
|
||||
* @param string|null $aad Additional Additional Authenticated Data
|
||||
* @param string $encoded_protected_header The Protected Header encoded in Base64Url
|
||||
* @param string $tag Tag
|
||||
*/
|
||||
public function encryptContent(
|
||||
string $data,
|
||||
string $cek,
|
||||
string $iv,
|
||||
?string $aad,
|
||||
string $encoded_protected_header,
|
||||
?string &$tag = null
|
||||
): string;
|
||||
|
||||
/**
|
||||
* This method tries to decrypt the data using the given CEK, IV, AAD, protected header and tag.
|
||||
*
|
||||
* @param string $data The data to decrypt
|
||||
* @param string $cek The content encryption key
|
||||
* @param string $iv The Initialization Vector
|
||||
* @param string|null $aad Additional Additional Authenticated Data
|
||||
* @param string $encoded_protected_header The Protected Header encoded in Base64Url
|
||||
* @param string $tag Tag
|
||||
*/
|
||||
public function decryptContent(
|
||||
string $data,
|
||||
string $cek,
|
||||
string $iv,
|
||||
?string $aad,
|
||||
string $encoded_protected_header,
|
||||
string $tag
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Returns the size of the IV used by this encryption method.
|
||||
*/
|
||||
public function getIVSize(): int;
|
||||
|
||||
/**
|
||||
* Returns the size of the CEK used by this encryption method.
|
||||
*/
|
||||
public function getCEKSize(): int;
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A128GCMKW.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A128GCMKW.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
final class A128GCMKW extends AESGCMKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'A128GCMKW';
|
||||
}
|
||||
|
||||
protected function getKeySize(): int
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A128KW.php
vendored
Normal file
21
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A128KW.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A128KW as Wrapper;
|
||||
use AESKW\Wrapper as WrapperInterface;
|
||||
|
||||
final class A128KW extends AESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'A128KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): WrapperInterface
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A192GCMKW.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A192GCMKW.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
final class A192GCMKW extends AESGCMKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'A192GCMKW';
|
||||
}
|
||||
|
||||
protected function getKeySize(): int
|
||||
{
|
||||
return 192;
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A192KW.php
vendored
Normal file
21
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A192KW.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A192KW as Wrapper;
|
||||
use AESKW\Wrapper as WrapperInterface;
|
||||
|
||||
final class A192KW extends AESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'A192KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): WrapperInterface
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A256GCMKW.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A256GCMKW.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
final class A256GCMKW extends AESGCMKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'A256GCMKW';
|
||||
}
|
||||
|
||||
protected function getKeySize(): int
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A256KW.php
vendored
Normal file
21
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/A256KW.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A256KW as Wrapper;
|
||||
use AESKW\Wrapper as WrapperInterface;
|
||||
|
||||
final class A256KW extends AESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'A256KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): WrapperInterface
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
}
|
||||
102
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AESGCMKW.php
vendored
Normal file
102
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AESGCMKW.php
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\Wrapper as WrapperInterface;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use RuntimeException;
|
||||
use function extension_loaded;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use const OPENSSL_RAW_DATA;
|
||||
|
||||
abstract class AESGCMKW implements KeyWrapping
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (! extension_loaded('openssl')) {
|
||||
throw new RuntimeException('Please install the OpenSSL extension');
|
||||
}
|
||||
if (! interface_exists(WrapperInterface::class)) {
|
||||
throw new RuntimeException('Please install "spomky-labs/aes-key-wrap" to use AES-KW algorithms');
|
||||
}
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['oct'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $completeHeader
|
||||
* @param array<string, mixed> $additionalHeader
|
||||
*/
|
||||
public function wrapKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string
|
||||
{
|
||||
$kek = $this->getKey($key);
|
||||
$iv = random_bytes(96 / 8);
|
||||
$additionalHeader['iv'] = Base64UrlSafe::encodeUnpadded($iv);
|
||||
|
||||
$mode = sprintf('aes-%d-gcm', $this->getKeySize());
|
||||
$tag = '';
|
||||
$encrypted_cek = openssl_encrypt($cek, $mode, $kek, OPENSSL_RAW_DATA, $iv, $tag, '');
|
||||
if ($encrypted_cek === false) {
|
||||
throw new RuntimeException('Unable to encrypt the CEK');
|
||||
}
|
||||
$additionalHeader['tag'] = Base64UrlSafe::encodeUnpadded($tag);
|
||||
|
||||
return $encrypted_cek;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $completeHeader
|
||||
*/
|
||||
public function unwrapKey(JWK $key, string $encrypted_cek, array $completeHeader): string
|
||||
{
|
||||
$kek = $this->getKey($key);
|
||||
(isset($completeHeader['iv']) && is_string($completeHeader['iv'])) || throw new InvalidArgumentException(
|
||||
'Parameter "iv" is missing.'
|
||||
);
|
||||
(isset($completeHeader['tag']) && is_string($completeHeader['tag'])) || throw new InvalidArgumentException(
|
||||
'Parameter "tag" is missing.'
|
||||
);
|
||||
|
||||
$tag = Base64UrlSafe::decodeNoPadding($completeHeader['tag']);
|
||||
$iv = Base64UrlSafe::decodeNoPadding($completeHeader['iv']);
|
||||
|
||||
$mode = sprintf('aes-%d-gcm', $this->getKeySize());
|
||||
$cek = openssl_decrypt($encrypted_cek, $mode, $kek, OPENSSL_RAW_DATA, $iv, $tag, '');
|
||||
if ($cek === false) {
|
||||
throw new RuntimeException('Unable to decrypt the CEK');
|
||||
}
|
||||
|
||||
return $cek;
|
||||
}
|
||||
|
||||
public function getKeyManagementMode(): string
|
||||
{
|
||||
return self::MODE_WRAP;
|
||||
}
|
||||
|
||||
protected function getKey(JWK $key): string
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
if (! $key->has('k')) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is missing.');
|
||||
}
|
||||
$k = $key->get('k');
|
||||
if (! is_string($k)) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is invalid.');
|
||||
}
|
||||
|
||||
return Base64UrlSafe::decodeNoPadding($k);
|
||||
}
|
||||
|
||||
abstract protected function getKeySize(): int;
|
||||
}
|
||||
74
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AESKW.php
vendored
Normal file
74
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AESKW.php
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\Wrapper as WrapperInterface;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use RuntimeException;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
|
||||
abstract class AESKW implements KeyWrapping
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (! interface_exists(WrapperInterface::class)) {
|
||||
throw new RuntimeException('Please install "spomky-labs/aes-key-wrap" to use AES-KW algorithms');
|
||||
}
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['oct'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $completeHeader
|
||||
* @param array<string, mixed> $additionalHeader
|
||||
*/
|
||||
public function wrapKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string
|
||||
{
|
||||
$k = $this->getKey($key);
|
||||
$wrapper = $this->getWrapper();
|
||||
|
||||
return $wrapper::wrap($k, $cek);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $completeHeader
|
||||
*/
|
||||
public function unwrapKey(JWK $key, string $encrypted_cek, array $completeHeader): string
|
||||
{
|
||||
$k = $this->getKey($key);
|
||||
$wrapper = $this->getWrapper();
|
||||
|
||||
return $wrapper::unwrap($k, $encrypted_cek);
|
||||
}
|
||||
|
||||
public function getKeyManagementMode(): string
|
||||
{
|
||||
return self::MODE_WRAP;
|
||||
}
|
||||
|
||||
abstract protected function getWrapper(): WrapperInterface;
|
||||
|
||||
private function getKey(JWK $key): string
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
if (! $key->has('k')) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is missing.');
|
||||
}
|
||||
$k = $key->get('k');
|
||||
if (! is_string($k)) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is invalid.');
|
||||
}
|
||||
|
||||
return Base64UrlSafe::decodeNoPadding($k);
|
||||
}
|
||||
}
|
||||
316
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDH.php
vendored
Normal file
316
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDH.php
vendored
Normal file
@ -0,0 +1,316 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Brick\Math\BigInteger;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use Jose\Component\Core\Util\Ecc\Curve;
|
||||
use Jose\Component\Core\Util\Ecc\EcDH;
|
||||
use Jose\Component\Core\Util\Ecc\NistCurve;
|
||||
use Jose\Component\Core\Util\Ecc\PrivateKey;
|
||||
use Jose\Component\Core\Util\ECKey;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\Util\ConcatKDF;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
use function array_key_exists;
|
||||
use function extension_loaded;
|
||||
use function function_exists;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
|
||||
abstract class AbstractECDH implements KeyAgreement
|
||||
{
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['EC', 'OKP'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $complete_header
|
||||
* @param array<string, mixed> $additional_header_values
|
||||
*/
|
||||
public function getAgreementKey(
|
||||
int $encryptionKeyLength,
|
||||
string $algorithm,
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
array $complete_header = [],
|
||||
array &$additional_header_values = []
|
||||
): string {
|
||||
if ($recipientKey->has('d')) {
|
||||
[$public_key, $private_key] = $this->getKeysFromPrivateKeyAndHeader($recipientKey, $complete_header);
|
||||
} else {
|
||||
[$public_key, $private_key] = $this->getKeysFromPublicKey(
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$additional_header_values
|
||||
);
|
||||
}
|
||||
|
||||
$agreed_key = $this->calculateAgreementKey($private_key, $public_key);
|
||||
|
||||
$apu = array_key_exists('apu', $complete_header) ? $complete_header['apu'] : '';
|
||||
is_string($apu) || throw new InvalidArgumentException('Invalid APU.');
|
||||
$apv = array_key_exists('apv', $complete_header) ? $complete_header['apv'] : '';
|
||||
is_string($apv) || throw new InvalidArgumentException('Invalid APU.');
|
||||
|
||||
return ConcatKDF::generate($agreed_key, $algorithm, $encryptionKeyLength, $apu, $apv);
|
||||
}
|
||||
|
||||
public function getKeyManagementMode(): string
|
||||
{
|
||||
return self::MODE_AGREEMENT;
|
||||
}
|
||||
|
||||
protected function calculateAgreementKey(JWK $private_key, JWK $public_key): string
|
||||
{
|
||||
$crv = $public_key->get('crv');
|
||||
if (! is_string($crv)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "crv"');
|
||||
}
|
||||
switch ($crv) {
|
||||
case 'P-256':
|
||||
case 'P-384':
|
||||
case 'P-521':
|
||||
$curve = $this->getCurve($crv);
|
||||
if (function_exists('openssl_pkey_derive')) {
|
||||
try {
|
||||
$publicPem = ECKey::convertPublicKeyToPEM($public_key);
|
||||
$privatePem = ECKey::convertPrivateKeyToPEM($private_key);
|
||||
|
||||
$res = openssl_pkey_derive($publicPem, $privatePem, $curve->getSize());
|
||||
if ($res === false) {
|
||||
throw new RuntimeException('Unable to derive the key');
|
||||
}
|
||||
|
||||
return $res;
|
||||
} catch (Throwable) {
|
||||
//Does nothing. Will fallback to the pure PHP function
|
||||
}
|
||||
}
|
||||
$x = $public_key->get('x');
|
||||
if (! is_string($x)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "x"');
|
||||
}
|
||||
$y = $public_key->get('y');
|
||||
if (! is_string($y)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "y"');
|
||||
}
|
||||
$d = $private_key->get('d');
|
||||
if (! is_string($d)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "d"');
|
||||
}
|
||||
|
||||
$rec_x = $this->convertBase64ToBigInteger($x);
|
||||
$rec_y = $this->convertBase64ToBigInteger($y);
|
||||
$sen_d = $this->convertBase64ToBigInteger($d);
|
||||
|
||||
$priv_key = PrivateKey::create($sen_d);
|
||||
$pub_key = $curve->getPublicKeyFrom($rec_x, $rec_y);
|
||||
|
||||
return $this->convertDecToBin(EcDH::computeSharedKey($curve, $pub_key, $priv_key));
|
||||
|
||||
case 'X25519':
|
||||
$this->checkSodiumExtensionIsAvailable();
|
||||
$x = $public_key->get('x');
|
||||
if (! is_string($x)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "x"');
|
||||
}
|
||||
$d = $private_key->get('d');
|
||||
if (! is_string($d)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "d"');
|
||||
}
|
||||
$sKey = Base64UrlSafe::decodeNoPadding($d);
|
||||
$recipientPublickey = Base64UrlSafe::decodeNoPadding($x);
|
||||
|
||||
return sodium_crypto_scalarmult($sKey, $recipientPublickey);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $additional_header_values
|
||||
* @return JWK[]
|
||||
*/
|
||||
protected function getKeysFromPublicKey(
|
||||
JWK $recipient_key,
|
||||
?JWK $senderKey,
|
||||
array &$additional_header_values
|
||||
): array {
|
||||
$this->checkKey($recipient_key, false);
|
||||
$public_key = $recipient_key;
|
||||
|
||||
$crv = $public_key->get('crv');
|
||||
if (! is_string($crv)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "crv"');
|
||||
}
|
||||
$private_key = match ($crv) {
|
||||
'P-256', 'P-384', 'P-521' => $senderKey ?? ECKey::createECKey($crv),
|
||||
'X25519' => $senderKey ?? $this->createOKPKey('X25519'),
|
||||
default => throw new InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv)),
|
||||
};
|
||||
$epk = $private_key->toPublic()
|
||||
->all();
|
||||
$additional_header_values['epk'] = $epk;
|
||||
|
||||
return [$public_key, $private_key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $complete_header
|
||||
* @return JWK[]
|
||||
*/
|
||||
protected function getKeysFromPrivateKeyAndHeader(JWK $recipient_key, array $complete_header): array
|
||||
{
|
||||
$this->checkKey($recipient_key, true);
|
||||
$private_key = $recipient_key;
|
||||
$public_key = $this->getPublicKey($complete_header);
|
||||
if ($private_key->get('crv') !== $public_key->get('crv')) {
|
||||
throw new InvalidArgumentException('Curves are different');
|
||||
}
|
||||
|
||||
return [$public_key, $private_key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $complete_header
|
||||
*/
|
||||
private function getPublicKey(array $complete_header): JWK
|
||||
{
|
||||
if (! isset($complete_header['epk'])) {
|
||||
throw new InvalidArgumentException('The header parameter "epk" is missing.');
|
||||
}
|
||||
if (! is_array($complete_header['epk'])) {
|
||||
throw new InvalidArgumentException('The header parameter "epk" is not an array of parameters');
|
||||
}
|
||||
$public_key = new JWK($complete_header['epk']);
|
||||
$this->checkKey($public_key, false);
|
||||
|
||||
return $public_key;
|
||||
}
|
||||
|
||||
private function checkKey(JWK $key, bool $is_private): void
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
foreach (['x', 'crv'] as $k) {
|
||||
if (! $key->has($k)) {
|
||||
throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k));
|
||||
}
|
||||
}
|
||||
|
||||
$crv = $key->get('crv');
|
||||
if (! is_string($crv)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "crv"');
|
||||
}
|
||||
switch ($crv) {
|
||||
case 'P-256':
|
||||
case 'P-384':
|
||||
case 'P-521':
|
||||
if (! $key->has('y')) {
|
||||
throw new InvalidArgumentException('The key parameter "y" is missing.');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'X25519':
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv));
|
||||
}
|
||||
if ($is_private === true && ! $key->has('d')) {
|
||||
throw new InvalidArgumentException('The key parameter "d" is missing.');
|
||||
}
|
||||
}
|
||||
|
||||
private function getCurve(string $crv): Curve
|
||||
{
|
||||
return match ($crv) {
|
||||
'P-256' => NistCurve::curve256(),
|
||||
'P-384' => NistCurve::curve384(),
|
||||
'P-521' => NistCurve::curve521(),
|
||||
default => throw new InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv)),
|
||||
};
|
||||
}
|
||||
|
||||
private function convertBase64ToBigInteger(string $value): BigInteger
|
||||
{
|
||||
$data = unpack('H*', Base64UrlSafe::decodeNoPadding($value));
|
||||
if (! is_array($data) || ! isset($data[1]) || ! is_string($data[1])) {
|
||||
throw new InvalidArgumentException('Unable to convert base64 to integer');
|
||||
}
|
||||
|
||||
return BigInteger::fromBase($data[1], 16);
|
||||
}
|
||||
|
||||
private function convertDecToBin(BigInteger $dec): string
|
||||
{
|
||||
if ($dec->compareTo(BigInteger::zero()) < 0) {
|
||||
throw new InvalidArgumentException('Unable to convert negative integer to string');
|
||||
}
|
||||
$hex = $dec->toBase(16);
|
||||
|
||||
if (mb_strlen($hex, '8bit') % 2 !== 0) {
|
||||
$hex = '0' . $hex;
|
||||
}
|
||||
|
||||
$bin = hex2bin($hex);
|
||||
if ($bin === false) {
|
||||
throw new InvalidArgumentException('Unable to convert integer to string');
|
||||
}
|
||||
|
||||
return $bin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $curve The curve
|
||||
*/
|
||||
private function createOKPKey(string $curve): JWK
|
||||
{
|
||||
$this->checkSodiumExtensionIsAvailable();
|
||||
|
||||
switch ($curve) {
|
||||
case 'X25519':
|
||||
$keyPair = sodium_crypto_box_keypair();
|
||||
$d = sodium_crypto_box_secretkey($keyPair);
|
||||
$x = sodium_crypto_box_publickey($keyPair);
|
||||
|
||||
break;
|
||||
|
||||
case 'Ed25519':
|
||||
$keyPair = sodium_crypto_sign_keypair();
|
||||
$secret = sodium_crypto_sign_secretkey($keyPair);
|
||||
$secretLength = mb_strlen($secret, '8bit');
|
||||
$d = mb_substr($secret, 0, -$secretLength / 2, '8bit');
|
||||
$x = sodium_crypto_sign_publickey($keyPair);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Unsupported "%s" curve', $curve));
|
||||
}
|
||||
|
||||
return new JWK([
|
||||
'kty' => 'OKP',
|
||||
'crv' => $curve,
|
||||
'x' => Base64UrlSafe::encodeUnpadded($x),
|
||||
'd' => Base64UrlSafe::encodeUnpadded($d),
|
||||
]);
|
||||
}
|
||||
|
||||
private function checkSodiumExtensionIsAvailable(): void
|
||||
{
|
||||
if (! extension_loaded('sodium')) {
|
||||
throw new RuntimeException('The extension "sodium" is not available. Please install it to use this method');
|
||||
}
|
||||
}
|
||||
}
|
||||
32
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDHAESKW.php
vendored
Normal file
32
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDHAESKW.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\Wrapper as WrapperInterface;
|
||||
use RuntimeException;
|
||||
|
||||
abstract class AbstractECDHAESKW implements KeyAgreementWithKeyWrapping
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (! interface_exists(WrapperInterface::class)) {
|
||||
throw new RuntimeException('Please install "spomky-labs/aes-key-wrap" to use AES-KW algorithms');
|
||||
}
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['EC', 'OKP'];
|
||||
}
|
||||
|
||||
public function getKeyManagementMode(): string
|
||||
{
|
||||
return self::MODE_WRAP;
|
||||
}
|
||||
|
||||
abstract protected function getWrapper(): WrapperInterface;
|
||||
|
||||
abstract protected function getKeyLength(): int;
|
||||
}
|
||||
45
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/Dir.php
vendored
Normal file
45
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/Dir.php
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
|
||||
final class Dir implements DirectEncryption
|
||||
{
|
||||
public function getCEK(JWK $key): string
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
if (! $key->has('k')) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is missing.');
|
||||
}
|
||||
$k = $key->get('k');
|
||||
if (! is_string($k)) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is invalid.');
|
||||
}
|
||||
|
||||
return Base64UrlSafe::decodeNoPadding($k);
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'dir';
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['oct'];
|
||||
}
|
||||
|
||||
public function getKeyManagementMode(): string
|
||||
{
|
||||
return self::MODE_DIRECT;
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/DirectEncryption.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/DirectEncryption.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryptionAlgorithm;
|
||||
|
||||
interface DirectEncryption extends KeyEncryptionAlgorithm
|
||||
{
|
||||
/**
|
||||
* Returns the CEK.
|
||||
*
|
||||
* @param JWK $key The key used to get the CEK
|
||||
*/
|
||||
public function getCEK(JWK $key): string;
|
||||
}
|
||||
13
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHES.php
vendored
Normal file
13
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHES.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
final class ECDHES extends AbstractECDH
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ECDH-ES';
|
||||
}
|
||||
}
|
||||
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHESA128KW.php
vendored
Normal file
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHESA128KW.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A128KW as Wrapper;
|
||||
|
||||
final class ECDHESA128KW extends ECDHESAESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ECDH-ES+A128KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getKeyLength(): int
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
}
|
||||
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHESA192KW.php
vendored
Normal file
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHESA192KW.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A192KW as Wrapper;
|
||||
|
||||
final class ECDHESA192KW extends ECDHESAESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ECDH-ES+A192KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getKeyLength(): int
|
||||
{
|
||||
return 192;
|
||||
}
|
||||
}
|
||||
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHESA256KW.php
vendored
Normal file
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHESA256KW.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A256KW as Wrapper;
|
||||
|
||||
final class ECDHESA256KW extends ECDHESAESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ECDH-ES+A256KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getKeyLength(): int
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
}
|
||||
59
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHESAESKW.php
vendored
Normal file
59
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHESAESKW.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
abstract class ECDHESAESKW extends AbstractECDHAESKW
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $complete_header
|
||||
* @param array<string, mixed> $additional_header_values
|
||||
*/
|
||||
public function wrapAgreementKey(
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
string $cek,
|
||||
int $encryption_key_length,
|
||||
array $complete_header,
|
||||
array &$additional_header_values
|
||||
): string {
|
||||
$ecdh_es = new ECDHES();
|
||||
$agreement_key = $ecdh_es->getAgreementKey(
|
||||
$this->getKeyLength(),
|
||||
$this->name(),
|
||||
$recipientKey->toPublic(),
|
||||
$senderKey,
|
||||
$complete_header,
|
||||
$additional_header_values
|
||||
);
|
||||
$wrapper = $this->getWrapper();
|
||||
|
||||
return $wrapper::wrap($agreement_key, $cek);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $complete_header
|
||||
*/
|
||||
public function unwrapAgreementKey(
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
string $encrypted_cek,
|
||||
int $encryption_key_length,
|
||||
array $complete_header
|
||||
): string {
|
||||
$ecdh_es = new ECDHES();
|
||||
$agreement_key = $ecdh_es->getAgreementKey(
|
||||
$this->getKeyLength(),
|
||||
$this->name(),
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$complete_header
|
||||
);
|
||||
$wrapper = $this->getWrapper();
|
||||
|
||||
return $wrapper::unwrap($agreement_key, $encrypted_cek);
|
||||
}
|
||||
}
|
||||
44
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSS.php
vendored
Normal file
44
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSS.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
use LogicException;
|
||||
|
||||
final class ECDHSS extends AbstractECDH
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ECDH-SS';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $complete_header
|
||||
* @param array<string, mixed> $additional_header_values
|
||||
*/
|
||||
public function getAgreementKey(
|
||||
int $encryptionKeyLength,
|
||||
string $algorithm,
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
array $complete_header = [],
|
||||
array &$additional_header_values = []
|
||||
): string {
|
||||
if ($senderKey === null) {
|
||||
throw new LogicException('The sender key shall be set');
|
||||
}
|
||||
$agreedKey = parent::getAgreementKey(
|
||||
$encryptionKeyLength,
|
||||
$algorithm,
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$complete_header,
|
||||
$additional_header_values
|
||||
);
|
||||
unset($additional_header_values['epk']);
|
||||
|
||||
return $agreedKey;
|
||||
}
|
||||
}
|
||||
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA128KW.php
vendored
Normal file
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA128KW.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A128KW as Wrapper;
|
||||
|
||||
final class ECDHSSA128KW extends ECDHSSAESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ECDH-SS+A128KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getKeyLength(): int
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
}
|
||||
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA192KW.php
vendored
Normal file
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA192KW.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A192KW as Wrapper;
|
||||
|
||||
final class ECDHSSA192KW extends ECDHSSAESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ECDH-SS+A192KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getKeyLength(): int
|
||||
{
|
||||
return 192;
|
||||
}
|
||||
}
|
||||
28
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA256KW.php
vendored
Normal file
28
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA256KW.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A256KW as Wrapper;
|
||||
|
||||
final class ECDHSSA256KW extends ECDHSSAESKW
|
||||
{
|
||||
/**
|
||||
* NOTE: the return name was modified
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return 'ECDH-SS+A256KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getKeyLength(): int
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
}
|
||||
59
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSAESKW.php
vendored
Normal file
59
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSAESKW.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
abstract class ECDHSSAESKW extends AbstractECDHAESKW
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $complete_header
|
||||
* @param array<string, mixed> $additional_header_values
|
||||
*/
|
||||
public function wrapAgreementKey(
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
string $cek,
|
||||
int $encryption_key_length,
|
||||
array $complete_header,
|
||||
array &$additional_header_values
|
||||
): string {
|
||||
$ecdh_ss = new ECDHSS();
|
||||
$agreement_key = $ecdh_ss->getAgreementKey(
|
||||
$this->getKeyLength(),
|
||||
$this->name(),
|
||||
$recipientKey->toPublic(),
|
||||
$senderKey,
|
||||
$complete_header,
|
||||
$additional_header_values
|
||||
);
|
||||
$wrapper = $this->getWrapper();
|
||||
|
||||
return $wrapper::wrap($agreement_key, $cek);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $complete_header
|
||||
*/
|
||||
public function unwrapAgreementKey(
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
string $encrypted_cek,
|
||||
int $encryption_key_length,
|
||||
array $complete_header
|
||||
): string {
|
||||
$ecdh_ss = new ECDHSS();
|
||||
$agreement_key = $ecdh_ss->getAgreementKey(
|
||||
$this->getKeyLength(),
|
||||
$this->name(),
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$complete_header
|
||||
);
|
||||
$wrapper = $this->getWrapper();
|
||||
|
||||
return $wrapper::unwrap($agreement_key, $encrypted_cek);
|
||||
}
|
||||
}
|
||||
26
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyAgreement.php
vendored
Normal file
26
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyAgreement.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryptionAlgorithm;
|
||||
|
||||
interface KeyAgreement extends KeyEncryptionAlgorithm
|
||||
{
|
||||
/**
|
||||
* Computes the agreement key.
|
||||
*
|
||||
* @param array<string, mixed> $completeHeader
|
||||
* @param array<string, mixed> $additionalHeaderValues
|
||||
*/
|
||||
public function getAgreementKey(
|
||||
int $encryptionKeyLength,
|
||||
string $algorithm,
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
array $completeHeader = [],
|
||||
array &$additionalHeaderValues = []
|
||||
): string;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryptionAlgorithm;
|
||||
|
||||
interface KeyAgreementWithKeyWrapping extends KeyEncryptionAlgorithm
|
||||
{
|
||||
/**
|
||||
* Compute and wrap the agreement key.
|
||||
*
|
||||
* @param JWK $recipientKey The receiver's key
|
||||
* @param string $cek The CEK to wrap
|
||||
* @param int $encryption_key_length Size of the key expected for the algorithm used for data encryption
|
||||
* @param array<string, mixed> $complete_header The complete header of the JWT
|
||||
* @param array<string, mixed> $additional_header_values Set additional header values if needed
|
||||
*/
|
||||
public function wrapAgreementKey(
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
string $cek,
|
||||
int $encryption_key_length,
|
||||
array $complete_header,
|
||||
array &$additional_header_values
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Unwrap and compute the agreement key.
|
||||
*
|
||||
* @param JWK $recipientKey The receiver's key
|
||||
* @param string $encrypted_cek The encrypted CEK
|
||||
* @param int $encryption_key_length Size of the key expected for the algorithm used for data encryption
|
||||
* @param array<string, mixed> $complete_header The complete header of the JWT
|
||||
*
|
||||
* @return string The decrypted CEK
|
||||
*/
|
||||
public function unwrapAgreementKey(
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
string $encrypted_cek,
|
||||
int $encryption_key_length,
|
||||
array $complete_header
|
||||
): string;
|
||||
}
|
||||
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyEncryption.php
vendored
Normal file
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyEncryption.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryptionAlgorithm;
|
||||
|
||||
interface KeyEncryption extends KeyEncryptionAlgorithm
|
||||
{
|
||||
/**
|
||||
* Encrypt the CEK.
|
||||
*
|
||||
* @param JWK $key The key used to wrap the CEK
|
||||
* @param string $cek The CEK to encrypt
|
||||
* @param array<string, mixed> $completeHeader The complete header of the JWT
|
||||
* @param array<string, mixed> $additionalHeader Additional header
|
||||
*/
|
||||
public function encryptKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string;
|
||||
|
||||
/**
|
||||
* Decrypt de CEK.
|
||||
*
|
||||
* @param JWK $key The key used to wrap the CEK
|
||||
* @param string $encrypted_cek The CEK to decrypt
|
||||
* @param array<string, mixed> $header The complete header of the JWT
|
||||
*/
|
||||
public function decryptKey(JWK $key, string $encrypted_cek, array $header): string;
|
||||
}
|
||||
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyWrapping.php
vendored
Normal file
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyWrapping.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryptionAlgorithm;
|
||||
|
||||
interface KeyWrapping extends KeyEncryptionAlgorithm
|
||||
{
|
||||
/**
|
||||
* Encrypt the CEK.
|
||||
*
|
||||
* @param JWK $key The key used to wrap the CEK
|
||||
* @param string $cek The CEK to encrypt
|
||||
* @param array<string, mixed> $completeHeader The complete header of the JWT
|
||||
* @param array<string, mixed> $additionalHeader The complete header of the JWT
|
||||
*/
|
||||
public function wrapKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string;
|
||||
|
||||
/**
|
||||
* Decrypt de CEK.
|
||||
*
|
||||
* @param JWK $key The key used to wrap the CEK
|
||||
* @param string $encrypted_cek The CEK to decrypt
|
||||
* @param array<string, mixed> $completeHeader The complete header of the JWT
|
||||
*/
|
||||
public function unwrapKey(JWK $key, string $encrypted_cek, array $completeHeader): string;
|
||||
}
|
||||
144
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2AESKW.php
vendored
Normal file
144
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2AESKW.php
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A128KW;
|
||||
use AESKW\A192KW;
|
||||
use AESKW\A256KW;
|
||||
use AESKW\Wrapper as WrapperInterface;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use RuntimeException;
|
||||
use function in_array;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
|
||||
abstract class PBES2AESKW implements KeyWrapping
|
||||
{
|
||||
public function __construct(
|
||||
private readonly int $salt_size = 64,
|
||||
private readonly int $nb_count = 4096
|
||||
) {
|
||||
if (! interface_exists(WrapperInterface::class)) {
|
||||
throw new RuntimeException('Please install "spomky-labs/aes-key-wrap" to use AES-KW algorithms');
|
||||
}
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['oct'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $completeHeader
|
||||
* @param array<string, mixed> $additionalHeader
|
||||
*/
|
||||
public function wrapKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string
|
||||
{
|
||||
$password = $this->getKey($key);
|
||||
$this->checkHeaderAlgorithm($completeHeader);
|
||||
$wrapper = $this->getWrapper();
|
||||
$hash_algorithm = $this->getHashAlgorithm();
|
||||
$key_size = $this->getKeySize();
|
||||
$salt = random_bytes($this->salt_size);
|
||||
|
||||
// We set header parameters
|
||||
$additionalHeader['p2s'] = Base64UrlSafe::encodeUnpadded($salt);
|
||||
$additionalHeader['p2c'] = $this->nb_count;
|
||||
|
||||
$derived_key = hash_pbkdf2(
|
||||
$hash_algorithm,
|
||||
$password,
|
||||
$completeHeader['alg'] . "\x00" . $salt,
|
||||
$this->nb_count,
|
||||
$key_size,
|
||||
true
|
||||
);
|
||||
|
||||
return $wrapper::wrap($derived_key, $cek);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $completeHeader
|
||||
*/
|
||||
public function unwrapKey(JWK $key, string $encrypted_cek, array $completeHeader): string
|
||||
{
|
||||
$password = $this->getKey($key);
|
||||
$this->checkHeaderAlgorithm($completeHeader);
|
||||
$this->checkHeaderAdditionalParameters($completeHeader);
|
||||
$wrapper = $this->getWrapper();
|
||||
$hash_algorithm = $this->getHashAlgorithm();
|
||||
$key_size = $this->getKeySize();
|
||||
$p2s = $completeHeader['p2s'];
|
||||
is_string($p2s) || throw new InvalidArgumentException('Invalid salt.');
|
||||
$salt = $completeHeader['alg'] . "\x00" . Base64UrlSafe::decodeNoPadding($p2s);
|
||||
$count = $completeHeader['p2c'];
|
||||
is_int($count) || throw new InvalidArgumentException('Invalid counter.');
|
||||
|
||||
$derived_key = hash_pbkdf2($hash_algorithm, $password, $salt, $count, $key_size, true);
|
||||
|
||||
return $wrapper::unwrap($derived_key, $encrypted_cek);
|
||||
}
|
||||
|
||||
public function getKeyManagementMode(): string
|
||||
{
|
||||
return self::MODE_WRAP;
|
||||
}
|
||||
|
||||
protected function getKey(JWK $key): string
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
if (! $key->has('k')) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is missing.');
|
||||
}
|
||||
$k = $key->get('k');
|
||||
if (! is_string($k)) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is invalid.');
|
||||
}
|
||||
|
||||
return Base64UrlSafe::decodeNoPadding($k);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $header
|
||||
*/
|
||||
protected function checkHeaderAlgorithm(array $header): void
|
||||
{
|
||||
if (! isset($header['alg'])) {
|
||||
throw new InvalidArgumentException('The header parameter "alg" is missing.');
|
||||
}
|
||||
if (! is_string($header['alg'])) {
|
||||
throw new InvalidArgumentException('The header parameter "alg" is not valid.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $header
|
||||
*/
|
||||
protected function checkHeaderAdditionalParameters(array $header): void
|
||||
{
|
||||
if (! isset($header['p2s'])) {
|
||||
throw new InvalidArgumentException('The header parameter "p2s" is missing.');
|
||||
}
|
||||
if (! is_string($header['p2s'])) {
|
||||
throw new InvalidArgumentException('The header parameter "p2s" is not valid.');
|
||||
}
|
||||
if (! isset($header['p2c'])) {
|
||||
throw new InvalidArgumentException('The header parameter "p2c" is missing.');
|
||||
}
|
||||
if (! is_int($header['p2c']) || $header['p2c'] <= 0) {
|
||||
throw new InvalidArgumentException('The header parameter "p2c" is not valid.');
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function getWrapper(): A256KW|A128KW|A192KW;
|
||||
|
||||
abstract protected function getHashAlgorithm(): string;
|
||||
|
||||
abstract protected function getKeySize(): int;
|
||||
}
|
||||
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS256A128KW.php
vendored
Normal file
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS256A128KW.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A128KW as Wrapper;
|
||||
|
||||
final class PBES2HS256A128KW extends PBES2AESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'PBES2-HS256+A128KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
|
||||
protected function getKeySize(): int
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS384A192KW.php
vendored
Normal file
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS384A192KW.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A192KW as Wrapper;
|
||||
|
||||
final class PBES2HS384A192KW extends PBES2AESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'PBES2-HS384+A192KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha384';
|
||||
}
|
||||
|
||||
protected function getKeySize(): int
|
||||
{
|
||||
return 24;
|
||||
}
|
||||
}
|
||||
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS512A256KW.php
vendored
Normal file
30
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS512A256KW.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use AESKW\A256KW as Wrapper;
|
||||
|
||||
final class PBES2HS512A256KW extends PBES2AESKW
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'PBES2-HS512+A256KW';
|
||||
}
|
||||
|
||||
protected function getWrapper(): Wrapper
|
||||
{
|
||||
return new Wrapper();
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha512';
|
||||
}
|
||||
|
||||
protected function getKeySize(): int
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
61
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSA.php
vendored
Normal file
61
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSA.php
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\RSAKey;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\Util\RSACrypt;
|
||||
use function in_array;
|
||||
|
||||
abstract class RSA implements KeyEncryption
|
||||
{
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['RSA'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $completeHeader
|
||||
* @param array<string, mixed> $additionalHeader
|
||||
*/
|
||||
public function encryptKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string
|
||||
{
|
||||
$this->checkKey($key);
|
||||
$pub = RSAKey::toPublic(RSAKey::createFromJWK($key));
|
||||
|
||||
return RSACrypt::encrypt($pub, $cek, $this->getEncryptionMode(), $this->getHashAlgorithm());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $header
|
||||
*/
|
||||
public function decryptKey(JWK $key, string $encrypted_cek, array $header): string
|
||||
{
|
||||
$this->checkKey($key);
|
||||
if (! $key->has('d')) {
|
||||
throw new InvalidArgumentException('The key is not a private key');
|
||||
}
|
||||
$priv = RSAKey::createFromJWK($key);
|
||||
|
||||
return RSACrypt::decrypt($priv, $encrypted_cek, $this->getEncryptionMode(), $this->getHashAlgorithm());
|
||||
}
|
||||
|
||||
public function getKeyManagementMode(): string
|
||||
{
|
||||
return self::MODE_ENCRYPT;
|
||||
}
|
||||
|
||||
protected function checkKey(JWK $key): void
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function getEncryptionMode(): int;
|
||||
|
||||
abstract protected function getHashAlgorithm(): ?string;
|
||||
}
|
||||
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSA15.php
vendored
Normal file
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSA15.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\Util\RSACrypt;
|
||||
|
||||
final class RSA15 extends RSA
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'RSA1_5';
|
||||
}
|
||||
|
||||
protected function getEncryptionMode(): int
|
||||
{
|
||||
return RSACrypt::ENCRYPTION_PKCS1;
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSAOAEP.php
vendored
Normal file
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSAOAEP.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\Util\RSACrypt;
|
||||
|
||||
final class RSAOAEP extends RSA
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'RSA-OAEP';
|
||||
}
|
||||
|
||||
protected function getEncryptionMode(): int
|
||||
{
|
||||
return RSACrypt::ENCRYPTION_OAEP;
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha1';
|
||||
}
|
||||
}
|
||||
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSAOAEP256.php
vendored
Normal file
25
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSAOAEP256.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption;
|
||||
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\Util\RSACrypt;
|
||||
|
||||
final class RSAOAEP256 extends RSA
|
||||
{
|
||||
public function getEncryptionMode(): int
|
||||
{
|
||||
return RSACrypt::ENCRYPTION_OAEP;
|
||||
}
|
||||
|
||||
public function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'RSA-OAEP-256';
|
||||
}
|
||||
}
|
||||
71
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/Util/ConcatKDF.php
vendored
Normal file
71
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/Util/ConcatKDF.php
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption\Util;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use const STR_PAD_LEFT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc7518#section-4.6.2
|
||||
*/
|
||||
final class ConcatKDF
|
||||
{
|
||||
/**
|
||||
* Key Derivation Function.
|
||||
*
|
||||
* @param string $Z Shared secret
|
||||
* @param string $algorithm Encryption algorithm
|
||||
* @param int $encryption_key_size Size of the encryption key
|
||||
* @param string $apu Agreement PartyUInfo (information about the producer)
|
||||
* @param string $apv Agreement PartyVInfo (information about the recipient)
|
||||
*/
|
||||
public static function generate(
|
||||
string $Z,
|
||||
string $algorithm,
|
||||
int $encryption_key_size,
|
||||
string $apu = '',
|
||||
string $apv = ''
|
||||
): string {
|
||||
$apu = ! self::isEmpty($apu) ? Base64UrlSafe::decodeNoPadding($apu) : '';
|
||||
$apv = ! self::isEmpty($apv) ? Base64UrlSafe::decodeNoPadding($apv) : '';
|
||||
$encryption_segments = [
|
||||
self::toInt32Bits(1), // Round number 1
|
||||
$Z, // Z (shared secret)
|
||||
self::toInt32Bits(mb_strlen($algorithm, '8bit')) . $algorithm, // Size of algorithm's name and algorithm
|
||||
self::toInt32Bits(mb_strlen($apu, '8bit')) . $apu, // PartyUInfo
|
||||
self::toInt32Bits(mb_strlen($apv, '8bit')) . $apv, // PartyVInfo
|
||||
self::toInt32Bits($encryption_key_size), // SuppPubInfo (the encryption key size)
|
||||
'', // SuppPrivInfo
|
||||
];
|
||||
|
||||
$input = implode('', $encryption_segments);
|
||||
$hash = hash('sha256', $input, true);
|
||||
|
||||
return mb_substr($hash, 0, $encryption_key_size / 8, '8bit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an integer into a 32 bits string.
|
||||
*
|
||||
* @param int $value Integer to convert
|
||||
*/
|
||||
private static function toInt32Bits(int $value): string
|
||||
{
|
||||
$result = hex2bin(str_pad(dechex($value), 8, '0', STR_PAD_LEFT));
|
||||
if ($result === false) {
|
||||
throw new InvalidArgumentException('Invalid result');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function isEmpty(?string $value): bool
|
||||
{
|
||||
return $value === null || $value === '';
|
||||
}
|
||||
}
|
||||
259
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/Util/RSACrypt.php
vendored
Normal file
259
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/Util/RSACrypt.php
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm\KeyEncryption\Util;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\Util\BigInteger;
|
||||
use Jose\Component\Core\Util\Hash;
|
||||
use Jose\Component\Core\Util\RSAKey;
|
||||
use LogicException;
|
||||
use RuntimeException;
|
||||
use function chr;
|
||||
use function count;
|
||||
use function ord;
|
||||
use const STR_PAD_LEFT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class RSACrypt
|
||||
{
|
||||
/**
|
||||
* Optimal Asymmetric Encryption Padding (OAEP).
|
||||
*/
|
||||
public const ENCRYPTION_OAEP = 1;
|
||||
|
||||
/**
|
||||
* Use PKCS#1 padding.
|
||||
*/
|
||||
public const ENCRYPTION_PKCS1 = 2;
|
||||
|
||||
public static function encrypt(RSAKey $key, string $data, int $mode, ?string $hash = null): string
|
||||
{
|
||||
switch ($mode) {
|
||||
case self::ENCRYPTION_OAEP:
|
||||
if ($hash === null) {
|
||||
throw new LogicException('Hash shall be defined for RSA OAEP cyphering');
|
||||
}
|
||||
|
||||
return self::encryptWithRSAOAEP($key, $data, $hash);
|
||||
case self::ENCRYPTION_PKCS1:
|
||||
return self::encryptWithRSA15($key, $data);
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported mode.');
|
||||
}
|
||||
}
|
||||
|
||||
public static function decrypt(RSAKey $key, string $plaintext, int $mode, ?string $hash = null): string
|
||||
{
|
||||
switch ($mode) {
|
||||
case self::ENCRYPTION_OAEP:
|
||||
if ($hash === null) {
|
||||
throw new LogicException('Hash shall be defined for RSA OAEP cyphering');
|
||||
}
|
||||
|
||||
return self::decryptWithRSAOAEP($key, $plaintext, $hash);
|
||||
case self::ENCRYPTION_PKCS1:
|
||||
return self::decryptWithRSA15($key, $plaintext);
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported mode.');
|
||||
}
|
||||
}
|
||||
|
||||
public static function encryptWithRSA15(RSAKey $key, string $data): string
|
||||
{
|
||||
$mLen = mb_strlen($data, '8bit');
|
||||
if ($mLen > $key->getModulusLength() - 11) {
|
||||
throw new InvalidArgumentException('Message too long');
|
||||
}
|
||||
|
||||
$psLen = $key->getModulusLength() - $mLen - 3;
|
||||
$ps = '';
|
||||
while (mb_strlen($ps, '8bit') !== $psLen) {
|
||||
$temp = random_bytes($psLen - mb_strlen($ps, '8bit'));
|
||||
$temp = str_replace("\x00", '', $temp);
|
||||
$ps .= $temp;
|
||||
}
|
||||
$type = 2;
|
||||
$data = chr(0) . chr($type) . $ps . chr(0) . $data;
|
||||
|
||||
$binaryData = BigInteger::createFromBinaryString($data);
|
||||
$c = self::getRSAEP($key, $binaryData);
|
||||
|
||||
return self::convertIntegerToOctetString($c, $key->getModulusLength());
|
||||
}
|
||||
|
||||
public static function decryptWithRSA15(RSAKey $key, string $c): string
|
||||
{
|
||||
if (mb_strlen($c, '8bit') !== $key->getModulusLength()) {
|
||||
throw new InvalidArgumentException('Unable to decrypt');
|
||||
}
|
||||
$c = BigInteger::createFromBinaryString($c);
|
||||
$m = self::getRSADP($key, $c);
|
||||
$em = self::convertIntegerToOctetString($m, $key->getModulusLength());
|
||||
if (ord($em[0]) !== 0 || ord($em[1]) > 2) {
|
||||
throw new InvalidArgumentException('Unable to decrypt');
|
||||
}
|
||||
$ps = mb_substr($em, 2, (int) mb_strpos($em, chr(0), 2, '8bit') - 2, '8bit');
|
||||
$m = mb_substr($em, mb_strlen($ps, '8bit') + 3, null, '8bit');
|
||||
if (mb_strlen($ps, '8bit') < 8) {
|
||||
throw new InvalidArgumentException('Unable to decrypt');
|
||||
}
|
||||
|
||||
return $m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encryption.
|
||||
*/
|
||||
public static function encryptWithRSAOAEP(RSAKey $key, string $plaintext, string $hash_algorithm): string
|
||||
{
|
||||
/** @var Hash $hash */
|
||||
$hash = Hash::$hash_algorithm();
|
||||
$length = $key->getModulusLength() - 2 * $hash->getLength() - 2;
|
||||
if ($length <= 0) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
$splitPlaintext = mb_str_split($plaintext, $length, '8bit');
|
||||
$ciphertext = '';
|
||||
foreach ($splitPlaintext as $m) {
|
||||
$ciphertext .= self::encryptRSAESOAEP($key, $m, $hash);
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decryption.
|
||||
*/
|
||||
public static function decryptWithRSAOAEP(RSAKey $key, string $ciphertext, string $hash_algorithm): string
|
||||
{
|
||||
if ($key->getModulusLength() <= 0) {
|
||||
throw new RuntimeException('Invalid modulus length');
|
||||
}
|
||||
$hash = Hash::$hash_algorithm();
|
||||
$splitCiphertext = mb_str_split($ciphertext, $key->getModulusLength(), '8bit');
|
||||
$splitCiphertext[count($splitCiphertext) - 1] = str_pad(
|
||||
$splitCiphertext[count($splitCiphertext) - 1],
|
||||
$key->getModulusLength(),
|
||||
chr(0),
|
||||
STR_PAD_LEFT
|
||||
);
|
||||
$plaintext = '';
|
||||
foreach ($splitCiphertext as $c) {
|
||||
$temp = self::getRSAESOAEP($key, $c, $hash);
|
||||
$plaintext .= $temp;
|
||||
}
|
||||
|
||||
return $plaintext;
|
||||
}
|
||||
|
||||
private static function convertIntegerToOctetString(BigInteger $x, int $xLen): string
|
||||
{
|
||||
$x = $x->toBytes();
|
||||
if (mb_strlen($x, '8bit') > $xLen) {
|
||||
throw new RuntimeException('Invalid length.');
|
||||
}
|
||||
|
||||
return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Octet-String-to-Integer primitive.
|
||||
*/
|
||||
private static function convertOctetStringToInteger(string $x): BigInteger
|
||||
{
|
||||
return BigInteger::createFromBinaryString($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA EP.
|
||||
*/
|
||||
private static function getRSAEP(RSAKey $key, BigInteger $m): BigInteger
|
||||
{
|
||||
if ($m->compare(BigInteger::createFromDecimal(0)) < 0 || $m->compare($key->getModulus()) > 0) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
return RSAKey::exponentiate($key, $m);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA DP.
|
||||
*/
|
||||
private static function getRSADP(RSAKey $key, BigInteger $c): BigInteger
|
||||
{
|
||||
if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare($key->getModulus()) > 0) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
return RSAKey::exponentiate($key, $c);
|
||||
}
|
||||
|
||||
/**
|
||||
* MGF1.
|
||||
*/
|
||||
private static function getMGF1(string $mgfSeed, int $maskLen, Hash $mgfHash): string
|
||||
{
|
||||
$t = '';
|
||||
$count = ceil($maskLen / $mgfHash->getLength());
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$c = pack('N', $i);
|
||||
$t .= $mgfHash->hash($mgfSeed . $c);
|
||||
}
|
||||
|
||||
return mb_substr($t, 0, $maskLen, '8bit');
|
||||
}
|
||||
|
||||
/**
|
||||
* RSAES-OAEP-ENCRYPT.
|
||||
*/
|
||||
private static function encryptRSAESOAEP(RSAKey $key, string $m, Hash $hash): string
|
||||
{
|
||||
$mLen = mb_strlen($m, '8bit');
|
||||
$lHash = $hash->hash('');
|
||||
$ps = str_repeat(chr(0), $key->getModulusLength() - $mLen - 2 * $hash->getLength() - 2);
|
||||
$db = $lHash . $ps . chr(1) . $m;
|
||||
$seed = random_bytes($hash->getLength());
|
||||
$dbMask = self::getMGF1($seed, $key->getModulusLength() - $hash->getLength() - 1, $hash/*MGF*/);
|
||||
$maskedDB = $db ^ $dbMask;
|
||||
$seedMask = self::getMGF1($maskedDB, $hash->getLength(), $hash/*MGF*/);
|
||||
$maskedSeed = $seed ^ $seedMask;
|
||||
$em = chr(0) . $maskedSeed . $maskedDB;
|
||||
|
||||
$m = self::convertOctetStringToInteger($em);
|
||||
$c = self::getRSAEP($key, $m);
|
||||
|
||||
return self::convertIntegerToOctetString($c, $key->getModulusLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* RSAES-OAEP-DECRYPT.
|
||||
*/
|
||||
private static function getRSAESOAEP(RSAKey $key, string $c, Hash $hash): string
|
||||
{
|
||||
$c = self::convertOctetStringToInteger($c);
|
||||
$m = self::getRSADP($key, $c);
|
||||
$em = self::convertIntegerToOctetString($m, $key->getModulusLength());
|
||||
$lHash = $hash->hash('');
|
||||
$maskedSeed = mb_substr($em, 1, $hash->getLength(), '8bit');
|
||||
$maskedDB = mb_substr($em, $hash->getLength() + 1, null, '8bit');
|
||||
$seedMask = self::getMGF1($maskedDB, $hash->getLength(), $hash/*MGF*/);
|
||||
$seed = $maskedSeed ^ $seedMask;
|
||||
$dbMask = self::getMGF1($seed, $key->getModulusLength() - $hash->getLength() - 1, $hash/*MGF*/);
|
||||
$db = $maskedDB ^ $dbMask;
|
||||
$lHash2 = mb_substr($db, 0, $hash->getLength(), '8bit');
|
||||
$m = mb_substr($db, $hash->getLength(), null, '8bit');
|
||||
if (! hash_equals($lHash, $lHash2)) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
$m = ltrim($m, chr(0));
|
||||
if (ord($m[0]) !== 1) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
return mb_substr($m, 1, null, '8bit');
|
||||
}
|
||||
}
|
||||
23
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryptionAlgorithm.php
vendored
Normal file
23
libraries/vendor/web-token/jwt-library/Encryption/Algorithm/KeyEncryptionAlgorithm.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Algorithm;
|
||||
|
||||
use Jose\Component\Core\Algorithm;
|
||||
|
||||
interface KeyEncryptionAlgorithm extends Algorithm
|
||||
{
|
||||
public const MODE_DIRECT = 'dir';
|
||||
|
||||
public const MODE_ENCRYPT = 'enc';
|
||||
|
||||
public const MODE_WRAP = 'wrap';
|
||||
|
||||
public const MODE_AGREEMENT = 'agree';
|
||||
|
||||
/**
|
||||
* Returns the key management mode used by the key encryption algorithm.
|
||||
*/
|
||||
public function getKeyManagementMode(): string;
|
||||
}
|
||||
30
libraries/vendor/web-token/jwt-library/Encryption/Compression/CompressionMethod.php
vendored
Normal file
30
libraries/vendor/web-token/jwt-library/Encryption/Compression/CompressionMethod.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Compression;
|
||||
|
||||
/**
|
||||
* @deprecated This class is deprecated and will be removed in v4.0. Compression is not recommended for JWE.
|
||||
*/
|
||||
interface CompressionMethod
|
||||
{
|
||||
/**
|
||||
* Returns the name of the method.
|
||||
*/
|
||||
public function name(): string;
|
||||
|
||||
/**
|
||||
* Compress the data. Throws an exception in case of failure.
|
||||
*
|
||||
* @param string $data The data to compress
|
||||
*/
|
||||
public function compress(string $data): string;
|
||||
|
||||
/**
|
||||
* Uncompress the data. Throws an exception in case of failure.
|
||||
*
|
||||
* @param string $data The data to uncompress
|
||||
*/
|
||||
public function uncompress(string $data): string;
|
||||
}
|
||||
71
libraries/vendor/web-token/jwt-library/Encryption/Compression/CompressionMethodManager.php
vendored
Normal file
71
libraries/vendor/web-token/jwt-library/Encryption/Compression/CompressionMethodManager.php
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Compression;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* @deprecated This class is deprecated and will be removed in v4.0. Compression is not recommended for JWE.
|
||||
*/
|
||||
class CompressionMethodManager
|
||||
{
|
||||
/**
|
||||
* @var CompressionMethod[]
|
||||
*/
|
||||
private array $compressionMethods = [];
|
||||
|
||||
/**
|
||||
* @param CompressionMethod[] $methods
|
||||
*/
|
||||
public function __construct(iterable $methods = [])
|
||||
{
|
||||
foreach ($methods as $method) {
|
||||
$this->add($method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the givn compression method is supported.
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return array_key_exists($name, $this->compressionMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the compression method with the given name. Throws an exception if the method is not
|
||||
* supported.
|
||||
*
|
||||
* @param string $name The name of the compression method
|
||||
*/
|
||||
public function get(string $name): CompressionMethod
|
||||
{
|
||||
if (! $this->has($name)) {
|
||||
throw new InvalidArgumentException(sprintf('The compression method "%s" is not supported.', $name));
|
||||
}
|
||||
|
||||
return $this->compressionMethods[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of compression method names supported by the manager.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function list(): array
|
||||
{
|
||||
return array_keys($this->compressionMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given compression method to the manager.
|
||||
*/
|
||||
protected function add(CompressionMethod $compressionMethod): void
|
||||
{
|
||||
$name = $compressionMethod->name();
|
||||
$this->compressionMethods[$name] = $compressionMethod;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Compression;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @deprecated This class is deprecated and will be removed in v4.0. Compression is not recommended for JWE.
|
||||
*/
|
||||
class CompressionMethodManagerFactory
|
||||
{
|
||||
/**
|
||||
* @var CompressionMethod[]
|
||||
*/
|
||||
private array $compressionMethods = [];
|
||||
|
||||
/**
|
||||
* This method adds a compression method to this factory. The method is uniquely identified by an alias. This allows
|
||||
* the same method to be added twice (or more) using several configuration options.
|
||||
*/
|
||||
public function add(string $alias, CompressionMethod $compressionMethod): void
|
||||
{
|
||||
$this->compressionMethods[$alias] = $compressionMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of compression method aliases supported by the factory.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function aliases(): array
|
||||
{
|
||||
return array_keys($this->compressionMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all compression methods supported by this factory.
|
||||
*
|
||||
* @return CompressionMethod[]
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->compressionMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a compression method manager using the compression methods identified by the given aliases. If one of the
|
||||
* aliases does not exist, an exception is thrown.
|
||||
*
|
||||
* @param string[] $aliases
|
||||
*/
|
||||
public function create(array $aliases): CompressionMethodManager
|
||||
{
|
||||
$compressionMethods = [];
|
||||
foreach ($aliases as $alias) {
|
||||
if (! isset($this->compressionMethods[$alias])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The compression method with the alias "%s" is not supported.',
|
||||
$alias
|
||||
));
|
||||
}
|
||||
$compressionMethods[] = $this->compressionMethods[$alias];
|
||||
}
|
||||
|
||||
return new CompressionMethodManager($compressionMethods);
|
||||
}
|
||||
}
|
||||
65
libraries/vendor/web-token/jwt-library/Encryption/Compression/Deflate.php
vendored
Normal file
65
libraries/vendor/web-token/jwt-library/Encryption/Compression/Deflate.php
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Compression;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
use function is_string;
|
||||
|
||||
/**
|
||||
* @deprecated This class is deprecated and will be removed in v4.0. Compression is not recommended for JWE.
|
||||
*/
|
||||
final class Deflate implements CompressionMethod
|
||||
{
|
||||
private int $compressionLevel = -1;
|
||||
|
||||
public function __construct(int $compressionLevel = -1)
|
||||
{
|
||||
if ($compressionLevel < -1 || $compressionLevel > 9) {
|
||||
throw new InvalidArgumentException(
|
||||
'The compression level can be given as 0 for no compression up to 9 for maximum compression. If -1 given, the default compression level will be the default compression level of the zlib library.'
|
||||
);
|
||||
}
|
||||
$this->compressionLevel = $compressionLevel;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'DEF';
|
||||
}
|
||||
|
||||
public function compress(string $data): string
|
||||
{
|
||||
try {
|
||||
$bin = gzdeflate($data, $this->getCompressionLevel());
|
||||
if (! is_string($bin)) {
|
||||
throw new InvalidArgumentException('Unable to encode the data');
|
||||
}
|
||||
|
||||
return $bin;
|
||||
} catch (Throwable $throwable) {
|
||||
throw new InvalidArgumentException('Unable to compress data.', $throwable->getCode(), $throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public function uncompress(string $data): string
|
||||
{
|
||||
try {
|
||||
$bin = gzinflate($data);
|
||||
if (! is_string($bin)) {
|
||||
throw new InvalidArgumentException('Unable to encode the data');
|
||||
}
|
||||
|
||||
return $bin;
|
||||
} catch (Throwable $throwable) {
|
||||
throw new InvalidArgumentException('Unable to uncompress data.', $throwable->getCode(), $throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private function getCompressionLevel(): int
|
||||
{
|
||||
return $this->compressionLevel;
|
||||
}
|
||||
}
|
||||
218
libraries/vendor/web-token/jwt-library/Encryption/JWE.php
vendored
Normal file
218
libraries/vendor/web-token/jwt-library/Encryption/JWE.php
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWT;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
|
||||
class JWE implements JWT
|
||||
{
|
||||
private ?string $payload = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly ?string $ciphertext,
|
||||
private readonly string $iv,
|
||||
private readonly string $tag,
|
||||
private readonly ?string $aad = null,
|
||||
private readonly array $sharedHeader = [],
|
||||
private readonly array $sharedProtectedHeader = [],
|
||||
private readonly ?string $encodedSharedProtectedHeader = null,
|
||||
private readonly array $recipients = []
|
||||
) {
|
||||
}
|
||||
|
||||
public function getPayload(): ?string
|
||||
{
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the payload. This method is immutable and a new object will be returned.
|
||||
*/
|
||||
public function withPayload(string $payload): self
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->payload = $payload;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of recipients associated with the JWS.
|
||||
*/
|
||||
public function countRecipients(): int
|
||||
{
|
||||
return count($this->recipients);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true is the JWE has already been encrypted.
|
||||
*/
|
||||
public function isEncrypted(): bool
|
||||
{
|
||||
return $this->getCiphertext() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recipients associated with the JWS.
|
||||
*
|
||||
* @return Recipient[]
|
||||
*/
|
||||
public function getRecipients(): array
|
||||
{
|
||||
return $this->recipients;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recipient object at the given index.
|
||||
*/
|
||||
public function getRecipient(int $id): Recipient
|
||||
{
|
||||
if (! isset($this->recipients[$id])) {
|
||||
throw new InvalidArgumentException('The recipient does not exist.');
|
||||
}
|
||||
|
||||
return $this->recipients[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ciphertext. This method will return null is the JWE has not yet been encrypted.
|
||||
*
|
||||
* @return string|null The ciphertext
|
||||
*/
|
||||
public function getCiphertext(): ?string
|
||||
{
|
||||
return $this->ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Additional Authentication Data if available.
|
||||
*/
|
||||
public function getAAD(): ?string
|
||||
{
|
||||
return $this->aad;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Initialization Vector if available.
|
||||
*/
|
||||
public function getIV(): ?string
|
||||
{
|
||||
return $this->iv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tag if available.
|
||||
*/
|
||||
public function getTag(): ?string
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoded shared protected header.
|
||||
*/
|
||||
public function getEncodedSharedProtectedHeader(): string
|
||||
{
|
||||
return $this->encodedSharedProtectedHeader ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared protected header.
|
||||
*/
|
||||
public function getSharedProtectedHeader(): array
|
||||
{
|
||||
return $this->sharedProtectedHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared protected header parameter identified by the given key. Throws an exception is the the
|
||||
* parameter is not available.
|
||||
*
|
||||
* @param string $key The key
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getSharedProtectedHeaderParameter(string $key)
|
||||
{
|
||||
if (! $this->hasSharedProtectedHeaderParameter($key)) {
|
||||
throw new InvalidArgumentException(sprintf('The shared protected header "%s" does not exist.', $key));
|
||||
}
|
||||
|
||||
return $this->sharedProtectedHeader[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the shared protected header has the parameter identified by the given key.
|
||||
*
|
||||
* @param string $key The key
|
||||
*/
|
||||
public function hasSharedProtectedHeaderParameter(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->sharedProtectedHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared header.
|
||||
*/
|
||||
public function getSharedHeader(): array
|
||||
{
|
||||
return $this->sharedHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared header parameter identified by the given key. Throws an exception is the the parameter is not
|
||||
* available.
|
||||
*
|
||||
* @param string $key The key
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getSharedHeaderParameter(string $key)
|
||||
{
|
||||
if (! $this->hasSharedHeaderParameter($key)) {
|
||||
throw new InvalidArgumentException(sprintf('The shared header "%s" does not exist.', $key));
|
||||
}
|
||||
|
||||
return $this->sharedHeader[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the shared header has the parameter identified by the given key.
|
||||
*
|
||||
* @param string $key The key
|
||||
*/
|
||||
public function hasSharedHeaderParameter(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->sharedHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method splits the JWE into a list of JWEs. It is only useful when the JWE contains more than one recipient
|
||||
* (JSON General Serialization).
|
||||
*
|
||||
* @return JWE[]
|
||||
*/
|
||||
public function split(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($this->recipients as $recipient) {
|
||||
$result[] = new self(
|
||||
$this->ciphertext,
|
||||
$this->iv,
|
||||
$this->tag,
|
||||
$this->aad,
|
||||
$this->sharedHeader,
|
||||
$this->sharedProtectedHeader,
|
||||
$this->encodedSharedProtectedHeader,
|
||||
[$recipient]
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
618
libraries/vendor/web-token/jwt-library/Encryption/JWEBuilder.php
vendored
Normal file
618
libraries/vendor/web-token/jwt-library/Encryption/JWEBuilder.php
vendored
Normal file
@ -0,0 +1,618 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\AlgorithmManager;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use Jose\Component\Core\Util\JsonConverter;
|
||||
use Jose\Component\Core\Util\KeyChecker;
|
||||
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\DirectEncryption;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyAgreement;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyAgreementWithKeyWrapping;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyEncryption;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyWrapping;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryptionAlgorithm;
|
||||
use Jose\Component\Encryption\Compression\CompressionMethod;
|
||||
use Jose\Component\Encryption\Compression\CompressionMethodManager;
|
||||
use LogicException;
|
||||
use RuntimeException;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function is_string;
|
||||
|
||||
class JWEBuilder
|
||||
{
|
||||
protected ?JWK $senderKey = null;
|
||||
|
||||
protected ?string $payload = null;
|
||||
|
||||
protected ?string $aad = null;
|
||||
|
||||
protected array $recipients = [];
|
||||
|
||||
protected array $sharedProtectedHeader = [];
|
||||
|
||||
protected array $sharedHeader = [];
|
||||
|
||||
private ?CompressionMethod $compressionMethod = null;
|
||||
|
||||
private ?string $keyManagementMode = null;
|
||||
|
||||
private ?ContentEncryptionAlgorithm $contentEncryptionAlgorithm = null;
|
||||
|
||||
private readonly AlgorithmManager $keyEncryptionAlgorithmManager;
|
||||
|
||||
private readonly AlgorithmManager $contentEncryptionAlgorithmManager;
|
||||
|
||||
public function __construct(
|
||||
AlgorithmManager $algorithmManager,
|
||||
null|AlgorithmManager $contentEncryptionAlgorithmManager = null,
|
||||
private readonly null|CompressionMethodManager $compressionManager = null
|
||||
) {
|
||||
if ($compressionManager !== null) {
|
||||
trigger_deprecation(
|
||||
'web-token/jwt-library',
|
||||
'3.3.0',
|
||||
'The parameter "$compressionManager" is deprecated and will be removed in 4.0.0. Compression is not recommended for JWE. Please set "null" instead.'
|
||||
);
|
||||
}
|
||||
if ($contentEncryptionAlgorithmManager !== null) {
|
||||
trigger_deprecation(
|
||||
'web-token/jwt-library',
|
||||
'3.3.0',
|
||||
'The parameter "$contentEncryptionAlgorithmManager" is deprecated and will be removed in 4.0.0. Please set all algorithms in the first argument and set "null" instead.'
|
||||
);
|
||||
$this->keyEncryptionAlgorithmManager = $algorithmManager;
|
||||
$this->contentEncryptionAlgorithmManager = $contentEncryptionAlgorithmManager;
|
||||
} else {
|
||||
$keyEncryptionAlgorithms = [];
|
||||
$contentEncryptionAlgorithms = [];
|
||||
foreach ($algorithmManager->all() as $algorithm) {
|
||||
if ($algorithm instanceof KeyEncryptionAlgorithm) {
|
||||
$keyEncryptionAlgorithms[] = $algorithm;
|
||||
}
|
||||
if ($algorithm instanceof ContentEncryptionAlgorithm) {
|
||||
$contentEncryptionAlgorithms[] = $algorithm;
|
||||
}
|
||||
}
|
||||
$this->keyEncryptionAlgorithmManager = new AlgorithmManager($keyEncryptionAlgorithms);
|
||||
$this->contentEncryptionAlgorithmManager = new AlgorithmManager($contentEncryptionAlgorithms);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current data.
|
||||
*/
|
||||
public function create(): self
|
||||
{
|
||||
$this->senderKey = null;
|
||||
$this->payload = null;
|
||||
$this->aad = null;
|
||||
$this->recipients = [];
|
||||
$this->sharedProtectedHeader = [];
|
||||
$this->sharedHeader = [];
|
||||
$this->compressionMethod = null;
|
||||
$this->keyManagementMode = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key encryption algorithm manager.
|
||||
*/
|
||||
public function getKeyEncryptionAlgorithmManager(): AlgorithmManager
|
||||
{
|
||||
return $this->keyEncryptionAlgorithmManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content encryption algorithm manager.
|
||||
*/
|
||||
public function getContentEncryptionAlgorithmManager(): AlgorithmManager
|
||||
{
|
||||
return $this->contentEncryptionAlgorithmManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compression method manager.
|
||||
* @deprecated This method is deprecated and will be removed in v4.0. Compression is not recommended for JWE.
|
||||
*/
|
||||
public function getCompressionMethodManager(): null|CompressionMethodManager
|
||||
{
|
||||
return $this->compressionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the payload of the JWE to build.
|
||||
*/
|
||||
public function withPayload(string $payload): self
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->payload = $payload;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Additional Authenticated Data of the JWE to build.
|
||||
*/
|
||||
public function withAAD(?string $aad): self
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->aad = $aad;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the shared protected header of the JWE to build.
|
||||
*/
|
||||
public function withSharedProtectedHeader(array $sharedProtectedHeader): self
|
||||
{
|
||||
$this->checkDuplicatedHeaderParameters($sharedProtectedHeader, $this->sharedHeader);
|
||||
foreach ($this->recipients as $recipient) {
|
||||
$this->checkDuplicatedHeaderParameters($sharedProtectedHeader, $recipient->getHeader());
|
||||
}
|
||||
$clone = clone $this;
|
||||
$clone->sharedProtectedHeader = $sharedProtectedHeader;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the shared header of the JWE to build.
|
||||
*/
|
||||
public function withSharedHeader(array $sharedHeader): self
|
||||
{
|
||||
$this->checkDuplicatedHeaderParameters($this->sharedProtectedHeader, $sharedHeader);
|
||||
foreach ($this->recipients as $recipient) {
|
||||
$this->checkDuplicatedHeaderParameters($sharedHeader, $recipient->getHeader());
|
||||
}
|
||||
$clone = clone $this;
|
||||
$clone->sharedHeader = $sharedHeader;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a recipient to the JWE to build.
|
||||
*/
|
||||
public function addRecipient(JWK $recipientKey, array $recipientHeader = []): self
|
||||
{
|
||||
$this->checkDuplicatedHeaderParameters($this->sharedProtectedHeader, $recipientHeader);
|
||||
$this->checkDuplicatedHeaderParameters($this->sharedHeader, $recipientHeader);
|
||||
$clone = clone $this;
|
||||
$completeHeader = array_merge($clone->sharedHeader, $recipientHeader, $clone->sharedProtectedHeader);
|
||||
$clone->checkAndSetContentEncryptionAlgorithm($completeHeader);
|
||||
$keyEncryptionAlgorithm = $clone->getKeyEncryptionAlgorithm($completeHeader);
|
||||
if ($clone->keyManagementMode === null) {
|
||||
$clone->keyManagementMode = $keyEncryptionAlgorithm->getKeyManagementMode();
|
||||
} else {
|
||||
if (! $clone->areKeyManagementModesCompatible(
|
||||
$clone->keyManagementMode,
|
||||
$keyEncryptionAlgorithm->getKeyManagementMode()
|
||||
)) {
|
||||
throw new InvalidArgumentException('Foreign key management mode forbidden.');
|
||||
}
|
||||
}
|
||||
|
||||
$compressionMethod = $clone->getCompressionMethod($completeHeader);
|
||||
if ($compressionMethod !== null) {
|
||||
if ($clone->compressionMethod === null) {
|
||||
$clone->compressionMethod = $compressionMethod;
|
||||
} elseif ($clone->compressionMethod->name() !== $compressionMethod->name()) {
|
||||
throw new InvalidArgumentException('Incompatible compression method.');
|
||||
}
|
||||
}
|
||||
if ($compressionMethod === null && $clone->compressionMethod !== null) {
|
||||
throw new InvalidArgumentException('Inconsistent compression method.');
|
||||
}
|
||||
$clone->checkKey($keyEncryptionAlgorithm, $recipientKey);
|
||||
$clone->recipients[] = [
|
||||
'key' => $recipientKey,
|
||||
'header' => $recipientHeader,
|
||||
'key_encryption_algorithm' => $keyEncryptionAlgorithm,
|
||||
];
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
//TODO: Verify if the key is compatible with the key encryption algorithm like is done to the ECDH-ES
|
||||
/**
|
||||
* Set the sender JWK to be used instead of the internal generated JWK
|
||||
*/
|
||||
public function withSenderKey(JWK $senderKey): self
|
||||
{
|
||||
$clone = clone $this;
|
||||
$completeHeader = array_merge($clone->sharedHeader, $clone->sharedProtectedHeader);
|
||||
$keyEncryptionAlgorithm = $clone->getKeyEncryptionAlgorithm($completeHeader);
|
||||
if ($clone->keyManagementMode === null) {
|
||||
$clone->keyManagementMode = $keyEncryptionAlgorithm->getKeyManagementMode();
|
||||
} else {
|
||||
if (! $clone->areKeyManagementModesCompatible(
|
||||
$clone->keyManagementMode,
|
||||
$keyEncryptionAlgorithm->getKeyManagementMode()
|
||||
)) {
|
||||
throw new InvalidArgumentException('Foreign key management mode forbidden.');
|
||||
}
|
||||
}
|
||||
$clone->checkKey($keyEncryptionAlgorithm, $senderKey);
|
||||
$clone->senderKey = $senderKey;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the JWE.
|
||||
*/
|
||||
public function build(): JWE
|
||||
{
|
||||
if ($this->payload === null) {
|
||||
throw new LogicException('Payload not set.');
|
||||
}
|
||||
if (count($this->recipients) === 0) {
|
||||
throw new LogicException('No recipient.');
|
||||
}
|
||||
|
||||
$additionalHeader = [];
|
||||
$cek = $this->determineCEK($additionalHeader);
|
||||
|
||||
$recipients = [];
|
||||
foreach ($this->recipients as $recipient) {
|
||||
$recipient = $this->processRecipient($recipient, $cek, $additionalHeader);
|
||||
$recipients[] = $recipient;
|
||||
}
|
||||
|
||||
if ((is_countable($additionalHeader) ? count($additionalHeader) : 0) !== 0 && count($this->recipients) === 1) {
|
||||
$sharedProtectedHeader = array_merge($additionalHeader, $this->sharedProtectedHeader);
|
||||
} else {
|
||||
$sharedProtectedHeader = $this->sharedProtectedHeader;
|
||||
}
|
||||
$encodedSharedProtectedHeader = count($sharedProtectedHeader) === 0 ? '' : Base64UrlSafe::encodeUnpadded(
|
||||
JsonConverter::encode($sharedProtectedHeader)
|
||||
);
|
||||
|
||||
[$ciphertext, $iv, $tag] = $this->encryptJWE($cek, $encodedSharedProtectedHeader);
|
||||
|
||||
return new JWE(
|
||||
$ciphertext,
|
||||
$iv,
|
||||
$tag,
|
||||
$this->aad,
|
||||
$this->sharedHeader,
|
||||
$sharedProtectedHeader,
|
||||
$encodedSharedProtectedHeader,
|
||||
$recipients
|
||||
);
|
||||
}
|
||||
|
||||
private function checkAndSetContentEncryptionAlgorithm(array $completeHeader): void
|
||||
{
|
||||
$contentEncryptionAlgorithm = $this->getContentEncryptionAlgorithm($completeHeader);
|
||||
if ($this->contentEncryptionAlgorithm === null) {
|
||||
$this->contentEncryptionAlgorithm = $contentEncryptionAlgorithm;
|
||||
} elseif ($contentEncryptionAlgorithm->name() !== $this->contentEncryptionAlgorithm->name()) {
|
||||
throw new InvalidArgumentException('Inconsistent content encryption algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
private function processRecipient(array $recipient, string $cek, array &$additionalHeader): Recipient
|
||||
{
|
||||
$completeHeader = array_merge($this->sharedHeader, $recipient['header'], $this->sharedProtectedHeader);
|
||||
$keyEncryptionAlgorithm = $recipient['key_encryption_algorithm'];
|
||||
if (! $keyEncryptionAlgorithm instanceof KeyEncryptionAlgorithm) {
|
||||
throw new InvalidArgumentException('The key encryption algorithm is not valid');
|
||||
}
|
||||
$encryptedContentEncryptionKey = $this->getEncryptedKey(
|
||||
$completeHeader,
|
||||
$cek,
|
||||
$keyEncryptionAlgorithm,
|
||||
$additionalHeader,
|
||||
$recipient['key'],
|
||||
$recipient['sender_key'] ?? $this->senderKey ?? null
|
||||
);
|
||||
$recipientHeader = $recipient['header'];
|
||||
if ((is_countable($additionalHeader) ? count($additionalHeader) : 0) !== 0 && count($this->recipients) !== 1) {
|
||||
$recipientHeader = array_merge($recipientHeader, $additionalHeader);
|
||||
$additionalHeader = [];
|
||||
}
|
||||
|
||||
return new Recipient($recipientHeader, $encryptedContentEncryptionKey);
|
||||
}
|
||||
|
||||
private function encryptJWE(string $cek, string $encodedSharedProtectedHeader): array
|
||||
{
|
||||
if (! $this->contentEncryptionAlgorithm instanceof ContentEncryptionAlgorithm) {
|
||||
throw new InvalidArgumentException('The content encryption algorithm is not valid');
|
||||
}
|
||||
$iv_size = $this->contentEncryptionAlgorithm->getIVSize();
|
||||
$iv = $this->createIV($iv_size);
|
||||
$payload = $this->preparePayload();
|
||||
$tag = null;
|
||||
$ciphertext = $this->contentEncryptionAlgorithm->encryptContent(
|
||||
$payload ?? '',
|
||||
$cek,
|
||||
$iv,
|
||||
$this->aad,
|
||||
$encodedSharedProtectedHeader,
|
||||
$tag
|
||||
);
|
||||
|
||||
return [$ciphertext, $iv, $tag];
|
||||
}
|
||||
|
||||
private function preparePayload(): ?string
|
||||
{
|
||||
$prepared = $this->payload;
|
||||
if ($this->compressionMethod === null) {
|
||||
return $prepared;
|
||||
}
|
||||
|
||||
return $this->compressionMethod->compress($prepared ?? '');
|
||||
}
|
||||
|
||||
private function getEncryptedKey(
|
||||
array $completeHeader,
|
||||
string $cek,
|
||||
KeyEncryptionAlgorithm $keyEncryptionAlgorithm,
|
||||
array &$additionalHeader,
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey
|
||||
): ?string {
|
||||
if ($keyEncryptionAlgorithm instanceof KeyEncryption) {
|
||||
return $this->getEncryptedKeyFromKeyEncryptionAlgorithm(
|
||||
$completeHeader,
|
||||
$cek,
|
||||
$keyEncryptionAlgorithm,
|
||||
$recipientKey,
|
||||
$additionalHeader
|
||||
);
|
||||
}
|
||||
if ($keyEncryptionAlgorithm instanceof KeyWrapping) {
|
||||
return $this->getEncryptedKeyFromKeyWrappingAlgorithm(
|
||||
$completeHeader,
|
||||
$cek,
|
||||
$keyEncryptionAlgorithm,
|
||||
$recipientKey,
|
||||
$additionalHeader
|
||||
);
|
||||
}
|
||||
if ($keyEncryptionAlgorithm instanceof KeyAgreementWithKeyWrapping) {
|
||||
return $this->getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm(
|
||||
$completeHeader,
|
||||
$cek,
|
||||
$keyEncryptionAlgorithm,
|
||||
$additionalHeader,
|
||||
$recipientKey,
|
||||
$senderKey
|
||||
);
|
||||
}
|
||||
if ($keyEncryptionAlgorithm instanceof KeyAgreement) {
|
||||
return null;
|
||||
}
|
||||
if ($keyEncryptionAlgorithm instanceof DirectEncryption) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Unsupported key encryption algorithm.');
|
||||
}
|
||||
|
||||
private function getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm(
|
||||
array $completeHeader,
|
||||
string $cek,
|
||||
KeyAgreementWithKeyWrapping $keyEncryptionAlgorithm,
|
||||
array &$additionalHeader,
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey
|
||||
): string {
|
||||
if ($this->contentEncryptionAlgorithm === null) {
|
||||
throw new InvalidArgumentException('Invalid content encryption algorithm');
|
||||
}
|
||||
|
||||
return $keyEncryptionAlgorithm->wrapAgreementKey(
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$cek,
|
||||
$this->contentEncryptionAlgorithm->getCEKSize(),
|
||||
$completeHeader,
|
||||
$additionalHeader
|
||||
);
|
||||
}
|
||||
|
||||
private function getEncryptedKeyFromKeyEncryptionAlgorithm(
|
||||
array $completeHeader,
|
||||
string $cek,
|
||||
KeyEncryption $keyEncryptionAlgorithm,
|
||||
JWK $recipientKey,
|
||||
array &$additionalHeader
|
||||
): string {
|
||||
return $keyEncryptionAlgorithm->encryptKey($recipientKey, $cek, $completeHeader, $additionalHeader);
|
||||
}
|
||||
|
||||
private function getEncryptedKeyFromKeyWrappingAlgorithm(
|
||||
array $completeHeader,
|
||||
string $cek,
|
||||
KeyWrapping $keyEncryptionAlgorithm,
|
||||
JWK $recipientKey,
|
||||
array &$additionalHeader
|
||||
): string {
|
||||
return $keyEncryptionAlgorithm->wrapKey($recipientKey, $cek, $completeHeader, $additionalHeader);
|
||||
}
|
||||
|
||||
private function checkKey(KeyEncryptionAlgorithm $keyEncryptionAlgorithm, JWK $recipientKey): void
|
||||
{
|
||||
if ($this->contentEncryptionAlgorithm === null) {
|
||||
throw new InvalidArgumentException('Invalid content encryption algorithm');
|
||||
}
|
||||
|
||||
KeyChecker::checkKeyUsage($recipientKey, 'encryption');
|
||||
if ($keyEncryptionAlgorithm->name() !== 'dir') {
|
||||
KeyChecker::checkKeyAlgorithm($recipientKey, $keyEncryptionAlgorithm->name());
|
||||
} else {
|
||||
KeyChecker::checkKeyAlgorithm($recipientKey, $this->contentEncryptionAlgorithm->name());
|
||||
}
|
||||
}
|
||||
|
||||
private function determineCEK(array &$additionalHeader): string
|
||||
{
|
||||
if ($this->contentEncryptionAlgorithm === null) {
|
||||
throw new InvalidArgumentException('Invalid content encryption algorithm');
|
||||
}
|
||||
|
||||
switch ($this->keyManagementMode) {
|
||||
case KeyEncryption::MODE_ENCRYPT:
|
||||
case KeyEncryption::MODE_WRAP:
|
||||
return $this->createCEK($this->contentEncryptionAlgorithm->getCEKSize());
|
||||
|
||||
case KeyEncryption::MODE_AGREEMENT:
|
||||
if (count($this->recipients) !== 1) {
|
||||
throw new LogicException(
|
||||
'Unable to encrypt for multiple recipients using key agreement algorithms.'
|
||||
);
|
||||
}
|
||||
$recipientKey = $this->recipients[0]['key'];
|
||||
$senderKey = $this->recipients[0]['sender_key'] ?? null;
|
||||
$algorithm = $this->recipients[0]['key_encryption_algorithm'];
|
||||
if (! $algorithm instanceof KeyAgreement) {
|
||||
throw new InvalidArgumentException('Invalid content encryption algorithm');
|
||||
}
|
||||
$completeHeader = array_merge(
|
||||
$this->sharedHeader,
|
||||
$this->recipients[0]['header'],
|
||||
$this->sharedProtectedHeader
|
||||
);
|
||||
|
||||
return $algorithm->getAgreementKey(
|
||||
$this->contentEncryptionAlgorithm->getCEKSize(),
|
||||
$this->contentEncryptionAlgorithm->name(),
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$completeHeader,
|
||||
$additionalHeader
|
||||
);
|
||||
|
||||
case KeyEncryption::MODE_DIRECT:
|
||||
if (count($this->recipients) !== 1) {
|
||||
throw new LogicException(
|
||||
'Unable to encrypt for multiple recipients using key agreement algorithms.'
|
||||
);
|
||||
}
|
||||
/** @var JWK $key */
|
||||
$key = $this->recipients[0]['key'];
|
||||
if ($key->get('kty') !== 'oct') {
|
||||
throw new RuntimeException('Wrong key type.');
|
||||
}
|
||||
$k = $key->get('k');
|
||||
if (! is_string($k)) {
|
||||
throw new RuntimeException('Invalid key.');
|
||||
}
|
||||
|
||||
return Base64UrlSafe::decodeNoPadding($k);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Unsupported key management mode "%s".',
|
||||
$this->keyManagementMode
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private function getCompressionMethod(array $completeHeader): ?CompressionMethod
|
||||
{
|
||||
if ($this->compressionManager === null || ! array_key_exists('zip', $completeHeader)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->compressionManager->get($completeHeader['zip']);
|
||||
}
|
||||
|
||||
private function areKeyManagementModesCompatible(string $current, string $new): bool
|
||||
{
|
||||
$agree = KeyEncryptionAlgorithm::MODE_AGREEMENT;
|
||||
$dir = KeyEncryptionAlgorithm::MODE_DIRECT;
|
||||
$enc = KeyEncryptionAlgorithm::MODE_ENCRYPT;
|
||||
$wrap = KeyEncryptionAlgorithm::MODE_WRAP;
|
||||
$supportedKeyManagementModeCombinations = [
|
||||
$enc . $enc => true,
|
||||
$enc . $wrap => true,
|
||||
$wrap . $enc => true,
|
||||
$wrap . $wrap => true,
|
||||
$agree . $agree => false,
|
||||
$agree . $dir => false,
|
||||
$agree . $enc => false,
|
||||
$agree . $wrap => false,
|
||||
$dir . $agree => false,
|
||||
$dir . $dir => false,
|
||||
$dir . $enc => false,
|
||||
$dir . $wrap => false,
|
||||
$enc . $agree => false,
|
||||
$enc . $dir => false,
|
||||
$wrap . $agree => false,
|
||||
$wrap . $dir => false,
|
||||
];
|
||||
|
||||
if (array_key_exists($current . $new, $supportedKeyManagementModeCombinations)) {
|
||||
return $supportedKeyManagementModeCombinations[$current . $new];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function createCEK(int $size): string
|
||||
{
|
||||
return random_bytes($size / 8);
|
||||
}
|
||||
|
||||
private function createIV(int $size): string
|
||||
{
|
||||
return random_bytes($size / 8);
|
||||
}
|
||||
|
||||
private function getKeyEncryptionAlgorithm(array $completeHeader): KeyEncryptionAlgorithm
|
||||
{
|
||||
if (! isset($completeHeader['alg'])) {
|
||||
throw new InvalidArgumentException('Parameter "alg" is missing.');
|
||||
}
|
||||
$keyEncryptionAlgorithm = $this->keyEncryptionAlgorithmManager->get($completeHeader['alg']);
|
||||
if (! $keyEncryptionAlgorithm instanceof KeyEncryptionAlgorithm) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The key encryption algorithm "%s" is not supported or not a key encryption algorithm instance.',
|
||||
$completeHeader['alg']
|
||||
));
|
||||
}
|
||||
|
||||
return $keyEncryptionAlgorithm;
|
||||
}
|
||||
|
||||
private function getContentEncryptionAlgorithm(array $completeHeader): ContentEncryptionAlgorithm
|
||||
{
|
||||
if (! isset($completeHeader['enc'])) {
|
||||
throw new InvalidArgumentException('Parameter "enc" is missing.');
|
||||
}
|
||||
$contentEncryptionAlgorithm = $this->contentEncryptionAlgorithmManager->get($completeHeader['enc']);
|
||||
if (! $contentEncryptionAlgorithm instanceof ContentEncryptionAlgorithm) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The content encryption algorithm "%s" is not supported or not a content encryption algorithm instance.',
|
||||
$completeHeader['enc']
|
||||
));
|
||||
}
|
||||
|
||||
return $contentEncryptionAlgorithm;
|
||||
}
|
||||
|
||||
private function checkDuplicatedHeaderParameters(array $header1, array $header2): void
|
||||
{
|
||||
$inter = array_intersect_key($header1, $header2);
|
||||
if (count($inter) !== 0) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The header contains duplicated entries: %s.',
|
||||
implode(', ', array_keys($inter))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
53
libraries/vendor/web-token/jwt-library/Encryption/JWEBuilderFactory.php
vendored
Normal file
53
libraries/vendor/web-token/jwt-library/Encryption/JWEBuilderFactory.php
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use Jose\Component\Core\AlgorithmManagerFactory;
|
||||
use Jose\Component\Encryption\Compression\CompressionMethodManagerFactory;
|
||||
|
||||
class JWEBuilderFactory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AlgorithmManagerFactory $algorithmManagerFactory,
|
||||
private readonly null|CompressionMethodManagerFactory $compressionMethodManagerFactory = null
|
||||
) {
|
||||
if ($compressionMethodManagerFactory !== null) {
|
||||
trigger_deprecation(
|
||||
'web-token/jwt-library',
|
||||
'3.3.0',
|
||||
'The parameter "$compressionMethodManagerFactory" is deprecated and will be removed in 4.0.0. Compression is not recommended for JWE. Please set "null" instead.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JWE Builder object using the given key encryption algorithms, content encryption algorithms and
|
||||
* compression methods.
|
||||
*
|
||||
* @param array<string> $encryptionAlgorithms
|
||||
* @param null|array<string> $contentEncryptionAlgorithm
|
||||
* @param null|string[] $compressionMethods
|
||||
*/
|
||||
public function create(
|
||||
array $encryptionAlgorithms,
|
||||
null|array $contentEncryptionAlgorithm = null,
|
||||
null|array $compressionMethods = null
|
||||
): JWEBuilder {
|
||||
if ($contentEncryptionAlgorithm !== null) {
|
||||
trigger_deprecation(
|
||||
'web-token/jwt-library',
|
||||
'3.3.0',
|
||||
'The parameter "$contentEncryptionAlgorithm" is deprecated and will be removed in 4.0.0. Please set "null" instead.'
|
||||
);
|
||||
$encryptionAlgorithms = array_merge($encryptionAlgorithms, $contentEncryptionAlgorithm);
|
||||
}
|
||||
$encryptionAlgorithmManager = $this->algorithmManagerFactory->create($encryptionAlgorithms);
|
||||
$compressionMethodManager = $compressionMethods === null ? null : $this->compressionMethodManagerFactory?->create(
|
||||
$compressionMethods
|
||||
);
|
||||
|
||||
return new JWEBuilder($encryptionAlgorithmManager, null, $compressionMethodManager);
|
||||
}
|
||||
}
|
||||
324
libraries/vendor/web-token/jwt-library/Encryption/JWEDecrypter.php
vendored
Normal file
324
libraries/vendor/web-token/jwt-library/Encryption/JWEDecrypter.php
vendored
Normal file
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\Algorithm;
|
||||
use Jose\Component\Core\AlgorithmManager;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\JWKSet;
|
||||
use Jose\Component\Core\Util\KeyChecker;
|
||||
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\DirectEncryption;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyAgreement;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyAgreementWithKeyWrapping;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyEncryption;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyWrapping;
|
||||
use Jose\Component\Encryption\Algorithm\KeyEncryptionAlgorithm;
|
||||
use Jose\Component\Encryption\Compression\CompressionMethodManager;
|
||||
use Throwable;
|
||||
use function array_key_exists;
|
||||
use function is_string;
|
||||
|
||||
class JWEDecrypter
|
||||
{
|
||||
private readonly AlgorithmManager $keyEncryptionAlgorithmManager;
|
||||
|
||||
private readonly AlgorithmManager $contentEncryptionAlgorithmManager;
|
||||
|
||||
public function __construct(
|
||||
AlgorithmManager $algorithmManager,
|
||||
null|AlgorithmManager $contentEncryptionAlgorithmManager,
|
||||
private readonly null|CompressionMethodManager $compressionMethodManager = null
|
||||
) {
|
||||
if ($compressionMethodManager !== null) {
|
||||
trigger_deprecation(
|
||||
'web-token/jwt-library',
|
||||
'3.3.0',
|
||||
'The parameter "$compressionMethodManager" is deprecated and will be removed in 4.0.0. Compression is not recommended for JWE. Please set "null" instead.'
|
||||
);
|
||||
}
|
||||
if ($contentEncryptionAlgorithmManager !== null) {
|
||||
trigger_deprecation(
|
||||
'web-token/jwt-library',
|
||||
'3.3.0',
|
||||
'The parameter "$contentEncryptionAlgorithmManager" is deprecated and will be removed in 4.0.0. Please set all algorithms in the first argument and set "null" instead.'
|
||||
);
|
||||
$this->keyEncryptionAlgorithmManager = $algorithmManager;
|
||||
$this->contentEncryptionAlgorithmManager = $contentEncryptionAlgorithmManager;
|
||||
} else {
|
||||
$keyEncryptionAlgorithms = [];
|
||||
$contentEncryptionAlgorithms = [];
|
||||
foreach ($algorithmManager->all() as $key => $algorithm) {
|
||||
if ($algorithm instanceof KeyEncryptionAlgorithm) {
|
||||
$keyEncryptionAlgorithms[$key] = $algorithm;
|
||||
}
|
||||
if ($algorithm instanceof ContentEncryptionAlgorithm) {
|
||||
$contentEncryptionAlgorithms[$key] = $algorithm;
|
||||
}
|
||||
}
|
||||
$this->keyEncryptionAlgorithmManager = new AlgorithmManager($keyEncryptionAlgorithms);
|
||||
$this->contentEncryptionAlgorithmManager = new AlgorithmManager($contentEncryptionAlgorithms);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key encryption algorithm manager.
|
||||
*/
|
||||
public function getKeyEncryptionAlgorithmManager(): AlgorithmManager
|
||||
{
|
||||
return $this->keyEncryptionAlgorithmManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content encryption algorithm manager.
|
||||
*/
|
||||
public function getContentEncryptionAlgorithmManager(): AlgorithmManager
|
||||
{
|
||||
return $this->contentEncryptionAlgorithmManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compression method manager.
|
||||
* @deprecated This method is deprecated and will be removed in v4.0. Compression is not recommended for JWE.
|
||||
*/
|
||||
public function getCompressionMethodManager(): null|CompressionMethodManager
|
||||
{
|
||||
return $this->compressionMethodManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to decrypt the given JWE and recipient using a JWK.
|
||||
*
|
||||
* @param JWE $jwe A JWE object to decrypt
|
||||
* @param JWK $jwk The key used to decrypt the input
|
||||
* @param int $recipient The recipient used to decrypt the token
|
||||
*/
|
||||
public function decryptUsingKey(JWE &$jwe, JWK $jwk, int $recipient, ?JWK $senderKey = null): bool
|
||||
{
|
||||
$jwkset = new JWKSet([$jwk]);
|
||||
|
||||
return $this->decryptUsingKeySet($jwe, $jwkset, $recipient, $senderKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to decrypt the given JWE and recipient using a JWKSet.
|
||||
*
|
||||
* @param JWE $jwe A JWE object to decrypt
|
||||
* @param JWKSet $jwkset The key set used to decrypt the input
|
||||
* @param JWK $jwk The key used to decrypt the token in case of success
|
||||
* @param int $recipient The recipient used to decrypt the token in case of success
|
||||
*/
|
||||
public function decryptUsingKeySet(
|
||||
JWE &$jwe,
|
||||
JWKSet $jwkset,
|
||||
int $recipient,
|
||||
?JWK &$jwk = null,
|
||||
?JWK $senderKey = null
|
||||
): bool {
|
||||
if ($jwkset->count() === 0) {
|
||||
throw new InvalidArgumentException('No key in the key set.');
|
||||
}
|
||||
if ($jwe->getPayload() !== null) {
|
||||
return true;
|
||||
}
|
||||
if ($jwe->countRecipients() === 0) {
|
||||
throw new InvalidArgumentException('The JWE does not contain any recipient.');
|
||||
}
|
||||
|
||||
$plaintext = $this->decryptRecipientKey($jwe, $jwkset, $recipient, $jwk, $senderKey);
|
||||
if ($plaintext !== null) {
|
||||
$jwe = $jwe->withPayload($plaintext);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function decryptRecipientKey(
|
||||
JWE $jwe,
|
||||
JWKSet $jwkset,
|
||||
int $i,
|
||||
?JWK &$successJwk = null,
|
||||
?JWK $senderKey = null
|
||||
): ?string {
|
||||
$recipient = $jwe->getRecipient($i);
|
||||
$completeHeader = array_merge(
|
||||
$jwe->getSharedProtectedHeader(),
|
||||
$jwe->getSharedHeader(),
|
||||
$recipient->getHeader()
|
||||
);
|
||||
$this->checkCompleteHeader($completeHeader);
|
||||
|
||||
$key_encryption_algorithm = $this->getKeyEncryptionAlgorithm($completeHeader);
|
||||
$content_encryption_algorithm = $this->getContentEncryptionAlgorithm($completeHeader);
|
||||
|
||||
$this->checkIvSize($jwe->getIV(), $content_encryption_algorithm->getIVSize());
|
||||
|
||||
foreach ($jwkset as $recipientKey) {
|
||||
try {
|
||||
KeyChecker::checkKeyUsage($recipientKey, 'decryption');
|
||||
if ($key_encryption_algorithm->name() !== 'dir') {
|
||||
KeyChecker::checkKeyAlgorithm($recipientKey, $key_encryption_algorithm->name());
|
||||
} else {
|
||||
KeyChecker::checkKeyAlgorithm($recipientKey, $content_encryption_algorithm->name());
|
||||
}
|
||||
$cek = $this->decryptCEK(
|
||||
$key_encryption_algorithm,
|
||||
$content_encryption_algorithm,
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$recipient,
|
||||
$completeHeader
|
||||
);
|
||||
$this->checkCekSize($cek, $key_encryption_algorithm, $content_encryption_algorithm);
|
||||
$payload = $this->decryptPayload($jwe, $cek, $content_encryption_algorithm, $completeHeader);
|
||||
$successJwk = $recipientKey;
|
||||
|
||||
return $payload;
|
||||
} catch (Throwable) {
|
||||
//We do nothing, we continue with other keys
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function checkCekSize(
|
||||
string $cek,
|
||||
KeyEncryptionAlgorithm $keyEncryptionAlgorithm,
|
||||
ContentEncryptionAlgorithm $algorithm
|
||||
): void {
|
||||
if ($keyEncryptionAlgorithm instanceof DirectEncryption || $keyEncryptionAlgorithm instanceof KeyAgreement) {
|
||||
return;
|
||||
}
|
||||
if (mb_strlen($cek, '8bit') * 8 !== $algorithm->getCEKSize()) {
|
||||
throw new InvalidArgumentException('Invalid CEK size');
|
||||
}
|
||||
}
|
||||
|
||||
private function checkIvSize(?string $iv, int $requiredIvSize): void
|
||||
{
|
||||
if ($iv === null && $requiredIvSize !== 0) {
|
||||
throw new InvalidArgumentException('Invalid IV size');
|
||||
}
|
||||
if (is_string($iv) && mb_strlen($iv, '8bit') !== $requiredIvSize / 8) {
|
||||
throw new InvalidArgumentException('Invalid IV size');
|
||||
}
|
||||
}
|
||||
|
||||
private function decryptCEK(
|
||||
Algorithm $key_encryption_algorithm,
|
||||
ContentEncryptionAlgorithm $content_encryption_algorithm,
|
||||
JWK $recipientKey,
|
||||
?JWK $senderKey,
|
||||
Recipient $recipient,
|
||||
array $completeHeader
|
||||
): string {
|
||||
if ($key_encryption_algorithm instanceof DirectEncryption) {
|
||||
return $key_encryption_algorithm->getCEK($recipientKey);
|
||||
}
|
||||
if ($key_encryption_algorithm instanceof KeyAgreement) {
|
||||
return $key_encryption_algorithm->getAgreementKey(
|
||||
$content_encryption_algorithm->getCEKSize(),
|
||||
$content_encryption_algorithm->name(),
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$completeHeader
|
||||
);
|
||||
}
|
||||
if ($key_encryption_algorithm instanceof KeyAgreementWithKeyWrapping) {
|
||||
return $key_encryption_algorithm->unwrapAgreementKey(
|
||||
$recipientKey,
|
||||
$senderKey,
|
||||
$recipient->getEncryptedKey() ?? '',
|
||||
$content_encryption_algorithm->getCEKSize(),
|
||||
$completeHeader
|
||||
);
|
||||
}
|
||||
if ($key_encryption_algorithm instanceof KeyEncryption) {
|
||||
return $key_encryption_algorithm->decryptKey(
|
||||
$recipientKey,
|
||||
$recipient->getEncryptedKey() ?? '',
|
||||
$completeHeader
|
||||
);
|
||||
}
|
||||
if ($key_encryption_algorithm instanceof KeyWrapping) {
|
||||
return $key_encryption_algorithm->unwrapKey(
|
||||
$recipientKey,
|
||||
$recipient->getEncryptedKey() ?? '',
|
||||
$completeHeader
|
||||
);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Unsupported CEK generation');
|
||||
}
|
||||
|
||||
private function decryptPayload(
|
||||
JWE $jwe,
|
||||
string $cek,
|
||||
ContentEncryptionAlgorithm $content_encryption_algorithm,
|
||||
array $completeHeader
|
||||
): string {
|
||||
$payload = $content_encryption_algorithm->decryptContent(
|
||||
$jwe->getCiphertext() ?? '',
|
||||
$cek,
|
||||
$jwe->getIV() ?? '',
|
||||
$jwe->getAAD(),
|
||||
$jwe->getEncodedSharedProtectedHeader(),
|
||||
$jwe->getTag() ?? ''
|
||||
);
|
||||
|
||||
return $this->decompressIfNeeded($payload, $completeHeader);
|
||||
}
|
||||
|
||||
private function decompressIfNeeded(string $payload, array $completeHeaders): string
|
||||
{
|
||||
if ($this->compressionMethodManager === null || ! array_key_exists('zip', $completeHeaders)) {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
$compression_method = $this->compressionMethodManager->get($completeHeaders['zip']);
|
||||
|
||||
return $compression_method->uncompress($payload);
|
||||
}
|
||||
|
||||
private function checkCompleteHeader(array $completeHeaders): void
|
||||
{
|
||||
foreach (['enc', 'alg'] as $key) {
|
||||
if (! isset($completeHeaders[$key])) {
|
||||
throw new InvalidArgumentException(sprintf("Parameter '%s' is missing.", $key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getKeyEncryptionAlgorithm(array $completeHeaders): KeyEncryptionAlgorithm
|
||||
{
|
||||
$key_encryption_algorithm = $this->keyEncryptionAlgorithmManager->get($completeHeaders['alg']);
|
||||
if (! $key_encryption_algorithm instanceof KeyEncryptionAlgorithm) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The key encryption algorithm "%s" is not supported or does not implement KeyEncryptionAlgorithm interface.',
|
||||
$completeHeaders['alg']
|
||||
));
|
||||
}
|
||||
|
||||
return $key_encryption_algorithm;
|
||||
}
|
||||
|
||||
private function getContentEncryptionAlgorithm(array $completeHeader): ContentEncryptionAlgorithm
|
||||
{
|
||||
$content_encryption_algorithm = $this->contentEncryptionAlgorithmManager->get($completeHeader['enc']);
|
||||
if (! $content_encryption_algorithm instanceof ContentEncryptionAlgorithm) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The key encryption algorithm "%s" is not supported or does not implement the ContentEncryption interface.',
|
||||
$completeHeader['enc']
|
||||
));
|
||||
}
|
||||
|
||||
return $content_encryption_algorithm;
|
||||
}
|
||||
}
|
||||
49
libraries/vendor/web-token/jwt-library/Encryption/JWEDecrypterFactory.php
vendored
Normal file
49
libraries/vendor/web-token/jwt-library/Encryption/JWEDecrypterFactory.php
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use Jose\Component\Core\AlgorithmManagerFactory;
|
||||
use Jose\Component\Encryption\Compression\CompressionMethodManagerFactory;
|
||||
|
||||
class JWEDecrypterFactory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AlgorithmManagerFactory $algorithmManagerFactory,
|
||||
private readonly null|CompressionMethodManagerFactory $compressionMethodManagerFactory = null
|
||||
) {
|
||||
if ($compressionMethodManagerFactory !== null) {
|
||||
trigger_deprecation(
|
||||
'web-token/jwt-library',
|
||||
'3.3.0',
|
||||
'The parameter "$compressionMethodManagerFactory" is deprecated and will be removed in 4.0.0. Compression is not recommended for JWE. Please set "null" instead.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JWE Decrypter object using the given key encryption algorithms, content encryption algorithms and
|
||||
* compression methods.
|
||||
*
|
||||
* @param string[] $encryptionAlgorithms
|
||||
* @param null|string[] $contentEncryptionAlgorithms
|
||||
* @param null|string[] $compressionMethods
|
||||
*/
|
||||
public function create(
|
||||
array $encryptionAlgorithms,
|
||||
null|array $contentEncryptionAlgorithms = null,
|
||||
null|array $compressionMethods = null
|
||||
): JWEDecrypter {
|
||||
if ($contentEncryptionAlgorithms !== null) {
|
||||
$encryptionAlgorithms = array_merge($encryptionAlgorithms, $contentEncryptionAlgorithms);
|
||||
}
|
||||
|
||||
$algorithmManager = $this->algorithmManagerFactory->create($encryptionAlgorithms);
|
||||
$compressionMethodManager = $compressionMethods === null ? null : $this->compressionMethodManagerFactory?->create(
|
||||
$compressionMethods
|
||||
);
|
||||
|
||||
return new JWEDecrypter($algorithmManager, null, $compressionMethodManager);
|
||||
}
|
||||
}
|
||||
96
libraries/vendor/web-token/jwt-library/Encryption/JWELoader.php
vendored
Normal file
96
libraries/vendor/web-token/jwt-library/Encryption/JWELoader.php
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use Jose\Component\Checker\HeaderCheckerManager;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\JWKSet;
|
||||
use Jose\Component\Encryption\Serializer\JWESerializerManager;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @see \Jose\Tests\Component\Encryption\JWELoaderTest
|
||||
*/
|
||||
class JWELoader
|
||||
{
|
||||
public function __construct(
|
||||
private readonly JWESerializerManager $serializerManager,
|
||||
private readonly JWEDecrypter $jweDecrypter,
|
||||
private readonly ?HeaderCheckerManager $headerCheckerManager
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JWE Decrypter object.
|
||||
*/
|
||||
public function getJweDecrypter(): JWEDecrypter
|
||||
{
|
||||
return $this->jweDecrypter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header checker manager if set.
|
||||
*/
|
||||
public function getHeaderCheckerManager(): ?HeaderCheckerManager
|
||||
{
|
||||
return $this->headerCheckerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serializer manager.
|
||||
*/
|
||||
public function getSerializerManager(): JWESerializerManager
|
||||
{
|
||||
return $this->serializerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to load and decrypt the given token using a JWK. If succeeded, the methods will populate the
|
||||
* $recipient variable and returns the JWE.
|
||||
*/
|
||||
public function loadAndDecryptWithKey(string $token, JWK $key, ?int &$recipient): JWE
|
||||
{
|
||||
$keyset = new JWKSet([$key]);
|
||||
|
||||
return $this->loadAndDecryptWithKeySet($token, $keyset, $recipient);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to load and decrypt the given token using a JWKSet. If succeeded, the methods will populate
|
||||
* the $recipient variable and returns the JWE.
|
||||
*/
|
||||
public function loadAndDecryptWithKeySet(string $token, JWKSet $keyset, ?int &$recipient): JWE
|
||||
{
|
||||
try {
|
||||
$jwe = $this->serializerManager->unserialize($token);
|
||||
$nbRecipients = $jwe->countRecipients();
|
||||
for ($i = 0; $i < $nbRecipients; ++$i) {
|
||||
if ($this->processRecipient($jwe, $keyset, $i)) {
|
||||
$recipient = $i;
|
||||
|
||||
return $jwe;
|
||||
}
|
||||
}
|
||||
} catch (Throwable) {
|
||||
// Nothing to do. Exception thrown just after
|
||||
}
|
||||
|
||||
throw new RuntimeException('Unable to load and decrypt the token.');
|
||||
}
|
||||
|
||||
private function processRecipient(JWE &$jwe, JWKSet $keyset, int $recipient): bool
|
||||
{
|
||||
try {
|
||||
if ($this->headerCheckerManager !== null) {
|
||||
$this->headerCheckerManager->check($jwe, $recipient);
|
||||
}
|
||||
|
||||
return $this->jweDecrypter->decryptUsingKeySet($jwe, $keyset, $recipient);
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
libraries/vendor/web-token/jwt-library/Encryption/JWELoaderFactory.php
vendored
Normal file
43
libraries/vendor/web-token/jwt-library/Encryption/JWELoaderFactory.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use Jose\Component\Checker\HeaderCheckerManagerFactory;
|
||||
use Jose\Component\Encryption\Serializer\JWESerializerManagerFactory;
|
||||
|
||||
class JWELoaderFactory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly JWESerializerManagerFactory $jweSerializerManagerFactory,
|
||||
private readonly JWEDecrypterFactory $jweDecrypterFactory,
|
||||
private readonly ?HeaderCheckerManagerFactory $headerCheckerManagerFactory
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JWELoader using the given serializer aliases, encryption algorithm aliases, compression method aliases
|
||||
* and header checker aliases.
|
||||
*/
|
||||
public function create(
|
||||
array $serializers,
|
||||
array $encryptionAlgorithms,
|
||||
null|array $contentEncryptionAlgorithms = null,
|
||||
null|array $compressionMethods = null,
|
||||
array $headerCheckers = []
|
||||
): JWELoader {
|
||||
if ($contentEncryptionAlgorithms !== null) {
|
||||
$encryptionAlgorithms = array_merge($encryptionAlgorithms, $contentEncryptionAlgorithms);
|
||||
}
|
||||
$serializerManager = $this->jweSerializerManagerFactory->create($serializers);
|
||||
$jweDecrypter = $this->jweDecrypterFactory->create($encryptionAlgorithms, null, $compressionMethods);
|
||||
if ($this->headerCheckerManagerFactory !== null) {
|
||||
$headerCheckerManager = $this->headerCheckerManagerFactory->create($headerCheckers);
|
||||
} else {
|
||||
$headerCheckerManager = null;
|
||||
}
|
||||
|
||||
return new JWELoader($serializerManager, $jweDecrypter, $headerCheckerManager);
|
||||
}
|
||||
}
|
||||
33
libraries/vendor/web-token/jwt-library/Encryption/JWETokenSupport.php
vendored
Normal file
33
libraries/vendor/web-token/jwt-library/Encryption/JWETokenSupport.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use Jose\Component\Checker\TokenTypeSupport;
|
||||
use Jose\Component\Core\JWT;
|
||||
|
||||
final class JWETokenSupport implements TokenTypeSupport
|
||||
{
|
||||
public function supports(JWT $jwt): bool
|
||||
{
|
||||
return $jwt instanceof JWE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $protectedHeader
|
||||
* @param array<string, mixed> $unprotectedHeader
|
||||
*/
|
||||
public function retrieveTokenHeaders(JWT $jwt, int $index, array &$protectedHeader, array &$unprotectedHeader): void
|
||||
{
|
||||
if (! $jwt instanceof JWE) {
|
||||
return;
|
||||
}
|
||||
$protectedHeader = $jwt->getSharedProtectedHeader();
|
||||
$unprotectedHeader = $jwt->getSharedHeader();
|
||||
$recipient = $jwt->getRecipient($index)
|
||||
->getHeader();
|
||||
|
||||
$unprotectedHeader = array_merge($unprotectedHeader, $recipient);
|
||||
}
|
||||
}
|
||||
62
libraries/vendor/web-token/jwt-library/Encryption/Recipient.php
vendored
Normal file
62
libraries/vendor/web-token/jwt-library/Encryption/Recipient.php
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Recipient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly array $header,
|
||||
private readonly ?string $encryptedKey
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recipient header.
|
||||
*/
|
||||
public function getHeader(): array
|
||||
{
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the recipient header parameter with the specified key.
|
||||
*
|
||||
* @param string $key The key
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getHeaderParameter(string $key)
|
||||
{
|
||||
if (! $this->hasHeaderParameter($key)) {
|
||||
throw new InvalidArgumentException(sprintf('The header "%s" does not exist.', $key));
|
||||
}
|
||||
|
||||
return $this->header[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the recipient header contains the parameter with the specified key.
|
||||
*
|
||||
* @param string $key The key
|
||||
*/
|
||||
public function hasHeaderParameter(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encrypted key.
|
||||
*/
|
||||
public function getEncryptedKey(): ?string
|
||||
{
|
||||
return $this->encryptedKey;
|
||||
}
|
||||
}
|
||||
111
libraries/vendor/web-token/jwt-library/Encryption/Serializer/CompactSerializer.php
vendored
Normal file
111
libraries/vendor/web-token/jwt-library/Encryption/Serializer/CompactSerializer.php
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Serializer;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use Jose\Component\Core\Util\JsonConverter;
|
||||
use Jose\Component\Encryption\JWE;
|
||||
use Jose\Component\Encryption\Recipient;
|
||||
use LogicException;
|
||||
use Throwable;
|
||||
use function count;
|
||||
use function is_array;
|
||||
|
||||
final class CompactSerializer implements JWESerializer
|
||||
{
|
||||
public const NAME = 'jwe_compact';
|
||||
|
||||
public function displayName(): string
|
||||
{
|
||||
return 'JWE Compact';
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
public function serialize(JWE $jwe, ?int $recipientIndex = null): string
|
||||
{
|
||||
if ($recipientIndex === null) {
|
||||
$recipientIndex = 0;
|
||||
}
|
||||
$recipient = $jwe->getRecipient($recipientIndex);
|
||||
|
||||
$this->checkHasNoAAD($jwe);
|
||||
$this->checkHasSharedProtectedHeader($jwe);
|
||||
$this->checkRecipientHasNoHeader($jwe, $recipientIndex);
|
||||
|
||||
return sprintf(
|
||||
'%s.%s.%s.%s.%s',
|
||||
$jwe->getEncodedSharedProtectedHeader(),
|
||||
Base64UrlSafe::encodeUnpadded($recipient->getEncryptedKey() ?? ''),
|
||||
Base64UrlSafe::encodeUnpadded($jwe->getIV() ?? ''),
|
||||
Base64UrlSafe::encodeUnpadded($jwe->getCiphertext() ?? ''),
|
||||
Base64UrlSafe::encodeUnpadded($jwe->getTag() ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
public function unserialize(string $input): JWE
|
||||
{
|
||||
$parts = explode('.', $input);
|
||||
if (count($parts) !== 5) {
|
||||
throw new InvalidArgumentException('Unsupported input');
|
||||
}
|
||||
|
||||
try {
|
||||
$encodedSharedProtectedHeader = $parts[0];
|
||||
$sharedProtectedHeader = JsonConverter::decode(
|
||||
Base64UrlSafe::decodeNoPadding($encodedSharedProtectedHeader)
|
||||
);
|
||||
if (! is_array($sharedProtectedHeader)) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
$encryptedKey = $parts[1] === '' ? null : Base64UrlSafe::decodeNoPadding($parts[1]);
|
||||
$iv = Base64UrlSafe::decodeNoPadding($parts[2]);
|
||||
$ciphertext = Base64UrlSafe::decodeNoPadding($parts[3]);
|
||||
$tag = Base64UrlSafe::decodeNoPadding($parts[4]);
|
||||
|
||||
return new JWE(
|
||||
$ciphertext,
|
||||
$iv,
|
||||
$tag,
|
||||
null,
|
||||
[],
|
||||
$sharedProtectedHeader,
|
||||
$encodedSharedProtectedHeader,
|
||||
[new Recipient([], $encryptedKey)]
|
||||
);
|
||||
} catch (Throwable $throwable) {
|
||||
throw new InvalidArgumentException('Unsupported input', $throwable->getCode(), $throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private function checkHasNoAAD(JWE $jwe): void
|
||||
{
|
||||
if ($jwe->getAAD() !== null) {
|
||||
throw new LogicException('This JWE has AAD and cannot be converted into Compact JSON.');
|
||||
}
|
||||
}
|
||||
|
||||
private function checkRecipientHasNoHeader(JWE $jwe, int $id): void
|
||||
{
|
||||
if (count($jwe->getSharedHeader()) !== 0 || count($jwe->getRecipient($id)->getHeader()) !== 0) {
|
||||
throw new LogicException(
|
||||
'This JWE has shared header parameters or recipient header parameters and cannot be converted into Compact JSON.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function checkHasSharedProtectedHeader(JWE $jwe): void
|
||||
{
|
||||
if (count($jwe->getSharedProtectedHeader()) === 0) {
|
||||
throw new LogicException(
|
||||
'This JWE does not have shared protected header parameters and cannot be converted into Compact JSON.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
107
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JSONFlattenedSerializer.php
vendored
Normal file
107
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JSONFlattenedSerializer.php
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Serializer;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use Jose\Component\Core\Util\JsonConverter;
|
||||
use Jose\Component\Encryption\JWE;
|
||||
use Jose\Component\Encryption\Recipient;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function is_array;
|
||||
|
||||
final class JSONFlattenedSerializer implements JWESerializer
|
||||
{
|
||||
public const NAME = 'jwe_json_flattened';
|
||||
|
||||
public function displayName(): string
|
||||
{
|
||||
return 'JWE JSON Flattened';
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
public function serialize(JWE $jwe, ?int $recipientIndex = null): string
|
||||
{
|
||||
if ($recipientIndex === null) {
|
||||
$recipientIndex = 0;
|
||||
}
|
||||
$recipient = $jwe->getRecipient($recipientIndex);
|
||||
$data = [
|
||||
'ciphertext' => Base64UrlSafe::encodeUnpadded($jwe->getCiphertext() ?? ''),
|
||||
'iv' => Base64UrlSafe::encodeUnpadded($jwe->getIV() ?? ''),
|
||||
'tag' => Base64UrlSafe::encodeUnpadded($jwe->getTag() ?? ''),
|
||||
];
|
||||
if ($jwe->getAAD() !== null) {
|
||||
$data['aad'] = Base64UrlSafe::encodeUnpadded($jwe->getAAD());
|
||||
}
|
||||
if (count($jwe->getSharedProtectedHeader()) !== 0) {
|
||||
$data['protected'] = $jwe->getEncodedSharedProtectedHeader();
|
||||
}
|
||||
if (count($jwe->getSharedHeader()) !== 0) {
|
||||
$data['unprotected'] = $jwe->getSharedHeader();
|
||||
}
|
||||
if (count($recipient->getHeader()) !== 0) {
|
||||
$data['header'] = $recipient->getHeader();
|
||||
}
|
||||
if ($recipient->getEncryptedKey() !== null) {
|
||||
$data['encrypted_key'] = Base64UrlSafe::encodeUnpadded($recipient->getEncryptedKey());
|
||||
}
|
||||
|
||||
return JsonConverter::encode($data);
|
||||
}
|
||||
|
||||
public function unserialize(string $input): JWE
|
||||
{
|
||||
$data = JsonConverter::decode($input);
|
||||
if (! is_array($data)) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
$this->checkData($data);
|
||||
|
||||
$ciphertext = Base64UrlSafe::decodeNoPadding($data['ciphertext']);
|
||||
$iv = Base64UrlSafe::decodeNoPadding($data['iv']);
|
||||
$tag = Base64UrlSafe::decodeNoPadding($data['tag']);
|
||||
$aad = array_key_exists('aad', $data) ? Base64UrlSafe::decodeNoPadding($data['aad']) : null;
|
||||
[$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader] = $this->processHeaders($data);
|
||||
$encryptedKey = array_key_exists('encrypted_key', $data) ? Base64UrlSafe::decodeNoPadding(
|
||||
$data['encrypted_key']
|
||||
) : null;
|
||||
$header = array_key_exists('header', $data) ? $data['header'] : [];
|
||||
|
||||
return new JWE(
|
||||
$ciphertext,
|
||||
$iv,
|
||||
$tag,
|
||||
$aad,
|
||||
$sharedHeader,
|
||||
$sharedProtectedHeader,
|
||||
$encodedSharedProtectedHeader,
|
||||
[new Recipient($header, $encryptedKey)]
|
||||
);
|
||||
}
|
||||
|
||||
private function checkData(?array $data): void
|
||||
{
|
||||
if ($data === null || ! isset($data['ciphertext']) || isset($data['recipients'])) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
}
|
||||
|
||||
private function processHeaders(array $data): array
|
||||
{
|
||||
$encodedSharedProtectedHeader = array_key_exists('protected', $data) ? $data['protected'] : null;
|
||||
$sharedProtectedHeader = $encodedSharedProtectedHeader ? JsonConverter::decode(
|
||||
Base64UrlSafe::decodeNoPadding($encodedSharedProtectedHeader)
|
||||
) : [];
|
||||
$sharedHeader = $data['unprotected'] ?? [];
|
||||
|
||||
return [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader];
|
||||
}
|
||||
}
|
||||
124
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JSONGeneralSerializer.php
vendored
Normal file
124
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JSONGeneralSerializer.php
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Serializer;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\Util\Base64UrlSafe;
|
||||
use Jose\Component\Core\Util\JsonConverter;
|
||||
use Jose\Component\Encryption\JWE;
|
||||
use Jose\Component\Encryption\Recipient;
|
||||
use LogicException;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function is_array;
|
||||
|
||||
final class JSONGeneralSerializer implements JWESerializer
|
||||
{
|
||||
public const NAME = 'jwe_json_general';
|
||||
|
||||
public function displayName(): string
|
||||
{
|
||||
return 'JWE JSON General';
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
public function serialize(JWE $jwe, ?int $recipientIndex = null): string
|
||||
{
|
||||
if ($jwe->countRecipients() === 0) {
|
||||
throw new LogicException('No recipient.');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'ciphertext' => Base64UrlSafe::encodeUnpadded($jwe->getCiphertext() ?? ''),
|
||||
'iv' => Base64UrlSafe::encodeUnpadded($jwe->getIV() ?? ''),
|
||||
'tag' => Base64UrlSafe::encodeUnpadded($jwe->getTag() ?? ''),
|
||||
];
|
||||
if ($jwe->getAAD() !== null) {
|
||||
$data['aad'] = Base64UrlSafe::encodeUnpadded($jwe->getAAD());
|
||||
}
|
||||
if (count($jwe->getSharedProtectedHeader()) !== 0) {
|
||||
$data['protected'] = $jwe->getEncodedSharedProtectedHeader();
|
||||
}
|
||||
if (count($jwe->getSharedHeader()) !== 0) {
|
||||
$data['unprotected'] = $jwe->getSharedHeader();
|
||||
}
|
||||
$data['recipients'] = [];
|
||||
foreach ($jwe->getRecipients() as $recipient) {
|
||||
$temp = [];
|
||||
if (count($recipient->getHeader()) !== 0) {
|
||||
$temp['header'] = $recipient->getHeader();
|
||||
}
|
||||
if ($recipient->getEncryptedKey() !== null) {
|
||||
$temp['encrypted_key'] = Base64UrlSafe::encodeUnpadded($recipient->getEncryptedKey());
|
||||
}
|
||||
$data['recipients'][] = $temp;
|
||||
}
|
||||
|
||||
return JsonConverter::encode($data);
|
||||
}
|
||||
|
||||
public function unserialize(string $input): JWE
|
||||
{
|
||||
$data = JsonConverter::decode($input);
|
||||
if (! is_array($data)) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
$this->checkData($data);
|
||||
|
||||
$ciphertext = Base64UrlSafe::decodeNoPadding($data['ciphertext']);
|
||||
$iv = Base64UrlSafe::decodeNoPadding($data['iv']);
|
||||
$tag = Base64UrlSafe::decodeNoPadding($data['tag']);
|
||||
$aad = array_key_exists('aad', $data) ? Base64UrlSafe::decodeNoPadding($data['aad']) : null;
|
||||
[$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader] = $this->processHeaders($data);
|
||||
$recipients = [];
|
||||
foreach ($data['recipients'] as $recipient) {
|
||||
[$encryptedKey, $header] = $this->processRecipient($recipient);
|
||||
$recipients[] = new Recipient($header, $encryptedKey);
|
||||
}
|
||||
|
||||
return new JWE(
|
||||
$ciphertext,
|
||||
$iv,
|
||||
$tag,
|
||||
$aad,
|
||||
$sharedHeader,
|
||||
$sharedProtectedHeader,
|
||||
$encodedSharedProtectedHeader,
|
||||
$recipients
|
||||
);
|
||||
}
|
||||
|
||||
private function checkData(?array $data): void
|
||||
{
|
||||
if ($data === null || ! isset($data['ciphertext']) || ! isset($data['recipients'])) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
}
|
||||
|
||||
private function processRecipient(array $recipient): array
|
||||
{
|
||||
$encryptedKey = array_key_exists('encrypted_key', $recipient) ? Base64UrlSafe::decodeNoPadding(
|
||||
$recipient['encrypted_key']
|
||||
) : null;
|
||||
$header = array_key_exists('header', $recipient) ? $recipient['header'] : [];
|
||||
|
||||
return [$encryptedKey, $header];
|
||||
}
|
||||
|
||||
private function processHeaders(array $data): array
|
||||
{
|
||||
$encodedSharedProtectedHeader = array_key_exists('protected', $data) ? $data['protected'] : null;
|
||||
$sharedProtectedHeader = $encodedSharedProtectedHeader ? JsonConverter::decode(
|
||||
Base64UrlSafe::decodeNoPadding($encodedSharedProtectedHeader)
|
||||
) : [];
|
||||
$sharedHeader = array_key_exists('unprotected', $data) ? $data['unprotected'] : [];
|
||||
|
||||
return [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader];
|
||||
}
|
||||
}
|
||||
33
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JWESerializer.php
vendored
Normal file
33
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JWESerializer.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Serializer;
|
||||
|
||||
use Jose\Component\Encryption\JWE;
|
||||
|
||||
interface JWESerializer
|
||||
{
|
||||
/**
|
||||
* The name of the serialization method.
|
||||
*/
|
||||
public function name(): string;
|
||||
|
||||
/**
|
||||
* Display name of the serialization method.
|
||||
*/
|
||||
public function displayName(): string;
|
||||
|
||||
/**
|
||||
* Converts a JWE into a string. If the JWE is designed for multiple recipients and the serializer only supports one
|
||||
* recipient, the recipient index has to be set.
|
||||
*/
|
||||
public function serialize(JWE $jws, ?int $recipientIndex = null): string;
|
||||
|
||||
/**
|
||||
* Loads data and return a JWE object. Throws an exception in case of failure.
|
||||
*
|
||||
* @param string $input A string that represents a JWE
|
||||
*/
|
||||
public function unserialize(string $input): JWE;
|
||||
}
|
||||
78
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JWESerializerManager.php
vendored
Normal file
78
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JWESerializerManager.php
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Serializer;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Encryption\JWE;
|
||||
|
||||
class JWESerializerManager
|
||||
{
|
||||
/**
|
||||
* @var JWESerializer[]
|
||||
*/
|
||||
private array $serializers = [];
|
||||
|
||||
/**
|
||||
* @param JWESerializer[] $serializers
|
||||
*/
|
||||
public function __construct(iterable $serializers)
|
||||
{
|
||||
foreach ($serializers as $serializer) {
|
||||
$this->add($serializer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serializer names supported by the manager.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function names(): array
|
||||
{
|
||||
return array_keys($this->serializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JWE into a string. Throws an exception if none of the serializer was able to convert the input.
|
||||
*/
|
||||
public function serialize(string $name, JWE $jws, ?int $recipientIndex = null): string
|
||||
{
|
||||
if (! isset($this->serializers[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name));
|
||||
}
|
||||
|
||||
return $this->serializers[$name]->serialize($jws, $recipientIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads data and return a JWE object. Throws an exception if none of the serializer was able to convert the input.
|
||||
*
|
||||
* @param string $input A string that represents a JWE
|
||||
* @param string|null $name the name of the serializer if the input is unserialized
|
||||
*/
|
||||
public function unserialize(string $input, ?string &$name = null): JWE
|
||||
{
|
||||
foreach ($this->serializers as $serializer) {
|
||||
try {
|
||||
$jws = $serializer->unserialize($input);
|
||||
$name = $serializer->name();
|
||||
|
||||
return $jws;
|
||||
} catch (InvalidArgumentException) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a serializer to the manager.
|
||||
*/
|
||||
private function add(JWESerializer $serializer): void
|
||||
{
|
||||
$this->serializers[$serializer->name()] = $serializer;
|
||||
}
|
||||
}
|
||||
61
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JWESerializerManagerFactory.php
vendored
Normal file
61
libraries/vendor/web-token/jwt-library/Encryption/Serializer/JWESerializerManagerFactory.php
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Encryption\Serializer;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class JWESerializerManagerFactory
|
||||
{
|
||||
/**
|
||||
* @var JWESerializer[]
|
||||
*/
|
||||
private array $serializers = [];
|
||||
|
||||
/**
|
||||
* Creates a serializer manager factory using the given serializers.
|
||||
*
|
||||
* @param string[] $names
|
||||
*/
|
||||
public function create(array $names): JWESerializerManager
|
||||
{
|
||||
$serializers = [];
|
||||
foreach ($names as $name) {
|
||||
if (! isset($this->serializers[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name));
|
||||
}
|
||||
$serializers[] = $this->serializers[$name];
|
||||
}
|
||||
|
||||
return new JWESerializerManager($serializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serializer names supported by the manager.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function names(): array
|
||||
{
|
||||
return array_keys($this->serializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all serializers supported by this factory.
|
||||
*
|
||||
* @return JWESerializer[]
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->serializers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a serializer to the manager.
|
||||
*/
|
||||
public function add(JWESerializer $serializer): void
|
||||
{
|
||||
$this->serializers[$serializer->name()] = $serializer;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user