Completed
Push — master ( d3ed9f...edab03 )
by Tony Karavasilev (Тони
07:44
created

AbstractKeyedHashFunction::hashObject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
/**
4
 * Abstraction for keyed hash objects like HMAC functions (keyed-hash message authentication code hash).
5
 */
6
7
namespace CryptoManana\Core\Abstractions\MessageDigestion;
8
9
use \CryptoManana\Core\Abstractions\MessageDigestion\AbstractHashAlgorithm as HashAlgorithm;
10
use \CryptoManana\Core\Interfaces\MessageDigestion\DigestionKeyInterface as KeyedHashing;
11
use \CryptoManana\Core\Interfaces\MessageDigestion\ObjectHashingInterface as ObjectHashing;
12
use \CryptoManana\Core\Interfaces\MessageDigestion\FileHashingInterface as FileHashing;
13
use \CryptoManana\Core\Traits\MessageDigestion\DigestionKeyTrait as DigestionKey;
14
use \CryptoManana\Core\StringBuilder as StringBuilder;
15
16
/**
17
 * Class AbstractKeyedHashFunction - Abstraction for keyed hash classes.
18
 *
19
 * @package CryptoManana\Core\Abstractions\MessageDigestion
20
 *
21
 * @mixin DigestionKey
22
 */
23
abstract class AbstractKeyedHashFunction extends HashAlgorithm implements KeyedHashing, ObjectHashing, FileHashing
24
{
25
    /**
26
     * Data salting capabilities.
27
     *
28
     * {@internal Reusable implementation of `DigestionKeyInterface`. }}
29
     */
30
    use DigestionKey;
31
32
    /**
33
     * The internal name of the algorithm.
34
     */
35
    const ALGORITHM_NAME = 'none';
36
37
    /**
38
     * Flag to force native code polyfill realizations, if available.
39
     *
40
     * @var bool Flag to force native realizations.
41
     */
42
    protected $useNative = false;
43
44
    /**
45
     * The key string property storage.
46
     *
47
     * @var string The digestion key string value.
48
     */
49
    protected $key = '';
50
51
    /**
52
     * Internal method for location and filename validation.
53
     *
54
     * @param string $filename The filename and location.
55
     *
56
     * @throws \Exception Validation errors.
57
     */
58 44
    protected function validateFileNamePath($filename)
59
    {
60 44
        $filename = StringBuilder::stringReplace("\0", '', $filename); // (ASCII 0 (0x00))
61 44
        $filename = realpath($filename); // Path traversal escape and absolute path fetching
62
63
        // Clear path cache
64 44
        if (!empty($filename)) {
65 22
            clearstatcache(true, $filename);
66
        }
67
68
        // Check if path is valid and the file is readable
69 44
        if ($filename === false || !file_exists($filename) || !is_readable($filename) || !is_file($filename)) {
70 22
            throw new \RuntimeException('File is not found or can not be accessed.');
71
        }
72 22
    }
73
74
    /**
75
     * Unkeyed hash algorithm constructor.
76
     */
77 374
    public function __construct()
78
    {
79 374
    }
80
81
    /**
82
     * Calculates a hash value for the given data.
83
     *
84
     * @param string $data The input string.
85
     *
86
     * @return string The digest.
87
     * @throws \Exception Validation errors.
88
     */
89 126
    public function hashData($data)
90
    {
91 126
        if (!is_string($data)) {
92 14
            throw new \InvalidArgumentException('The data for hashing must be a string or a binary string.');
93
        }
94
95 112
        $data = $this->addSaltString($data);
96
97 112
        $digest = hash_hmac(
98 112
            static::ALGORITHM_NAME,
99
            $data,
100 112
            $this->key,
101 112
            ($this->digestFormat === self::DIGEST_OUTPUT_RAW)
102
        );
103
104 112
        $digest = $this->changeOutputFormat($digest);
105
106 112
        return $digest;
107
    }
108
109
    /**
110
     * Calculates a hash value for the content of the given filename and location.
111
     *
112
     * @param string $filename The full path and name of the file for hashing.
113
     *
114
     * @return string The digest.
115
     * @throws \Exception Validation errors.
116
     */
117 66
    public function hashFile($filename)
118
    {
119
        // Validate input type
120 66
        if (!is_string($filename)) {
121 22
            throw new \InvalidArgumentException('The file path must be of type string.');
122
        }
123
124 44
        $this->validateFileNamePath($filename);
125
126 22
        if ($this->useNative) {
127 22
            $oldSalt = $this->getSalt();
128 22
            $oldMode = $this->getSaltingMode();
129
130 22
            $this->setSalt('')->setSaltingMode(self::SALTING_MODE_NONE);
131
132 22
            $digest = $this->hashData(file_get_contents($filename));
133
134 22
            $this->setSalt($oldSalt)->setSaltingMode($oldMode);
135
        } else {
136 22
            $digest = hash_hmac_file(
137 22
                static::ALGORITHM_NAME,
138
                $filename,
139 22
                $this->key,
140 22
                ($this->digestFormat === self::DIGEST_OUTPUT_RAW)
141
            );
142
143 22
            $digest = $this->changeOutputFormat($digest);
144
        }
145
146 22
        return $digest;
147
    }
148
149
    /**
150
     * Calculates a hash value for the serialized value of the given object.
151
     *
152
     * @param object|\stdClass $object The full path and name of the file for hashing.
153
     *
154
     * @return string The digest.
155
     * @throws \Exception Validation errors.
156
     */
157 44
    public function hashObject($object)
158
    {
159 44
        if (is_object($object)) {
160 22
            $object = serialize($object);
161
        } else {
162 22
            throw new \InvalidArgumentException('The data for hashing must be an object instance.');
163
        }
164
165 22
        return $this->hashData($object);
166
    }
167
168
    /**
169
     * Get debug information for the class instance.
170
     *
171
     * @return array Debug information.
172
     */
173 22
    public function __debugInfo()
174
    {
175
        return [
176 22
            'standard' => static::ALGORITHM_NAME,
177 22
            'type' => 'keyed digestion or HMAC',
178 22
            'key' => $this->key,
179 22
            'salt' => $this->salt,
180 22
            'mode' => $this->saltingMode,
181
        ];
182
    }
183
}
184