Completed
Push — master ( 0f6cd0...ce5be5 )
by Florent
41:39 queued 33s
created

Encrypter::createIV()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
c 4
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2016 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace Jose;
13
14
use Base64Url\Base64Url;
15
use Jose\Algorithm\ContentEncryptionAlgorithmInterface;
16
use Jose\Algorithm\JWAManagerInterface;
17
use Jose\Algorithm\KeyEncryption\DirectEncryptionInterface;
18
use Jose\Algorithm\KeyEncryption\KeyAgreementInterface;
19
use Jose\Algorithm\KeyEncryption\KeyAgreementWrappingInterface;
20
use Jose\Algorithm\KeyEncryption\KeyEncryptionInterface;
21
use Jose\Algorithm\KeyEncryption\KeyWrappingInterface;
22
use Jose\Algorithm\KeyEncryptionAlgorithmInterface;
23
use Jose\Behaviour\HasCompressionManager;
24
use Jose\Behaviour\HasJWAManager;
25
use Jose\Behaviour\HasKeyChecker;
26
use Jose\Behaviour\HasLogger;
27
use Jose\Compression\CompressionManagerInterface;
28
use Jose\Object\JWEInterface;
29
use Jose\Object\JWKInterface;
30
use Jose\Object\Recipient;
31
use Jose\Util\StringUtil;
32
use Psr\Log\LoggerInterface;
33
34
/**
35
 */
