| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 | <?phpnamespace Aws\Crypto;use Aws\Exception\CryptoException;use Aws\Kms\KmsClient;/** * Uses KMS to supply materials for encrypting and decrypting data. This * V2 implementation should be used with the V2 encryption clients (i.e. * S3EncryptionClientV2). */class KmsMaterialsProviderV2 extends MaterialsProviderV2 implements MaterialsProviderInterfaceV2{    const WRAP_ALGORITHM_NAME = 'kms+context';    private $kmsClient;    private $kmsKeyId;    /**     * @param KmsClient $kmsClient A KMS Client for use encrypting and     *                             decrypting keys.     * @param string $kmsKeyId The private KMS key id to be used for encrypting     *                         and decrypting keys.     */    public function __construct(        KmsClient $kmsClient,        $kmsKeyId = null    ) {        $this->kmsClient = $kmsClient;        $this->kmsKeyId = $kmsKeyId;    }    /**     * @inheritDoc     */    public function getWrapAlgorithmName()    {        return self::WRAP_ALGORITHM_NAME;    }    /**     * @inheritDoc     */    public function decryptCek($encryptedCek, $materialDescription, $options)    {        $params = [            'CiphertextBlob' => $encryptedCek,            'EncryptionContext' => $materialDescription        ];        if (empty($options['@KmsAllowDecryptWithAnyCmk'])) {            if (empty($this->kmsKeyId)) {                throw new CryptoException('KMS CMK ID was not specified and the'                    . ' operation is not opted-in to attempting to use any valid'                    . ' CMK it discovers. Please specify a CMK ID, or explicitly'                    . ' enable attempts to use any valid KMS CMK with the'                    . ' @KmsAllowDecryptWithAnyCmk option.');            }            $params['KeyId'] = $this->kmsKeyId;        }        $result = $this->kmsClient->decrypt($params);        return $result['Plaintext'];    }    /**     * @inheritDoc     */    public function generateCek($keySize, $context, $options)    {        if (empty($this->kmsKeyId)) {            throw new CryptoException('A KMS key id is required for encryption'                . ' with KMS keywrap. Use a KmsMaterialsProviderV2 that has been'                . ' instantiated with a KMS key id.');        }        $options = array_change_key_case($options);        if (!isset($options['@kmsencryptioncontext'])            || !is_array($options['@kmsencryptioncontext'])        ) {            throw new CryptoException("'@KmsEncryptionContext' is a"                . " required argument when using KmsMaterialsProviderV2, and"                . " must be an associative array (or empty array).");        }        if (isset($options['@kmsencryptioncontext']['aws:x-amz-cek-alg'])) {            throw new CryptoException("Conflict in reserved @KmsEncryptionContext"                . " key aws:x-amz-cek-alg. This value is reserved for the S3"                . " Encryption Client and cannot be set by the user.");        }        $context = array_merge($options['@kmsencryptioncontext'], $context);        $result = $this->kmsClient->generateDataKey([            'KeyId' => $this->kmsKeyId,            'KeySpec' => "AES_{$keySize}",            'EncryptionContext' => $context        ]);        return [            'Plaintext' => $result['Plaintext'],            'Ciphertext' => base64_encode($result['CiphertextBlob']),            'UpdatedContext' => $context        ];    }}
 |