|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace NFePHP\eFinanc\Common; |
|
4
|
|
|
|
|
5
|
|
|
/** |
|
6
|
|
|
* Crypto class Performs message encryption processes |
|
7
|
|
|
* |
|
8
|
|
|
* @category API |
|
9
|
|
|
* @package NFePHP\eFinanc |
|
10
|
|
|
* @copyright Copyright (c) 2018 |
|
11
|
|
|
* @license http://www.gnu.org/licenses/lesser.html LGPL v3 |
|
12
|
|
|
* @author Roberto L. Machado <linux.rlm at gmail dot com> |
|
13
|
|
|
* @link http://github.com/nfephp-org/sped-efinanceira for the canonical source repository |
|
14
|
|
|
*/ |
|
15
|
|
|
class Crypto |
|
16
|
|
|
{ |
|
17
|
|
|
/** |
|
18
|
|
|
* @var integer |
|
19
|
|
|
*/ |
|
20
|
|
|
protected $cipher; |
|
21
|
|
|
/** |
|
22
|
|
|
* @var string |
|
23
|
|
|
*/ |
|
24
|
|
|
protected $key; |
|
25
|
|
|
/** |
|
26
|
|
|
* @var string |
|
27
|
|
|
*/ |
|
28
|
|
|
protected $iv; |
|
29
|
|
|
/** |
|
30
|
|
|
* @var string |
|
31
|
|
|
*/ |
|
32
|
|
|
protected $certificate; |
|
33
|
|
|
/** |
|
34
|
|
|
* @var string |
|
35
|
|
|
*/ |
|
36
|
|
|
protected $fingerprint; |
|
37
|
|
|
/** |
|
38
|
|
|
* @var string |
|
39
|
|
|
*/ |
|
40
|
|
|
protected $keyencrypted; |
|
41
|
|
|
/** |
|
42
|
|
|
* constants |
|
43
|
|
|
*/ |
|
44
|
|
|
const AES_128_CBC = 'aes-128-cbc'; |
|
45
|
|
|
const AES_128_CBF = 'aes-128-cfb'; |
|
46
|
|
|
const AES_128_CBF1 = 'aes-128-cfb1'; |
|
47
|
|
|
const AES_128_CBF8 = 'aes-128-cfb8'; |
|
48
|
|
|
const AES_128_OFB = 'aes-128-ofb'; |
|
49
|
|
|
const AES_192_CBC = 'aes-192-cbc'; |
|
50
|
|
|
const AES_192_CBF = 'aes-192-cbf'; |
|
51
|
|
|
const AES_192_CBF1 = 'aes-192-cbf1'; |
|
52
|
|
|
const AES_192_CBF8 = 'aes-192-cbf8'; |
|
53
|
|
|
const AES_192_OFB = 'aes-192-ofb'; |
|
54
|
|
|
const AES_256_CBC = 'aes-256-cbc'; |
|
55
|
|
|
const AES_256_CBF = 'aes-256-cbf'; |
|
56
|
|
|
const AES_256_CBF1 = 'aes-256-cbf1'; |
|
57
|
|
|
const AES_256_CBF8 = 'aes-256-cbf8'; |
|
58
|
|
|
const AES_256_OFB = 'aes-256-ofb'; |
|
59
|
|
|
|
|
60
|
|
|
/** |
|
61
|
|
|
* Constructor |
|
62
|
|
|
* Recive cer content and convert to pem, get certificate fingerprint and |
|
63
|
|
|
* creates a encryption key and initialization vector |
|
64
|
|
|
* @param string $derdata certificate content in DER format (usual) |
|
65
|
|
|
* @param int $cipher encoded cipher |
|
66
|
|
|
*/ |
|
67
|
|
|
public function __construct($derdata, $cipher = self::AES_128_CBC) |
|
68
|
|
|
{ |
|
69
|
|
|
$this->cipher = $cipher; |
|
|
|
|
|
|
70
|
|
|
$this->certificate = $this->convertDERtoPEM($derdata); |
|
71
|
|
|
$this->fingerprint = $this->thumbprint($this->certificate); |
|
72
|
|
|
$this->keyGenerate(); |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
/** |
|
76
|
|
|
* Generate a key and initialization vector |
|
77
|
|
|
* and encrypt this key with a certificate |
|
78
|
|
|
* and combine with initialization vector in base64 format |
|
79
|
|
|
*/ |
|
80
|
|
|
public function keyGenerate() |
|
81
|
|
|
{ |
|
82
|
|
|
$length = openssl_cipher_iv_length($this->cipher); |
|
83
|
|
|
$this->key = openssl_random_pseudo_bytes($length); |
|
84
|
|
|
$this->iv = openssl_random_pseudo_bytes($length); |
|
85
|
|
|
$this->keyencrypted = $this->encryptkey($this->key, $this->iv); |
|
86
|
|
|
} |
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* Recover encryped key+iv in base64 |
|
90
|
|
|
* @return string |
|
91
|
|
|
*/ |
|
92
|
|
|
public function getEncrypedKey() |
|
93
|
|
|
{ |
|
94
|
|
|
return $this->keyencrypted; |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
/** |
|
98
|
|
|
* Recover Thumbprint (or fingerprint) from certificate |
|
99
|
|
|
* @return string |
|
100
|
|
|
*/ |
|
101
|
|
|
public function getThumbprint() |
|
102
|
|
|
{ |
|
103
|
|
|
return $this->fingerprint; |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* Return an array with KEY and IV used to encripy and decript |
|
108
|
|
|
* @return array |
|
109
|
|
|
*/ |
|
110
|
|
|
public function getKeyAndIV() |
|
111
|
|
|
{ |
|
112
|
|
|
return ['key' => $this->key, 'iv' => $this->iv]; |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
/** |
|
116
|
|
|
* Encrypt message whith generate randon key and iv |
|
117
|
|
|
* @param string $datamsg |
|
118
|
|
|
* @return string |
|
119
|
|
|
*/ |
|
120
|
|
|
public function encryptMsg($datamsg) |
|
121
|
|
|
{ |
|
122
|
|
|
return openssl_encrypt($datamsg, $this->cipher, $this->key, 0, $this->iv); |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
/** |
|
126
|
|
|
* Decript message with private key and randon key and iv |
|
127
|
|
|
* @param string $cryptedmsg encrytped message |
|
128
|
|
|
* @param string $privateKey in PEM format |
|
129
|
|
|
* @param string $keyencrypted key+iv im base64 format |
|
130
|
|
|
* @param string $cipher for encrypt and decrypt |
|
131
|
|
|
* @return string |
|
132
|
|
|
*/ |
|
133
|
|
|
public function decriptMsg($cryptedmsg, $privateKey, $keyencrypted, $cipher = self::AES_128_CBC) |
|
|
|
|
|
|
134
|
|
|
{ |
|
135
|
|
|
openssl_private_decrypt( |
|
136
|
|
|
base64_decode($keyencrypted), |
|
137
|
|
|
$decryptedkey, |
|
138
|
|
|
$privateKey, |
|
139
|
|
|
OPENSSL_PKCS1_PADDING |
|
140
|
|
|
); |
|
141
|
|
|
$key = substr($decryptedkey, 0, strlen($decryptedkey)-16); |
|
142
|
|
|
$iv = substr($decryptedkey, -16); |
|
143
|
|
|
return openssl_decrypt($cryptedmsg, $this->cipher, $key, 0, $iv); |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
/** |
|
147
|
|
|
* Recover certificate info |
|
148
|
|
|
* @return array |
|
149
|
|
|
*/ |
|
150
|
|
|
public function certificateInfo() |
|
151
|
|
|
{ |
|
152
|
|
|
$resource = openssl_x509_read($this->certificate); |
|
153
|
|
|
$detail = openssl_x509_parse($resource, false); |
|
154
|
|
|
$validFrom = \DateTime::createFromFormat('ymdHis\Z', $detail['validFrom']); |
|
155
|
|
|
$validTo = \DateTime::createFromFormat('ymdHis\Z', $detail['validTo']); |
|
156
|
|
|
return [ |
|
157
|
|
|
'validFrom' => $validFrom, |
|
158
|
|
|
'validTo' => $validTo, |
|
159
|
|
|
'details' => $detail |
|
160
|
|
|
]; |
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
|
|
/** |
|
164
|
|
|
* Extract fingerprint from certificate |
|
165
|
|
|
* @param string $certificate |
|
166
|
|
|
* @return string |
|
167
|
|
|
*/ |
|
168
|
|
|
protected function thumbprint($certificate) |
|
169
|
|
|
{ |
|
170
|
|
|
return openssl_x509_fingerprint($certificate, "sha1", false); |
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
/** |
|
174
|
|
|
* Encrypt key with certificate, add iv and converts to base64 |
|
175
|
|
|
* @param string $key |
|
176
|
|
|
* @param string $iv |
|
177
|
|
|
* @return string |
|
178
|
|
|
*/ |
|
179
|
|
|
protected function encryptkey($key, $iv) |
|
180
|
|
|
{ |
|
181
|
|
|
openssl_public_encrypt($key.$iv, $cryptedkey, $this->certificate, OPENSSL_PKCS1_PADDING); |
|
182
|
|
|
return base64_encode($cryptedkey); |
|
183
|
|
|
} |
|
184
|
|
|
|
|
185
|
|
|
/** |
|
186
|
|
|
* Converts certificate in DER format to PEM format |
|
187
|
|
|
* @param string $derdata |
|
188
|
|
|
* @return string |
|
189
|
|
|
*/ |
|
190
|
|
|
protected function convertDERtoPEM($derdata) |
|
191
|
|
|
{ |
|
192
|
|
|
$certificate = chunk_split(base64_encode($derdata), 64, "\n"); |
|
193
|
|
|
return "-----BEGIN CERTIFICATE-----\n" |
|
194
|
|
|
. $certificate |
|
195
|
|
|
."-----END CERTIFICATE-----\n"; |
|
196
|
|
|
} |
|
197
|
|
|
} |
|
198
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountIdthat can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theidproperty of an instance of theAccountclass. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.