/** * 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; }
/** * 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]; }