619 lines
22 KiB
PHP
619 lines
22 KiB
PHP
<?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))
|
|
));
|
|
}
|
|
}
|
|
}
|