/**
  * Generate a new key pair.
  *
  * @return KeyPair the new key pair
  */
 public final function generateKeyPair()
 {
     /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
     $kp = \Sodium\crypto_box_keypair();
     /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
     return new KeyPair(\Sodium\crypto_box_secretkey($kp), \Sodium\crypto_box_publickey($kp));
 }
Example #2
0
 /**
  * Generate a key pair for public key encryption
  * 
  * @param type $secret_key
  * @return \ParagonIE\Halite\EncryptionKeyPair
  */
 public static function generateEncryptionKeyPair(string &$secret_key = '') : EncryptionKeyPair
 {
     // Encryption keypair
     $kp = \Sodium\crypto_box_keypair();
     $secret_key = \Sodium\crypto_box_secretkey($kp);
     // Let's wipe our $kp variable
     \Sodium\memzero($kp);
     return new EncryptionKeyPair(new EncryptionSecretKey($secret_key));
 }
Example #3
0
 /**
  * Return an EncryptionSecretKey and EncryptionPublicKey which are related
  *
  * @param string $driver
  * @return Key[]
  */
 public static function generateEncryptionKeyPair($driver = Common::DRIVER_SODIUM)
 {
     if ($driver === Common::DRIVER_SODIUM) {
         $kp = \Sodium\crypto_box_keypair();
         return [new EncryptionSecretKey(\Sodium\crypto_box_secretkey($kp, $driver)), new EncryptionPublicKey(\Sodium\crypto_box_publickey($kp, $driver))];
     } elseif ($driver === Common::DRIVER_OPENSSL) {
         $dhres = \openssl_pkey_new(['dh' => ['p' => self::GROUP14PRIME, 'g' => 2], 'private_key_bits' => 2048, 'private_key_type' => OPENSSL_KEYTYPE_DH]);
         $details = \openssl_pkey_get_details($dhres);
         return [new EncryptionSecretKey($details['dh']['priv_key'], $driver), new EncryptionPublicKey($details['dh']['pub_key'], $driver)];
     }
 }
 /**
  * Returns a new set of keys for message encryption and signing.
  *
  * @param string $seed The seed to use to create repeatable keys.
  * @param string $hashKey The key to hash the key with.
  * @return array
  */
 public static function generateKeys($seed = null, $hashKey = '')
 {
     # The keys are being generated from a seed.
     if ($seed !== null) {
         # Generate some repeatable hashes to create keys against for recovery
         $encrHash = Hash::hash($seed, $hashKey, Constants::BOX_SEEDBYTES);
         $signHash = Hash::hash($seed, $hashKey, Constants::SIGN_SEEDBYTES);
         # Build recoverable pre-seeded key pairs.
         $seeds = ['encr' => \Sodium\crypto_box_keypair($encrHash), 'sign' => \Sodium\crypto_sign_keypair($signHash)];
     } else {
         # Build un-recoverable key pairs.
         $seeds = ['encr' => \Sodium\crypto_box_keypair(), 'sign' => \Sodium\crypto_sign_keypair()];
     }
     # Return the two generated key pairs to the client.
     return ['encr' => ['pri' => Helpers::bin2hex(\Sodium\crypto_box_secretkey($seeds['encr'])), 'pub' => Helpers::bin2hex(\Sodium\crypto_box_publickey($seeds['encr']))], 'sign' => ['pri' => Helpers::bin2hex(\Sodium\crypto_sign_secretkey($seeds['sign'])), 'pub' => Helpers::bin2hex(\Sodium\crypto_sign_publickey($seeds['sign']))]];
 }
