stream = $plainText; $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() && $plainTextSize !== null) { // PKCS7 padding requires that between 1 and self::BLOCK_SIZE be // added to the plaintext to make it an even number of blocks. $padding = self::BLOCK_SIZE - $plainTextSize % self::BLOCK_SIZE; return $plainTextSize + $padding; } return $plainTextSize; } public function isWritable() : bool { return \false; } public function read($length) : string { if ($length > \strlen($this->buffer)) { $this->buffer .= $this->encryptBlock((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 ($whence === \SEEK_CUR) { $offset = $this->tell() + $offset; $whence = \SEEK_SET; } if ($whence === \SEEK_SET) { $this->buffer = ''; $wholeBlockOffset = (int) ($offset / self::BLOCK_SIZE) * self::BLOCK_SIZE; $this->stream->seek($wholeBlockOffset); $this->cipherMethod->seek($wholeBlockOffset); $this->read($offset - $wholeBlockOffset); } else { throw new LogicException('Unrecognized whence.'); } } private function encryptBlock($length) { if ($this->stream->eof()) { return ''; } $plainText = ''; do { $plainText .= $this->stream->read((int) ($length - \strlen($plainText))); } while (\strlen($plainText) < $length && !$this->stream->eof()); $options = \OPENSSL_RAW_DATA; if (!$this->stream->eof() || $this->stream->getSize() !== $this->stream->tell()) { $options |= \OPENSSL_ZERO_PADDING; } $cipherText = \openssl_encrypt($plainText, $this->cipherMethod->getOpenSslName(), $this->key, $options, $this->cipherMethod->getCurrentIv()); $this->cipherMethod->update($cipherText); return $cipherText; } }