/** * @covers Asymmetric::seal() * @covers Asymmetric::unseal() */ public function testSeal() { if (\Sodium\library_version_major() < 7 || \Sodium\library_version_major() == 7 && \Sodium\library_version_minor() < 5) { $this->markTestSkipped("Your version of libsodium is too old"); } $alice = KeyFactory::generateEncryptionKeyPair(); $enc_secret = $alice->getSecretKey(); $enc_public = $alice->getPublicKey(); $this->assertEquals(\Sodium\crypto_box_publickey_from_secretkey($enc_secret->getRawKeyMaterial()), $enc_public->getRawKeyMaterial()); $message = 'This is for your eyes only'; $kp = \Sodium\crypto_box_keypair(); $test = \Sodium\crypto_box_seal($message, \Sodium\crypto_box_publickey($kp)); $decr = \Sodium\crypto_box_seal_open($test, $kp); $this->assertTrue($decr !== false); $sealed = Asymmetric::seal($message, new EncryptionPublicKey(\Sodium\crypto_box_publickey($kp))); $opened = Asymmetric::unseal($sealed, new EncryptionSecretKey(\Sodium\crypto_box_secretkey($kp))); $sealed = Asymmetric::seal($message, $enc_public); $opened = Asymmetric::unseal($sealed, $enc_secret); $this->assertEquals($opened, $message); $sealed_raw = Asymmetric::seal($message, $alice->getPublicKey()); $opened_raw = Asymmetric::unseal($sealed_raw, $alice->getSecretKey()); $this->assertEquals($opened_raw, $message); }
/** * Decrypt a sealed message with our private key * * @param string $source Encrypted message (string or resource for a file) * @param Contract\CryptoKeyInterface $privateKey * @param boolean $raw Don't hex decode the input? * * @return string */ public static function unseal($source, Contract\CryptoKeyInterface $privateKey, $raw = false) { if (!$raw) { $source = \Sodium\hex2bin($source); } if ($privateKey->isSecretKey()) { if (function_exists('\\Sodium\\crypto_box_seal_open')) { // Get a box keypair (needed by crypto_box_seal_open) $secret_key = $privateKey->get(); $public_key = \Sodium\crypto_box_publickey_from_secretkey($secret_key); $kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($secret_key, $public_key); // Now let's open that sealed box $message = \Sodium\crypto_box_seal_open($source, $kp); // Always memzero after retrieving a value \Sodium\memzero($secret_key); \Sodium\memzero($public_key); \Sodium\memzero($kp); } else { /** * Polyfill for libsodium < 1.0.3 */ // Let's generate the box keypair $my_secret = $privateKey->get(); $my_public = \Sodium\crypto_box_publickey_from_secretkey($my_secret); $eph_public = mb_substr($source, 0, \Sodium\CRYPTO_BOX_PUBLICKEYBYTES, '8bit'); $box_kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($my_secret, $eph_public); // Calculate the nonce as libsodium does $nonce = \Sodium\crypto_generichash($eph_public . $my_public, null, \Sodium\CRYPTO_BOX_NONCEBYTES); // $boxed is the ciphertext from crypto_box_seal $boxed = mb_substr($source, \Sodium\CRYPTO_BOX_PUBLICKEYBYTES, null, '8bit'); $message = \Sodium\crypto_box_open($boxed, $nonce, $box_kp); \Sodium\memzero($my_secret); \Sodium\memzero($my_public); \Sodium\memzero($box_kp); \Sodium\memzero($nonce); \Sodium\memzero($eph_public); } if ($message === false) { throw new CryptoAlert\InvalidKey('Incorrect secret key'); } // We have our encrypted message here return $message; } throw new CryptoAlert\InvalidKey('Expected a secret key'); }
/** * Decrypt a sealed message with our private key * * @param string $source Encrypted message (string or resource for a file) * @param EncryptionSecretKey $privateKey * @param boolean $raw Don't hex decode the input? * @return string * @throws CryptoException\InvalidKey */ public static function unseal(string $source, EncryptionSecretKey $privateKey, bool $raw = false) : string { if (!$raw) { $source = \Sodium\hex2bin($source); } // Get a box keypair (needed by crypto_box_seal_open) $secret_key = $privateKey->getRawKeyMaterial(); $public_key = \Sodium\crypto_box_publickey_from_secretkey($secret_key); $kp = \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($source, $kp); // Always memzero after retrieving a value \Sodium\memzero($kp); if ($message === false) { throw new CryptoException\InvalidKey('Incorrect secret key for this sealed message'); } // We have our encrypted message here return $message; }
/** * Decrypt a sealed message with our private key * * @param string $source Encrypted message (string or resource for a file) * @param Contract\CryptoKeyInterface $privateKey * @param boolean $raw Don't hex decode the input? * * @return string */ public static function unseal($source, Contract\CryptoKeyInterface $privateKey, $raw = false) { if (!$raw) { $source = \Sodium\hex2bin($source); } if ($privateKey->isSecretKey()) { if (function_exists('\\Sodium\\crypto_box_seal_open')) { // Get a box keypair (needed by crypto_box_seal_open) $secret_key = $privateKey->get(); $public_key = \Sodium\crypto_box_publickey_from_secretkey($secret_key); $kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($secret_key, $public_key); // Now let's open that sealed box $message = \Sodium\crypto_box_seal_open($source, $kp); // Always memzero after retrieving a value \Sodium\memzero($secret_key); \Sodium\memzero($public_key); \Sodium\memzero($kp); } else { throw new CryptoException\CannotPerformOperation('crypto_box_seal_open is not available'); } if ($message === false) { throw new CryptoException\InvalidKey('Incorrect secret key'); } // We have our encrypted message here return $message; } throw new CryptoException\InvalidKey('Expected a secret key'); }
/** * Decrypt a sealed message with our private key * * @param string $source Encrypted message (string or resource for a file) * @param EncryptionSecretKey $privateKey * @param boolean $raw Don't hex decode the input? * * @return string * * @throws CryptoException\InvalidKey * @throws CryptoException\CannotPerformOperation */ public static function unseal($source, Contract\KeyInterface $privateKey, $raw = false) { if (!$privateKey instanceof EncryptionSecretKey) { throw new CryptoException\InvalidKey('Argument 2: Expected an instance of EncryptionSecretKey'); } if (!$raw) { $source = \Sodium\hex2bin($source); } if (!function_exists('\\Sodium\\crypto_box_seal_open')) { throw new CryptoException\CannotPerformOperation('crypto_box_seal_open is not available, please update/reinstall libsodium'); } // Get a box keypair (needed by crypto_box_seal_open) $secret_key = $privateKey->get(); $public_key = \Sodium\crypto_box_publickey_from_secretkey($secret_key); $kp = \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($source, $kp); // Always memzero after retrieving a value \Sodium\memzero($kp); if ($message === false) { throw new CryptoException\InvalidKey('Incorrect secret key for this sealed message'); } // We have our encrypted message here return $message; }
/** * 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); }