36
final class Encrypter implements EncrypterInterface
37
{
38
    use HasKeyChecker;
39
    use HasJWAManager;
40
    use HasCompressionManager;
41
    use HasLogger;
42
43
    /**
44
     * Encrypter constructor.
45
     *
46
     * @param \Jose\Algorithm\JWAManagerInterface           $jwa_manager
47
     * @param \Jose\Compression\CompressionManagerInterface $compression_manager
48
     * @param \Psr\Log\LoggerInterface|null                 $logger
49
     */
50
    public function __construct(
51
        JWAManagerInterface $jwa_manager,
52
        CompressionManagerInterface $compression_manager,
53
        LoggerInterface $logger = null
54
    ) {
55
        $this->setJWAManager($jwa_manager);
56
        $this->setCompressionManager($compression_manager);
57
58
        if (null !== $logger) {
59
            $this->setLogger($logger);
60
        }
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function addRecipient(JWEInterface &$jwe, JWKInterface $recipient_key, JWKInterface $sender_key = null, array $recipient_headers = [])
67
    {
68
        $complete_headers = array_merge(
69
            $jwe->getSharedProtectedHeaders(),
70
            $jwe->getSharedHeaders(),
71
            $recipient_headers
72
        );
73
74
        // Key Encryption Algorithm
75
        $key_encryption_algorithm = $this->findKeyEncryptionAlgorithm($complete_headers);
76
77
        // Content Encryption Algorithm
78
        $content_encryption_algorithm = $this->findContentEncryptionAlgorithm($complete_headers);
79
80
        // We check keys (usage and algorithm if restrictions are set)
81
        $this->checkKeys($key_encryption_algorithm, $content_encryption_algorithm, $recipient_key, $sender_key);
82
83
        if (null === $jwe->getCiphertext()) {
84
            // the content is not yet encrypted (no recipient)
85
86
            $this->encryptJWE($jwe, $complete_headers, $key_encryption_algorithm, $content_encryption_algorithm, $recipient_key, $sender_key);
87
        } else {
88
            if (0 === $jwe->countRecipients()) {
89
                throw new \InvalidArgumentException('Invalid JWE. The payload is encrypted but no recipient is available.');
90
            }
91
            if (null === $jwe->getContentEncryptionKey()) {
92
                throw new \InvalidArgumentException('Unable to add a recipient. The JWE must be decrypted first.');
93
            }
94
            $current_key_management_mode = $this->getCurrentKeyManagementMode($jwe);
95
96
            if (false === $this->areKeyManagementModesCompatible($current_key_management_mode, $key_encryption_algorithm->getKeyManagementMode())) {
97
                throw new \InvalidArgumentException('Foreign key management mode forbidden.');
98
            }
99
        }
100
101
        $recipient = $this->computeRecipient(
102
            $jwe,
103
            $key_encryption_algorithm,
104
            $content_encryption_algorithm,
105
            $complete_headers,
106
            $recipient_headers,
107
            $recipient_key,
108
            $sender_key
109
        );
110
111
        $jwe = $jwe->addRecipient($recipient);
112
    }
113
114
    /**
115
     * @param \Jose\Object\JWEInterface                           $jwe
116
     * @param array                                               $complete_headers
117
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
118
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
119
     * @param \Jose\Object\JWKInterface                           $recipient_key
120
     * @param \Jose\Object\JWKInterface|null                      $sender_key
121
     */
122
    private function encryptJWE(JWEInterface &$jwe,
123
                                array $complete_headers,
124
                                KeyEncryptionAlgorithmInterface $key_encryption_algorithm,
125
                                ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
126
                                JWKInterface $recipient_key,
127
                                JWKInterface $sender_key = null
128
    ) {
129
        if (!empty($jwe->getSharedProtectedHeaders())) {
130
            $jwe = $jwe->withEncodedSharedProtectedHeaders(Base64Url::encode(json_encode($jwe->getSharedProtectedHeaders())));
131
        }
132
133
        // CEK
134
        $content_encryption_key = $this->getCEK(
135
            $complete_headers,
136
            $key_encryption_algorithm,
137
            $content_encryption_algorithm,
138
            $recipient_key,
139
            $sender_key
140
        );
141
        $jwe = $jwe->withContentEncryptionKey($content_encryption_key);
142
143
        // IV
144
        if (null !== $iv_size = $content_encryption_algorithm->getIVSize()) {
145
            $iv = $this->createIV($iv_size);
146
            $jwe = $jwe->withIV($iv);
147
        }
148
149
        // We encrypt the payload and get the tag
150
        $tag = null;
151
        $payload = $this->preparePayload($jwe->getPayload(), $complete_headers);
152
153
        $ciphertext = $content_encryption_algorithm->encryptContent(
154
            $payload,
155
            $content_encryption_key,
156
            $jwe->getIV(),
157
            $jwe->getAAD(),
158
            $jwe->getEncodedSharedProtectedHeaders(),
159
            $tag
160
        );
161
        $jwe = $jwe->withCiphertext($ciphertext);
162
163
        // Tag
164
        if (null !== $tag) {
165
            $jwe = $jwe->withTag($tag);
166
        }
167
    }
168
169
    /**
170
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
171
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
172
     * @param \Jose\Object\JWKInterface                           $recipient_key
173
     * @param \Jose\Object\JWKInterface|null                      $sender_key
174
     */
175
    private function checkKeys(KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, JWKInterface $recipient_key, JWKInterface $sender_key = null)
176
    {
177
        $this->checkKeyUsage($recipient_key, 'encryption');
178
        if ('dir' !== $key_encryption_algorithm->getAlgorithmName()) {
179
            $this->checkKeyAlgorithm($recipient_key, $key_encryption_algorithm->getAlgorithmName());
180
        } else {
181
            $this->checkKeyAlgorithm($recipient_key, $content_encryption_algorithm->getAlgorithmName());
182
        }
183
        if ($sender_key instanceof JWKInterface) {
184
            $this->checkKeyUsage($sender_key, 'encryption');
185
            if ('dir' !== $key_encryption_algorithm->getAlgorithmName()) {
186
                $this->checkKeyAlgorithm($sender_key, $key_encryption_algorithm->getAlgorithmName());
187
            } else {
188
                $this->checkKeyAlgorithm($sender_key, $content_encryption_algorithm->getAlgorithmName());
189
            }
190
        }
191
    }
192
193
    /**
194
     * @param \Jose\Object\JWEInterface $jwe
195
     *
196
     * @return string
197
     */
198
    private function getCurrentKeyManagementMode(JWEInterface $jwe)
199
    {
200
        $complete_headers = array_merge(
201
            $jwe->getSharedProtectedHeaders(),
202
            $jwe->getSharedHeaders(),
203
            $jwe->getRecipient(0)->getHeaders()
204
        );
205
        $key_encryption_algorithm = $this->findKeyEncryptionAlgorithm($complete_headers);
206
207
        return $key_encryption_algorithm->getKeyManagementMode();
208
    }
209
210
    /**
211
     * @param \Jose\Object\JWEInterface                           $jwe
212
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
213
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
214
     * @param array                                               $complete_headers
215
     * @param array                                               $recipient_headers
216
     * @param \Jose\Object\JWKInterface                           $recipient_key
217
     * @param \Jose\Object\JWKInterface|null                      $sender_key
218
     *
219
     * @return \Jose\Object\RecipientInterface
220
     */
221
    private function computeRecipient(JWEInterface $jwe, KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array $complete_headers, array $recipient_headers, JWKInterface $recipient_key, JWKInterface $sender_key = null)
222
    {
223
        $recipient = new Recipient();
224
        $recipient = $recipient->withHeaders($recipient_headers);
225
226
        $additional_headers = [];
227
        $encrypted_content_encryption_key = $this->getEncryptedKey(
228
            $complete_headers,
229
            $jwe->getContentEncryptionKey(),
230
            $key_encryption_algorithm,
231
            $content_encryption_algorithm,
232
            $additional_headers,
233
            $recipient_key,
234
            $sender_key
235
        );
236
        if (!empty($additional_headers)) {
237
            foreach ($additional_headers as $key => $value) {
238
                $recipient = $recipient->withHeader($key, $value);
239
            }
240
        }
241
        if (null !== $encrypted_content_encryption_key) {
242
            $recipient = $recipient->withEncryptedKey($encrypted_content_encryption_key);
243
        }
244
245
        return $recipient;
246
    }
247
248
    /**
249
     * @param string $current
250
     * @param string $new
251
     *
252
     * @return bool
253
     */
254
    private function areKeyManagementModesCompatible($current, $new)
255
    {
256
        $agree = KeyEncryptionAlgorithmInterface::MODE_AGREEMENT;
257
        $dir = KeyEncryptionAlgorithmInterface::MODE_DIRECT;
258
        $enc = KeyEncryptionAlgorithmInterface::MODE_ENCRYPT;
259
        $wrap = KeyEncryptionAlgorithmInterface::MODE_WRAP;
260
261
        $supported_key_management_mode_combinations = [
262
            $agree.$enc   => true,
263
            $agree.$wrap  => true,
264
            $dir.$enc     => true,
265
            $dir.$wrap    => true,
266
            $enc.$enc     => true,
267
            $enc.$wrap    => true,
268
            $wrap.$enc    => true,
269
            $wrap.$wrap   => true,
270
            $agree.$agree => false,
271
            $agree.$dir   => false,
272
            $dir.$agree   => false,
273
            $dir.$dir     => false,
274
            $enc.$agree   => false,
275
            $enc.$dir     => false,
276
            $wrap.$agree  => false,
277
            $wrap.$dir    => false,
278
        ];
279
280
        if (array_key_exists($current.$new, $supported_key_management_mode_combinations)) {
281
            return $supported_key_management_mode_combinations[$current.$new];
282
        }
283
284
        return false;
285
    }
286
287
    /**
288
     * @param string $payload
289
     * @param array  $complete_headers
290
     *
291
     * @return string
292
     */
293
    private function preparePayload($payload, array $complete_headers)
294
    {
295
        $prepared = is_string($payload) ? $payload : json_encode($payload);
296
297
        if (null === $prepared) {
298
            throw new \InvalidArgumentException('The payload is empty or cannot encoded into JSON.');
299
        }
300
        if (!array_key_exists('zip', $complete_headers)) {
301
            return $prepared;
302
        }
303
304
        $compression_method = $this->getCompressionManager()->getCompressionAlgorithm($complete_headers['zip']);
305
        if (null === $compression_method) {
306
            throw new \RuntimeException(sprintf('Compression method "%s" not supported', $complete_headers['zip']));
307
        }
308
        $compressed_payload = $compression_method->compress($prepared);
309
        if (!is_string($compressed_payload)) {
310
            throw new \RuntimeException('Compression failed.');
311
        }
312
313
        return $compressed_payload;
314
    }
315
316
    /**
317
     * @param array                                               $complete_headers
318
     * @param string                                              $cek
319
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
320
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
321
     * @param \Jose\Object\JWKInterface                           $recipient_key
322
     * @param \Jose\Object\JWKInterface|null                      $sender_key
323
     * @param array                                               $additional_headers
324
     *
325
     * @return string|null
326
     */
327
    private function getEncryptedKey(array $complete_headers, $cek, KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key, JWKInterface $sender_key = null)
328
    {
329
        if ($key_encryption_algorithm instanceof KeyEncryptionInterface) {
330
            return $this->getEncryptedKeyFromKeyEncryptionAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $recipient_key, $additional_headers);
331
        } elseif ($key_encryption_algorithm instanceof KeyWrappingInterface) {
332
            return $this->getEncryptedKeyFromKeyWrappingAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $recipient_key);
333
        } elseif ($key_encryption_algorithm instanceof KeyAgreementWrappingInterface) {
334
            return $this->getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $content_encryption_algorithm, $additional_headers, $recipient_key, $sender_key);
335
        } elseif ($key_encryption_algorithm instanceof KeyAgreementInterface) {
336
            return $this->getEncryptedKeyFromKeyAgreementAlgorithm($complete_headers, $key_encryption_algorithm, $content_encryption_algorithm, $additional_headers, $recipient_key, $sender_key);
337
        }