Example #5
0
 /**
  * @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);
 }
Example #6
0
 /**
  * Encrypt a message with a target users' public key
  * 
  * @param string $source Message to encrypt
  * @param string $publicKey
  * @param boolean $raw Don't hex encode the output?
  * 
  * @return string
  */
 public static function seal($source, Contract\CryptoKeyInterface $publicKey, $raw = false)
 {
     if ($publicKey->isPublicKey()) {
         if (function_exists('\\Sodium\\crypto_box_seal')) {
             $sealed = \Sodium\crypto_box_seal($source, $publicKey->get());
         } else {
             /**
              * Polyfill for libsodium < 1.0.3
              */
             // Generate an ephemeral keypair
             $eph_kp = \Sodium\crypto_box_keypair();
             $eph_secret = \Sodium\crypto_box_secretkey($eph_kp);
             $eph_public = \Sodium\crypto_box_publickey($eph_kp);
             $seal_pubkey = $publicKey->get();
             $box_kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($eph_secret, $seal_pubkey);
             // Calculate the nonce
             $nonce = \Sodium\crypto_generichash($eph_public . $seal_pubkey, null, \Sodium\CRYPTO_BOX_NONCEBYTES);
             // Seal the message
             $sealed = $eph_public . \Sodium\crypto_box($source, $nonce, $box_kp);
             // Don't forget to wipe
             \Sodium\memzero($seal_pubkey);
             \Sodium\memzero($eph_kp);
             \Sodium\memzero($eph_secret);
             \Sodium\memzero($eph_public);
             \Sodium\memzero($nonce);
             \Sodium\memzero($box_kp);
         }
         if ($raw) {
             return $sealed;
         }
         return \Sodium\bin2hex($sealed);
     }
     throw new CryptoAlert\InvalidKey('Expected a public key');
 }
