iv = str_repeat("\0", self::IV_SIZE); $keyStrengthBytes = (int) ($encryptionStrengthBits / 8); $hashLength = $keyStrengthBytes * 2 + self::PASSWORD_VERIFIER_SIZE * 8; $hash = hash_pbkdf2( 'sha1', $password, $salt, self::ITERATION_COUNT, $hashLength, true ); $this->key = substr($hash, 0, $keyStrengthBytes); $sha1Mac = substr($hash, $keyStrengthBytes, $keyStrengthBytes); $this->hmacContext = hash_init('sha1', \HASH_HMAC, $sha1Mac); $this->passwordVerifier = substr($hash, 2 * $keyStrengthBytes, self::PASSWORD_VERIFIER_SIZE); } /** * @return string */ public function getPasswordVerifier() { return $this->passwordVerifier; } public function updateIv() { for ($ivCharIndex = 0; $ivCharIndex < self::IV_SIZE; $ivCharIndex++) { $ivByte = \ord($this->iv[$ivCharIndex]); if (++$ivByte === 256) { // overflow, set this one to 0, increment next $this->iv[$ivCharIndex] = "\0"; } else { // no overflow, just write incremented number back and abort $this->iv[$ivCharIndex] = \chr($ivByte); break; } } } /** * @param string $data * * @return string */ public function decryption($data) { hash_update($this->hmacContext, $data); return CryptoUtil::decryptAesCtr($data, $this->key, $this->iv); } /** * @param string $data * * @return string */ public function encrypt($data) { $encryptionData = CryptoUtil::encryptAesCtr($data, $this->key, $this->iv); hash_update($this->hmacContext, $encryptionData); return $encryptionData; } /** * @param string $authCode * * @throws ZipAuthenticationException */ public function checkAuthCode($authCode) { $hmac = $this->getHmac(); // check authenticationCode if (strcmp($hmac, $authCode) !== 0) { throw new ZipAuthenticationException('Authenticated WinZip AES entry content has been tampered with.'); } } /** * @return string */ public function getHmac() { return substr( hash_final($this->hmacContext, true), 0, self::FOOTER_SIZE ); } }