示例#1
0
 public function testOurSubstrOutOfBorders()
 {
     // See: https://secure.php.net/manual/en/function.mb-substr.php#50275
     // We want to be like substr, so confirm that behavior.
     $this->assertSame(false, substr('abc', 5, 2));
     // Confirm that mb_substr does not have that behavior.
     if (function_exists('mb_substr')) {
         if (ini_get('mbstring.func_overload') == 0) {
             $this->assertSame('', \mb_substr('abc', 5, 2));
         } else {
             $this->assertSame(false, \mb_substr('abc', 5, 2));
         }
         // YES, THE BEHAVIOR OF mb_substr IS REALLY THIS INSANE!!!!
     }
     // Check if we actually have that behavior.
     $this->assertSame(false, Core::ourSubstr('abc', 5, 2));
 }
示例#2
0
 /**
  * Decrypts a ciphertext to a string with either a key or a password.
  *
  * @param string        $ciphertext
  * @param KeyOrPassword $secret
  * @param bool          $raw_binary
  *
  * @throws Ex\EnvironmentIsBrokenException
  * @throws Ex\WrongKeyOrModifiedCiphertextException
  *
  * @return string
  */
 private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw_binary)
 {
     RuntimeTests::runtimeTest();
     if (!$raw_binary) {
         try {
             $ciphertext = Encoding::hexToBin($ciphertext);
         } catch (Ex\BadFormatException $ex) {
             throw new Ex\WrongKeyOrModifiedCiphertextException('Ciphertext has invalid hex encoding.');
         }
     }
     if (Core::ourStrlen($ciphertext) < Core::MINIMUM_CIPHERTEXT_SIZE) {
         throw new Ex\WrongKeyOrModifiedCiphertextException('Ciphertext is too short.');
     }
     // Get and check the version header.
     $header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE);
     if ($header !== Core::CURRENT_VERSION) {
         throw new Ex\WrongKeyOrModifiedCiphertextException('Bad version header.');
     }
     // Get the salt.
     $salt = Core::ourSubstr($ciphertext, Core::HEADER_VERSION_SIZE, Core::SALT_BYTE_SIZE);
     if ($salt === false) {
         throw new Ex\EnvironmentIsBrokenException();
     }
     // Get the IV.
     $iv = Core::ourSubstr($ciphertext, Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE, Core::BLOCK_BYTE_SIZE);
     if ($iv === false) {
         throw new Ex\EnvironmentIsBrokenException();
     }
     // Get the HMAC.
     $hmac = Core::ourSubstr($ciphertext, Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE, Core::MAC_BYTE_SIZE);
     if ($hmac === false) {
         throw new Ex\EnvironmentIsBrokenException();
     }
     // Get the actual encrypted ciphertext.
     $encrypted = Core::ourSubstr($ciphertext, Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE, Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE - Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE);
     if ($encrypted === false) {
         throw new Ex\EnvironmentIsBrokenException();
     }
     // Derive the separate encryption and authentication keys from the key
     // or password, whichever it is.
     $keys = $secret->deriveKeys($salt);
     if (self::verifyHMAC($hmac, $header . $salt . $iv . $encrypted, $keys->getAuthenticationKey())) {
         $plaintext = self::plainDecrypt($encrypted, $keys->getEncryptionKey(), $iv, Core::CIPHER_METHOD);
         return $plaintext;
     } else {
         throw new Ex\WrongKeyOrModifiedCiphertextException('Integrity check failed.');
     }
 }
示例#3
0
 /**
  * INTERNAL USE ONLY: Decodes, verifies the header and checksum, and returns
  * the encoded byte string.
  *
  * @param string $expected_header
  * @param string $string
  *
  * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
  * @throws \Defuse\Crypto\Exception\BadFormatException
  *
  * @return string
  */
 public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string)
 {
     // Headers must be a constant length to prevent one type's header from
     // being a prefix of another type's header, leading to ambiguity.
     if (Core::ourStrlen($expected_header) !== self::SERIALIZE_HEADER_BYTES) {
         throw new Ex\EnvironmentIsBrokenException('Header must be 4 bytes.');
     }
     $bytes = Encoding::hexToBin($string);
     /* Make sure we have enough bytes to get the version header and checksum. */
     if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) {
         throw new Ex\BadFormatException('Encoded data is shorter than expected.');
     }
     /* Grab the version header. */
     $actual_header = Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES);
     if ($actual_header !== $expected_header) {
         throw new Ex\BadFormatException('Invalid header.');
     }
     /* Grab the bytes that are part of the checksum. */
     $checked_bytes = Core::ourSubstr($bytes, 0, Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE);
     /* Grab the included checksum. */
     $checksum_a = Core::ourSubstr($bytes, Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE, self::CHECKSUM_BYTE_SIZE);
     /* Re-compute the checksum. */
     $checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true);
     /* Check if the checksum matches. */
     if (!Core::hashEquals($checksum_a, $checksum_b)) {
         throw new Ex\BadFormatException("Data is corrupted, the checksum doesn't match");
     }
     return Core::ourSubstr($bytes, self::SERIALIZE_HEADER_BYTES, Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE);
 }