Example #7
0
 /**
  * Generate a key
  * 
  * @param int $type
  * @param &string $secret_key - Reference to optional variable to store secret key in
  * @return array|Key
  */
 public static function generate($type = self::CRYPTO_SECRETBOX, &$secret_key = null)
 {
     // Set this to true to flag a key as a signing key
     $signing = false;
     /**
      * Are we doing public key cryptography?
      */
     if (($type & self::ASYMMETRIC) !== 0) {
         /**
          * Are we doing encryption or digital signing?
          */
         if (($type & self::ENCRYPTION) !== 0) {
             // Encryption keypair
             $kp = \Sodium\crypto_box_keypair();
             $secret_key = \Sodium\crypto_box_secretkey($kp);
             $public_key = \Sodium\crypto_box_publickey($kp);
         } elseif (($type & self::SIGNATURE) !== 0) {
             // Digital signature keypair
             $signing = true;
             $kp = \Sodium\crypto_sign_keypair();
             $secret_key = \Sodium\crypto_sign_secretkey($kp);
             $public_key = \Sodium\crypto_sign_publickey($kp);
         } else {
             throw new CryptoException\InvalidFlags('Must specify encryption or authentication');
         }
         // Let's wipe our $kp variable
         \Sodium\memzero($kp);
         // Let's return an array with two keys
         return [new ASecretKey($secret_key, $signing), new APublicKey($public_key, $signing)];
     } elseif ($type & self::SECRET_KEY !== 0) {
         /**
          * Are we doing encryption or authentication?
          */
         if ($type & self::ENCRYPTION !== 0) {
             $secret_key = \random_bytes(\Sodium\CRYPTO_SECRETBOX_KEYBYTES);
         } elseif ($type & self::SIGNATURE !== 0) {
             $signing = true;
             // ...let it throw, let it throw!
             $secret_key = \random_bytes(\Sodium\CRYPTO_AUTH_KEYBYTES);
         }
         return new SecretKey($secret_key, $signing);
     } else {
         throw new CryptoException\InvalidFlags('Must specify symmetric-key or asymmetric-key');
     }
 }
 /**
  * Check if a password is known by the knownpassword.org API.
  *
  * @param string $password      	The password to check.
  * @param string $passwordFormat    The format of the given password (Blake2b, Sha512, Cleartext) [Default: Blake2b].
  * @return mixed               		Exception on error, true if the password is known and false if the password is unknown.
  * @access public
  */
 public function checkPassword($password, $passwordFormat = "Blake2b")
 {
     $apiData = array();
     switch ($passwordFormat) {
         case "Blake2b":
             $apiData = array("Blake2b" => $password);
             break;
         case "Sha512":
             $apiData = array("Sha512" => $password);
             break;
         case "Cleartext":
             $apiData = array("Cleartext" => $password);
             break;
         default:
             throw new \Exception("Unknown passwordFormat.");
     }
     $nonce = \Sodium\randombytes_buf(24);
     $signature = \Sodium\crypto_sign_detached($nonce, $this->_privatekey);
     $clearJson = json_encode($apiData);
     $encryptionNonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_BOX_NONCEBYTES);
     $encryptionKeyPair = \Sodium\crypto_box_keypair();
     $encryptionSecretkey = \Sodium\crypto_box_secretkey($encryptionKeyPair);
     $encryptionPublickey = \Sodium\crypto_box_publickey($encryptionKeyPair);
     $encryptionKeyPair = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($encryptionSecretkey, $this->_serverEncryptionPublicKey);
     $ciphertext = \Sodium\crypto_box($clearJson, $encryptionNonce, $encryptionKeyPair);
     $encryptedApiData = array("PublicKey" => \Sodium\bin2hex($encryptionPublickey), "Nonce" => \Sodium\bin2hex($encryptionNonce), "Ciphertext" => \Sodium\bin2hex($ciphertext));
     $data_string = json_encode($encryptedApiData);
     $ch = curl_init($this->_apiurl . "/checkpassword");
     curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
     curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
     curl_setopt($ch, CURLOPT_HEADER, 1);
     curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
     curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: ' . strlen($data_string), 'User-Agent: ' . 'Laravel 5', 'X-Public: ' . \Sodium\bin2hex($this->_publickey), 'X-Nonce: ' . \Sodium\bin2hex($nonce), 'X-Signature: ' . \Sodium\bin2hex($signature)));
     if (!($result = curl_exec($ch))) {
         throw new \Exception("Request failed");
     }
     $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
     $header = substr($result, 0, $header_size);
     $headers = $this->get_headers_from_curl_response($header);
     if (array_key_exists("http_code", $headers[0]) && array_key_exists("X-Powered-By", $headers[0]) && array_key_exists("X-Signature", $headers[0])) {
         $httpCode = $headers[0]["http_code"];
         $responsePowered = $headers[0]["X-Powered-By"];
         $responseSignature = $headers[0]["X-Signature"];
         $responseNonce = $headers[0]["X-Nonce"];
         if ($httpCode === "HTTP/1.1 200 OK" || $httpCode === "HTTP/2.0 200 OK") {
             if ($responsePowered === "bitbeans") {
                 // validate the response signature
                 if (!\Sodium\crypto_sign_verify_detached(\Sodium\hex2bin($responseSignature), \Sodium\crypto_generichash(\Sodium\hex2bin($responseNonce), null, 64), $this->_serverSignaturePublicKey)) {
                     throw new \Exception("Invalid signature");
                 }
             } else {
                 throw new \Exception("Invalid server");
             }
         } else {
             throw new \Exception("Invalid response code");
         }
     } else {
         throw new \Exception("Invalid header");
     }
     $result = substr($result, $header_size);
     curl_close($ch);
     $resultJson = json_decode($result);
     $decryptionKeyPair = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($encryptionSecretkey, \Sodium\hex2bin($resultJson->{'publicKey'}));
     $plaintext = \Sodium\crypto_box_open(\Sodium\hex2bin($resultJson->{'ciphertext'}), \Sodium\hex2bin($resultJson->{'nonce'}), $decryptionKeyPair);
     if ($plaintext === FALSE) {
         throw new \Exception("Malformed message or invalid MAC");
     }
     $plaintextJson = json_decode($plaintext);
     return !$plaintextJson->{'FoundPassword'};
 }