Пример #1
0
/**
 * If the libsodium PHP extension is loaded, we'll use it above any other
 * solution.
 *
 * libsodium-php project:
 * @ref https://github.com/jedisct1/libsodium-php
 *
 * @param int $bytes
 *
 * @throws Exception
 *
 * @return string
 */
function random_bytes($bytes)
{
    try {
        $bytes = RandomCompat_intval($bytes);
    } catch (TypeError $ex) {
        throw new TypeError('random_bytes(): $bytes must be an integer');
    }
    if ($bytes < 1) {
        throw new Error('Length must be greater than 0');
    }
    /**
     * \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be
     * generated in one invocation.
     */
    if ($bytes > 2147483647) {
        $buf = '';
        for ($i = 0; $i < $bytes; $i += 1073741824) {
            $n = $bytes - $i > 1073741824 ? 1073741824 : $bytes - $i;
            $buf .= \Sodium\randombytes_buf($n);
        }
    } else {
        $buf = \Sodium\randombytes_buf($bytes);
    }
    if ($buf !== false) {
        if (RandomCompat_strlen($buf) === $bytes) {
            return $buf;
        }
    }
    /**
     * If we reach here, PHP has failed us.
     */
    throw new Exception('Could not gather sufficient random data');
}
Пример #2
0
function safeEncrypt($message, $key)
{
    $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
    $cipher = base64_encode($nonce . \Sodium\crypto_secretbox($message, $nonce, $key));
    \Sodium\memzero($message);
    \Sodium\memzero($key);
    return $cipher;
}
Пример #3
0
 public function testChecksum()
 {
     $csum = File::checksumFile(__DIR__ . '/tmp/paragon_avatar.png');
     $this->assertEquals($csum, "09f9f74a0e742d057ca08394db4c2e444be88c0c94fe9a914c3d3758c7eccafb" . "8dd286e3d6bc37f353e76c0c5aa2036d978ca28ffaccfa59f5dc1f076c5517a0");
     $data = \Sodium\randombytes_buf(32);
     \file_put_contents(__DIR__ . '/tmp/garbage.dat', $data);
     $hash = \Sodium\crypto_generichash($data, null, 64);
     $file = File::checksumFile(__DIR__ . '/tmp/garbage.dat', null, true);
     $this->assertEquals($hash, $file);
 }
Пример #4
0
 public function testFileRead()
 {
     $filename = \tempnam('/tmp', 'x');
     $buf = \Sodium\randombytes_buf(65537);
     \file_put_contents($filename, $buf);
     $fStream = new ReadOnlyFile($filename);
     $this->assertSame($fStream->readBytes(65537), $buf);
     $fStream->reset(0);
     \file_put_contents($filename, Util::safeSubstr($buf, 0, 32768) . 'x' . Util::safeSubstr($buf, 32768));
     try {
         $fStream->readBytes(65537);
         throw new \Exception('fail');
     } catch (CryptoException\FileModified $ex) {
         $this->assertTrue($ex instanceof CryptoException\FileModified);
     }
 }
Пример #5
0
 /**
  * Encrypt a message using the Halite encryption protocol
  * (Encrypt then MAC -- Xsalsa20 then HMAC-SHA-512/256)
  * 
  * @param string $plaintext
  * @param EncryptionKey $secretKey
  * @param boolean $raw Don't hex encode the output?
  * @return string
  */
 public static function encrypt(string $plaintext, EncryptionKey $secretKey, bool $raw = false) : string
 {
     $config = SymmetricConfig::getConfig(Halite::HALITE_VERSION, 'encrypt');
     // Generate a nonce and HKDF salt:
     $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
     $salt = \Sodium\randombytes_buf($config->HKDF_SALT_LEN);
     // Split our keys according to the HKDF salt:
     list($eKey, $aKey) = self::splitKeys($secretKey, $salt, $config);
     // Encrypt our message with the encryption key:
     $xored = \Sodium\crypto_stream_xor($plaintext, $nonce, $eKey);
     \Sodium\memzero($eKey);
     // Calculate an authentication tag:
     $auth = self::calculateMAC(Halite::HALITE_VERSION . $salt . $nonce . $xored, $aKey);
     \Sodium\memzero($aKey);
     if (!$raw) {
         return \Sodium\bin2hex(Halite::HALITE_VERSION . $salt . $nonce . $xored . $auth);
     }
     return Halite::HALITE_VERSION . $salt . $nonce . $xored . $auth;
 }