338
    }
339
340
    /**
341
     * @param array                                               $complete_headers
342
     * @param \Jose\Algorithm\KeyEncryption\KeyAgreementInterface $key_encryption_algorithm
343
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
344
     * @param array                                               $additional_headers
345
     * @param \Jose\Object\JWKInterface                           $recipient_key
346
     * @param \Jose\Object\JWKInterface|null                      $sender_key
347
     *
348
     * @return mixed
349
     */
350
    private function getEncryptedKeyFromKeyAgreementAlgorithm(array $complete_headers, KeyAgreementInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key, JWKInterface $sender_key = null)
351
    {
352
        if (!$sender_key instanceof JWKInterface) {
353
            throw new \RuntimeException('The sender key must be set using Key Agreement or Key Agreement with Wrapping algorithms.');
354
        }
355
        $jwt_cek = $key_encryption_algorithm->getAgreementKey(
356
            $content_encryption_algorithm->getCEKSize(),
357
            $content_encryption_algorithm->getAlgorithmName(),
358
            $sender_key,
359
            $recipient_key,
360
            $complete_headers,
361
            $additional_headers
362
        );
363
364
        return $jwt_cek;
365
    }
366
367
    /**
368
     * @param array                                                       $complete_headers
369
     * @param string                                                      $cek
370
     * @param \Jose\Algorithm\KeyEncryption\KeyAgreementWrappingInterface $key_encryption_algorithm
371
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface         $content_encryption_algorithm
372
     * @param array                                                       $additional_headers
373
     * @param \Jose\Object\JWKInterface                                   $recipient_key
374
     * @param \Jose\Object\JWKInterface|null                              $sender_key
375
     *
376
     * @return string
377
     */
