3 declare(strict_types=1);
5 namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
7 use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
8 use ParagonIE\ConstantTime\Base64UrlSafe;
10 use function extension_loaded;
11 use const OPENSSL_RAW_DATA;
13 abstract class AESCBCHS implements ContentEncryptionAlgorithm
15 public function __construct()
17 if (! extension_loaded('openssl')) {
18 throw new RuntimeException('Please install the OpenSSL extension');
22 public function allowedKeyTypes(): array
24 return []; //Irrelevant
27 public function encryptContent(
32 string $encoded_protected_header,
35 $k = mb_substr($cek, $this->getCEKSize() / 16, null, '8bit');
36 $result = openssl_encrypt($data, $this->getMode(), $k, OPENSSL_RAW_DATA, $iv);
37 if ($result === false) {
38 throw new RuntimeException('Unable to encrypt the content');
41 $tag = $this->calculateAuthenticationTag($result, $cek, $iv, $aad, $encoded_protected_header);
46 public function decryptContent(
51 string $encoded_protected_header,
54 if (! $this->isTagValid($data, $cek, $iv, $aad, $encoded_protected_header, $tag)) {
55 throw new RuntimeException('Unable to decrypt or to verify the tag.');
57 $k = mb_substr($cek, $this->getCEKSize() / 16, null, '8bit');
59 $result = openssl_decrypt($data, $this->getMode(), $k, OPENSSL_RAW_DATA, $iv);
60 if ($result === false) {
61 throw new RuntimeException('Unable to decrypt or to verify the tag.');
67 public function getIVSize(): int
72 protected function calculateAuthenticationTag(
73 string $encrypted_data,
77 string $encoded_header
79 $calculated_aad = $encoded_header;
81 $calculated_aad .= '.' . Base64UrlSafe::encodeUnpadded($aad);
83 $mac_key = mb_substr($cek, 0, $this->getCEKSize() / 16, '8bit');
84 $auth_data_length = mb_strlen($encoded_header, '8bit');
86 $secured_input = implode('', [
90 pack('N2', ($auth_data_length / 2_147_483_647) * 8, ($auth_data_length % 2_147_483_647) * 8),
92 $hash = hash_hmac($this->getHashAlgorithm(), $secured_input, $mac_key, true);
94 return mb_substr($hash, 0, mb_strlen($hash, '8bit') / 2, '8bit');
97 protected function isTagValid(
98 string $encrypted_data,
102 string $encoded_header,
103 string $authentication_tag
107 $this->calculateAuthenticationTag($encrypted_data, $cek, $iv, $aad, $encoded_header)
111 abstract protected function getHashAlgorithm(): string;
113 abstract protected function getMode(): string;