Пример #6
0
 /**
  * Encrypt a message using the Halite encryption protocol
  * 
  * @param string $plaintext
  * @param EncryptionKey $secretKey
  * @param boolean $raw Don't hex encode the output?
  * @return string
  */
 public static function encrypt($plaintext, Contract\KeyInterface $secretKey, $raw = false)
 {
     if (!$secretKey instanceof EncryptionKey) {
         throw new CryptoException\InvalidKey('Expected an instance of EncryptionKey');
     }
     $config = SymmetricConfig::getConfig(Halite::HALITE_VERSION, 'encrypt');
     $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
     $salt = \Sodium\randombytes_buf($config->HKDF_SALT_LEN);
     list($eKey, $aKey) = self::splitKeys($secretKey, $salt, $config);
     $xored = \Sodium\crypto_stream_xor($plaintext, $nonce, $eKey);
     $auth = self::calculateMAC(Halite::HALITE_VERSION . $salt . $nonce . $xored, $aKey);
     \Sodium\memzero($eKey);
     \Sodium\memzero($aKey);
     if (!$raw) {
         return \Sodium\bin2hex(Halite::HALITE_VERSION . $salt . $nonce . $xored . $auth);
     }
     return Halite::HALITE_VERSION . $salt . $nonce . $xored . $auth;
 }
Пример #7
0
 /**
  * Seal a (file handle)
  *
  * @param ReadOnlyFile $input
  * @param MutableFile $output
  * @param EncryptionPublicKey $publickey
  * @return int
  */
 protected static function sealData(ReadOnlyFile $input, MutableFile $output, EncryptionPublicKey $publickey) : int
 {
     // Generate a new keypair for this encryption
     $eph_kp = KeyFactory::generateEncryptionKeyPair();
     $eph_secret = $eph_kp->getSecretKey();
     $eph_public = $eph_kp->getPublicKey();
     unset($eph_kp);
     // Calculate the shared secret key
     $key = AsymmetricCrypto::getSharedSecret($eph_secret, $publickey, true);
     // Destroy the secre tkey after we have the shared secret
     unset($eph_secret);
     $config = self::getConfig(Halite::HALITE_VERSION_FILE, 'seal');
     // Generate a nonce as per crypto_box_seal
     $nonce = \Sodium\crypto_generichash($eph_public->getRawKeyMaterial() . $publickey->getRawKeyMaterial(), '', \Sodium\CRYPTO_STREAM_NONCEBYTES);
     // Generate a random HKDF salt
     $hkdfsalt = \Sodium\randombytes_buf($config->HKDF_SALT_LEN);
     // Split the keys
     list($encKey, $authKey) = self::splitKeys($key, $hkdfsalt, $config);
     // We no longer need the original key after we split it
     unset($key);
     $output->writeBytes(Halite::HALITE_VERSION_FILE, Halite::VERSION_TAG_LEN);
     $output->writeBytes($eph_public->getRawKeyMaterial(), \Sodium\CRYPTO_BOX_PUBLICKEYBYTES);
     $output->writeBytes($hkdfsalt, $config->HKDF_SALT_LEN);
     if ($config->USE_BLAKE2B) {
         $mac = \Sodium\crypto_generichash_init($authKey);
         \Sodium\crypto_generichash_update($mac, Halite::HALITE_VERSION_FILE);
         \Sodium\crypto_generichash_update($mac, $eph_public->getRawKeyMaterial());
         \Sodium\crypto_generichash_update($mac, $hkdfsalt);
     } else {
         $mac = \hash_init('sha256', HASH_HMAC, $authKey);
         // We no longer need $authKey after we set up the hash context
         unset($authKey);
         \hash_update($mac, Halite::HALITE_VERSION_FILE);
         \hash_update($mac, $eph_public->getRawKeyMaterial());
         \hash_update($mac, $hkdfsalt);
     }
     \Sodium\memzero($authKey);
     unset($eph_public);
     return self::streamEncrypt($input, $output, new EncryptionKey($encKey), $nonce, $mac, $config);
 }
