<?php

/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;

use DeliciousBrains\WP_Offload_Media\Gcp\phpseclib\Crypt\RSA as RSA2;
use DeliciousBrains\WP_Offload_Media\Gcp\phpseclib3\Crypt\RSA as RSA3;
/**
 * Trait which provides helper methods for customer-supplied encryption.
 */
trait EncryptionTrait
{
    /**
     * @var array
     */
    private $copySourceEncryptionHeaderNames = ['algorithm' => 'x-goog-copy-source-encryption-algorithm', 'key' => 'x-goog-copy-source-encryption-key', 'keySHA256' => 'x-goog-copy-source-encryption-key-sha256'];
    /**
     * @var array
     */
    private $encryptionHeaderNames = ['algorithm' => 'x-goog-encryption-algorithm', 'key' => 'x-goog-encryption-key', 'keySHA256' => 'x-goog-encryption-key-sha256'];
    /**
     * Formats options for customer-supplied encryption headers.
     *
     * @param array $options
     * @return array
     * @access private
     */
    public function formatEncryptionHeaders(array $options)
    {
        $encryptionHeaders = [];
        $useCopySourceHeaders = $options['useCopySourceHeaders'] ?? \false;
        $key = $options['encryptionKey'] ?? null;
        $keySHA256 = $options['encryptionKeySHA256'] ?? null;
        $destinationKey = $options['destinationEncryptionKey'] ?? null;
        $destinationKeySHA256 = $options['destinationEncryptionKeySHA256'] ?? null;
        unset($options['useCopySourceHeaders']);
        unset($options['encryptionKey']);
        unset($options['encryptionKeySHA256']);
        unset($options['destinationEncryptionKey']);
        unset($options['destinationEncryptionKeySHA256']);
        $encryptionHeaders = $this->buildHeaders($key, $keySHA256, $useCopySourceHeaders) + $this->buildHeaders($destinationKey, $destinationKeySHA256, \false);
        if (!empty($encryptionHeaders)) {
            if (isset($options['restOptions']['headers'])) {
                $options['restOptions']['headers'] += $encryptionHeaders;
            } else {
                $options['restOptions']['headers'] = $encryptionHeaders;
            }
        }
        return $options;
    }
    /**
     * Builds out customer-supplied encryption headers.
     *
     * @param string $key
     * @param string $keySHA256
     * @param bool $useCopySourceHeaders
     * @return array
     */
    private function buildHeaders($key, $keySHA256, $useCopySourceHeaders)
    {
        if ($key) {
            $headerNames = $useCopySourceHeaders ? $this->copySourceEncryptionHeaderNames : $this->encryptionHeaderNames;
            if (!$keySHA256) {
                $decodedKey = \base64_decode($key);
                $keySHA256 = \base64_encode(\hash('SHA256', $decodedKey, \true));
            }
            return [$headerNames['algorithm'] => 'AES256', $headerNames['key'] => $key, $headerNames['keySHA256'] => $keySHA256];
        }
        return [];
    }
    /**
     * Sign a string using a given private key.
     *
     * @deprecated Please use the {@see Google\Auth\SignBlobInterface::signBlob()}
     *        and implementations for signing strings.
     *        This method will be removed in a future release.
     *
     * @param string $privateKey The private key to use to sign the data.
     * @param string $data The data to sign.
     * @param bool $forceOpenssl If true, OpenSSL will be used regardless of
     *        whether phpseclib is available. **Defaults to** `false`.
     * @return string The signature
     */
    protected function signString($privateKey, $data, $forceOpenssl = \false)
    {
        $signature = '';
        if (\class_exists(RSA3::class) && !$forceOpenssl) {
            $rsa = RSA3::loadPrivateKey($privateKey);
            $rsa = $rsa->withPadding(RSA3::SIGNATURE_PKCS1)->withHash('sha256');
            $signature = $rsa->sign($data);
        } elseif (\class_exists(RSA2::class) && !$forceOpenssl) {
            $rsa = new RSA2();
            $rsa->loadKey($privateKey);
            $rsa->setSignatureMode(RSA2::SIGNATURE_PKCS1);
            $rsa->setHash('sha256');
            $signature = $rsa->sign($data);
        } elseif (\extension_loaded('openssl')) {
            \openssl_sign($data, $signature, $privateKey, 'sha256WithRSAEncryption');
        } else {
            // @codeCoverageIgnoreStart
            throw new \RuntimeException('OpenSSL is not installed.');
        }
        // @codeCoverageIgnoreEnd
        return $signature;
    }
}
