Example #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);
 }
Example #2
0
 /**
  * Encrypts a string with either a key or a password.
  *
  * @param string        $plaintext
  * @param KeyOrPassword $secret
  * @param bool          $raw_binary
  *
  * @return string
  */
 private static function encryptInternal($plaintext, KeyOrPassword $secret, $raw_binary)
 {
     RuntimeTests::runtimeTest();
     $salt = Core::secureRandom(Core::SALT_BYTE_SIZE);
     $keys = $secret->deriveKeys($salt);
     $ekey = $keys->getEncryptionKey();
     $akey = $keys->getAuthenticationKey();
     $iv = Core::secureRandom(Core::BLOCK_BYTE_SIZE);
     $ciphertext = Core::CURRENT_VERSION . $salt . $iv . self::plainEncrypt($plaintext, $ekey, $iv);
     $auth = \hash_hmac(Core::HASH_FUNCTION_NAME, $ciphertext, $akey, true);
     $ciphertext = $ciphertext . $auth;
     if ($raw_binary) {
         return $ciphertext;
     }
     return Encoding::binToHex($ciphertext);
 }
Example #3
0
 /**
  * Encrypt the contents of a file handle $inputHandle and store the results
  * in $outputHandle using HKDF of $key to perform authenticated encryption
  *
  * @param resource $inputHandle
  * @param resource $outputHandle
  * @param Key $key
  * @return boolean
  */
 public static function encryptResource($inputHandle, $outputHandle, Key $key)
 {
     // Because we don't have strict typing in PHP 5
     if (!\is_resource($inputHandle)) {
         throw new Ex\InvalidInput('Input handle must be a resource!');
     }
     if (!\is_resource($outputHandle)) {
         throw new Ex\InvalidInput('Output handle must be a resource!');
     }
     $config = self::getFileVersionConfigFromHeader(Core::CURRENT_FILE_VERSION, Core::CURRENT_FILE_VERSION);
     $inputStat = \fstat($inputHandle);
     $inputSize = $inputStat['size'];
     // Let's add this check before anything
     if (!\in_array($config->hashFunctionName(), \hash_algos())) {
         throw new Ex\CannotPerformOperationException('The specified hash function does not exist');
     }
     /**
      *  Let's split our keys
      */
     $file_salt = Core::secureRandom($config->saltByteSize());
     // $ekey -- Encryption Key -- used for AES
     $ekey = Core::HKDF($config->hashFunctionName(), $key->getRawBytes(), $config->keyByteSize(), $config->encryptionInfoString(), $file_salt, $config);
     // $akey -- Authentication Key -- used for HMAC
     $akey = Core::HKDF($config->hashFunctionName(), $key->getRawBytes(), $config->keyByteSize(), $config->authenticationInfoString(), $file_salt, $config);
     /**
      *  Generate a random initialization vector.
      */
     Core::ensureFunctionExists("openssl_cipher_iv_length");
     $ivsize = \openssl_cipher_iv_length($config->cipherMethod());
     if ($ivsize === false || $ivsize <= 0) {
         throw new Ex\CannotPerformOperationException('Improper IV size');
     }
     $iv = Core::secureRandom($ivsize);
     /**
      * First let's write our header, file salt, and IV to the first N blocks of the output file
      */
     self::writeBytes($outputHandle, Core::CURRENT_FILE_VERSION . $file_salt . $iv, Core::HEADER_VERSION_SIZE + $config->saltByteSize() + $ivsize);
     /**
      * We're going to initialize a HMAC-SHA256 with the given $akey
      * and update it with each ciphertext chunk
      */
     $hmac = \hash_init($config->hashFunctionName(), HASH_HMAC, $akey);
     if ($hmac === false) {
         throw new Ex\CannotPerformOperationException('Cannot initialize a hash context');
     }
     /**
      * We operate on $thisIv using a hash-based PRF derived from the initial
      * IV for the first block
      */
     $thisIv = $iv;
     /**
      * How much do we increase the counter after each buffered encryption to
      * prevent nonce reuse?
      */
     $inc = $config->bufferByteSize() / $config->blockByteSize();
     /**
      * Let's MAC our salt and IV/nonce
      */
     \hash_update($hmac, Core::CURRENT_FILE_VERSION);
     \hash_update($hmac, $file_salt);
     \hash_update($hmac, $iv);
     /**
      * Iterate until we reach the end of the input file
      */
     $breakR = false;
     while (!\feof($inputHandle)) {
         $pos = \ftell($inputHandle);
         if ($pos + $config->bufferByteSize() >= $inputSize) {
             $breakR = true;
             // We need to break after this loop iteration
             $read = self::readBytes($inputHandle, $inputSize - $pos);
         } else {
             $read = self::readBytes($inputHandle, $config->bufferByteSize());
         }
         $thisIv = Core::incrementCounter($thisIv, $inc, $config);
         /**
          * Perform the AES encryption. Encrypts the plaintext.
          */
         $encrypted = \openssl_encrypt($read, $config->cipherMethod(), $ekey, OPENSSL_RAW_DATA, $thisIv);
         /**
          * Check that the encryption was performed successfully
          */
         if ($encrypted === false) {
             throw new Ex\CannotPerformOperationException('OpenSSL encryption error');
         }
         /**
          * Write the ciphertext to the output file
          */
         self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted));
         /**
          * Update the HMAC for the entire file with the data from this block
          */
         \hash_update($hmac, $encrypted);
         if ($breakR) {
             break;
         }
     }
     // Now let's get our HMAC and append it
     $finalHMAC = \hash_final($hmac, true);
     self::writeBytes($outputHandle, $finalHMAC, $config->macByteSize());
     return true;
 }