Пример #8
0
 /**
  * @covers Symmetric::unpackMessageForDecryption()
  */
 public function testUnpack()
 {
     $key = new EncryptionKey(new HiddenString(\str_repeat('A', 32)));
     // Randomly sized plaintext
     $size = \Sodium\randombytes_uniform(1023) + 1;
     $plaintext = \Sodium\randombytes_buf($size);
     $message = Symmetric::encrypt(new HiddenString($plaintext), $key, true);
     // Let's unpack our message
     $unpacked = Symmetric::unpackMessageForDecryption($message);
     // Now to test our expected results!
     $this->assertSame(Util::safeStrlen($unpacked[0]), Halite::VERSION_TAG_LEN);
     $this->assertTrue($unpacked[1] instanceof \ParagonIE\Halite\Symmetric\Config);
     $config = $unpacked[1];
     if ($config instanceof \ParagonIE\Halite\Symmetric\Config) {
         $this->assertSame(Util::safeStrlen($unpacked[2]), $config->HKDF_SALT_LEN);
         $this->assertSame(Util::safeStrlen($unpacked[3]), \Sodium\CRYPTO_STREAM_NONCEBYTES);
         $this->assertSame(Util::safeStrlen($unpacked[4]), Util::safeStrlen($message) - (Halite::VERSION_TAG_LEN + $config->HKDF_SALT_LEN + \Sodium\CRYPTO_STREAM_NONCEBYTES + $config->MAC_SIZE));
         $this->assertSame(Util::safeStrlen($unpacked[5]), $config->MAC_SIZE);
     } else {
         $this->fail('Cannot continue');
     }
 }
Пример #9
0
 /**
  * Generates a string of random binary data of the specified length
  *
  * @param integer $length The number of bytes of random binary data to generate
  * @return string A binary string
  */
 public function generate($length)
 {
     return \Sodium\randombytes_buf($length);
 }
Пример #10
0
function _appBaseEncrypt($data)
{
    //return($data);
    $key = substr(_configBaseQuery("loadedHash"), 0, \Sodium\CRYPTO_SECRETBOX_KEYBYTES);
    $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
    $res = $nonce . \Sodium\crypto_secretbox($data, $nonce, $key);
    return $res;
}
Пример #11
0
 /**
  * Encrypt a message using the Halite encryption protocol
  * 
  * @param string $plaintext
  * @param Key $secretKey
  * @param boolean $raw Don't hex encode the output?
  * @return string
  */
 public static function encrypt($plaintext, Contract\CryptoKeyInterface $secretKey, $raw = false)
 {
     if ($secretKey->isAsymmetricKey()) {
         throw new CryptoAlert\InvalidKey('Expected a symmetric key, not an asymmetric key');
     }
     if (!$secretKey->isEncryptionKey()) {
         throw new CryptoAlert\InvalidKey('Encryption key expected');
     }
     $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
     $salt = \Sodium\randombytes_buf(Config::HKDF_SALT_LEN);
     list($eKey, $aKey) = self::splitKeys($secretKey, $salt);
     $xored = \Sodium\crypto_stream_xor($plaintext, $nonce, $eKey);
     $auth = self::calculateMAC(Config::HALITE_VERSION . $salt . $nonce . $xored, $aKey);
     \Sodium\memzero($eKey);
     \Sodium\memzero($aKey);
     if (!$raw) {
         return \Sodium\bin2hex(Config::HALITE_VERSION . $salt . $nonce . $xored . $auth);
     }
     return Config::HALITE_VERSION . $salt . $nonce . $xored . $auth;
 }
Пример #12
0
 public function generatePublicKey()
 {
     return \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
 }
 /**
  * @param int $size
  * @return string
  */
 protected function createRandom($size)
 {
     /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
     return \Sodium\randombytes_buf($size);
 }
Пример #14
0
 /**
  * Seal a (file handle)
  * 
  * @param ReadOnlyFile $input
  * @param MutableFile $output
  * @param EncryptionPublicKey $publickey
  */
 public static function sealStream(ReadOnlyFile $input, MutableFile $output, KeyInterface $publickey)
 {
     if (!$publickey instanceof EncryptionPublicKey) {
         throw new \ParagonIE\Halite\Alerts\InvalidKey('Argument 3: Expected an instance of EncryptionPublicKey');
     }
     // Generate a new keypair for this encryption
     $eph_kp = KeyFactory::generateEncryptionKeyPair();
     $eph_secret = $eph_kp->getSecretKey();
     $eph_public = $eph_kp->getPublicKey();
     unset($eph_kp);
     // Calculate the shared secret key
     $key = AsymmetricCrypto::getSharedSecret($eph_secret, $publickey, true);
     // Destroy the secre tkey after we have the shared secret
     unset($eph_secret);
     $config = self::getConfig(Halite::HALITE_VERSION_FILE, 'seal');
     // Generate a nonce as per crypto_box_seal
     $nonce = \Sodium\crypto_generichash($eph_public->get() . $publickey->get(), null, \Sodium\CRYPTO_STREAM_NONCEBYTES);
     // Generate a random HKDF salt
     $hkdfsalt = \Sodium\randombytes_buf($config->HKDF_SALT_LEN);
     // Split the keys
     list($encKey, $authKey) = self::splitKeys($key, $hkdfsalt, $config);
     // We no longer need the original key after we split it
     unset($key);
     $mac = \hash_init('sha256', HASH_HMAC, $authKey);
     // We no longer need to retain this after we've set up the hash context
     unset($authKey);
     $output->writeBytes(Halite::HALITE_VERSION_FILE, Halite::VERSION_TAG_LEN);
     $output->writeBytes($eph_public->get(), \Sodium\CRYPTO_BOX_PUBLICKEYBYTES);
     $output->writeBytes($hkdfsalt, $config->HKDF_SALT_LEN);
     \hash_update($mac, Halite::HALITE_VERSION_FILE);
     \hash_update($mac, $eph_public->get());
     \hash_update($mac, $hkdfsalt);
     unset($eph_public);
     return self::streamEncrypt($input, $output, new EncryptionKey($encKey), $nonce, $mac, $config);
 }
