1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Cryptobase.php |
5
|
|
|
* |
6
|
|
|
* PHP version 5 |
7
|
|
|
* |
8
|
|
|
* @category Dcrypt |
9
|
|
|
* @package Dcrypt |
10
|
|
|
* @author Michael Meyer (mmeyer2k) <[email protected]> |
11
|
|
|
* @license http://opensource.org/licenses/MIT The MIT License (MIT) |
12
|
|
|
* @link https://github.com/mmeyer2k/dcrypt |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
namespace Dcrypt; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Provides functionality common to Dcrypt's block ciphers. |
19
|
|
|
* |
20
|
|
|
* @category Dcrypt |
21
|
|
|
* @package Dcrypt |
22
|
|
|
* @author Michael Meyer (mmeyer2k) <[email protected]> |
23
|
|
|
* @license http://opensource.org/licenses/MIT The MIT License (MIT) |
24
|
|
|
* @link https://github.com/mmeyer2k/dcrypt |
25
|
|
|
* @link https://apigen.ci/github/mmeyer2k/dcrypt/namespace-Dcrypt.html |
26
|
|
|
*/ |
27
|
|
|
class Cryptobase |
28
|
|
|
{ |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Create a message authentication checksum. |
32
|
|
|
* |
33
|
|
|
* @param string $cyphertext Cyphertext that needs a checksum. |
34
|
|
|
* @param string $iv Initialization vector. |
35
|
|
|
* @param string $key HMAC key |
36
|
|
|
* @param string $cipher Cipher string |
37
|
|
|
* @param string $mode Cipher mode string |
38
|
|
|
* @param string $algo Hashing algorithm to use for internal operations |
39
|
|
|
* |
40
|
|
|
* @return string |
41
|
|
|
*/ |
42
|
11 |
|
protected static function checksum($cyphertext, $iv, $key, $cipher = 'rijndael-128', $mode = 'cbc', $algo = 'sha256') |
43
|
|
|
{ |
44
|
|
|
// Prevent potentially large string concat by hmac-ing the cyphertext |
45
|
|
|
// by itself... |
46
|
11 |
|
$sum = \hash_hmac($algo, $cyphertext, $key, true); |
47
|
|
|
|
48
|
|
|
// ... then hash other elements with previous hmac and return |
49
|
11 |
|
return \hash_hmac($algo, $sum . $iv . $mode . $cipher, $key, true); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* This will normalize a hash to a certain length by extending it if |
54
|
|
|
* too short and truncating it if too long. This ensures that any |
55
|
|
|
* hash algo will work with any combination of other settings. However, |
56
|
|
|
* it is probably best to make sure that the keysize and algo size |
57
|
|
|
* are identical so that the input hash passes through unchanged. |
58
|
|
|
* |
59
|
|
|
* @param string $hash Hash to be normalized |
60
|
|
|
* @param int $size Size of the desired output hash, in bytes |
61
|
|
|
* @param string $algo Hashing algorithm to use for internal operations |
62
|
|
|
* |
63
|
|
|
* @return string |
64
|
|
|
*/ |
65
|
11 |
|
private static function hashNormalize($hash, $size, $algo) |
66
|
|
|
{ |
67
|
|
|
// Extend hash if too short |
68
|
11 |
|
while (Str::strlen($hash) < $size) { |
69
|
2 |
|
$hash .= \hash($algo, $hash, true); |
70
|
2 |
|
} |
71
|
|
|
|
72
|
|
|
// Truncate to specified number of bytes (if needed) and return |
73
|
11 |
|
return Str::substr($hash, 0, $size); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Transform password into key and perform iterative HMAC (if specified) |
78
|
|
|
* |
79
|
|
|
* @param string $password Encryption key |
80
|
|
|
* @param string $iv Initialization vector |
81
|
|
|
* @param int $cost Number of HMAC iterations to perform on key |
82
|
|
|
* @param string $cipher Mcrypt cipher |
83
|
|
|
* @param string $mode Mcrypt block mode |
84
|
|
|
* @param string $algo Hashing algorithm to use for internal operations |
85
|
|
|
* |
86
|
|
|
* @return string |
87
|
|
|
*/ |
88
|
11 |
|
protected static function key($password, $iv, $cost, $cipher = 'rijndael-128', $mode = 'cbc', $algo = 'sha256') |
89
|
|
|
{ |
90
|
|
|
// This if statement allows the usage of the Openssl library without |
91
|
|
|
// the need to have the mcrypt plugin installed at all. |
92
|
11 |
|
if ($cipher === Aes::RIJNDA) { |
93
|
11 |
|
$keysize = 32; |
94
|
11 |
|
} else { |
95
|
2 |
|
$keysize = \mcrypt_get_key_size($cipher, $mode); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
// Perform key derivation |
99
|
11 |
|
$key = Hash::ihmac($iv . $cipher . $mode, $password, $cost, $algo); |
100
|
|
|
|
101
|
|
|
// Return hash normalized to key length |
102
|
11 |
|
return self::hashNormalize($key, $keysize, $algo); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Verify checksum during decryption step and throw error if mismatching. |
107
|
|
|
* |
108
|
|
|
* @param string $calculated |
109
|
|
|
* @param string $supplied |
110
|
|
|
*/ |
111
|
11 |
|
protected static function checksumVerify($calculated, $supplied) |
112
|
|
|
{ |
113
|
11 |
|
if (!Str::equal($calculated, $supplied)) { |
114
|
4 |
|
$e = 'Decryption can not proceed due to invalid cyphertext checksum.'; |
115
|
4 |
|
throw new \InvalidArgumentException($e); |
116
|
|
|
} |
117
|
10 |
|
} |
118
|
|
|
|
119
|
|
|
} |
120
|
|
|
|