22
22
*/
23
23
class PasswordEncoder
24
24
{
25
+ const ALGORITHM_MD2 = 'MD2 ' ;
26
+ const ALGORITHM_MD4 = 'MD4 ' ;
27
+ const ALGORITHM_MD5 = 'MD5 ' ;
28
+ const ALGORITHM_SHA_1 = 'SHA-1 ' ;
29
+ const ALGORITHM_SHA_256 = 'SHA-256 ' ;
30
+ const ALGORITHM_SHA_384 = 'SHA-384 ' ;
31
+ const ALGORITHM_SHA_512 = 'SHA-512 ' ;
32
+ const ALGORITHM_RIPEMD = 'RIPEMD ' ;
33
+ const ALGORITHM_RIPEMD_160 = 'RIPEMD-160 ' ;
34
+ const ALGORITHM_MAC = 'MAC ' ;
35
+ const ALGORITHM_HMAC = 'HMAC ' ;
36
+
37
+ /**
38
+ * Mapping between algorithm name and algorithm ID
39
+ *
40
+ * @var array
41
+ * @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.writeprotection.cryptographicalgorithmsid(v=office.14).aspx
42
+ */
25
43
private static $ algorithmMapping = array (
26
- 1 => 'md2 ' ,
27
- 2 => 'md4 ' ,
28
- 3 => 'md5 ' ,
29
- 4 => 'sha1 ' ,
30
- 5 => '' , // 'mac' -> not possible with hash()
31
- 6 => 'ripemd ' ,
32
- 7 => 'ripemd160 ' ,
33
- 8 => '' ,
34
- 9 => '' , //'hmac' -> not possible with hash()
35
- 10 => '' ,
36
- 11 => '' ,
37
- 12 => 'sha256 ' ,
38
- 13 => 'sha384 ' ,
39
- 14 => 'sha512 ' ,
44
+ self ::ALGORITHM_MD2 => array (1 , 'md2 ' ),
45
+ self ::ALGORITHM_MD4 => array (2 , 'md4 ' ),
46
+ self ::ALGORITHM_MD5 => array (3 , 'md5 ' ),
47
+ self ::ALGORITHM_SHA_1 => array (4 , 'sha1 ' ),
48
+ self ::ALGORITHM_MAC => array (5 , '' ), // 'mac' -> not possible with hash()
49
+ self ::ALGORITHM_RIPEMD => array (6 , 'ripemd ' ),
50
+ self ::ALGORITHM_RIPEMD_160 => array (7 , 'ripemd160 ' ),
51
+ self ::ALGORITHM_HMAC => array (9 , '' ), //'hmac' -> not possible with hash()
52
+ self ::ALGORITHM_SHA_256 => array (12 , 'sha256 ' ),
53
+ self ::ALGORITHM_SHA_384 => array (13 , 'sha384 ' ),
54
+ self ::ALGORITHM_SHA_512 => array (14 , 'sha512 ' ),
40
55
);
41
56
42
57
private static $ initialCodeArray = array (
@@ -82,12 +97,12 @@ class PasswordEncoder
82
97
* @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/
83
98
*
84
99
* @param string $password
85
- * @param number $algorithmSid
100
+ * @param string $algorithmName
86
101
* @param string $salt
87
- * @param number $spinCount
102
+ * @param integer $spinCount
88
103
* @return string
89
104
*/
90
- public static function hashPassword ($ password , $ algorithmSid = 4 , $ salt = null , $ spinCount = 10000 )
105
+ public static function hashPassword ($ password , $ algorithmName = PasswordEncoder:: ALGORITHM_SHA_1 , $ salt = null , $ spinCount = 10000 )
91
106
{
92
107
$ origEncoding = mb_internal_encoding ();
93
108
mb_internal_encoding ('UTF-8 ' );
@@ -118,7 +133,7 @@ public static function hashPassword($password, $algorithmSid = 4, $salt = null,
118
133
// Implementation Notes List:
119
134
// Word requires that the initial hash of the password with the salt not be considered in the count.
120
135
// The initial hash of salt + key is not included in the iteration count.
121
- $ algorithm = self ::getAlgorithm ($ algorithmSid );
136
+ $ algorithm = self ::getAlgorithm ($ algorithmName );
122
137
$ generatedKey = hash ($ algorithm , $ salt . $ generatedKey , true );
123
138
124
139
for ($ i = 0 ; $ i < $ spinCount ; $ i ++) {
@@ -134,12 +149,12 @@ public static function hashPassword($password, $algorithmSid = 4, $salt = null,
134
149
/**
135
150
* Get algorithm from self::$algorithmMapping
136
151
*
137
- * @param int $sid
152
+ * @param string $algorithmName
138
153
* @return string
139
154
*/
140
- private static function getAlgorithm ($ sid )
155
+ private static function getAlgorithm ($ algorithmName )
141
156
{
142
- $ algorithm = self ::$ algorithmMapping [$ sid ];
157
+ $ algorithm = self ::$ algorithmMapping [$ algorithmName ][ 1 ];
143
158
if ($ algorithm == '' ) {
144
159
$ algorithm = 'sha1 ' ;
145
160
}
@@ -155,16 +170,17 @@ private static function getAlgorithm($sid)
155
170
*/
156
171
private static function buildCombinedKey ($ byteChars )
157
172
{
173
+ $ byteCharsLength = count ($ byteChars );
158
174
// Compute the high-order word
159
175
// Initialize from the initial code array (see above), depending on the passwords length.
160
- $ highOrderWord = self ::$ initialCodeArray [count ( $ byteChars ) - 1 ];
176
+ $ highOrderWord = self ::$ initialCodeArray [$ byteCharsLength - 1 ];
161
177
162
178
// For each character in the password:
163
179
// For every bit in the character, starting with the least significant and progressing to (but excluding)
164
180
// the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from
165
181
// the Encryption Matrix
166
- for ($ i = 0 ; $ i < count ( $ byteChars ) ; $ i ++) {
167
- $ tmp = self ::$ passwordMaxLength - count ( $ byteChars ) + $ i ;
182
+ for ($ i = 0 ; $ i < $ byteCharsLength ; $ i ++) {
183
+ $ tmp = self ::$ passwordMaxLength - $ byteCharsLength + $ i ;
168
184
$ matrixRow = self ::$ encryptionMatrix [$ tmp ];
169
185
for ($ intBit = 0 ; $ intBit < 7 ; $ intBit ++) {
170
186
if (($ byteChars [$ i ] & (0x0001 << $ intBit )) != 0 ) {
@@ -177,12 +193,12 @@ private static function buildCombinedKey($byteChars)
177
193
// Initialize with 0
178
194
$ lowOrderWord = 0 ;
179
195
// For each character in the password, going backwards
180
- for ($ i = count ( $ byteChars ) - 1 ; $ i >= 0 ; $ i --) {
196
+ for ($ i = $ byteCharsLength - 1 ; $ i >= 0 ; $ i --) {
181
197
// low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character
182
198
$ lowOrderWord = (((($ lowOrderWord >> 14 ) & 0x0001 ) | (($ lowOrderWord << 1 ) & 0x7FFF )) ^ $ byteChars [$ i ]);
183
199
}
184
200
// Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B.
185
- $ lowOrderWord = (((($ lowOrderWord >> 14 ) & 0x0001 ) | (($ lowOrderWord << 1 ) & 0x7FFF )) ^ count ( $ byteChars ) ^ 0xCE4B );
201
+ $ lowOrderWord = (((($ lowOrderWord >> 14 ) & 0x0001 ) | (($ lowOrderWord << 1 ) & 0x7FFF )) ^ $ byteCharsLength ^ 0xCE4B );
186
202
187
203
// Combine the Low and High Order Word
188
204
return self ::int32 (($ highOrderWord << 16 ) + $ lowOrderWord );
0 commit comments