Пример #15
0
 /**
  * Generate an an encryption key (symmetric-key cryptography)
  * 
  * @param &string $secret_key
  * @return EncryptionKey
  */
 public static function generateEncryptionKey(string &$secret_key = '') : EncryptionKey
 {
     $secret_key = \Sodium\randombytes_buf(\Sodium\CRYPTO_STREAM_KEYBYTES);
     return new EncryptionKey($secret_key);
 }
Пример #16
0
 /**
  * Encrypt a message using the Halite encryption protocol
  *
  * (Encrypt then MAC -- xsalsa20 then keyed-Blake2b)
  * You don't need to worry about chosen-ciphertext attacks.
  *
  * @param HiddenString $plaintext
  * @param EncryptionKey $secretKey
  * @param mixed $encoding
  * @return string
  */
 public static function encrypt(HiddenString $plaintext, EncryptionKey $secretKey, $encoding = Halite::ENCODE_BASE64URLSAFE) : string
 {
     $config = SymmetricConfig::getConfig(Halite::HALITE_VERSION, 'encrypt');
     // Generate a nonce and HKDF salt:
     $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
     $salt = \Sodium\randombytes_buf($config->HKDF_SALT_LEN);
     /* Split our key into two keys: One for encryption, the other for
                authentication. By using separate keys, we can reasonably dismiss
                likely cross-protocol attacks.
     
                This uses salted HKDF to split the keys, which is why we need the
                salt in the first place. */
     list($encKey, $authKey) = self::splitKeys($secretKey, $salt, $config);
     // Encrypt our message with the encryption key:
     $encrypted = \Sodium\crypto_stream_xor($plaintext->getString(), $nonce, $encKey);
     \Sodium\memzero($encKey);
     // Calculate an authentication tag:
     $auth = self::calculateMAC(Halite::HALITE_VERSION . $salt . $nonce . $encrypted, $authKey, $config);
     \Sodium\memzero($authKey);
     $message = Halite::HALITE_VERSION . $salt . $nonce . $encrypted . $auth;
     // Wipe every superfluous piece of data from memory
     \Sodium\memzero($nonce);
     \Sodium\memzero($salt);
     \Sodium\memzero($encrypted);
     \Sodium\memzero($auth);
     $encoder = Halite::chooseEncoder($encoding);
     if ($encoder) {
         return $encoder($message);
     }
     return $message;
 }
