wpdatatables
/
lib
/
phpoffice
/
phpspreadsheet
/
src
/
PhpSpreadsheet
/
Shared
/
PasswordHasher.php
PasswordHasher.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin 6.5.1.7, at lib/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/PasswordHasher.php
| 1 | <?php |
| 2 | |
| 3 | namespace PhpOffice\PhpSpreadsheet\Shared; |
| 4 | |
| 5 | use PhpOffice\PhpSpreadsheet\Exception as SpException; |
| 6 | use PhpOffice\PhpSpreadsheet\Worksheet\Protection; |
| 7 | |
| 8 | class PasswordHasher |
| 9 | { |
| 10 | const MAX_PASSWORD_LENGTH = 255; |
| 11 | |
| 12 | /** |
| 13 | * Get algorithm name for PHP. |
| 14 | */ |
| 15 | private static function getAlgorithm(string $algorithmName): string |
| 16 | { |
| 17 | if (!$algorithmName) { |
| 18 | return ''; |
| 19 | } |
| 20 | |
| 21 | // Mapping between algorithm name in Excel and algorithm name in PHP |
| 22 | $mapping = [ |
| 23 | Protection::ALGORITHM_MD2 => 'md2', |
| 24 | Protection::ALGORITHM_MD4 => 'md4', |
| 25 | Protection::ALGORITHM_MD5 => 'md5', |
| 26 | Protection::ALGORITHM_SHA_1 => 'sha1', |
| 27 | Protection::ALGORITHM_SHA_256 => 'sha256', |
| 28 | Protection::ALGORITHM_SHA_384 => 'sha384', |
| 29 | Protection::ALGORITHM_SHA_512 => 'sha512', |
| 30 | Protection::ALGORITHM_RIPEMD_128 => 'ripemd128', |
| 31 | Protection::ALGORITHM_RIPEMD_160 => 'ripemd160', |
| 32 | Protection::ALGORITHM_WHIRLPOOL => 'whirlpool', |
| 33 | ]; |
| 34 | |
| 35 | if (array_key_exists($algorithmName, $mapping)) { |
| 36 | return $mapping[$algorithmName]; |
| 37 | } |
| 38 | |
| 39 | throw new SpException('Unsupported password algorithm: ' . $algorithmName); |
| 40 | } |
| 41 | |
| 42 | /** |
| 43 | * Create a password hash from a given string. |
| 44 | * |
| 45 | * This method is based on the spec at: |
| 46 | * https://interoperability.blob.core.windows.net/files/MS-OFFCRYPTO/[MS-OFFCRYPTO].pdf |
| 47 | * 2.3.7.1 Binary Document Password Verifier Derivation Method 1 |
| 48 | * |
| 49 | * It replaces a method based on the algorithm provided by |
| 50 | * Daniel Rentz of OpenOffice and the PEAR package |
| 51 | * Spreadsheet_Excel_Writer by Xavier Noguer <xnoguer@rezebra.com>. |
| 52 | * |
| 53 | * Scrutinizer will squawk at the use of bitwise operations here, |
| 54 | * but it should ultimately pass. |
| 55 | * |
| 56 | * @param string $password Password to hash |
| 57 | */ |
| 58 | private static function defaultHashPassword(string $password): string |
| 59 | { |
| 60 | $verifier = 0; |
| 61 | $pwlen = strlen($password); |
| 62 | $passwordArray = pack('c', $pwlen) . $password; |
| 63 | for ($i = $pwlen; $i >= 0; --$i) { |
| 64 | $intermediate1 = (($verifier & 0x4000) === 0) ? 0 : 1; |
| 65 | $intermediate2 = 2 * $verifier; |
| 66 | $intermediate2 = $intermediate2 & 0x7fff; |
| 67 | $intermediate3 = $intermediate1 | $intermediate2; |
| 68 | $verifier = $intermediate3 ^ ord($passwordArray[$i]); |
| 69 | } |
| 70 | $verifier ^= 0xCE4B; |
| 71 | |
| 72 | return strtoupper(dechex($verifier)); |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Create a password hash from a given string by a specific algorithm. |
| 77 | * |
| 78 | * 2.4.2.4 ISO Write Protection Method |
| 79 | * |
| 80 | * @see https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-offcrypto/1357ea58-646e-4483-92ef-95d718079d6f |
| 81 | * |
| 82 | * @param string $password Password to hash |
| 83 | * @param string $algorithm Hash algorithm used to compute the password hash value |
| 84 | * @param string $salt Pseudorandom string |
| 85 | * @param int $spinCount Number of times to iterate on a hash of a password |
| 86 | * |
| 87 | * @return string Hashed password |
| 88 | */ |
| 89 | public static function hashPassword(string $password, string $algorithm = '', string $salt = '', int $spinCount = 10000): string |
| 90 | { |
| 91 | if (strlen($password) > self::MAX_PASSWORD_LENGTH) { |
| 92 | throw new SpException('Password exceeds ' . self::MAX_PASSWORD_LENGTH . ' characters'); |
| 93 | } |
| 94 | $phpAlgorithm = self::getAlgorithm($algorithm); |
| 95 | if (!$phpAlgorithm) { |
| 96 | return self::defaultHashPassword($password); |
| 97 | } |
| 98 | |
| 99 | $saltValue = base64_decode($salt); |
| 100 | $encodedPassword = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); |
| 101 | |
| 102 | $hashValue = hash($phpAlgorithm, $saltValue . /** @scrutinizer ignore-type */ $encodedPassword, true); |
| 103 | for ($i = 0; $i < $spinCount; ++$i) { |
| 104 | $hashValue = hash($phpAlgorithm, $hashValue . pack('L', $i), true); |
| 105 | } |
| 106 | |
| 107 | return base64_encode($hashValue); |
| 108 | } |
| 109 | } |
| 110 |