Example #4
0
 /**
  * Encrypts a message.
  *
  * $plaintext is the message to encrypt.
  * $key is the encryption key, a value generated by CreateNewRandomKey().
  * You MUST catch exceptions thrown by this function. Read the docs.
  *
  * @param string $plaintext
  * @param string $key
  * @param boolean $raw_binary
  * @return string
  * @throws Ex\CannotPerformOperationException
  * @throws Ex\CryptoTestFailedException
  */
 public static function encrypt($plaintext, $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();
     $config = self::getVersionConfigFromHeader(Core::CURRENT_VERSION, Core::CURRENT_VERSION);
     if (Core::ourStrlen($key) !== $config->keyByteSize()) {
         throw new Ex\CannotPerformOperationException("Key is the wrong size.");
     }
     $salt = Core::secureRandom($config->saltByteSize());
     // Generate a sub-key for encryption.
     $ekey = Core::HKDF($config->hashFunctionName(), $key, $config->keyByteSize(), $config->encryptionInfoString(), $salt, $config);
     // Generate a sub-key for authentication and apply the HMAC.
     $akey = Core::HKDF($config->hashFunctionName(), $key, $config->keyByteSize(), $config->authenticationInfoString(), $salt, $config);
     // Generate a random initialization vector.
     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");
     }
     $iv = Core::secureRandom($ivsize);
     $ciphertext = $salt . $iv . self::plainEncrypt($plaintext, $ekey, $iv, $config);
     $auth = \hash_hmac($config->hashFunctionName(), Core::CURRENT_VERSION . $ciphertext, $akey, true);
     // We're now appending the header as of 2.00
     $ciphertext = Core::CURRENT_VERSION . $auth . $ciphertext;
     if ($raw_binary) {
         return $ciphertext;
     }
     return Encoding::binToHex($ciphertext);
 }
Example #5
0
 public static function CreateNewRandomKey()
 {
     return Key::CreateKey(function ($size) {
         return Core::secureRandom($size);
     });
 }
Example #6
0
 /**
  * Encrypts a resource with either a key or a password.
  *
  * @param resource      $inputHandle
  * @param resource      $outputHandle
  * @param KeyOrPassword $secret
  *
  * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException
  * @throws Defuse\Crypto\Exception\IOException
  */
 private static function encryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret)
 {
     if (!\is_resource($inputHandle)) {
         throw new Ex\IOException('Input handle must be a resource!');
     }
     if (!\is_resource($outputHandle)) {
         throw new Ex\IOException('Output handle must be a resource!');
     }
     $inputStat = \fstat($inputHandle);
     $inputSize = $inputStat['size'];
     $file_salt = Core::secureRandom(Core::SALT_BYTE_SIZE);
     $keys = $secret->deriveKeys($file_salt);
     $ekey = $keys->getEncryptionKey();
     $akey = $keys->getAuthenticationKey();
     $ivsize = Core::BLOCK_BYTE_SIZE;
     $iv = Core::secureRandom($ivsize);
     /* Initialize a streaming HMAC state. */
     $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
     if ($hmac === false) {
         throw new Ex\EnvironmentIsBrokenException('Cannot initialize a hash context');
     }
     /* Write the header, salt, and IV. */
     self::writeBytes($outputHandle, Core::CURRENT_VERSION . $file_salt . $iv, Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + $ivsize);
     /* Add the header, salt, and IV to the HMAC. */
     \hash_update($hmac, Core::CURRENT_VERSION);
     \hash_update($hmac, $file_salt);
     \hash_update($hmac, $iv);
     /* $thisIv will be incremented after each call to the encryption. */
     $thisIv = $iv;
     /* How many blocks do we encrypt at a time? We increment by this value. */
     $inc = Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE;
     /* Loop until we reach the end of the input file. */
     $at_file_end = false;
     while (!(\feof($inputHandle) || $at_file_end)) {
         /* Find out if we can read a full buffer, or only a partial one. */
         $pos = \ftell($inputHandle);
         if ($pos === false) {
             throw new Ex\IOException('Could not get current position in input file during encryption');
         }
         if ($pos + Core::BUFFER_BYTE_SIZE >= $inputSize) {
             /* We're at the end of the file, so we need to break out of the loop. */
             $at_file_end = true;
             $read = self::readBytes($inputHandle, $inputSize - $pos);
         } else {
             $read = self::readBytes($inputHandle, Core::BUFFER_BYTE_SIZE);
         }
         /* Encrypt this buffer. */
         $encrypted = \openssl_encrypt($read, Core::CIPHER_METHOD, $ekey, OPENSSL_RAW_DATA, $thisIv);
         if ($encrypted === false) {
             throw new Ex\EnvironmentIsBrokenException('OpenSSL encryption error');
         }
         /* Write this buffer's ciphertext. */
         self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted));
         /* Add this buffer's ciphertext to the HMAC. */
         \hash_update($hmac, $encrypted);
         /* Increment the counter by the number of blocks in a buffer. */
         $thisIv = Core::incrementCounter($thisIv, $inc);
         /* WARNING: Usually, unless the file is a multiple of the buffer
          * size, $thisIv will contain an incorrect value here on the last
          * iteration of this loop. */
     }
     /* Get the HMAC and append it to the ciphertext. */
     $final_mac = \hash_final($hmac, true);
     self::writeBytes($outputHandle, $final_mac, CORE::MAC_BYTE_SIZE);
 }