378
    private function getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm(array $complete_headers, $cek, KeyAgreementWrappingInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key, JWKInterface $sender_key = null)
379
    {
380
        if (!$sender_key instanceof JWKInterface) {
381
            throw new \RuntimeException('The sender key must be set using Key Agreement or Key Agreement with Wrapping algorithms.');
382
        }
383
        $jwt_cek = $key_encryption_algorithm->wrapAgreementKey($sender_key, $recipient_key, $cek, $content_encryption_algorithm->getCEKSize(), $complete_headers, $additional_headers);
384
385
        return $jwt_cek;
386
    }
387
388
    /**
389
     * @param array                                                $complete_headers
390
     * @param string                                               $cek
391
     * @param \Jose\Algorithm\KeyEncryption\KeyEncryptionInterface $key_encryption_algorithm
392
     * @param \Jose\Object\JWKInterface                            $recipient_key
393
     * @param array                                                $additional_headers
394
     *
395
     * @return string
396
     */
397
    private function getEncryptedKeyFromKeyEncryptionAlgorithm(array $complete_headers, $cek, KeyEncryptionInterface $key_encryption_algorithm, JWKInterface $recipient_key, array &$additional_headers)
398
    {
399
        return $key_encryption_algorithm->encryptKey(
400
            $recipient_key,
401
            $cek,
402
            $complete_headers,
403
            $additional_headers
404
        );
405
    }
406
407
    /**
408
     * @param array                                              $complete_headers
409
     * @param string                                             $cek
410
     * @param \Jose\Algorithm\KeyEncryption\KeyWrappingInterface $key_encryption_algorithm
411
     * @param \Jose\Object\JWKInterface                          $recipient_key
412
     *
413
     * @return string
414
     */
415
    private function getEncryptedKeyFromKeyWrappingAlgorithm(array $complete_headers, $cek, KeyWrappingInterface $key_encryption_algorithm, JWKInterface $recipient_key)
416
    {
417
        return $key_encryption_algorithm->wrapKey(
418
            $recipient_key,
419
            $cek,
420
            $complete_headers
421
        );
422
    }