Пример #17
0
 /**
  * Seal a (file handle)
  * 
  * @param $input
  * @param $output
  * @param \ParagonIE\Halite\Contract\CryptoKeyInterface $publickey
  */
 public static function sealResource($input, $output, \ParagonIE\Halite\Contract\CryptoKeyInterface $publickey)
 {
     // Input validation
     if (!\is_resource($input)) {
         throw new \ParagonIE\Halite\Alerts\InvalidType('Expected input handle to be a resource');
     }
     if (!\is_resource($output)) {
         throw new \ParagonIE\Halite\Alerts\InvalidType('Expected output handle to be a resource');
     }
     if (!$publickey->isPublicKey()) {
         throw new CryptoAlert\InvalidKey('Especter a public key');
     }
     if (!$publickey->isAsymmetricKey()) {
         throw new CryptoAlert\InvalidKey('Expected a key intended for asymmetric-key cryptography');
     }
     // Generate a new keypair for this encryption
     list($eph_secret, $eph_public) = Key::generate(Key::CRYPTO_BOX);
     // Calculate the shared secret key
     $key = Asymmetric::getSharedSecret($eph_secret, $publickey, true);
     // Destroy the secre tkey after we have the shared secret
     unset($eph_secret);
     $config = self::getConfig(Halite::HALITE_VERSION, 'seal');
     // Generate a nonce as per crypto_box_seal
     $nonce = \Sodium\crypto_generichash($eph_public->get() . $publickey->get(), null, \Sodium\CRYPTO_STREAM_NONCEBYTES);
     // Generate a random HKDF salt
     $hkdfsalt = \Sodium\randombytes_buf($config['HKDF_SALT_LEN']);
     // Split the keys
     list($encKey, $authKey) = self::splitKeys($key, $hkdfsalt);
     // We no longer need the original key after we split it
     unset($key);
     $mac = \hash_init('sha256', HASH_HMAC, $authKey);
     // We no longer need to retain this after we've set up the hash context
     unset($authKey);
     $written = \fwrite($output, Halite::HALITE_VERSION, Halite::VERSION_TAG_LEN);
     if ($written === false) {
         throw new FileAlert\AccessDenied('Could not write to the file');
     }
     $written &= \fwrite($output, $eph_public->get(), \Sodium\CRYPTO_BOX_PUBLICKEYBYTES);
     if ($written === false) {
         throw new FileAlert\AccessDenied('Could not write to the file');
     }
     $written &= \fwrite($output, $hkdfsalt, Halite::HKDF_SALT_LEN);
     if ($written === false) {
         throw new FileAlert\AccessDenied('Could not write to the file');
     }
     \hash_update($mac, Halite::HALITE_VERSION);
     \hash_update($mac, $eph_public->get());
     \hash_update($mac, $hkdfsalt);
     unset($eph_public);
     return self::streamEncrypt($input, $output, new Key($encKey), $nonce, $mac, $config);
 }
Пример #18
0
 /**
  * Generate an an encryption key (symmetric-key cryptography)
  * 
  * @param &string $secret_key
  * @return EncryptionKey
  */
 public static function generateEncryptionKey(&$secret_key = null)
 {
     $secret_key = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_KEYBYTES);
     return new EncryptionKey($secret_key);
 }
