/** * PKCS #7 unpadding function. * * @param string $input Padded string to unpad * * @return string */ public static function unpad($input) { // Determine the padding size by converting the final byte of the // input to its decimal value $padsize = \ord(Str::substr($input, -1)); // Return string minus the padding amount return Str::substr($input, 0, Str::strlen($input) - $padsize); }
/** * This will normalize a hash to a certain length by extending it if * too short and truncating it if too long. This ensures that any * hash algo will work with any combination of other settings. However, * it is probably best to make sure that the keysize and algo size * are identical so that the input hash passes through unchanged. * * @param string $hash Hash to be normalized * @param int $size Size of the desired output hash, in bytes * @param string $algo Hashing algorithm to use for internal operations * * @return string */ private static function hashNormalize($hash, $size, $algo) { // Extend hash if too short while (Str::strlen($hash) < $size) { $hash .= \hash($algo, $hash, true); } // Truncate to specified number of bytes (if needed) and return return Str::substr($hash, 0, $size); }
/** * Decrypt cyphertext * * @param string $cyphertext Cyphertext to decrypt * @param string $password Password that should be used to decrypt input data * @param int $cost Number of HMAC iterations to perform on key * * @return string */ public static function decrypt($cyphertext, $password, $cost = 0) { // Find the IV at the beginning of the cypher text $iv = Str::substr($cyphertext, 0, self::IVSIZE); // Gather the checksum portion of the cypher text $chksum = Str::substr($cyphertext, self::IVSIZE, self::CKSIZE); // Gather message portion of cyphertext after iv and checksum $message = Str::substr($cyphertext, self::IVSIZE + self::CKSIZE); // Derive key from password $key = self::key($password, $iv, $cost, self::RIJNDA, self::mode()); // Calculate verification checksum $verify = self::checksum($message, $iv, $key, self::RIJNDA, self::mode()); // Verify HMAC before decrypting self::checksumVerify($verify, $chksum); // Decrypt message and return return \openssl_decrypt($message, static::CIPHER, $key, 1, $iv); }
/** * Decrypt cyphertext * * @param string $cyphertext Cypher text to decrypt * @param string $password Password that should be used to decrypt input data * @param int $cost Number of HMAC iterations to perform on key * @param string $cipher Mcrypt cipher * @param string $mode Mcrypt mode * @param string $algo Hashing algorithm to use for internal operations * * @return string|boolean Returns false on checksum validation failure */ public static function decrypt($cyphertext, $password, $cost = 0, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC, $algo = 'sha256') { // Determine that size of the IV in bytes $ivsize = \mcrypt_get_iv_size($cipher, $mode); // Find the IV at the beginning of the cypher text $iv = Str::substr($cyphertext, 0, $ivsize); // Gather the checksum portion of the cypher text $chksum = Str::substr($cyphertext, $ivsize, Str::hashSize($algo)); // Gather message portion of cyphertext after iv and checksum $message = Str::substr($cyphertext, $ivsize + Str::hashSize($algo)); // Derive key from password $key = self::key($password, $iv, $cost, $cipher, $mode, $algo); // Calculate verification checksum $verify = self::checksum($message, $iv, $key, $cipher, $mode, $algo); // If checksum could not be verified return false self::checksumVerify($verify, $chksum); // Decrypt unpad return return Pkcs7::unpad(\mcrypt_decrypt($cipher, $key, $message, $mode, $iv)); }
/** * Check the validity of a hash. * * @param string $input Input to test. * @param string $hash Known hash to validate against. * @param string $password HMAC password to use during iterative hash. * * @return boolean */ public static function verify($input, $hash, $password) { // Get the salt value from the decrypted prefix $salt = Str::substr($hash, 0, 16); // Get the encrypted cost bytes $cost = self::bin2dec(Otp::crypt(Str::substr($hash, 28, 4), $password)); // Get the entire cost+hash blob for comparison $blob = Str::substr($hash, 16, 16); if (!Str::equal(self::costHash($cost, $salt, $password), $blob)) { return false; } // Return the boolean equivalence return Str::equal($hash, self::build($input, $password, $cost, $salt)); }