Spomky-Labs /
jose
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /* |
||
| 4 | * The MIT License (MIT) |
||
| 5 | * |
||
| 6 | * Copyright (c) 2014-2016 Spomky-Labs |
||
| 7 | * |
||
| 8 | * This software may be modified and distributed under the terms |
||
| 9 | * of the MIT license. See the LICENSE file for details. |
||
| 10 | */ |
||
| 11 | |||
| 12 | namespace Jose\Behaviour; |
||
| 13 | |||
| 14 | use Assert\Assertion; |
||
| 15 | use Base64Url\Base64Url; |
||
| 16 | use Jose\Algorithm; |
||
| 17 | use Jose\Compression; |
||
| 18 | use Jose\Object; |
||
| 19 | |||
| 20 | trait EncrypterTrait |
||
| 21 | { |
||
| 22 | /** |
||
| 23 | * @param \Jose\Object\JWEInterface $jwe |
||
| 24 | * @param null $content_encryption_algorithm |
||
| 25 | * @param null $compression_method |
||
| 26 | * @param null $key_management_mode |
||
| 27 | * @param null $cek |
||
| 28 | * @param array $additional_headers |
||
| 29 | */ |
||
| 30 | private function prepareEncryptionProcess(Object\JWEInterface &$jwe, &$content_encryption_algorithm, &$compression_method, &$key_management_mode, &$cek, array &$additional_headers) |
||
| 31 | { |
||
| 32 | $content_encryption_algorithm = $this->getContentEncryptionAlgorithm($jwe); |
||
| 33 | $compression_method = $this->getCompressionMethod($jwe); |
||
| 34 | $key_management_mode = $this->getKeyManagementMode($jwe); |
||
| 35 | $cek = $this->determineCEK($jwe, $content_encryption_algorithm, $key_management_mode, $additional_headers); |
||
| 36 | } |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @param \Jose\Object\JWEInterface $jwe |
||
| 40 | * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm |
||
| 41 | * @param string $key_management_mode |
||
| 42 | * @param array $additional_headers |
||
| 43 | * |
||
| 44 | * @return string |
||
| 45 | */ |
||
| 46 | private function determineCEK(Object\JWEInterface $jwe, Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm, $key_management_mode, array &$additional_headers) |
||
| 47 | { |
||
| 48 | switch ($key_management_mode) { |
||
| 49 | case Algorithm\KeyEncryption\KeyEncryptionInterface::MODE_ENCRYPT: |
||
| 50 | case Algorithm\KeyEncryption\KeyEncryptionInterface::MODE_WRAP: |
||
| 51 | return $this->createCEK($content_encryption_algorithm->getCEKSize()); |
||
| 52 | case Algorithm\KeyEncryption\KeyEncryptionInterface::MODE_AGREEMENT: |
||
| 53 | Assertion::eq(1, $jwe->countRecipients(), 'Unable to encrypt for multiple recipients using key agreement algorithms.'); |
||
| 54 | $complete_headers = array_merge($jwe->getSharedProtectedHeaders(), $jwe->getSharedHeaders(), $jwe->getRecipient(0)->getHeaders()); |
||
| 55 | $algorithm = $this->findKeyEncryptionAlgorithm($complete_headers); |
||
|
0 ignored issues
–
show
|
|||
| 56 | |||
| 57 | return $algorithm->getAgreementKey($content_encryption_algorithm->getCEKSize(), $content_encryption_algorithm->getAlgorithmName(), $jwe->getRecipient(0)->getRecipientKey(), $complete_headers, $additional_headers); |
||
| 58 | case Algorithm\KeyEncryption\KeyEncryptionInterface::MODE_DIRECT: |
||
| 59 | Assertion::eq(1, $jwe->countRecipients(), 'Unable to encrypt for multiple recipients using key agreement algorithms.'); |
||
| 60 | Assertion::eq($jwe->getRecipient(0)->getRecipientKey()->get('kty'), 'oct', 'Wrong key type.'); |
||
| 61 | Assertion::true($jwe->getRecipient(0)->getRecipientKey()->has('k'), 'The key parameter "k" is missing.'); |
||
| 62 | |||
| 63 | return Base64Url::decode($jwe->getRecipient(0)->getRecipientKey()->get('k')); |
||
| 64 | default: |
||
| 65 | throw new \InvalidArgumentException(sprintf('Unsupported key management mode "%s".', $key_management_mode)); |
||
| 66 | } |
||
| 67 | } |
||
| 68 | |||
| 69 | /** |
||
| 70 | * @param \Jose\Object\JWEInterface $jwe |
||
| 71 | * |
||
| 72 | * @return string |
||
| 73 | */ |
||
| 74 | private function getKeyManagementMode(Object\JWEInterface $jwe) |
||
| 75 | { |
||
| 76 | $mode = null; |
||
| 77 | $recipients = $jwe->getRecipients(); |
||
| 78 | |||
| 79 | foreach ($recipients as $recipient) { |
||
| 80 | $complete_headers = array_merge($jwe->getSharedProtectedHeaders(), $jwe->getSharedHeaders(), $recipient->getHeaders()); |
||
| 81 | Assertion::keyExists($complete_headers, 'alg', 'Parameter "alg" is missing.'); |
||
| 82 | |||
| 83 | $key_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']); |
||
|
0 ignored issues
–
show
It seems like
getJWAManager() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the Loading history...
|
|||
| 84 | Assertion::isInstanceOf($key_encryption_algorithm, Algorithm\KeyEncryptionAlgorithmInterface::class, sprintf('The key encryption algorithm "%s" is not supported or not a key encryption algorithm instance.', $complete_headers['alg'])); |
||
| 85 | |||
| 86 | if (null === $mode) { |
||
| 87 | $mode = $key_encryption_algorithm->getKeyManagementMode(); |
||
| 88 | } else { |
||
| 89 | Assertion::true($this->areKeyManagementModesCompatible($mode, $key_encryption_algorithm->getKeyManagementMode()), 'Foreign key management mode forbidden.'); |
||
| 90 | } |
||
| 91 | } |
||
| 92 | |||
| 93 | return $mode; |
||
| 94 | } |
||
| 95 | |||
| 96 | /** |
||
| 97 | * @param \Jose\Object\JWEInterface $jwe |
||
| 98 | * |
||
| 99 | * @return \Jose\Compression\CompressionInterface|null |
||
| 100 | */ |
||
| 101 | private function getCompressionMethod(Object\JWEInterface $jwe) |
||
| 102 | { |
||
| 103 | $method = null; |
||
| 104 | $nb_recipients = $jwe->countRecipients(); |
||
| 105 | |||
| 106 | for ($i = 0; $i < $nb_recipients; $i++) { |
||
| 107 | $complete_headers = array_merge($jwe->getSharedProtectedHeaders(), $jwe->getSharedHeaders(), $jwe->getRecipient($i)->getHeaders()); |
||
| 108 | if (array_key_exists('zip', $complete_headers)) { |
||
| 109 | if (null === $method) { |
||
| 110 | if (0 === $i) { |
||
| 111 | $method = $complete_headers['zip']; |
||
| 112 | } else { |
||
| 113 | throw new \InvalidArgumentException('Inconsistent "zip" parameter.'); |
||
| 114 | } |
||
| 115 | } else { |
||
| 116 | Assertion::eq($method, $complete_headers['zip'], 'Inconsistent "zip" parameter.'); |
||
| 117 | } |
||
| 118 | } else { |
||
| 119 | Assertion::eq(null, $method, 'Inconsistent "zip" parameter.'); |
||
| 120 | } |
||
| 121 | } |
||
| 122 | |||
| 123 | if (null === $method) { |
||
| 124 | return; |
||
| 125 | } |
||
| 126 | |||
| 127 | $compression_method = $this->getCompressionManager()->getCompressionAlgorithm($method); |
||
|
0 ignored issues
–
show
It seems like
getCompressionManager() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the Loading history...
|
|||
| 128 | Assertion::isInstanceOf($compression_method, Compression\CompressionInterface::class, sprintf('Compression method "%s" not supported.', $method)); |
||
| 129 | |||
| 130 | return $compression_method; |
||
| 131 | } |
||
| 132 | |||
| 133 | /** |
||
| 134 | * @param \Jose\Object\JWEInterface $jwe |
||
| 135 | * |
||
| 136 | * @return \Jose\Algorithm\ContentEncryptionAlgorithmInterface |
||
| 137 | */ |
||
| 138 | private function getContentEncryptionAlgorithm(Object\JWEInterface $jwe) |
||
| 139 | { |
||
| 140 | $algorithm = null; |
||
| 141 | |||
| 142 | foreach ($jwe->getRecipients() as $recipient) { |
||
| 143 | $complete_headers = array_merge($jwe->getSharedProtectedHeaders(), $jwe->getSharedHeaders(), $recipient->getHeaders()); |
||
| 144 | Assertion::keyExists($complete_headers, 'enc', 'Parameter "enc" is missing.'); |
||
| 145 | if (null === $algorithm) { |
||
| 146 | $algorithm = $complete_headers['enc']; |
||
| 147 | } else { |
||
| 148 | Assertion::eq($algorithm, $complete_headers['enc'], 'Foreign content encryption algorithms are not allowed.'); |
||
| 149 | } |
||
| 150 | } |
||
| 151 | |||
| 152 | $content_encryption_algorithm = $this->getJWAManager()->getAlgorithm($algorithm); |
||
|
0 ignored issues
–
show
It seems like
getJWAManager() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the Loading history...
|
|||
| 153 | Assertion::isInstanceOf($content_encryption_algorithm, Algorithm\ContentEncryptionAlgorithmInterface::class, sprintf('The content encryption algorithm "%s" is not supported or not a content encryption algorithm instance.', $algorithm)); |
||
| 154 | |||
| 155 | return $content_encryption_algorithm; |
||
| 156 | } |
||
| 157 | |||
| 158 | /** |
||
| 159 | * @param string $current |
||
| 160 | * @param string $new |
||
| 161 | * |
||
| 162 | * @return bool |
||
| 163 | */ |
||
| 164 | private function areKeyManagementModesCompatible($current, $new) |
||
| 165 | { |
||
| 166 | $agree = Algorithm\KeyEncryptionAlgorithmInterface::MODE_AGREEMENT; |
||
| 167 | $dir = Algorithm\KeyEncryptionAlgorithmInterface::MODE_DIRECT; |
||
| 168 | $enc = Algorithm\KeyEncryptionAlgorithmInterface::MODE_ENCRYPT; |
||
| 169 | $wrap = Algorithm\KeyEncryptionAlgorithmInterface::MODE_WRAP; |
||
| 170 | $supported_key_management_mode_combinations = [$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,]; |
||
| 171 | |||
| 172 | if (array_key_exists($current.$new, $supported_key_management_mode_combinations)) { |
||
| 173 | return $supported_key_management_mode_combinations[$current.$new]; |
||
| 174 | } |
||
| 175 | |||
| 176 | return false; |
||
| 177 | } |
||
| 178 | |||
| 179 | /** |
||
| 180 | * @param int $size |
||
| 181 | * |
||
| 182 | * @return string |
||
| 183 | */ |
||
| 184 | private function createCEK($size) |
||
| 185 | { |
||
| 186 | return random_bytes($size / 8); |
||
| 187 | } |
||
| 188 | } |
||
| 189 |
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idableprovides a methodequalsIdthat in turn relies on the methodgetId(). If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()as an abstract method to the trait will make sure it is available.