@@ -71,7 +71,7 @@ public function __construct(
71
71
/**
72
72
* Check using binary?
73
73
*/
74
- public bool $ NOFILE = false
74
+ public bool $ NOFILE = false ,
75
75
) {
76
76
}
77
77
@@ -149,20 +149,25 @@ public function output(?string $filePath = null)
149
149
'cipherAlgorithm ' => 'AES ' , // Cipher algorithm to use. Excel uses AES.
150
150
'cipherChaining ' => 'ChainingModeCBC ' , // Cipher chaining mode to use. Excel uses CBC.
151
151
'saltValue ' => (array ) unpack ('C* ' , random_bytes (16 )), // Random value to use as encryption salt. Excel uses 16 bytes.
152
- 'hashAlgorithm ' => 'sha512 ' , // Hash algorithm to use. Excel uses SHA512.
152
+ 'hashAlgorithm ' => 'SHA512 ' , // Hash algorithm to use. Excel uses SHA512.
153
153
'hashSize ' => 64 , // The size of the hash in bytes. SHA512 results in 64-byte hashes
154
154
'blockSize ' => 16 , // The number of bytes used to encrypt one block of data. It MUST be at least 2, no greater than 4096, and a multiple of 2. Excel uses 16
155
155
'spinCount ' => 100000 , // The number of times to iterate on a hash of a password. It MUST NOT be greater than 10,000,000. Excel uses 100,000.
156
156
'keyBits ' => 256 , // The length of the key to generate from the password. Must be a multiple of 8. Excel uses 256.
157
157
],
158
158
];
159
159
160
+ $ lowerKeyHashAlgo = \strtolower ($ encryptionInfo ['key ' ]['hashAlgorithm ' ]);
161
+ $ lowerPackageHashAlgo = $ encryptionInfo ['key ' ]['hashAlgorithm ' ] === $ encryptionInfo ['package ' ]['hashAlgorithm ' ] ? $ lowerKeyHashAlgo : \strtolower ($ encryptionInfo ['package ' ]['hashAlgorithm ' ]);
162
+ $ lowerKeyCipherAlgo = \strtolower ($ encryptionInfo ['key ' ]['cipherAlgorithm ' ]);
163
+ $ lowerPackageCipherAlgo = $ encryptionInfo ['key ' ]['cipherAlgorithm ' ] === $ encryptionInfo ['package ' ]['cipherAlgorithm ' ] ? $ lowerKeyCipherAlgo : \strtolower ($ encryptionInfo ['package ' ]['cipherAlgorithm ' ]);
164
+
160
165
// Package Encryption
161
166
$ encryptedPackage = $ this ->_cryptPackage (
162
167
true ,
163
- $ encryptionInfo [ ' package ' ][ ' cipherAlgorithm ' ] ,
168
+ $ lowerPackageCipherAlgo ,
164
169
$ encryptionInfo ['package ' ]['cipherChaining ' ],
165
- $ encryptionInfo [ ' package ' ][ ' hashAlgorithm ' ] ,
170
+ $ lowerPackageHashAlgo ,
166
171
$ encryptionInfo ['package ' ]['blockSize ' ],
167
172
$ encryptionInfo ['package ' ]['saltValue ' ],
168
173
$ this ->data ,
@@ -179,41 +184,41 @@ public function output(?string $filePath = null)
179
184
$ hmacKey = unpack ('C* ' , random_bytes (64 ));
180
185
// Then create an initialization vector using the package encryption info and the appropriate block key.
181
186
$ hmacKeyIV = $ this ->_createIV (
182
- $ encryptionInfo [ ' package ' ][ ' hashAlgorithm ' ] ,
187
+ $ lowerPackageHashAlgo ,
183
188
$ encryptionInfo ['package ' ]['saltValue ' ],
184
189
$ encryptionInfo ['package ' ]['blockSize ' ],
185
- $ this ->_block_keys ['dataIntegrity ' ]['hmacKey ' ]
190
+ $ this ->_block_keys ['dataIntegrity ' ]['hmacKey ' ],
186
191
);
187
192
188
193
// Use the package key and the IV to encrypt the HMAC key
189
194
$ encryptedHmacKey = $ this ->_crypt (
190
195
true ,
191
- $ encryptionInfo [ ' package ' ][ ' cipherAlgorithm ' ] ,
196
+ $ lowerPackageCipherAlgo ,
192
197
$ encryptionInfo ['package ' ]['cipherChaining ' ],
193
198
$ packageKey ,
194
199
$ hmacKeyIV ,
195
- $ hmacKey
200
+ $ hmacKey,
196
201
);
197
202
198
203
// Now create the HMAC
199
- $ hmacValue = $ this ->_hmac ($ encryptionInfo [ ' package ' ][ ' hashAlgorithm ' ] , $ hmacKey , $ encryptedPackage ['tmpFile ' ]);
204
+ $ hmacValue = $ this ->_hmac ($ lowerPackageHashAlgo , $ hmacKey , $ encryptedPackage ['tmpFile ' ]);
200
205
201
206
// Next generate an initialization vector for encrypting the resulting HMAC value.
202
207
$ hmacValueIV = $ this ->_createIV (
203
- $ encryptionInfo [ ' package ' ][ ' hashAlgorithm ' ] ,
208
+ $ lowerPackageHashAlgo ,
204
209
$ encryptionInfo ['package ' ]['saltValue ' ],
205
210
$ encryptionInfo ['package ' ]['blockSize ' ],
206
- $ this ->_block_keys ['dataIntegrity ' ]['hmacValue ' ]
211
+ $ this ->_block_keys ['dataIntegrity ' ]['hmacValue ' ],
207
212
);
208
213
209
214
// Now encrypt the value
210
215
$ encryptedHmacValue = $ this ->_crypt (
211
216
true ,
212
- $ encryptionInfo [ ' package ' ][ ' cipherAlgorithm ' ] ,
217
+ $ lowerPackageCipherAlgo ,
213
218
$ encryptionInfo ['package ' ]['cipherChaining ' ],
214
219
$ packageKey ,
215
220
$ hmacValueIV ,
216
- $ hmacValue
221
+ $ hmacValue,
217
222
);
218
223
219
224
// Put the encrypted key and value on the encryption info
@@ -227,21 +232,21 @@ public function output(?string $filePath = null)
227
232
// Convert the password to an encryption key
228
233
$ key = $ this ->_convertPasswordToKey (
229
234
$ password ,
230
- $ encryptionInfo [ ' key ' ][ ' hashAlgorithm ' ] ,
235
+ $ lowerKeyHashAlgo ,
231
236
$ encryptionInfo ['key ' ]['saltValue ' ],
232
237
$ encryptionInfo ['key ' ]['spinCount ' ],
233
238
$ encryptionInfo ['key ' ]['keyBits ' ],
234
- $ this ->_block_keys ['key ' ]
239
+ $ this ->_block_keys ['key ' ],
235
240
);
236
241
237
242
// // Encrypt the package key with the
238
243
$ encryptionInfo ['key ' ]['encryptedKeyValue ' ] = $ this ->_crypt (
239
244
true ,
240
- $ encryptionInfo [ ' key ' ][ ' cipherAlgorithm ' ] ,
245
+ $ lowerKeyCipherAlgo ,
241
246
$ encryptionInfo ['key ' ]['cipherChaining ' ],
242
247
$ key ,
243
248
$ encryptionInfo ['key ' ]['saltValue ' ],
244
- $ packageKey
249
+ $ packageKey,
245
250
);
246
251
247
252
// Verifier hash with random byte array for hashing
@@ -250,44 +255,44 @@ public function output(?string $filePath = null)
250
255
// Create an encryption key from the password for the input
251
256
$ verifierHashInputKey = $ this ->_convertPasswordToKey (
252
257
$ password ,
253
- $ encryptionInfo [ ' key ' ][ ' hashAlgorithm ' ] ,
258
+ $ lowerKeyHashAlgo ,
254
259
$ encryptionInfo ['key ' ]['saltValue ' ],
255
260
$ encryptionInfo ['key ' ]['spinCount ' ],
256
261
$ encryptionInfo ['key ' ]['keyBits ' ],
257
- $ this ->_block_keys ['verifierHash ' ]['input ' ]
262
+ $ this ->_block_keys ['verifierHash ' ]['input ' ],
258
263
);
259
264
260
265
// Use the key to encrypt the verifier input
261
266
$ encryptionInfo ['key ' ]['encryptedVerifierHashInput ' ] = $ this ->_crypt (
262
267
true ,
263
- $ encryptionInfo [ ' key ' ][ ' cipherAlgorithm ' ] ,
268
+ $ lowerKeyCipherAlgo ,
264
269
$ encryptionInfo ['key ' ]['cipherChaining ' ],
265
270
$ verifierHashInputKey ,
266
271
$ encryptionInfo ['key ' ]['saltValue ' ],
267
- $ verifierHashInput
272
+ $ verifierHashInput,
268
273
);
269
274
270
275
// Create a hash of the input
271
- $ verifierHashValue = $ this ->_hash ($ encryptionInfo [ ' key ' ][ ' hashAlgorithm ' ] , $ verifierHashInput );
276
+ $ verifierHashValue = $ this ->_hash ($ lowerKeyHashAlgo , $ verifierHashInput );
272
277
273
278
// Create an encryption key from the password for the hash
274
279
$ verifierHashValueKey = $ this ->_convertPasswordToKey (
275
280
$ password ,
276
- $ encryptionInfo [ ' key ' ][ ' hashAlgorithm ' ] ,
281
+ $ lowerKeyHashAlgo ,
277
282
$ encryptionInfo ['key ' ]['saltValue ' ],
278
283
$ encryptionInfo ['key ' ]['spinCount ' ],
279
284
$ encryptionInfo ['key ' ]['keyBits ' ],
280
- $ this ->_block_keys ['verifierHash ' ]['value ' ]
285
+ $ this ->_block_keys ['verifierHash ' ]['value ' ],
281
286
);
282
287
283
288
// Use the key to encrypt the hash value
284
289
$ encryptionInfo ['key ' ]['encryptedVerifierHashValue ' ] = $ this ->_crypt (
285
290
true ,
286
- $ encryptionInfo [ ' key ' ][ ' cipherAlgorithm ' ] ,
291
+ $ lowerKeyCipherAlgo ,
287
292
$ encryptionInfo ['key ' ]['cipherChaining ' ],
288
293
$ verifierHashValueKey ,
289
294
$ encryptionInfo ['key ' ]['saltValue ' ],
290
- $ verifierHashValue
295
+ $ verifierHashValue,
291
296
);
292
297
293
298
// Build the encryption info buffer
@@ -430,7 +435,7 @@ private function arrayToXml(array $array = [])
430
435
*/
431
436
private function _crypt ($ encrypt , $ cipherAlgorithm , $ cipherChaining , $ key , $ iv , $ input )
432
437
{
433
- $ algorithm = strtolower ( $ cipherAlgorithm) . '- ' . (count ($ key ) * 8 );
438
+ $ algorithm = $ cipherAlgorithm . '- ' . (count ($ key ) * 8 );
434
439
435
440
if ($ cipherChaining === 'ChainingModeCBC ' ) {
436
441
$ algorithm .= '-cbc ' ;
@@ -446,7 +451,7 @@ private function _crypt($encrypt, $cipherAlgorithm, $cipherChaining, $key, $iv,
446
451
$ algorithm ,
447
452
pack ('C* ' , ...$ key ),
448
453
OPENSSL_NO_PADDING ,
449
- pack ('C* ' , ...$ iv )
454
+ pack ('C* ' , ...$ iv ),
450
455
);
451
456
$ cipher = (array ) unpack ('C* ' , (string ) $ ciphertext );
452
457
}
@@ -463,8 +468,7 @@ private function _crypt($encrypt, $cipherAlgorithm, $cipherChaining, $key, $iv,
463
468
*/
464
469
private function _hash ($ algorithm , ...$ buffers )
465
470
{
466
- $ algorithm = strtolower ($ algorithm );
467
- $ buffers = array_merge ([], ...$ buffers );
471
+ $ buffers = [...[], ...$ buffers ];
468
472
469
473
if (! in_array ($ algorithm , hash_algos (), true )) {
470
474
throw new Exception ("Hash algorithm ' {$ algorithm }' not supported! " ); // @codeCoverageIgnore
@@ -489,10 +493,10 @@ private function _hash($algorithm, ...$buffers)
489
493
private function _hmac ($ algorithm , $ key , $ fileName )
490
494
{
491
495
return (array ) unpack ('C* ' , hash_hmac_file (
492
- strtolower ( $ algorithm) ,
496
+ $ algorithm ,
493
497
$ fileName ,
494
498
pack ('C* ' , ...$ key ),
495
- true
499
+ true ,
496
500
));
497
501
}
498
502
@@ -511,20 +515,16 @@ private function _convertPasswordToKey($password, $hashAlgorithm, $saltValue, $s
511
515
{
512
516
// Password must be in unicode buffer
513
517
$ passwordBuffer = array_map ('hexdec ' , str_split (bin2hex (mb_convert_encoding ($ password , 'UTF-16LE ' , 'utf-8 ' )), 2 ));
518
+
514
519
// Generate the initial hash
515
520
$ key = $ this ->_hash ($ hashAlgorithm , $ saltValue , $ passwordBuffer );
516
521
517
- // Now regenerate until spin count
518
- // Prepare for hash(). Algo is known to be OK. Previous call to _hash()
519
- // would have thrown an exception if not.
520
- $ algo = strtolower ($ hashAlgorithm );
521
-
522
522
// Get back to a binary string
523
523
$ bKey = pack ('C* ' , ...$ key );
524
524
525
525
// Now regenerate until spin count
526
526
for ($ i = 0 ; $ i < $ spinCount ; $ i ++) {
527
- $ bKey = hash ($ algo , pack ('V ' , $ i ) . $ bKey , true );
527
+ $ bKey = hash ($ hashAlgorithm , pack ('V ' , $ i ) . $ bKey , true );
528
528
}
529
529
530
530
// Convert binary string back to unpacked C* form
0 commit comments