Пример #19
0
 function crCryptoProcess($dir, $input, $eckey, $cipher)
 {
     //  sanity checks
     $allowedDir = array('encrypt', 'decrypt');
     $inputTypes = array('string', 'ad');
     $cipherList = array('aes256gcm', 'chacha');
     if (!in_array($dir, $allowedDir)) {
         $this->webLog($this->crLanguage('generic', 'invalidKey', array('dir', implode('|', $allowedDir))), __METHOD__, 'error');
         return false;
     }
     if (is_string($input)) {
         $input = (object) array('string' => $input, 'ad' => '');
     }
     if (is_object($input)) {
         if (count((array) $input) === 2) {
             foreach ($input as $key => $value) {
                 if (!in_array($key, $inputTypes)) {
                     $this->webLog($this->crLanguage('generic', 'invalidKey', array('input', implode('|', $inputTypes))), __METHOD__, 'error');
                     return false;
                 }
             }
         } else {
             $this->webLog($this->crLanguage('generic', 'tooManyKeys', array(count($inputTypes), count($input), "input::(" . implode('|', $inputTypes) . ")")), __METHOD__, 'error');
             return false;
         }
     }
     /*if ( !is_string($eckey) ) {
     		
     			$this->webLog($this->crLanguage('generic', 'missingKeyType', 'eckey'), __METHOD__, 'error');
     			return false;
     			
     		}*/
     if (!in_array($cipher, $cipherList)) {
         $this->webLog($this->crLanguage('generic', 'invalidKey', array('cipher', implode('|', $cipherList))), __METHOD__, 'error');
         return false;
     }
     //  if the eckey matches the name of a stored key we'll map it to the proper eckey
     $keyid = '00-';
     if (isset($this->crCryptoKeys->{$eckey})) {
         //  set our keyid
         $keyid = $this->crCryptoKeys->{$eckey}->keyid;
         //  create our index
         $this->crCryptoKeys->index->{$keyid} = $eckey;
         //  set our eckey to the hex value
         $eckey = $this->crCryptoKeys->{$eckey}->eckey;
     }
     //  process the request
     $start = microtime(true);
     //  if we're decrypting then the input should be nonce.ciphertext
     if ($dir === 'decrypt') {
         //  grab our nonce bytes param
         if ($cipher === 'aes256gcm') {
             $bytes = \Sodium\CRYPTO_AEAD_AES256GCM_NPUBBYTES;
         }
         if ($cipher === 'chacha') {
             $bytes = \Sodium\CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES;
         }
         //  grab our message data
         //  accepts two input types: <keyid>$<ciphertext> or just <ciphertext>
         $data = explode('$', $input->string);
         if (count($data) === 2) {
             //  located a keyid and ciphertext
             $keyid = $data[0];
             $message = $data[1];
             //  no keyid was located, so treat it as pure ciphertext
         } else {
             $data = $input->string;
         }
         //  parse the message contents
         $message = \Sodium\hex2bin($message);
         $nonce = mb_substr($message, 0, $bytes, '8bit');
         $ciphertext = mb_substr($message, $bytes, null, '8bit');
         //  on decrypt only: check if a key has been provided yet
         if ($eckey === false) {
             //  check if the keyid is indexed
             if (isset($this->crCryptoKeys->index->{$keyid})) {
                 //  found a match; set our eckey
                 $eckey = $this->crCryptoKeys->{$this->crCryptoKeys->index->{$keyid}}->eckey;
             } else {
                 //  no match and this far along means we can't decrypt
                 $this->webLog("Cannot decrypt ciphertext because no suitable eckey was located", __METHOD__, 'error');
                 return false;
             }
         }
     }
     //  if eckey is false, we cannot proceed
     if ($eckey === false) {
         $this->webLog();
         return false;
     }
     //  set our eckey to the actual encryption key
     $eckey = \Sodium\hex2bin($eckey);
     //  process AES-256-GCM methods
     if ($cipher === 'aes256gcm') {
         //$eckey = ( $eckey === false ) ? \Sodium\randombytes_buf(\Sodium\CRYPTO_AEAD_AES256GCM_KEYBYTES) : \Sodium\hex2bin($eckey);
         if ($dir === 'encrypt') {
             //  create the ciphertext
             $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_AEAD_AES256GCM_NPUBBYTES);
             $resultString = \Sodium\crypto_aead_aes256gcm_encrypt($input->string, $input->ad, $nonce, $eckey);
         } else {
             //  decrypt the ciphertext
             $resultString = \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $input->ad, $nonce, $eckey);
         }
         //  process CHACHA20-POLY1305 methods
     } else {
         if ($cipher === 'chacha') {
             //$eckey = ( $eckey === false ) ? \Sodium\randombytes_buf(\Sodium\CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) : \Sodium\hex2bin($eckey);
             if ($dir === 'encrypt') {
                 //  create the ciphertext
                 $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES);
                 $resultString = \Sodium\crypto_aead_chacha20poly1305_encrypt($input->string, $input->ad, $nonce, $eckey);
             } else {
                 //  decrypt the ciphertext
                 $resultString = \Sodium\crypto_aead_chacha20poly1305_decrypt($ciphertext, $input->ad, $nonce, $eckey);
             }
         }
     }
     //  finishing up
     $totalTime = number_format(microtime(true) - $start, $this->config->precison + 10);
     $this->webLog("Performed '{$dir}' on a string with {$cipher} in {$totalTime} seconds", __METHOD__);
     $this->crCryptoAnalytics($eckey, $nonce, $dir, $cipher, strlen($input->string), $totalTime);
     \Sodium\memzero($eckey);
     //  if decrypt, just send the string
     if ($dir === 'decrypt') {
         \Sodium\memzero($nonce);
         if ($resultString === false) {
             $this->webLog("Decryption failed!", __METHOD__, 'warn');
         }
         return $resultString;
     }
     //  if encrypt, send back the data in case we generated it
     $ciphertext = \Sodium\bin2hex($nonce . $resultString);
     \Sodium\memzero($nonce);
     return $keyid . '$' . $ciphertext;
 }
Пример #20
0
 /**
  * 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'};
 }
Пример #21
0
 /**
  * Return a secrete nonce string as entropy to the client.
  *
  * @return string
  */
 static function generateNonce()
 {
     return \Sodium\randombytes_buf(Constants::SECRETBOX_NONCEBYTES);
 }
Пример #22
0
 /**
  * Generate a random string of the specified size
  *
  * @param int $size The size of the requested random string
  *
  * @return string A string of the requested size
  */
 public function generate($size)
 {
     if (!$this->hasLibsodium || $size < 1) {
         return str_repeat(chr(0), $size);
     }
     return \Sodium\randombytes_buf($size);
 }