Пример #1
0
 /**
  * Unseal a (file handle)
  *
  * @param ReadOnlyFile $input
  * @param MutableFile $output
  * @param EncryptionSecretKey $secretkey
  *
  * @return bool
  * @throws CryptoException\CannotPerformOperation
  * @throws CryptoException\InvalidMessage
  */
 protected static function unsealData(ReadOnlyFile $input, MutableFile $output, EncryptionSecretKey $secretkey) : bool
 {
     $secret_key = $secretkey->getRawKeyMaterial();
     $public_key = \Sodium\crypto_box_publickey_from_secretkey($secret_key);
     if ($input->getSize() < Halite::VERSION_TAG_LEN) {
         throw new CryptoException\InvalidMessage("File is too small to have been encrypted by Halite.");
     }
     // Parse the header, ensuring we get 4 bytes
     $header = $input->readBytes(Halite::VERSION_TAG_LEN);
     // Load the config
     $config = self::getConfig($header, 'seal');
     if ($input->getSize() < $config->SHORTEST_CIPHERTEXT_LENGTH) {
         throw new CryptoException\InvalidMessage("File is too small to have been encrypted by Halite.");
     }
     // Let's grab the public key and salt
     $eph_public = $input->readBytes($config->PUBLICKEY_BYTES);
     $hkdfsalt = $input->readBytes($config->HKDF_SALT_LEN);
     $nonce = \Sodium\crypto_generichash($eph_public . $public_key, '', \Sodium\CRYPTO_STREAM_NONCEBYTES);
     $ephemeral = new EncryptionPublicKey($eph_public);
     $key = AsymmetricCrypto::getSharedSecret($secretkey, $ephemeral, true);
     list($encKey, $authKey) = self::splitKeys($key, $hkdfsalt, $config);
     // We no longer need the original key after we split it
     unset($key);
     if ($config->USE_BLAKE2B) {
         $mac = \Sodium\crypto_generichash_init($authKey);
         \Sodium\crypto_generichash_update($mac, $header);
         \Sodium\crypto_generichash_update($mac, $eph_public);
         \Sodium\crypto_generichash_update($mac, $hkdfsalt);
         $old_macs = self::streamVerify($input, '' . $mac, $config);
     } else {
         $mac = \hash_init('sha256', HASH_HMAC, $authKey);
         \hash_update($mac, $header);
         \hash_update($mac, $eph_public);
         \hash_update($mac, $hkdfsalt);
         // This will throw an exception if it fails.
         $old_macs = self::streamVerify($input, \hash_copy($mac), $config);
     }
     $ret = self::streamDecrypt($input, $output, new EncryptionKey($encKey), $nonce, $mac, $config, $old_macs);
     unset($encKey);
     unset($authKey);
     unset($nonce);
     unset($mac);
     unset($config);
     unset($old_macs);
     return $ret;
 }
Пример #2
0
 /**
  * Unseal the contents of a file.
  *
  * @param ReadOnlyFile $input
  * @param MutableFile $output
  * @param EncryptionSecretKey $secretKey
  * @return bool
  * @throws CannotPerformOperation
  * @throws InvalidMessage
  */
 protected static function unsealData(ReadOnlyFile $input, MutableFile $output, EncryptionSecretKey $secretKey) : bool
 {
     $publicKey = $secretKey->derivePublicKey();
     // Is the file at least as long as a header?
     if ($input->getSize() < Halite::VERSION_TAG_LEN) {
         throw new InvalidMessage("Input file is too small to have been encrypted by Halite.");
     }
     // Parse the header, ensuring we get 4 bytes
     $header = $input->readBytes(Halite::VERSION_TAG_LEN);
     // Load the config
     $config = self::getConfig($header, 'seal');
     if ($input->getSize() < $config->SHORTEST_CIPHERTEXT_LENGTH) {
         throw new InvalidMessage("Input file is too small to have been encrypted by Halite.");
     }
     // Let's grab the public key and salt
     $ephPublic = $input->readBytes($config->PUBLICKEY_BYTES);
     $hkdfSalt = $input->readBytes($config->HKDF_SALT_LEN);
     // Generate the same nonce, as per sealData()
     $nonce = \Sodium\crypto_generichash($ephPublic . $publicKey->getRawKeyMaterial(), '', \Sodium\CRYPTO_STREAM_NONCEBYTES);
     // Create a key object out of the public key:
     $ephemeral = new EncryptionPublicKey(new HiddenString($ephPublic));
     $key = AsymmetricCrypto::getSharedSecret($secretKey, $ephemeral, true);
     unset($ephemeral);
     list($encKey, $authKey) = self::splitKeys($key, $hkdfSalt, $config);
     // We no longer need the original key after we split it
     unset($key);
     $mac = \Sodium\crypto_generichash_init($authKey);
     \Sodium\crypto_generichash_update($mac, $header);
     \Sodium\crypto_generichash_update($mac, $ephPublic);
     \Sodium\crypto_generichash_update($mac, $hkdfSalt);
     $oldMACs = self::streamVerify($input, Util::safeStrcpy($mac), $config);
     // We no longer need this:
     \Sodium\memzero($hkdfSalt);
     $ret = self::streamDecrypt($input, $output, new EncryptionKey(new HiddenString($encKey)), $nonce, $mac, $config, $oldMACs);
     unset($encKey);
     unset($authKey);
     unset($nonce);
     unset($mac);
     unset($config);
     unset($oldMACs);
     return $ret;
 }
Пример #3
0
 /**
  * Set up our key pair
  *
  * @param EncryptionSecretKey $secret
  */
 protected function setupKeyPair(EncryptionSecretKey $secret)
 {
     $this->secretKey = $secret;
     $this->publicKey = $this->secretKey->derivePublicKey();
 }
Пример #4
0
 /**
  * Decrypt a sealed message with our private key
  * 
  * @param string $ciphertext Encrypted message
  * @param EncryptionSecretKey $privateKey
  * @param mixed $encoding Which encoding scheme to use?
  * @return HiddenString
  * @throws InvalidKey
  * @throws InvalidMessage
  */
 public static function unseal(string $ciphertext, EncryptionSecretKey $privateKey, $encoding = Halite::ENCODE_BASE64URLSAFE) : HiddenString
 {
     $decoder = Halite::chooseEncoder($encoding, true);
     if ($decoder) {
         // We were given hex data:
         try {
             $ciphertext = $decoder($ciphertext);
         } catch (\RangeException $ex) {
             throw new InvalidMessage('Invalid character encoding');
         }
     }
     // Get a box keypair (needed by crypto_box_seal_open)
     $secret_key = $privateKey->getRawKeyMaterial();
     $public_key = \Sodium\crypto_box_publickey_from_secretkey($secret_key);
     $key_pair = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($secret_key, $public_key);
     // Wipe these immediately:
     \Sodium\memzero($secret_key);
     \Sodium\memzero($public_key);
     // Now let's open that sealed box
     $message = \Sodium\crypto_box_seal_open($ciphertext, $key_pair);
     // Always memzero after retrieving a value
     \Sodium\memzero($key_pair);
     if ($message === false) {
         throw new InvalidKey('Incorrect secret key for this sealed message');
     }
     // We have our encrypted message here
     return new HiddenString($message);
 }