22
33namespace PhpOffice \PhpSpreadsheet \Shared ;
44
5+ use PhpOffice \PhpSpreadsheet \Exception ;
6+ use PhpOffice \PhpSpreadsheet \Worksheet \Protection ;
7+
58class PasswordHasher
69{
7- const ALGORITHM_MD2 = 'MD2 ' ;
8- const ALGORITHM_MD4 = 'MD4 ' ;
9- const ALGORITHM_MD5 = 'MD5 ' ;
10- const ALGORITHM_SHA_1 = 'SHA-1 ' ;
11- const ALGORITHM_SHA_256 = 'SHA-256 ' ;
12- const ALGORITHM_SHA_384 = 'SHA-384 ' ;
13- const ALGORITHM_SHA_512 = 'SHA-512 ' ;
14- const ALGORITHM_RIPEMD_128 = 'RIPEMD-128 ' ;
15- const ALGORITHM_RIPEMD_160 = 'RIPEMD-160 ' ;
16- const ALGORITHM_WHIRLPOOL = 'WHIRLPOOL ' ;
17-
1810 /**
19- * Mapping between algorithm name in Excel and algorithm name in PHP.
20- *
21- * @var array
11+ * Get algorithm name for PHP.
2212 */
23- private static $ algorithmArray = [
24- self ::ALGORITHM_MD2 => 'md2 ' ,
25- self ::ALGORITHM_MD4 => 'md4 ' ,
26- self ::ALGORITHM_MD5 => 'md5 ' ,
27- self ::ALGORITHM_SHA_1 => 'sha1 ' ,
28- self ::ALGORITHM_SHA_256 => 'sha256 ' ,
29- self ::ALGORITHM_SHA_384 => 'sha384 ' ,
30- self ::ALGORITHM_SHA_512 => 'sha512 ' ,
31- self ::ALGORITHM_RIPEMD_128 => 'ripemd128 ' ,
32- self ::ALGORITHM_RIPEMD_160 => 'ripemd160 ' ,
33- self ::ALGORITHM_WHIRLPOOL => 'whirlpool ' ,
34- ];
35-
36- /**
37- * Get algorithm from self::$algorithmArray.
38- *
39- * @param string $pAlgorithmName
40- *
41- * @return string
42- */
43- private static function getAlgorithm ($ pAlgorithmName )
13+ private static function getAlgorithm (string $ algorithmName ): string
4414 {
45- if (array_key_exists ($ pAlgorithmName , self ::$ algorithmArray )) {
46- return self ::$ algorithmArray [$ pAlgorithmName ];
15+ if (!$ algorithmName ) {
16+ return '' ;
17+ }
18+
19+ // Mapping between algorithm name in Excel and algorithm name in PHP
20+ $ mapping = [
21+ Protection::ALGORITHM_MD2 => 'md2 ' ,
22+ Protection::ALGORITHM_MD4 => 'md4 ' ,
23+ Protection::ALGORITHM_MD5 => 'md5 ' ,
24+ Protection::ALGORITHM_SHA_1 => 'sha1 ' ,
25+ Protection::ALGORITHM_SHA_256 => 'sha256 ' ,
26+ Protection::ALGORITHM_SHA_384 => 'sha384 ' ,
27+ Protection::ALGORITHM_SHA_512 => 'sha512 ' ,
28+ Protection::ALGORITHM_RIPEMD_128 => 'ripemd128 ' ,
29+ Protection::ALGORITHM_RIPEMD_160 => 'ripemd160 ' ,
30+ Protection::ALGORITHM_WHIRLPOOL => 'whirlpool ' ,
31+ ];
32+
33+ if (array_key_exists ($ algorithmName , $ mapping )) {
34+ return $ mapping [$ algorithmName ];
4735 }
4836
49- return '' ;
37+ throw new Exception ( ' Unsupported password algorithm: ' . $ algorithmName ) ;
5038 }
5139
5240 /**
@@ -57,10 +45,8 @@ private static function getAlgorithm($pAlgorithmName)
5745 * Spreadsheet_Excel_Writer by Xavier Noguer <[email protected] >. 5846 *
5947 * @param string $pPassword Password to hash
60- *
61- * @return string Hashed password
6248 */
63- public static function defaultHashPassword ($ pPassword )
49+ private static function defaultHashPassword (string $ pPassword ): string
6450 {
6551 $ password = 0x0000 ;
6652 $ charPos = 1 ; // char position
@@ -87,40 +73,28 @@ public static function defaultHashPassword($pPassword)
8773 *
8874 * @see https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-offcrypto/1357ea58-646e-4483-92ef-95d718079d6f
8975 *
90- * @param string $pPassword Password to hash
91- * @param string $pAlgorithmName Hash algorithm used to compute the password hash value
92- * @param string $pSaltValue Pseudorandom string
93- * @param string $pSpinCount Number of times to iterate on a hash of a password
76+ * @param string $password Password to hash
77+ * @param string $algorithm Hash algorithm used to compute the password hash value
78+ * @param string $salt Pseudorandom string
79+ * @param int $spinCount Number of times to iterate on a hash of a password
9480 *
9581 * @return string Hashed password
9682 */
97- public static function hashPassword ($ pPassword , $ pAlgorithmName = '' , $ pSaltValue = '' , $ pSpinCount = 10000 )
83+ public static function hashPassword (string $ password , string $ algorithm = '' , string $ salt = '' , int $ spinCount = 10000 ): string
9884 {
99- $ algorithmName = self ::getAlgorithm ($ pAlgorithmName );
100- if (!$ pAlgorithmName ) {
101- return self ::defaultHashPassword ($ pPassword );
85+ $ phpAlgorithm = self ::getAlgorithm ($ algorithm );
86+ if (!$ phpAlgorithm ) {
87+ return self ::defaultHashPassword ($ password );
10288 }
10389
104- $ saltValue = base64_decode ($ pSaltValue );
105- $ password = mb_convert_encoding ($ pPassword , 'UCS-2LE ' , 'UTF-8 ' );
90+ $ saltValue = base64_decode ($ salt );
91+ $ encodedPassword = mb_convert_encoding ($ password , 'UCS-2LE ' , 'UTF-8 ' );
10692
107- $ hashValue = hash ($ algorithmName , $ saltValue . $ password , true );
108- for ($ i = 0 ; $ i < $ pSpinCount ; ++$ i ) {
109- $ hashValue = hash ($ algorithmName , $ hashValue . pack ('L ' , $ i ), true );
93+ $ hashValue = hash ($ phpAlgorithm , $ saltValue . $ encodedPassword , true );
94+ for ($ i = 0 ; $ i < $ spinCount ; ++$ i ) {
95+ $ hashValue = hash ($ phpAlgorithm , $ hashValue . pack ('L ' , $ i ), true );
11096 }
11197
11298 return base64_encode ($ hashValue );
11399 }
114-
115- /**
116- * Create a pseudorandom string.
117- *
118- * @param int $pSize Length of the output string in bytes
119- *
120- * @return string Pseudorandom string
121- */
122- public static function generateSalt ($ pSize = 16 )
123- {
124- return base64_encode (random_bytes ($ pSize ));
125- }
126100}
0 commit comments