Completed
Push — master ( 272748...4e7f9b )
by Tony Karavasilev (Тони
16:59
created

AbstractHardwareResistantDerivation::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * Abstraction for the strong/slow digestion algorithm objects that are resistant to hardware computational attacks.
5
 */
6
7
namespace CryptoManana\Core\Abstractions\MessageDigestion;
8
9
use \CryptoManana\Core\Abstractions\MessageDigestion\AbstractPasswordBasedDerivationFunction as PasswordDerivation;
10
use \CryptoManana\Core\StringBuilder as StringBuilder;
11
12
/**
13
 * Class AbstractHardwareResistantDerivation - The hardware resistant digestion algorithm abstraction representation.
14
 *
15
 * @package CryptoManana\Core\Abstractions\MessageDigestion
16
 */
17
abstract class AbstractHardwareResistantDerivation extends PasswordDerivation
18
{
19
    /**
20
     * The internal maximum length in bytes of the raw output digest for the algorithm.
21
     */
22
    const ALGORITHM_MAXIMUM_OUTPUT = PHP_INT_MAX;
23
24
    /**
25
     * The digest output format property storage.
26
     *
27
     * @var int The output format integer code value.
28
     */
29
    protected $digestFormat = self::DIGEST_OUTPUT_RAW;
30
31
    /**
32
     * Internal method for converting the digest's output format representation via the chosen format.
33
     *
34
     * @param string $digest The output digest.
35
     *
36
     * @return string The input data with proper salting.
37
     */
38 32
    protected function changeOutputFormat($digest)
39
    {
40 32
        switch ($this->digestFormat) {
41 32
            case self::DIGEST_OUTPUT_HEX_LOWER:
42 8
                $digest = bin2hex($digest);
43 8
                break;
44 28
            case self::DIGEST_OUTPUT_HEX_UPPER:
45 4
                $digest = StringBuilder::stringToUpper(bin2hex($digest));
46 4
                break;
47 28
            case self::DIGEST_OUTPUT_BASE_64:
48 4
                $digest = base64_encode($digest);
49 4
                break;
50 28
            case self::DIGEST_OUTPUT_BASE_64_URL:
51 4
                $digest = base64_encode($digest);
52 4
                $digest = StringBuilder::stringReplace(['+', '/', '='], ['-', '_', ''], $digest);
53 4
                break;
54
            default: // case self::DIGEST_OUTPUT_RAW:
55 28
                break;
56
        }
57
58 32
        return $digest;
59
    }
60
61
    /**
62
     * Internal method for converting a formatted digest to raw bytes.
63
     *
64
     * @param string $digest The digest string.
65
     *
66
     * @return string The raw bytes digest representation.
67
     */
68 12
    protected function convertFormattedDigest($digest)
69
    {
70 12
        $hexCasePattern = '/^[a-f0-9]+$/';
71 12
        $base64Pattern = '%^[a-zA-Z0-9/+]*={0,2}$%';
72 12
        $base64UrlFriendlyPattern = '/^[a-zA-Z0-9_-]+$/';
73
74 12
        if (preg_match($hexCasePattern, StringBuilder::stringToLower($digest))) {
75 4
            $digest = hex2bin(StringBuilder::stringToLower($digest));
76 12
        } elseif (preg_match($base64Pattern, $digest) && StringBuilder::stringLength($digest) % 4 === 0) {
77 4
            $digest = base64_decode($digest);
78 12
        } elseif (preg_match($base64UrlFriendlyPattern, $digest)) {
79 4
            $digest = StringBuilder::stringReplace(['-', '_'], ['+', '/'], $digest);
80 4
            $digest .= str_repeat('=', StringBuilder::stringLength($digest) % 4);
81 4
            $digest = base64_decode($digest);
82
        }
83
84 12
        return $digest;
85
    }
86
87
    /**
88
     * Fetch the correctly formatted internal variation for digestion.
89
     *
90
     * @return int|string The chosen variation for password hashing.
91
     */
92
    abstract protected function fetchAlgorithmVariation();
93
94
    /**
95
     * Fetch the correctly formatted internal parameters for digestion.
96
     *
97
     * @return array The chosen parameters for password hashing.
98
     */
99
    abstract protected function fetchAlgorithmParameters();
100
101
    /**
102
     * Password-based key derivation algorithm constructor.
103
     */
104 70
    public function __construct()
105
    {
106 70
        parent::__construct();
107 70
    }
108
109
    /**
110
     * Calculates a hash value for the given data.
111
     *
112
     * @param string $data The input string.
113
     *
114
     * @return string The digest.
115
     * @throws \Exception Validation errors.
116
     */
117 36
    public function hashData($data)
118
    {
119 36
        if (!is_string($data)) {
120 4
            throw new \InvalidArgumentException('The data for hashing must be a string or a binary string.');
121
        }
122
123 32
        $data = $this->addSaltString($data);
124
125 32
        $digest = password_hash($data, $this->fetchAlgorithmVariation(), $this->fetchAlgorithmParameters());
126
127 32
        $digest = $this->changeOutputFormat($digest);
128
129 32
        return $digest;
130
    }
131
132
    /**
133
     * Securely compares and verifies if a digestion value is for the given input data.
134
     *
135
     * @param string $data The input string.
136
     * @param string $digest The digest string.
137
     *
138
     * @return bool The result of the secure comparison.
139
     * @throws \Exception Validation errors.
140
     */
141 20
    public function verifyHash($data, $digest)
142
    {
143 20
        if (!is_string($data)) {
144 4
            throw new \InvalidArgumentException('The data for hashing must be a string or a binary string.');
145 16
        } elseif (!is_string($digest)) {
146 4
            throw new \InvalidArgumentException('The digest must be a string or a binary string.');
147
        }
148
149 12
        $data = $this->addSaltString($data);
150
151 12
        $digest = $this->convertFormattedDigest($digest);
152
153 12
        return password_verify($data, $digest);
154
    }
155
156
    /**
157
     * Get debug information for the class instance.
158
     *
159
     * @return array Debug information.
160
     */
161 4
    public function __debugInfo()
162
    {
163
        return [
164 4
            'standard' => static::ALGORITHM_NAME,
165 4
            'type' => 'key stretching or password-based key derivation',
166 4
            'salt' => $this->salt,
167 4
            'mode' => $this->saltingMode,
168 4
            'algorithm variation version' => $this->fetchAlgorithmVariation(),
169 4
            'digestion parameters' => $this->fetchAlgorithmParameters(),
170
        ];
171
    }
172
}
173