示例#4
0
文件: File.php 项目: robstoll/PuMa
 /**
  * Write to a stream; prevent partial writes
  *
  * @param resource $stream
  * @param string $buf
  * @param int $num (number of bytes)
  * @return string
  * @throws Ex\CannotPerformOperationException
  */
 public static final function writeBytes($stream, $buf, $num = null)
 {
     $bufSize = Core::ourStrlen($buf);
     if ($num === null) {
         $num = $bufSize;
     }
     if ($num > $bufSize) {
         throw new Ex\CannotPerformOperationException('Trying to write more bytes than the buffer contains.');
     }
     if ($num < 0) {
         throw new Ex\CannotPerformOperationException('Tried to write less than 0 bytes');
     }
     $remaining = $num;
     while ($remaining > 0) {
         $written = \fwrite($stream, $buf, $remaining);
         if ($written === false) {
             throw new Ex\CannotPerformOperationException('Could not write to the file');
         }
         $buf = Core::ourSubstr($buf, $written, null);
         $remaining -= $written;
     }
     return $num;
 }
示例#5
0
文件: Crypto.php 项目: robstoll/PuMa
 /**
  * Get the encryption configuration based on the version in a header.
  *
  * @param string $header The header to read the version number from.
  * @param string $min_ver_header The header of the minimum version number allowed.
  * @return array
  * @throws Ex\InvalidCiphertextException
  */
 public static function getVersionConfigFromHeader($header, $min_ver_header)
 {
     if (Core::ourSubstr($header, 0, 2) !== Core::ourSubstr(Core::HEADER_MAGIC, 0, 2)) {
         throw new Ex\InvalidCiphertextException("Ciphertext has a bad magic number.");
     }
     $major = \ord($header[2]);
     $minor = \ord($header[3]);
     $min_major = \ord($min_ver_header[2]);
     $min_minor = \ord($min_ver_header[3]);
     if ($major < $min_major || $major === $min_major && $minor < $min_minor) {
         throw new Ex\InvalidCiphertextException("Ciphertext is requesting an insecure fallback.");
     }
     $config = self::getVersionConfigFromMajorMinor($major, $minor);
     return $config;
 }
示例#6
0
文件: Key.php 项目: robstoll/PuMa
 public static function LoadFromAsciiSafeString($savedKeyString)
 {
     try {
         $bytes = Encoding::hexToBin($savedKeyString);
     } catch (\RangeException $ex) {
         throw new Ex\CannotPerformOperationException("Key has invalid hex encoding.");
     }
     /* Make sure we have enough bytes to get the version header. */
     if (Core::ourStrlen($bytes) < self::KEY_HEADER_SIZE) {
         throw new Ex\CannotPerformOperationException("Saved Key is shorter than the version header.");
     }
     /* Grab the version header. */
     $version_header = Core::ourSubstr($bytes, 0, self::KEY_HEADER_SIZE);
     /* Grab the config for that version. */
     $config = self::GetKeyVersionConfigFromKeyHeader($version_header);
     /* Now that we know the version, check the length is correct. */
     if (Core::ourStrlen($bytes) !== self::KEY_HEADER_SIZE + $config->keyByteSize() + $config->checksumByteSize()) {
         throw new Ex\CannotPerformOperationException("Saved Key is not the correct size.");
     }
     /* Grab the bytes that are part of the checksum. */
     $checked_bytes = Core::ourSubstr($bytes, 0, self::KEY_HEADER_SIZE + $config->keyByteSize());
     /* Grab the included checksum. */
     $checksum_a = Core::ourSubstr($bytes, self::KEY_HEADER_SIZE + $config->keyByteSize(), $config->checksumByteSize());
     /* Re-compute the checksum. */
     $checksum_b = hash($config->checksumHashFunction(), $checked_bytes, true);
     /* Validate it. It *is* important for this to be constant time. */
     if (!Core::hashEquals($checksum_a, $checksum_b)) {
         throw new Ex\CannotPerformOperationException("Saved key is corrupted -- checksums don't match.");
     }
     /* Everything checks out. Grab the key and create a Key object. */
     $key_bytes = Core::ourSubstr($bytes, self::KEY_HEADER_SIZE, $config->keyByteSize());
     return new Key($version_header, $key_bytes);
 }