123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- <?php
- namespace Aws\Crypto;
- use GuzzleHttp\Psr7\StreamDecoratorTrait;
- use \LogicException;
- use Psr\Http\Message\StreamInterface;
- use Aws\Crypto\Cipher\CipherMethod;
- /**
- * @internal Represents a stream of data to be decrypted with passed cipher.
- */
- class AesDecryptingStream implements AesStreamInterface
- {
- const BLOCK_SIZE = 16; // 128 bits
- use StreamDecoratorTrait;
- /**
- * @var string
- */
- private $buffer = '';
- /**
- * @var CipherMethod
- */
- private $cipherMethod;
- /**
- * @var string
- */
- private $key;
- /**
- * @var StreamInterface
- */
- private $stream;
- /**
- * @param StreamInterface $cipherText
- * @param string $key
- * @param CipherMethod $cipherMethod
- */
- public function __construct(
- StreamInterface $cipherText,
- $key,
- CipherMethod $cipherMethod
- ) {
- $this->stream = $cipherText;
- $this->key = $key;
- $this->cipherMethod = clone $cipherMethod;
- }
- public function getOpenSslName()
- {
- return $this->cipherMethod->getOpenSslName();
- }
- public function getAesName()
- {
- return $this->cipherMethod->getAesName();
- }
- public function getCurrentIv()
- {
- return $this->cipherMethod->getCurrentIv();
- }
- public function getSize(): ?int
- {
- $plainTextSize = $this->stream->getSize();
- if ($this->cipherMethod->requiresPadding()) {
- // PKCS7 padding requires that between 1 and self::BLOCK_SIZE be
- // added to the plaintext to make it an even number of blocks. The
- // plaintext is between strlen($cipherText) - self::BLOCK_SIZE and
- // strlen($cipherText) - 1
- return null;
- }
- return $plainTextSize;
- }
- public function isWritable(): bool
- {
- return false;
- }
- public function read($length): string
- {
- if ($length > strlen($this->buffer)) {
- $this->buffer .= $this->decryptBlock(
- (int) (
- self::BLOCK_SIZE * ceil(($length - strlen($this->buffer)) / self::BLOCK_SIZE)
- )
- );
- }
- $data = substr($this->buffer, 0, $length);
- $this->buffer = substr($this->buffer, $length);
- return $data ? $data : '';
- }
- public function seek($offset, $whence = SEEK_SET): void
- {
- if ($offset === 0 && $whence === SEEK_SET) {
- $this->buffer = '';
- $this->cipherMethod->seek(0, SEEK_SET);
- $this->stream->seek(0, SEEK_SET);
- } else {
- throw new LogicException('AES encryption streams only support being'
- . ' rewound, not arbitrary seeking.');
- }
- }
- private function decryptBlock($length)
- {
- if ($this->stream->eof()) {
- return '';
- }
- $cipherText = '';
- do {
- $cipherText .= $this->stream->read((int) ($length - strlen($cipherText)));
- } while (strlen($cipherText) < $length && !$this->stream->eof());
- $options = OPENSSL_RAW_DATA;
- if (!$this->stream->eof()
- && $this->stream->getSize() !== $this->stream->tell()
- ) {
- $options |= OPENSSL_ZERO_PADDING;
- }
- $plaintext = openssl_decrypt(
- $cipherText,
- $this->cipherMethod->getOpenSslName(),
- $this->key,
- $options,
- $this->cipherMethod->getCurrentIv()
- );
- $this->cipherMethod->update($cipherText);
- return $plaintext;
- }
- }
|