Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body