/** * 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'); }
/** * Verify the authenticity of a message, given a shared MAC key * * @param string $message * @param AuthenticationKey $secretKey * @param string $mac * @param mixed $encoding * @param SymmetricConfig $config * @return bool */ public static function verify(string $message, AuthenticationKey $secretKey, string $mac, $encoding = Halite::ENCODE_BASE64URLSAFE, SymmetricConfig $config = null) : bool { $decoder = Halite::chooseEncoder($encoding, true); if ($decoder) { // We were given hex data: $mac = $decoder($mac); } if ($config === null) { // Default to the current version $config = SymmetricConfig::getConfig(Halite::HALITE_VERSION, 'auth'); } return self::verifyMAC($mac, $message, $secretKey->getRawKeyMaterial(), $config); }
/** * Unpack a message string into an array. * * @param string $ciphertext * @return array * @throws CryptoException\InvalidMessage */ public static function unpackMessageForDecryption(string $ciphertext) : array { $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'); if ($length < $config->SHORTEST_CIPHERTEXT_LENGTH) { throw new CryptoException\InvalidMessage('Message is too short'); } // 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]; }