423
424
    /**
425
     * @param array                                               $complete_headers
426
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
427
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
428
     * @param \Jose\Object\JWKInterface                           $recipient_key
429
     * @param \Jose\Object\JWKInterface|null                      $sender_key
430
     *
431
     * @return string
432
     */
433
    private function getCEK(array $complete_headers, KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, JWKInterface $recipient_key, JWKInterface $sender_key = null)
434
    {
435
        if ($key_encryption_algorithm instanceof KeyEncryptionInterface) {
436
            return $this->createCEK($content_encryption_algorithm->getCEKSize());
437
        } elseif ($key_encryption_algorithm instanceof KeyWrappingInterface) {
438
            return $this->createCEK($content_encryption_algorithm->getCEKSize());
439
        } elseif ($key_encryption_algorithm instanceof KeyAgreementWrappingInterface) {
440
            return $this->createCEK($content_encryption_algorithm->getCEKSize());
441
        } elseif ($key_encryption_algorithm instanceof KeyAgreementInterface) {
442
            return $this->calculateAgreementKey($complete_headers, $key_encryption_algorithm, $content_encryption_algorithm, $recipient_key, $sender_key);
443
        } elseif ($key_encryption_algorithm instanceof DirectEncryptionInterface) {
444
            return $key_encryption_algorithm->getCEK($recipient_key);
445
        } else {
446
            throw new \RuntimeException('Unable to get key management mode.');
447
        }
448
    }
449
450
    /**
451
     * @param array $complete_headers
452
     *
453
     * @return \Jose\Algorithm\KeyEncryptionAlgorithmInterface
454
     */
455
    private function findKeyEncryptionAlgorithm(array $complete_headers)
456
    {
457
        if (!array_key_exists('alg', $complete_headers)) {
458
            throw new \InvalidArgumentException('Parameter "alg" is missing.');
459
        }
460
        $key_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
461
        if ($key_encryption_algorithm instanceof KeyEncryptionAlgorithmInterface) {
462
            return $key_encryption_algorithm;
463
        }
464
        throw new \InvalidArgumentException(sprintf('The key encryption algorithm "%s" is not supported or not a key encryption algorithm instance.', $complete_headers['alg']));
465
    }
466
467
    /**
468
     * @param array $complete_headers
469
     *
470
     * @return \Jose\Algorithm\ContentEncryptionAlgorithmInterface
471
     */
472
    private function findContentEncryptionAlgorithm(array $complete_headers)
473
    {
474
        if (!array_key_exists('enc', $complete_headers)) {
475
            throw new \InvalidArgumentException('Parameter "enc" is missing.');
476
        }
477
478
        $content_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['enc']);
479
        if (!$content_encryption_algorithm instanceof ContentEncryptionAlgorithmInterface) {
480
            throw new \RuntimeException(sprintf('The algorithm "%s" is not enabled or does not implement ContentEncryptionInterface.', $complete_headers['enc']));
481
        }
482
483
        return $content_encryption_algorithm;
484
    }
485
486
    /**
487
     * @param array                                               $complete_headers
488
     * @param \Jose\Algorithm\KeyEncryption\KeyAgreementInterface $key_encryption_algorithm
489
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
490
     * @param \Jose\Object\JWKInterface                           $recipient_key
491
     * @param \Jose\Object\JWKInterface|null                      $sender_key
492
     *
493
     * @return string
494
     */
495
    private function calculateAgreementKey(array $complete_headers, KeyAgreementInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, JWKInterface $recipient_key, JWKInterface $sender_key = null)
496
    {
497
        if (!$sender_key instanceof JWKInterface) {
498
            throw new \RuntimeException('The sender key must be set using Key Agreement or Key Agreement with Wrapping algorithms.');
499
        }
500
        $additional_header_values = [];
501
        $cek = $key_encryption_algorithm->getAgreementKey(
502
            $content_encryption_algorithm->getCEKSize(),
503
            $content_encryption_algorithm->getAlgorithmName(),
504
            $sender_key, $recipient_key,
505
            $complete_headers,
506
            $additional_header_values
507
        );
508
509
        return $cek;
510
    }
511
512
    /**
513
     * @param int $size
514
     *
515
     * @return string
516
     */
517
    private function createCEK($size)
518
    {
519
        return StringUtil::generateRandomBytes($size / 8);
520
    }
521
522
    /**
523
     * @param int $size
524
     *
525
     * @return string
526
     */
527
    private function createIV($size)
528
    {
529
        return StringUtil::generateRandomBytes($size / 8);
530
    }
531
}
532