123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- <?php
- namespace Aws\Crypto;
- use GuzzleHttp\Psr7;
- use GuzzleHttp\Psr7\AppendStream;
- use GuzzleHttp\Psr7\Stream;
- trait EncryptionTrait
- {
- private static $allowedOptions = [
- 'Cipher' => true,
- 'KeySize' => true,
- 'Aad' => true,
- ];
-
- abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
-
- public function encrypt(
- Stream $plaintext,
- array $cipherOptions,
- MaterialsProvider $provider,
- MetadataEnvelope $envelope
- ) {
- $materialsDescription = $provider->getMaterialsDescription();
- $cipherOptions = array_intersect_key(
- $cipherOptions,
- self::$allowedOptions
- );
- if (empty($cipherOptions['Cipher'])) {
- throw new \InvalidArgumentException('An encryption cipher must be'
- . ' specified in the "cipher_options".');
- }
- if (!self::isSupportedCipher($cipherOptions['Cipher'])) {
- throw new \InvalidArgumentException('The cipher requested is not'
- . ' supported by the SDK.');
- }
- if (empty($cipherOptions['KeySize'])) {
- $cipherOptions['KeySize'] = 256;
- }
- if (!is_int($cipherOptions['KeySize'])) {
- throw new \InvalidArgumentException('The cipher "KeySize" must be'
- . ' an integer.');
- }
- if (!MaterialsProvider::isSupportedKeySize(
- $cipherOptions['KeySize']
- )) {
- throw new \InvalidArgumentException('The cipher "KeySize" requested'
- . ' is not supported by AES (128, 192, or 256).');
- }
- $cipherOptions['Iv'] = $provider->generateIv(
- $this->getCipherOpenSslName(
- $cipherOptions['Cipher'],
- $cipherOptions['KeySize']
- )
- );
- $cek = $provider->generateCek($cipherOptions['KeySize']);
- list($encryptingStream, $aesName) = $this->getEncryptingStream(
- $plaintext,
- $cek,
- $cipherOptions
- );
-
- $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] =
- $provider->encryptCek(
- $cek,
- $materialsDescription
- );
- unset($cek);
- $envelope[MetadataEnvelope::IV_HEADER] =
- base64_encode($cipherOptions['Iv']);
- $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER] =
- $provider->getWrapAlgorithmName();
- $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] = $aesName;
- $envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_LENGTH_HEADER] =
- strlen($plaintext);
- $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER] =
- json_encode($materialsDescription);
- if (!empty($cipherOptions['Tag'])) {
- $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] =
- strlen($cipherOptions['Tag']) * 8;
- }
- return $encryptingStream;
- }
-
- protected function getEncryptingStream(
- Stream $plaintext,
- $cek,
- &$cipherOptions
- ) {
- switch ($cipherOptions['Cipher']) {
- case 'gcm':
- $cipherOptions['TagLength'] = 16;
- $cipherTextStream = new AesGcmEncryptingStream(
- $plaintext,
- $cek,
- $cipherOptions['Iv'],
- $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
- ? $cipherOptions['Aad']
- : '',
- $cipherOptions['TagLength'],
- $cipherOptions['KeySize']
- );
- if (!empty($cipherOptions['Aad'])) {
- trigger_error("'Aad' has been supplied for content encryption"
- . " with " . $cipherTextStream->getAesName() . ". The"
- . " PHP SDK encryption client can decrypt an object"
- . " encrypted in this way, but other AWS SDKs may not be"
- . " able to.", E_USER_WARNING);
- }
- $appendStream = new AppendStream([
- $cipherTextStream->createStream()
- ]);
- $cipherOptions['Tag'] = $cipherTextStream->getTag();
- $appendStream->addStream(Psr7\Utils::streamFor($cipherOptions['Tag']));
- return [$appendStream, $cipherTextStream->getAesName()];
- default:
- $cipherMethod = $this->buildCipherMethod(
- $cipherOptions['Cipher'],
- $cipherOptions['Iv'],
- $cipherOptions['KeySize']
- );
- $cipherTextStream = new AesEncryptingStream(
- $plaintext,
- $cek,
- $cipherMethod
- );
- return [$cipherTextStream, $cipherTextStream->getAesName()];
- }
- }
- }
|