示例#1
0
 /**
  * @expectedException \Defuse\Crypto\Exception\BadFormatException
  * @expectedExceptionMessage not a hex string
  */
 public function testBadHexEncoding()
 {
     $header = Core::secureRandom(Core::HEADER_VERSION_SIZE);
     $str = Encoding::saveBytesToChecksummedAsciiSafeString($header, Core::secureRandom(Core::KEY_BYTE_SIZE));
     $str[0] = 'Z';
     Encoding::loadBytesFromChecksummedAsciiSafeString($header, $str);
 }
示例#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
 /**
  * Test AES against test vectors.
  *
  * @throws Ex\EnvironmentIsBrokenException
  */
 private static function AESTestVector()
 {
     // AES CTR mode test vector from NIST SP 800-38A
     $key = Encoding::hexToBin('603deb1015ca71be2b73aef0857d7781' . '1f352c073b6108d72d9810a30914dff4');
     $iv = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff');
     $plaintext = Encoding::hexToBin('6bc1bee22e409f96e93d7e117393172a' . 'ae2d8a571e03ac9c9eb76fac45af8e51' . '30c81c46a35ce411e5fbc1191a0a52ef' . 'f69f2445df4f9b17ad2b417be66c3710');
     $ciphertext = Encoding::hexToBin('601ec313775789a5b7a7f504bbf3d228' . 'f443e3ca4d62b59aca84e990cacaf5c5' . '2b0930daa23de94ce87017ba2d84988d' . 'dfc9c58db67aada613c2dd08457941a6');
     $computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv);
     if ($computed_ciphertext !== $ciphertext) {
         echo \str_repeat("\n", 30);
         echo \bin2hex($computed_ciphertext);
         echo "\n---\n";
         echo \bin2hex($ciphertext);
         echo \str_repeat("\n", 30);
         throw new Ex\EnvironmentIsBrokenException();
     }
     $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD);
     if ($computed_plaintext !== $plaintext) {
         throw new Ex\EnvironmentIsBrokenException();
     }
 }
示例#5
0
文件: Crypto.php 项目: robstoll/PuMa
 /**
  * Decrypts a ciphertext.
  * $ciphertext is the ciphertext to decrypt.
  * $key is the key that the ciphertext was encrypted with.
  * You MUST catch exceptions thrown by this function. Read the docs.
  *
  * @param string $ciphertext
  * @param string $key
  * @param boolean $raw_binary
  * @return string
  * @throws Ex\CannotPerformOperationException
  * @throws Ex\CryptoTestFailedException
  * @throws Ex\InvalidCiphertextException
  */
 public static function decrypt($ciphertext, $key, $raw_binary = false)
 {
     RuntimeTests::runtimeTest();
     /* Attempt to validate that the key was generated safely. */
     if (!is_a($key, "\\Defuse\\Crypto\\Key")) {
         throw new Ex\CannotPerformOperationException("The given key is not a valid Key object.");
     }
     $key = $key->getRawBytes();
     if (!$raw_binary) {
         try {
             $ciphertext = Encoding::hexToBin($ciphertext);
         } catch (\RangeException $ex) {
             throw new Ex\InvalidCiphertextException("Ciphertext has invalid hex encoding.");
         }
     }
     // Grab the header tag
     $version = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE);
     // Load the configuration for this version
     $config = self::getVersionConfigFromHeader($version, Core::CURRENT_VERSION);
     // Now let's operate on the remainder of the ciphertext as normal
     $ciphertext = Core::ourSubstr($ciphertext, Core::HEADER_VERSION_SIZE, null);
     // Extract the HMAC from the front of the ciphertext.
     if (Core::ourStrlen($ciphertext) <= $config->macByteSize()) {
         throw new Ex\InvalidCiphertextException("Ciphertext is too short.");
     }
     $hmac = Core::ourSubstr($ciphertext, 0, $config->macByteSize());
     if ($hmac === false) {
         throw new Ex\CannotPerformOperationException();
     }
     $salt = Core::ourSubstr($ciphertext, $config->macByteSize(), $config->saltByteSize());
     if ($salt === false) {
         throw new Ex\CannotPerformOperationException();
     }
     $ciphertext = Core::ourSubstr($ciphertext, $config->macByteSize() + $config->saltByteSize());
     if ($ciphertext === false) {
         throw new Ex\CannotPerformOperationException();
     }
     // Regenerate the same authentication sub-key.
     $akey = Core::HKDF($config->hashFunctionName(), $key, $config->keyByteSize(), $config->authenticationInfoString(), $salt, $config);
     if (self::verifyHMAC($hmac, $version . $salt . $ciphertext, $akey, $config)) {
         // Regenerate the same encryption sub-key.
         $ekey = Core::HKDF($config->hashFunctionName(), $key, $config->keyByteSize(), $config->encryptionInfoString(), $salt, $config);
         // Extract the initialization vector from the ciphertext.
         Core::EnsureFunctionExists("openssl_cipher_iv_length");
         $ivsize = \openssl_cipher_iv_length($config->cipherMethod());
         if ($ivsize === false || $ivsize <= 0) {
             throw new Ex\CannotPerformOperationException("Could not get the IV length from OpenSSL");
         }
         if (Core::ourStrlen($ciphertext) <= $ivsize) {
             throw new Ex\InvalidCiphertextException("Ciphertext is too short.");
         }
         $iv = Core::ourSubstr($ciphertext, 0, $ivsize);
         if ($iv === false) {
             throw new Ex\CannotPerformOperationException();
         }
         $ciphertext = Core::ourSubstr($ciphertext, $ivsize);
         if ($ciphertext === false) {
             throw new Ex\CannotPerformOperationException();
         }
         $plaintext = self::plainDecrypt($ciphertext, $ekey, $iv, $config);
         return $plaintext;
     } else {
         /*
          * We throw an exception instead of returning false because we want
          * a script that doesn't handle this condition to CRASH, instead
          * of thinking the ciphertext decrypted to the value false.
          */
         throw new Ex\InvalidCiphertextException("Integrity check failed.");
     }
 }
示例#6
0
文件: Key.php 项目: robstoll/PuMa
 public function saveToAsciiSafeString()
 {
     return Encoding::binToHex($this->key_version_header . $this->key_bytes . hash($this->config->checksumHashFunction(), $this->key_version_header . $this->key_bytes, true));
 }
 /**
  * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException
  */
 public function testDecryptLegacyCiphertextWrongKey()
 {
     $cipher = Encoding::hexToBin('cfdad83ebd506d2c9ada8d48030d0bca' . '2ff94760e6d39c186adb1290d6c47e35' . '821e262673c5631c42ebbaf70774d6ef' . '29aa5eee0e412d646ae380e08189c85d' . '024b5e2009106870f1db25d8b85fd01f');
     $plain = Crypto::legacyDecrypt($cipher, "\t\n\v\f\r");
 }
 /**
  * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException
  * @expectedExceptionMessage Bad version header
  */
 public function testDecryptLegacyWithWrongMethodStraightUpBinary()
 {
     $cipher = Encoding::hexToBin('cfdad83ebd506d2c9ada8d48030d0bca' . '2ff94760e6d39c186adb1290d6c47e35' . '821e262673c5631c42ebbaf70774d6ef' . '29aa5eee0e412d646ae380e08189c85d' . '024b5e2009106870f1db25d8b85fd01f' . '00000000000000000000000000000000');
     /* This time, treat the binary as binary. */
     $plain = Crypto::decrypt($cipher, Key::loadFromRawBytesForTestingPurposesOnlyInsecure("\t\n\v\f\r" . "\t\n\v\f\r"), true);
 }