| 1 | <?php |
||
| 22 | abstract class RSAESKeyAlgorithm extends KeyManagementAlgorithm |
||
| 23 | { |
||
| 24 | use RandomCEK; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * Mapping from algorithm name to class name. |
||
| 28 | * |
||
| 29 | * @internal |
||
| 30 | * |
||
| 31 | * @var array |
||
| 32 | */ |
||
| 33 | const MAP_ALGO_TO_CLASS = [ |
||
| 34 | JWA::ALGO_RSA1_5 => RSAESPKCS1Algorithm::class, |
||
| 35 | JWA::ALGO_RSA_OAEP => RSAESOAEPAlgorithm::class, |
||
| 36 | ]; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * Public key. |
||
| 40 | * |
||
| 41 | * @var RSAPublicKeyJWK |
||
| 42 | */ |
||
| 43 | protected $_publicKey; |
||
| 44 | |||
| 45 | /** |
||
| 46 | * Private key. |
||
| 47 | * |
||
| 48 | * @var null|RSAPrivateKeyJWK |
||
| 49 | */ |
||
| 50 | protected $_privateKey; |
||
| 51 | |||
| 52 | /** |
||
| 53 | * Constructor. |
||
| 54 | * |
||
| 55 | * Use <code>fromPublicKey</code> or <code>fromPrivateKey</code> instead! |
||
| 56 | * |
||
| 57 | * @param RSAPublicKeyJWK $pub_key RSA public key |
||
| 58 | * @param RSAPrivateKeyJWK $priv_key Optional RSA private key |
||
| 59 | */ |
||
| 60 | 18 | protected function __construct(RSAPublicKeyJWK $pub_key, |
|
| 61 | ?RSAPrivateKeyJWK $priv_key = null) |
||
| 62 | { |
||
| 63 | 18 | $this->_publicKey = $pub_key; |
|
| 64 | 18 | $this->_privateKey = $priv_key; |
|
| 65 | 18 | } |
|
| 66 | |||
| 67 | /** |
||
| 68 | * Initialize from JWK. |
||
| 69 | * |
||
| 70 | * @param JWK $jwk |
||
| 71 | * @param Header $header |
||
| 72 | * |
||
| 73 | * @throws \UnexpectedValueException |
||
| 74 | * |
||
| 75 | * @return self |
||
| 76 | */ |
||
| 77 | 3 | public static function fromJWK(JWK $jwk, Header $header): KeyManagementAlgorithm |
|
| 78 | { |
||
| 79 | 3 | $alg = JWA::deriveAlgorithmName($header, $jwk); |
|
| 80 | 3 | if (!array_key_exists($alg, self::MAP_ALGO_TO_CLASS)) { |
|
| 81 | 1 | throw new \UnexpectedValueException("Unsupported algorithm '{$alg}'."); |
|
| 82 | } |
||
| 83 | 2 | $cls = self::MAP_ALGO_TO_CLASS[$alg]; |
|
| 84 | 2 | if ($jwk->has(...RSAPrivateKeyJWK::MANAGED_PARAMS)) { |
|
| 85 | 1 | return $cls::fromPrivateKey(RSAPrivateKeyJWK::fromJWK($jwk)); |
|
| 86 | } |
||
| 87 | 1 | return $cls::fromPublicKey(RSAPublicKeyJWK::fromJWK($jwk)); |
|
| 88 | } |
||
| 89 | |||
| 90 | /** |
||
| 91 | * Initialize from a public key. |
||
| 92 | * |
||
| 93 | * @param RSAPublicKeyJWK $jwk |
||
| 94 | * |
||
| 95 | * @return self |
||
| 96 | */ |
||
| 97 | 3 | public static function fromPublicKey(RSAPublicKeyJWK $jwk): self |
|
| 98 | { |
||
| 99 | 3 | return new static($jwk); |
|
| 100 | } |
||
| 101 | |||
| 102 | /** |
||
| 103 | * Initialize from a private key. |
||
| 104 | * |
||
| 105 | * @param RSAPrivateKeyJWK $jwk |
||
| 106 | * |
||
| 107 | * @return self |
||
| 108 | */ |
||
| 109 | 15 | public static function fromPrivateKey(RSAPrivateKeyJWK $jwk): self |
|
| 112 | } |
||
| 113 | |||
| 114 | /** |
||
| 115 | * Get the public key. |
||
| 116 | * |
||
| 117 | * @return RSAPublicKeyJWK |
||
| 118 | */ |
||
| 119 | 11 | public function publicKey(): RSAPublicKeyJWK |
|
| 120 | { |
||
| 121 | 11 | return $this->_publicKey; |
|
| 122 | } |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Check whether the private key is present. |
||
| 126 | * |
||
| 127 | * @return bool |
||
| 128 | */ |
||
| 129 | 13 | public function hasPrivateKey(): bool |
|
| 130 | { |
||
| 131 | 13 | return isset($this->_privateKey); |
|
| 132 | } |
||
| 133 | |||
| 134 | /** |
||
| 135 | * Get the private key. |
||
| 136 | * |
||
| 137 | * @throws \LogicException |
||
| 138 | * |
||
| 139 | * @return RSAPrivateKeyJWK |
||
| 140 | */ |
||
| 141 | 12 | public function privateKey(): RSAPrivateKeyJWK |
|
| 142 | { |
||
| 143 | 12 | if (!$this->hasPrivateKey()) { |
|
| 144 | 1 | throw new \LogicException('Private key not set.'); |
|
| 145 | } |
||
| 146 | 11 | return $this->_privateKey; |
|
|
1 ignored issue
–
show
|
|||
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * {@inheritdoc} |
||
| 151 | */ |
||
| 152 | 3 | public function headerParameters(): array |
|
| 153 | { |
||
| 154 | 3 | return array_merge(parent::headerParameters(), |
|
| 155 | 3 | [AlgorithmParameter::fromAlgorithm($this)]); |
|
| 156 | } |
||
| 157 | |||
| 158 | /** |
||
| 159 | * Get the padding scheme. |
||
| 160 | * |
||
| 161 | * @return int |
||
| 162 | */ |
||
| 163 | abstract protected function _paddingScheme(): int; |
||
| 164 | |||
| 165 | /** |
||
| 166 | * {@inheritdoc} |
||
| 167 | */ |
||
| 168 | 10 | protected function _encryptKey(string $key, Header &$header): string |
|
| 169 | { |
||
| 170 | 10 | $pubkey = openssl_pkey_get_public( |
|
| 171 | 10 | $this->publicKey()->toPEM()->string()); |
|
| 172 | 10 | if (false === $pubkey) { |
|
| 173 | 1 | throw new \RuntimeException( |
|
| 174 | 'openssl_pkey_get_public() failed: ' . |
||
| 175 | 1 | $this->_getLastOpenSSLError()); |
|
| 176 | } |
||
| 177 | 9 | $result = openssl_public_encrypt($key, $crypted, $pubkey, |
|
| 178 | 9 | $this->_paddingScheme()); |
|
| 179 | 9 | if (!$result) { |
|
| 180 | 1 | throw new \RuntimeException( |
|
| 181 | 'openssl_public_encrypt() failed: ' . |
||
| 182 | 1 | $this->_getLastOpenSSLError()); |
|
| 183 | } |
||
| 184 | 8 | return $crypted; |
|
| 185 | } |
||
| 186 | |||
| 187 | /** |
||
| 188 | * {@inheritdoc} |
||
| 189 | */ |
||
| 190 | 10 | protected function _decryptKey(string $ciphertext, Header $header): string |
|
| 191 | { |
||
| 192 | 10 | $privkey = openssl_pkey_get_private( |
|
| 193 | 10 | $this->privateKey()->toPEM()->string()); |
|
| 194 | 10 | if (false === $privkey) { |
|
| 195 | 1 | throw new \RuntimeException( |
|
| 196 | 'openssl_pkey_get_private() failed: ' . |
||
| 197 | 1 | $this->_getLastOpenSSLError()); |
|
| 198 | } |
||
| 199 | 9 | $result = openssl_private_decrypt($ciphertext, $cek, $privkey, |
|
| 200 | 9 | $this->_paddingScheme()); |
|
| 201 | 9 | if (!$result) { |
|
| 202 | 1 | throw new \RuntimeException( |
|
| 203 | 'openssl_private_decrypt() failed: ' . |
||
| 204 | 1 | $this->_getLastOpenSSLError()); |
|
| 205 | } |
||
| 206 | 8 | return $cek; |
|
| 207 | } |
||
| 208 | |||
| 209 | /** |
||
| 210 | * Get last OpenSSL error message. |
||
| 211 | * |
||
| 212 | * @return null|string |
||
| 213 | */ |
||
| 214 | 4 | protected function _getLastOpenSSLError(): ?string |
|
| 221 | } |
||
| 222 | } |
||
| 223 |