safeSubstr() public static method

Safe substring
public static safeSubstr ( string $str, integer $start, integer $length = null ) : string
$str string
$start integer
$length integer
return string
Example #1
0
 /**
  * Get the configuration for this version of halite
  *
  * @param string $stored   A stored password hash
  * @return SymmetricConfig
  * @throws InvalidMessage
  */
 protected static function getConfig(string $stored) : SymmetricConfig
 {
     $length = Util::safeStrlen($stored);
     // This doesn't even have a header.
     if ($length < 8) {
         throw new InvalidMessage('Encrypted password hash is way too short.');
     }
     if (\hash_equals(Util::safeSubstr($stored, 0, 5), Halite::VERSION_PREFIX)) {
         return SymmetricConfig::getConfig(Base64UrlSafe::decode($stored), 'encrypt');
     }
     $v = \Sodium\hex2bin(Util::safeSubstr($stored, 0, 8));
     return SymmetricConfig::getConfig($v, 'encrypt');
 }
Example #2
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);
     }
 }
Example #3
0
 /**
  * Decrypt a message using the Halite encryption protocol
  * 
  * @param string $ciphertext
  * @param Key $secretKey
  * @param boolean $raw Don't hex decode the input?
  */
 public static function decrypt($ciphertext, 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');
     }
     if (!$raw) {
         // We were given hex data:
         $ciphertext = \Sodium\hex2bin($ciphertext);
     }
     $length = CryptoUtil::safeStrlen($ciphertext);
     // The first 4 bytes are reserved for the version size
     $version = CryptoUtil::safeSubstr($ciphertext, 0, Config::VERSION_TAG_LEN);
     // The HKDF is used for key splitting
     $salt = CryptoUtil::safeSubstr($ciphertext, Config::VERSION_TAG_LEN, Config::HKDF_SALT_LEN);
     // This is the nonce (we authenticated it):
     $nonce = CryptoUtil::safeSubstr($ciphertext, Config::VERSION_TAG_LEN + Config::HKDF_SALT_LEN, \Sodium\CRYPTO_STREAM_NONCEBYTES);
     // This is the crypto_stream_xor()ed ciphertext
     $xored = CryptoUtil::safeSubstr($ciphertext, Config::VERSION_TAG_LEN + Config::HKDF_SALT_LEN + \Sodium\CRYPTO_STREAM_NONCEBYTES, $length - (Config::VERSION_TAG_LEN + Config::HKDF_SALT_LEN + \Sodium\CRYPTO_STREAM_NONCEBYTES + \Sodium\CRYPTO_AUTH_BYTES));
     // $auth is the last 32 bytes
     $auth = CryptoUtil::safeSubstr($ciphertext, $length - \Sodium\CRYPTO_AUTH_BYTES);
     // Split our keys
     list($eKey, $aKey) = self::splitKeys($secretKey, $salt);
     // Check the MAC first
     if (!self::verifyMAC($auth, $version . $salt . $nonce . $xored, $aKey)) {
         throw new CryptoAlert\InvalidMessage('Invalid message authenticaiton code');
     }
     // Down the road, do whatever logic around $version here, in case we
     // need to upgrade our protocol.
     // Add version logic above
     $plaintext = \Sodium\crypto_stream_xor($xored, $nonce, $eKey);
     if ($plaintext === false) {
         throw new CryptoAlert\InvalidMessage('Invalid message authenticaiton code');
     }
     return $plaintext;
 }
Example #4
0
 /**
  * Write to a stream; prevent partial writes
  * 
  * @param resource $stream
  * @param string $buf
  * @param int $num (number of bytes)
  * @throws FileAlert\AccessDenied
  */
 public function writeBytes($buf, $num = null)
 {
     $bufSize = Util::safeStrlen($buf);
     if ($num === null || $num > $bufSize) {
         $num = $bufSize;
     }
     if ($num < 0) {
         throw new \Exception('num < 0');
     }
     $remaining = $num;
     do {
         if ($remaining <= 0) {
             break;
         }
         $written = \fwrite($this->fp, $buf, $remaining);
         if ($written === false) {
             throw new CryptoException\FileAccessDenied('Could not write to the file');
         }
         $buf = Util::safeSubstr($buf, $written, null);
         $this->pos += $written;
         $this->stat = \fstat($this->fp);
         $remaining -= $written;
     } while ($remaining > 0);
     return $num;
 }
Example #5
0
 /**
  * Take a stored key string, get the derived key (after verifying the
  * checksum)
  * 
  * @param string $data
  * @return string
  * @throws Alerts\InvalidKey
  */
 public static function getKeyDataFromString(string $data) : string
 {
     $vtag = Util::safeSubstr($data, 0, Halite::VERSION_TAG_LEN);
     $kdat = Util::safeSubstr($data, Halite::VERSION_TAG_LEN, -\Sodium\CRYPTO_GENERICHASH_BYTES_MAX);
     $csum = Util::safeSubstr($data, -\Sodium\CRYPTO_GENERICHASH_BYTES_MAX, \Sodium\CRYPTO_GENERICHASH_BYTES_MAX);
     $calc = \Sodium\crypto_generichash($vtag . $kdat, '', \Sodium\CRYPTO_GENERICHASH_BYTES_MAX);
     if (!\hash_equals($calc, $csum)) {
         throw new Alerts\InvalidKey('Checksum validation fail');
     }
     \Sodium\memzero($data);
     \Sodium\memzero($vtag);
     \Sodium\memzero($calc);
     \Sodium\memzero($csum);
     return $kdat;
 }
Example #6
0
 /**
  * Unpack a message string into an array.
  * 
  * @param string $ciphertext
  * @return array
  */
 public static function unpackMessageForDecryption($ciphertext)
 {
     $length = CryptoUtil::safeStrlen($ciphertext);
     // The first 4 bytes are reserved for the version size
     $version = CryptoUtil::safeSubstr($ciphertext, 0, Halite::VERSION_TAG_LEN);
     $config = SymmetricConfig::getConfig($version, 'encrypt');
     // The HKDF is used for key splitting
     $salt = CryptoUtil::safeSubstr($ciphertext, Halite::VERSION_TAG_LEN, $config->HKDF_SALT_LEN);
     // This is the nonce (we authenticated it):
     $nonce = CryptoUtil::safeSubstr($ciphertext, Halite::VERSION_TAG_LEN + $config->HKDF_SALT_LEN, \Sodium\CRYPTO_STREAM_NONCEBYTES);
     // This is the crypto_stream_xor()ed ciphertext
     $xored = CryptoUtil::safeSubstr($ciphertext, Halite::VERSION_TAG_LEN + $config->HKDF_SALT_LEN + \Sodium\CRYPTO_STREAM_NONCEBYTES, $length - (Halite::VERSION_TAG_LEN + $config->HKDF_SALT_LEN + \Sodium\CRYPTO_STREAM_NONCEBYTES + \Sodium\CRYPTO_AUTH_BYTES));
     // $auth is the last 32 bytes
     $auth = CryptoUtil::safeSubstr($ciphertext, $length - \Sodium\CRYPTO_AUTH_BYTES);
     // We don't need this anymore.
     \Sodium\memzero($ciphertext);
     return [$version, $config, $salt, $nonce, $xored, $auth];
 }