1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Libsodium compatibility layer |
5
|
|
|
* |
6
|
|
|
* This is the only class you should be interfacing with, as a user of |
7
|
|
|
* sodium_compat. |
8
|
|
|
* |
9
|
|
|
* If the PHP extension for libsodium is installed, it will always use that |
10
|
|
|
* instead of our implementations. You get better performance and stronger |
11
|
|
|
* guarantees against side-channels that way. |
12
|
|
|
* |
13
|
|
|
* However, if your users don't have the PHP extension installed, we offer a |
14
|
|
|
* compatible interface here. It will give you the correct results as if the |
15
|
|
|
* PHP extension was installed. It won't be as fast, of course. |
16
|
|
|
* |
17
|
|
|
* CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * |
18
|
|
|
* * |
19
|
|
|
* Until audited, this is probably not safe to use! DANGER WILL ROBINSON * |
20
|
|
|
* * |
21
|
|
|
* CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
if (class_exists('ParagonIE_Sodium_Compat', false)) { |
25
|
|
|
return; |
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
class ParagonIE_Sodium_Compat |
29
|
|
|
{ |
30
|
|
|
/** |
31
|
|
|
* This parameter prevents the use of the PECL extension. |
32
|
|
|
* It should only be used for unit testing. |
33
|
|
|
* |
34
|
|
|
* @var bool |
35
|
|
|
*/ |
36
|
|
|
public static $disableFallbackForUnitTests = false; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Use fast multiplication rather than our constant-time multiplication |
40
|
|
|
* implementation. Can be enabled at runtime. Only enable this if you |
41
|
|
|
* are absolutely certain that there is no timing leak on your platform. |
42
|
|
|
* |
43
|
|
|
* @var bool |
44
|
|
|
*/ |
45
|
|
|
public static $fastMult = false; |
46
|
|
|
|
47
|
|
|
const LIBRARY_VERSION_MAJOR = 9; |
48
|
|
|
const LIBRARY_VERSION_MINOR = 1; |
49
|
|
|
const VERSION_STRING = 'polyfill-1.0.8'; |
50
|
|
|
|
51
|
|
|
// From libsodium |
52
|
|
|
const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32; |
53
|
|
|
const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0; |
54
|
|
|
const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8; |
55
|
|
|
const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16; |
56
|
|
|
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32; |
57
|
|
|
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0; |
58
|
|
|
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12; |
59
|
|
|
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16; |
60
|
|
|
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32; |
61
|
|
|
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0; |
62
|
|
|
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24; |
63
|
|
|
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16; |
64
|
|
|
const CRYPTO_AUTH_BYTES = 32; |
65
|
|
|
const CRYPTO_AUTH_KEYBYTES = 32; |
66
|
|
|
const CRYPTO_BOX_SEALBYTES = 16; |
67
|
|
|
const CRYPTO_BOX_SECRETKEYBYTES = 32; |
68
|
|
|
const CRYPTO_BOX_PUBLICKEYBYTES = 32; |
69
|
|
|
const CRYPTO_BOX_KEYPAIRBYTES = 64; |
70
|
|
|
const CRYPTO_BOX_MACBYTES = 16; |
71
|
|
|
const CRYPTO_BOX_NONCEBYTES = 24; |
72
|
|
|
const CRYPTO_BOX_SEEDBYTES = 32; |
73
|
|
|
const CRYPTO_KX_BYTES = 32; |
74
|
|
|
const CRYPTO_KX_PUBLICKEYBYTES = 32; |
75
|
|
|
const CRYPTO_KX_SECRETKEYBYTES = 32; |
76
|
|
|
const CRYPTO_GENERICHASH_BYTES = 32; |
77
|
|
|
const CRYPTO_GENERICHASH_BYTES_MIN = 16; |
78
|
|
|
const CRYPTO_GENERICHASH_BYTES_MAX = 64; |
79
|
|
|
const CRYPTO_GENERICHASH_KEYBYTES = 32; |
80
|
|
|
const CRYPTO_GENERICHASH_KEYBYTES_MIN = 16; |
81
|
|
|
const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64; |
82
|
|
|
const CRYPTO_PWHASH_SALTBYTES = 16; |
83
|
|
|
const CRYPTO_PWHASH_STRPREFIX = '$argon2i$'; |
84
|
|
|
const CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432; |
85
|
|
|
const CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4; |
86
|
|
|
const CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728; |
87
|
|
|
const CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6; |
88
|
|
|
const CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912; |
89
|
|
|
const CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8; |
90
|
|
|
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32; |
91
|
|
|
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$'; |
92
|
|
|
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288; |
93
|
|
|
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE = 16777216; |
94
|
|
|
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432; |
95
|
|
|
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE = 1073741824; |
96
|
|
|
const CRYPTO_SCALARMULT_BYTES = 32; |
97
|
|
|
const CRYPTO_SCALARMULT_SCALARBYTES = 32; |
98
|
|
|
const CRYPTO_SHORTHASH_BYTES = 8; |
99
|
|
|
const CRYPTO_SHORTHASH_KEYBYTES = 16; |
100
|
|
|
const CRYPTO_SECRETBOX_KEYBYTES = 32; |
101
|
|
|
const CRYPTO_SECRETBOX_MACBYTES = 16; |
102
|
|
|
const CRYPTO_SECRETBOX_NONCEBYTES = 24; |
103
|
|
|
const CRYPTO_SIGN_BYTES = 64; |
104
|
|
|
const CRYPTO_SIGN_SEEDBYTES = 32; |
105
|
|
|
const CRYPTO_SIGN_PUBLICKEYBYTES = 32; |
106
|
|
|
const CRYPTO_SIGN_SECRETKEYBYTES = 64; |
107
|
|
|
const CRYPTO_SIGN_KEYPAIRBYTES = 96; |
108
|
|
|
const CRYPTO_STREAM_KEYBYTES = 32; |
109
|
|
|
const CRYPTO_STREAM_NONCEBYTES = 24; |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Cache-timing-safe implementation of bin2hex(). |
113
|
|
|
* |
114
|
|
|
* @param string $string A string (probably raw binary) |
115
|
|
|
* @return string A hexadecimal-encoded string |
116
|
|
|
* @throws TypeError |
117
|
|
|
*/ |
118
|
|
View Code Duplication |
public static function bin2hex($string) |
|
|
|
|
119
|
|
|
{ |
120
|
|
|
/* Type checks: */ |
121
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1); |
122
|
|
|
|
123
|
|
|
if (self::isPhp72OrGreater()) { |
124
|
|
|
return bin2hex($string); |
125
|
|
|
} |
126
|
|
|
if (self::use_fallback('bin2hex')) { |
127
|
|
|
return call_user_func('\\Sodium\\bin2hex', $string); |
128
|
|
|
} |
129
|
|
|
return ParagonIE_Sodium_Core_Util::bin2hex($string); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Compare two strings, in constant-time. |
134
|
|
|
* Compared to memcmp(), compare() is more useful for sorting. |
135
|
|
|
* |
136
|
|
|
* @param string $left The left operand; must be a string |
137
|
|
|
* @param string $right The right operand; must be a string |
138
|
|
|
* @return int < 0 if the left operand is less than the right |
139
|
|
|
* 0 if both strings are equal |
140
|
|
|
* > 0 if the right operand is less than the left |
141
|
|
|
* @throws TypeError |
142
|
|
|
*/ |
143
|
|
View Code Duplication |
public static function compare($left, $right) |
|
|
|
|
144
|
|
|
{ |
145
|
|
|
/* Type checks: */ |
146
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1); |
147
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2); |
148
|
|
|
|
149
|
|
|
if (self::isPhp72OrGreater()) { |
150
|
|
|
return sodium_compare($left, $right); |
151
|
|
|
} |
152
|
|
|
if (self::use_fallback('compare')) { |
153
|
|
|
return call_user_func('\\Sodium\\compare', $left, $right); |
154
|
|
|
} |
155
|
|
|
return ParagonIE_Sodium_Core_Util::compare($left, $right); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Authenticated Encryption with Associated Data: Decryption |
160
|
|
|
* |
161
|
|
|
* Algorithm: |
162
|
|
|
* ChaCha20-Poly1305 |
163
|
|
|
* |
164
|
|
|
* This mode uses a 64-bit random nonce with a 64-bit counter. |
165
|
|
|
* IETF mode uses a 96-bit random nonce with a 32-bit counter. |
166
|
|
|
* |
167
|
|
|
* @param string $ciphertext Encrypted message (with Poly1305 MAC appended) |
168
|
|
|
* @param string $assocData Authenticated Associated Data (unencrypted) |
169
|
|
|
* @param string $nonce Number to be used only Once; must be 8 bytes |
170
|
|
|
* @param string $key Encryption key |
171
|
|
|
* |
172
|
|
|
* @return string The original plaintext message |
173
|
|
|
* @throws Error |
174
|
|
|
* @throws TypeError |
175
|
|
|
*/ |
176
|
|
View Code Duplication |
public static function crypto_aead_chacha20poly1305_decrypt( |
|
|
|
|
177
|
|
|
$ciphertext = '', |
178
|
|
|
$assocData = '', |
179
|
|
|
$nonce = '', |
180
|
|
|
$key = '' |
181
|
|
|
) { |
182
|
|
|
/* Type checks: */ |
183
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); |
184
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); |
185
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); |
186
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); |
187
|
|
|
|
188
|
|
|
/* Input validation: */ |
189
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { |
190
|
|
|
throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); |
191
|
|
|
} |
192
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { |
193
|
|
|
throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); |
194
|
|
|
} |
195
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { |
196
|
|
|
throw new Error('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
if (self::isPhp72OrGreater()) { |
200
|
|
|
return sodium_crypto_aead_chacha20poly1305_decrypt( |
201
|
|
|
$ciphertext, |
202
|
|
|
$assocData, |
203
|
|
|
$nonce, |
204
|
|
|
$key |
205
|
|
|
); |
206
|
|
|
} |
207
|
|
|
if (self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) { |
208
|
|
|
return call_user_func( |
209
|
|
|
'\\Sodium\\crypto_aead_chacha20poly1305_decrypt', |
210
|
|
|
$ciphertext, |
211
|
|
|
$assocData, |
212
|
|
|
$nonce, |
213
|
|
|
$key |
214
|
|
|
); |
215
|
|
|
} |
216
|
|
|
if (PHP_INT_SIZE === 4) { |
217
|
|
|
return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_decrypt( |
218
|
|
|
$ciphertext, |
219
|
|
|
$assocData, |
220
|
|
|
$nonce, |
221
|
|
|
$key |
222
|
|
|
); |
223
|
|
|
} |
224
|
|
|
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt( |
225
|
|
|
$ciphertext, |
226
|
|
|
$assocData, |
227
|
|
|
$nonce, |
228
|
|
|
$key |
229
|
|
|
); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Authenticated Encryption with Associated Data |
234
|
|
|
* |
235
|
|
|
* Algorithm: |
236
|
|
|
* ChaCha20-Poly1305 |
237
|
|
|
* |
238
|
|
|
* This mode uses a 64-bit random nonce with a 64-bit counter. |
239
|
|
|
* IETF mode uses a 96-bit random nonce with a 32-bit counter. |
240
|
|
|
* |
241
|
|
|
* @param string $plaintext Message to be encrypted |
242
|
|
|
* @param string $assocData Authenticated Associated Data (unencrypted) |
243
|
|
|
* @param string $nonce Number to be used only Once; must be 8 bytes |
244
|
|
|
* @param string $key Encryption key |
245
|
|
|
* |
246
|
|
|
* @return string Ciphertext with a 16-byte Poly1305 message |
247
|
|
|
* authentication code appended |
248
|
|
|
* @throws Error |
249
|
|
|
* @throws TypeError |
250
|
|
|
*/ |
251
|
|
View Code Duplication |
public static function crypto_aead_chacha20poly1305_encrypt( |
|
|
|
|
252
|
|
|
$plaintext = '', |
253
|
|
|
$assocData = '', |
254
|
|
|
$nonce = '', |
255
|
|
|
$key = '' |
256
|
|
|
) { |
257
|
|
|
/* Type checks: */ |
258
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); |
259
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); |
260
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); |
261
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); |
262
|
|
|
|
263
|
|
|
/* Input validation: */ |
264
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { |
265
|
|
|
throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); |
266
|
|
|
} |
267
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { |
268
|
|
|
throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
if (self::isPhp72OrGreater()) { |
272
|
|
|
return sodium_crypto_aead_chacha20poly1305_encrypt( |
273
|
|
|
$plaintext, |
274
|
|
|
$assocData, |
275
|
|
|
$nonce, |
276
|
|
|
$key |
277
|
|
|
); |
278
|
|
|
} |
279
|
|
|
if (self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) { |
280
|
|
|
return call_user_func( |
281
|
|
|
'\\Sodium\\crypto_aead_chacha20poly1305_encrypt', |
282
|
|
|
$plaintext, |
283
|
|
|
$assocData, |
284
|
|
|
$nonce, |
285
|
|
|
$key |
286
|
|
|
); |
287
|
|
|
} |
288
|
|
|
if (PHP_INT_SIZE === 4) { |
289
|
|
|
return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_encrypt( |
290
|
|
|
$plaintext, |
291
|
|
|
$assocData, |
292
|
|
|
$nonce, |
293
|
|
|
$key |
294
|
|
|
); |
295
|
|
|
} |
296
|
|
|
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt( |
297
|
|
|
$plaintext, |
298
|
|
|
$assocData, |
299
|
|
|
$nonce, |
300
|
|
|
$key |
301
|
|
|
); |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* Authenticated Encryption with Associated Data: Decryption |
306
|
|
|
* |
307
|
|
|
* Algorithm: |
308
|
|
|
* ChaCha20-Poly1305 |
309
|
|
|
* |
310
|
|
|
* IETF mode uses a 96-bit random nonce with a 32-bit counter. |
311
|
|
|
* Regular mode uses a 64-bit random nonce with a 64-bit counter. |
312
|
|
|
* |
313
|
|
|
* @param string $ciphertext Encrypted message (with Poly1305 MAC appended) |
314
|
|
|
* @param string $assocData Authenticated Associated Data (unencrypted) |
315
|
|
|
* @param string $nonce Number to be used only Once; must be 12 bytes |
316
|
|
|
* @param string $key Encryption key |
317
|
|
|
* |
318
|
|
|
* @return string The original plaintext message |
319
|
|
|
* @throws Error |
320
|
|
|
* @throws TypeError |
321
|
|
|
*/ |
322
|
|
View Code Duplication |
public static function crypto_aead_chacha20poly1305_ietf_decrypt( |
|
|
|
|
323
|
|
|
$ciphertext = '', |
324
|
|
|
$assocData = '', |
325
|
|
|
$nonce = '', |
326
|
|
|
$key = '' |
327
|
|
|
) { |
328
|
|
|
/* Type checks: */ |
329
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); |
330
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); |
331
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); |
332
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); |
333
|
|
|
|
334
|
|
|
/* Input validation: */ |
335
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { |
336
|
|
|
throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); |
337
|
|
|
} |
338
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { |
339
|
|
|
throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); |
340
|
|
|
} |
341
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { |
342
|
|
|
throw new Error('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
if (self::isPhp72OrGreater()) { |
346
|
|
|
return sodium_crypto_aead_chacha20poly1305_ietf_decrypt( |
347
|
|
|
$ciphertext, |
348
|
|
|
$assocData, |
349
|
|
|
$nonce, |
350
|
|
|
$key |
351
|
|
|
); |
352
|
|
|
} |
353
|
|
|
if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt')) { |
354
|
|
|
return call_user_func( |
355
|
|
|
'\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt', |
356
|
|
|
$ciphertext, |
357
|
|
|
$assocData, |
358
|
|
|
$nonce, |
359
|
|
|
$key |
360
|
|
|
); |
361
|
|
|
} |
362
|
|
|
if (PHP_INT_SIZE === 4) { |
363
|
|
|
return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_decrypt( |
364
|
|
|
$ciphertext, |
365
|
|
|
$assocData, |
366
|
|
|
$nonce, |
367
|
|
|
$key |
368
|
|
|
); |
369
|
|
|
} |
370
|
|
|
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt( |
371
|
|
|
$ciphertext, |
372
|
|
|
$assocData, |
373
|
|
|
$nonce, |
374
|
|
|
$key |
375
|
|
|
); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* Authenticated Encryption with Associated Data |
380
|
|
|
* |
381
|
|
|
* Algorithm: |
382
|
|
|
* ChaCha20-Poly1305 |
383
|
|
|
* |
384
|
|
|
* IETF mode uses a 96-bit random nonce with a 32-bit counter. |
385
|
|
|
* Regular mode uses a 64-bit random nonce with a 64-bit counter. |
386
|
|
|
* |
387
|
|
|
* @param string $plaintext Message to be encrypted |
388
|
|
|
* @param string $assocData Authenticated Associated Data (unencrypted) |
389
|
|
|
* @param string $nonce Number to be used only Once; must be 8 bytes |
390
|
|
|
* @param string $key Encryption key |
391
|
|
|
* |
392
|
|
|
* @return string Ciphertext with a 16-byte Poly1305 message |
393
|
|
|
* authentication code appended |
394
|
|
|
* @throws Error |
395
|
|
|
* @throws TypeError |
396
|
|
|
*/ |
397
|
|
View Code Duplication |
public static function crypto_aead_chacha20poly1305_ietf_encrypt( |
|
|
|
|
398
|
|
|
$plaintext = '', |
399
|
|
|
$assocData = '', |
400
|
|
|
$nonce = '', |
401
|
|
|
$key = '' |
402
|
|
|
) { |
403
|
|
|
/* Type checks: */ |
404
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); |
405
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); |
406
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); |
407
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); |
408
|
|
|
|
409
|
|
|
/* Input validation: */ |
410
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { |
411
|
|
|
throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); |
412
|
|
|
} |
413
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { |
414
|
|
|
throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
if (self::isPhp72OrGreater()) { |
418
|
|
|
return sodium_crypto_aead_chacha20poly1305_ietf_encrypt( |
419
|
|
|
$plaintext, |
420
|
|
|
$assocData, |
421
|
|
|
$nonce, |
422
|
|
|
$key |
423
|
|
|
); |
424
|
|
|
} |
425
|
|
|
if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt')) { |
426
|
|
|
return call_user_func( |
427
|
|
|
'\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt', |
428
|
|
|
$plaintext, |
429
|
|
|
$assocData, |
430
|
|
|
$nonce, |
431
|
|
|
$key |
432
|
|
|
); |
433
|
|
|
} |
434
|
|
|
if (PHP_INT_SIZE === 4) { |
435
|
|
|
return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_encrypt( |
436
|
|
|
$plaintext, |
437
|
|
|
$assocData, |
438
|
|
|
$nonce, |
439
|
|
|
$key |
440
|
|
|
); |
441
|
|
|
} |
442
|
|
|
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt( |
443
|
|
|
$plaintext, |
444
|
|
|
$assocData, |
445
|
|
|
$nonce, |
446
|
|
|
$key |
447
|
|
|
); |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
/** |
451
|
|
|
* Authenticated Encryption with Associated Data: Decryption |
452
|
|
|
* |
453
|
|
|
* Algorithm: |
454
|
|
|
* XChaCha20-Poly1305 |
455
|
|
|
* |
456
|
|
|
* This mode uses a 64-bit random nonce with a 64-bit counter. |
457
|
|
|
* IETF mode uses a 96-bit random nonce with a 32-bit counter. |
458
|
|
|
* |
459
|
|
|
* @param string $ciphertext Encrypted message (with Poly1305 MAC appended) |
460
|
|
|
* @param string $assocData Authenticated Associated Data (unencrypted) |
461
|
|
|
* @param string $nonce Number to be used only Once; must be 8 bytes |
462
|
|
|
* @param string $key Encryption key |
463
|
|
|
* |
464
|
|
|
* @return string The original plaintext message |
465
|
|
|
* @throws Error |
466
|
|
|
* @throws TypeError |
467
|
|
|
*/ |
468
|
|
|
public static function crypto_aead_xchacha20poly1305_ietf_decrypt( |
469
|
|
|
$ciphertext = '', |
470
|
|
|
$assocData = '', |
471
|
|
|
$nonce = '', |
472
|
|
|
$key = '' |
473
|
|
|
) { |
474
|
|
|
/* Type checks: */ |
475
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); |
476
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); |
477
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); |
478
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); |
479
|
|
|
|
480
|
|
|
/* Input validation: */ |
481
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { |
482
|
|
|
throw new Error('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long'); |
483
|
|
|
} |
484
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { |
485
|
|
|
throw new Error('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long'); |
486
|
|
|
} |
487
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) { |
488
|
|
|
throw new Error('Message must be at least CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long'); |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
if (PHP_INT_SIZE === 4) { |
492
|
|
|
return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_decrypt( |
493
|
|
|
$ciphertext, |
494
|
|
|
$assocData, |
495
|
|
|
$nonce, |
496
|
|
|
$key |
497
|
|
|
); |
498
|
|
|
} |
499
|
|
|
return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt( |
500
|
|
|
$ciphertext, |
501
|
|
|
$assocData, |
502
|
|
|
$nonce, |
503
|
|
|
$key |
504
|
|
|
); |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
/** |
508
|
|
|
* Authenticated Encryption with Associated Data |
509
|
|
|
* |
510
|
|
|
* Algorithm: |
511
|
|
|
* XChaCha20-Poly1305 |
512
|
|
|
* |
513
|
|
|
* This mode uses a 64-bit random nonce with a 64-bit counter. |
514
|
|
|
* IETF mode uses a 96-bit random nonce with a 32-bit counter. |
515
|
|
|
* |
516
|
|
|
* @param string $plaintext Message to be encrypted |
517
|
|
|
* @param string $assocData Authenticated Associated Data (unencrypted) |
518
|
|
|
* @param string $nonce Number to be used only Once; must be 8 bytes |
519
|
|
|
* @param string $key Encryption key |
520
|
|
|
* |
521
|
|
|
* @return string Ciphertext with a 16-byte Poly1305 message |
522
|
|
|
* authentication code appended |
523
|
|
|
* @throws Error |
524
|
|
|
* @throws TypeError |
525
|
|
|
*/ |
526
|
|
|
public static function crypto_aead_xchacha20poly1305_ietf_encrypt( |
527
|
|
|
$plaintext = '', |
528
|
|
|
$assocData = '', |
529
|
|
|
$nonce = '', |
530
|
|
|
$key = '' |
531
|
|
|
) { |
532
|
|
|
/* Type checks: */ |
533
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); |
534
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); |
535
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); |
536
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); |
537
|
|
|
|
538
|
|
|
/* Input validation: */ |
539
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { |
540
|
|
|
throw new Error('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long'); |
541
|
|
|
} |
542
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { |
543
|
|
|
throw new Error('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long'); |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
if (PHP_INT_SIZE === 4) { |
547
|
|
|
return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_encrypt( |
548
|
|
|
$plaintext, |
549
|
|
|
$assocData, |
550
|
|
|
$nonce, |
551
|
|
|
$key |
552
|
|
|
); |
553
|
|
|
} |
554
|
|
|
return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt( |
555
|
|
|
$plaintext, |
556
|
|
|
$assocData, |
557
|
|
|
$nonce, |
558
|
|
|
$key |
559
|
|
|
); |
560
|
|
|
} |
561
|
|
|
|
562
|
|
|
/** |
563
|
|
|
* Authenticate a message. Uses symmetric-key cryptography. |
564
|
|
|
* |
565
|
|
|
* Algorithm: |
566
|
|
|
* HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits. |
567
|
|
|
* Not to be confused with HMAC-SHA-512/256 which would use the |
568
|
|
|
* SHA-512/256 hash function (uses different initial parameters |
569
|
|
|
* but still truncates to 256 bits to sidestep length-extension |
570
|
|
|
* attacks). |
571
|
|
|
* |
572
|
|
|
* @param string $message Message to be authenticated |
573
|
|
|
* @param string $key Symmetric authentication key |
574
|
|
|
* @return string Message authentication code |
575
|
|
|
* @throws Error |
576
|
|
|
* @throws TypeError |
577
|
|
|
*/ |
578
|
|
View Code Duplication |
public static function crypto_auth($message, $key) |
|
|
|
|
579
|
|
|
{ |
580
|
|
|
/* Type checks: */ |
581
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); |
582
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); |
583
|
|
|
|
584
|
|
|
/* Input validation: */ |
585
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { |
586
|
|
|
throw new Error('Argument 2 must be CRYPTO_AUTH_KEYBYTES long.'); |
587
|
|
|
} |
588
|
|
|
|
589
|
|
|
if (self::isPhp72OrGreater()) { |
590
|
|
|
return sodium_crypto_auth($message, $key); |
591
|
|
|
} |
592
|
|
|
if (self::use_fallback('crypto_auth')) { |
593
|
|
|
return call_user_func('\\Sodium\\crypto_auth', $message, $key); |
594
|
|
|
} |
595
|
|
|
if (PHP_INT_SIZE === 4) { |
596
|
|
|
return ParagonIE_Sodium_Crypto32::auth($message, $key); |
597
|
|
|
} |
598
|
|
|
return ParagonIE_Sodium_Crypto::auth($message, $key); |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
/** |
602
|
|
|
* Verify the MAC of a message previously authenticated with crypto_auth. |
603
|
|
|
* |
604
|
|
|
* @param string $mac Message authentication code |
605
|
|
|
* @param string $message Message whose authenticity you are attempting to |
606
|
|
|
* verify (with a given MAC and key) |
607
|
|
|
* @param string $key Symmetric authentication key |
608
|
|
|
* @return bool TRUE if authenticated, FALSE otherwise |
609
|
|
|
* @throws Error |
610
|
|
|
* @throws TypeError |
611
|
|
|
*/ |
612
|
|
View Code Duplication |
public static function crypto_auth_verify($mac, $message, $key) |
|
|
|
|
613
|
|
|
{ |
614
|
|
|
/* Type checks: */ |
615
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($mac, 'string', 1); |
616
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); |
617
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); |
618
|
|
|
|
619
|
|
|
/* Input validation: */ |
620
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($mac) !== self::CRYPTO_AUTH_BYTES) { |
621
|
|
|
throw new Error('Argument 1 must be CRYPTO_AUTH_BYTES long.'); |
622
|
|
|
} |
623
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { |
624
|
|
|
throw new Error('Argument 3 must be CRYPTO_AUTH_KEYBYTES long.'); |
625
|
|
|
} |
626
|
|
|
|
627
|
|
|
if (self::isPhp72OrGreater()) { |
628
|
|
|
return sodium_crypto_auth_verify($mac, $message, $key); |
629
|
|
|
} |
630
|
|
|
if (self::use_fallback('crypto_auth_verify')) { |
631
|
|
|
return call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message, $key); |
632
|
|
|
} |
633
|
|
|
if (PHP_INT_SIZE === 4) { |
634
|
|
|
return ParagonIE_Sodium_Crypto32::auth_verify($mac, $message, $key); |
635
|
|
|
} |
636
|
|
|
return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key); |
637
|
|
|
} |
638
|
|
|
|
639
|
|
|
/** |
640
|
|
|
* Authenticated asymmetric-key encryption. Both the sender and recipient |
641
|
|
|
* may decrypt messages. |
642
|
|
|
* |
643
|
|
|
* Algorithm: X25519-XSalsa20-Poly1305. |
644
|
|
|
* X25519: Elliptic-Curve Diffie Hellman over Curve25519. |
645
|
|
|
* XSalsa20: Extended-nonce variant of salsa20. |
646
|
|
|
* Poyl1305: Polynomial MAC for one-time message authentication. |
647
|
|
|
* |
648
|
|
|
* @param string $plaintext The message to be encrypted |
649
|
|
|
* @param string $nonce A Number to only be used Once; must be 24 bytes |
650
|
|
|
* @param string $keypair Your secret key and your recipient's public key |
651
|
|
|
* @return string Ciphertext with 16-byte Poly1305 MAC |
652
|
|
|
* @throws Error |
653
|
|
|
* @throws TypeError |
654
|
|
|
*/ |
655
|
|
View Code Duplication |
public static function crypto_box($plaintext, $nonce, $keypair) |
|
|
|
|
656
|
|
|
{ |
657
|
|
|
/* Type checks: */ |
658
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); |
659
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); |
660
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3); |
661
|
|
|
|
662
|
|
|
/* Input validation: */ |
663
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { |
664
|
|
|
throw new Error('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); |
665
|
|
|
} |
666
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { |
667
|
|
|
throw new Error('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); |
668
|
|
|
} |
669
|
|
|
|
670
|
|
|
if (self::isPhp72OrGreater()) { |
671
|
|
|
return sodium_crypto_box($plaintext, $nonce, $keypair); |
672
|
|
|
} |
673
|
|
|
if (self::use_fallback('crypto_box')) { |
674
|
|
|
return call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce, $keypair); |
675
|
|
|
} |
676
|
|
|
if (PHP_INT_SIZE === 4) { |
677
|
|
|
return ParagonIE_Sodium_Crypto32::box($plaintext, $nonce, $keypair); |
678
|
|
|
} |
679
|
|
|
return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair); |
680
|
|
|
} |
681
|
|
|
|
682
|
|
|
/** |
683
|
|
|
* Anonymous public-key encryption. Only the recipient may decrypt messages. |
684
|
|
|
* |
685
|
|
|
* Algorithm: X25519-XSalsa20-Poly1305, as with crypto_box. |
686
|
|
|
* The sender's X25519 keypair is ephemeral. |
687
|
|
|
* Nonce is generated from the BLAKE2b hash of both public keys. |
688
|
|
|
* |
689
|
|
|
* This provides ciphertext integrity. |
690
|
|
|
* |
691
|
|
|
* @param string $plaintext Message to be sealed |
692
|
|
|
* @param string $publicKey Your recipient's public key |
693
|
|
|
* @return string Sealed message that only your recipient can |
694
|
|
|
* decrypt |
695
|
|
|
* @throws Error |
696
|
|
|
* @throws TypeError |
697
|
|
|
*/ |
698
|
|
View Code Duplication |
public static function crypto_box_seal($plaintext, $publicKey) |
|
|
|
|
699
|
|
|
{ |
700
|
|
|
/* Type checks: */ |
701
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); |
702
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); |
703
|
|
|
|
704
|
|
|
/* Input validation: */ |
705
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { |
706
|
|
|
throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); |
707
|
|
|
} |
708
|
|
|
|
709
|
|
|
if (self::isPhp72OrGreater()) { |
710
|
|
|
return sodium_crypto_box_seal($plaintext, $publicKey); |
711
|
|
|
} |
712
|
|
|
if (self::use_fallback('crypto_box_seal')) { |
713
|
|
|
return call_user_func('\\Sodium\\crypto_box_seal', $plaintext, $publicKey); |
714
|
|
|
} |
715
|
|
|
if (PHP_INT_SIZE === 4) { |
716
|
|
|
return ParagonIE_Sodium_Crypto32::box_seal($plaintext, $publicKey); |
717
|
|
|
} |
718
|
|
|
return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey); |
719
|
|
|
} |
720
|
|
|
|
721
|
|
|
/** |
722
|
|
|
* Opens a message encrypted with crypto_box_seal(). Requires |
723
|
|
|
* the recipient's keypair (sk || pk) to decrypt successfully. |
724
|
|
|
* |
725
|
|
|
* This validates ciphertext integrity. |
726
|
|
|
* |
727
|
|
|
* @param string $ciphertext Sealed message to be opened |
728
|
|
|
* @param string $keypair Your crypto_box keypair |
729
|
|
|
* @return string The original plaintext message |
730
|
|
|
* @throws Error |
731
|
|
|
* @throws TypeError |
732
|
|
|
*/ |
733
|
|
View Code Duplication |
public static function crypto_box_seal_open($ciphertext, $keypair) |
|
|
|
|
734
|
|
|
{ |
735
|
|
|
/* Type checks: */ |
736
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); |
737
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 2); |
738
|
|
|
|
739
|
|
|
/* Input validation: */ |
740
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { |
741
|
|
|
throw new Error('Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.'); |
742
|
|
|
} |
743
|
|
|
|
744
|
|
|
if (self::isPhp72OrGreater()) { |
745
|
|
|
return sodium_crypto_box_seal_open($ciphertext, $keypair); |
746
|
|
|
} |
747
|
|
|
if (self::use_fallback('crypto_box_seal_open')) { |
748
|
|
|
return call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext, $keypair); |
749
|
|
|
} |
750
|
|
|
if (PHP_INT_SIZE === 4) { |
751
|
|
|
return ParagonIE_Sodium_Crypto32::box_seal_open($ciphertext, $keypair); |
752
|
|
|
} |
753
|
|
|
return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext, $keypair); |
754
|
|
|
} |
755
|
|
|
|
756
|
|
|
/** |
757
|
|
|
* Generate a new random X25519 keypair. |
758
|
|
|
* |
759
|
|
|
* @return string A 64-byte string; the first 32 are your secret key, while |
760
|
|
|
* the last 32 are your public key. crypto_box_secretkey() |
761
|
|
|
* and crypto_box_publickey() exist to separate them so you |
762
|
|
|
* don't accidentally get them mixed up! |
763
|
|
|
*/ |
764
|
|
|
public static function crypto_box_keypair() |
765
|
|
|
{ |
766
|
|
|
if (self::isPhp72OrGreater()) { |
767
|
|
|
return sodium_crypto_box_keypair(); |
768
|
|
|
} |
769
|
|
|
if (self::use_fallback('crypto_box_keypair')) { |
770
|
|
|
return call_user_func('\\Sodium\\crypto_box_keypair'); |
771
|
|
|
} |
772
|
|
|
return ParagonIE_Sodium_Crypto::box_keypair(); |
773
|
|
|
} |
774
|
|
|
|
775
|
|
|
/** |
776
|
|
|
* Combine two keys into a keypair for use in library methods that expect |
777
|
|
|
* a keypair. This doesn't necessarily have to be the same person's keys. |
778
|
|
|
* |
779
|
|
|
* @param string $secretKey Secret key |
780
|
|
|
* @param string $publicKey Public key |
781
|
|
|
* @return string Keypair |
782
|
|
|
* @throws Error |
783
|
|
|
* @throws TypeError |
784
|
|
|
*/ |
785
|
|
View Code Duplication |
public static function crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey) |
|
|
|
|
786
|
|
|
{ |
787
|
|
|
/* Type checks: */ |
788
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); |
789
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); |
790
|
|
|
|
791
|
|
|
/* Input validation: */ |
792
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { |
793
|
|
|
throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); |
794
|
|
|
} |
795
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { |
796
|
|
|
throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); |
797
|
|
|
} |
798
|
|
|
|
799
|
|
|
if (self::isPhp72OrGreater()) { |
800
|
|
|
return sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); |
801
|
|
|
} |
802
|
|
|
if (self::use_fallback('crypto_box_keypair_from_secretkey_and_publickey')) { |
803
|
|
|
return call_user_func('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey', $secretKey, $publicKey); |
804
|
|
|
} |
805
|
|
|
if (PHP_INT_SIZE === 4) { |
806
|
|
|
return ParagonIE_Sodium_Crypto32::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); |
807
|
|
|
} |
808
|
|
|
return ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); |
809
|
|
|
} |
810
|
|
|
|
811
|
|
|
/** |
812
|
|
|
* Decrypt a message previously encrypted with crypto_box(). |
813
|
|
|
* |
814
|
|
|
* @param string $ciphertext Encrypted message |
815
|
|
|
* @param string $nonce Number to only be used Once; must be 24 bytes |
816
|
|
|
* @param string $keypair Your secret key and the sender's public key |
817
|
|
|
* @return string The original plaintext message |
818
|
|
|
* @throws Error |
819
|
|
|
* @throws TypeError |
820
|
|
|
*/ |
821
|
|
|
public static function crypto_box_open($ciphertext, $nonce, $keypair) |
822
|
|
|
{ |
823
|
|
|
/* Type checks: */ |
824
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); |
825
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); |
826
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3); |
827
|
|
|
|
828
|
|
|
/* Input validation: */ |
829
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_BOX_MACBYTES) { |
830
|
|
|
throw new Error('Argument 1 must be at least CRYPTO_BOX_MACBYTES long.'); |
831
|
|
|
} |
832
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { |
833
|
|
|
throw new Error('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); |
834
|
|
|
} |
835
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { |
836
|
|
|
throw new Error('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); |
837
|
|
|
} |
838
|
|
|
|
839
|
|
|
if (self::isPhp72OrGreater()) { |
840
|
|
|
return sodium_crypto_box_open($ciphertext, $nonce, $keypair); |
841
|
|
|
} |
842
|
|
|
if (self::use_fallback('crypto_box_open')) { |
843
|
|
|
return call_user_func('\\Sodium\\crypto_box_open', $ciphertext, $nonce, $keypair); |
844
|
|
|
} |
845
|
|
|
if (PHP_INT_SIZE === 4) { |
846
|
|
|
return ParagonIE_Sodium_Crypto32::box_open($ciphertext, $nonce, $keypair); |
847
|
|
|
} |
848
|
|
|
return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce, $keypair); |
849
|
|
|
} |
850
|
|
|
|
851
|
|
|
/** |
852
|
|
|
* Extract the public key from a crypto_box keypair. |
853
|
|
|
* |
854
|
|
|
* @param string $keypair |
855
|
|
|
* @return string Your crypto_box public key |
856
|
|
|
* @throws Error |
857
|
|
|
* @throws TypeError |
858
|
|
|
*/ |
859
|
|
View Code Duplication |
public static function crypto_box_publickey($keypair) |
|
|
|
|
860
|
|
|
{ |
861
|
|
|
/* Type checks: */ |
862
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); |
863
|
|
|
|
864
|
|
|
/* Input validation: */ |
865
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { |
866
|
|
|
throw new Error('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); |
867
|
|
|
} |
868
|
|
|
|
869
|
|
|
if (self::isPhp72OrGreater()) { |
870
|
|
|
return sodium_crypto_box_publickey($keypair); |
871
|
|
|
} |
872
|
|
|
if (self::use_fallback('crypto_box_publickey')) { |
873
|
|
|
return call_user_func('\\Sodium\\crypto_box_publickey', $keypair); |
874
|
|
|
} |
875
|
|
|
if (PHP_INT_SIZE === 4) { |
876
|
|
|
return ParagonIE_Sodium_Crypto32::box_publickey($keypair); |
877
|
|
|
} |
878
|
|
|
return ParagonIE_Sodium_Crypto::box_publickey($keypair); |
879
|
|
|
} |
880
|
|
|
|
881
|
|
|
/** |
882
|
|
|
* Calculate the X25519 public key from a given X25519 secret key. |
883
|
|
|
* |
884
|
|
|
* @param string $secretKey Any X25519 secret key |
885
|
|
|
* @return string The corresponding X25519 public key |
886
|
|
|
* @throws Error |
887
|
|
|
* @throws TypeError |
888
|
|
|
*/ |
889
|
|
View Code Duplication |
public static function crypto_box_publickey_from_secretkey($secretKey) |
|
|
|
|
890
|
|
|
{ |
891
|
|
|
/* Type checks: */ |
892
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); |
893
|
|
|
|
894
|
|
|
/* Input validation: */ |
895
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { |
896
|
|
|
throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); |
897
|
|
|
} |
898
|
|
|
|
899
|
|
|
if (self::isPhp72OrGreater()) { |
900
|
|
|
return sodium_crypto_box_publickey_from_secretkey($secretKey); |
901
|
|
|
} |
902
|
|
|
if (self::use_fallback('crypto_box_publickey_from_secretkey')) { |
903
|
|
|
return call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey', $secretKey); |
904
|
|
|
} |
905
|
|
|
if (PHP_INT_SIZE === 4) { |
906
|
|
|
return ParagonIE_Sodium_Crypto32::box_publickey_from_secretkey($secretKey); |
907
|
|
|
} |
908
|
|
|
return ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey); |
909
|
|
|
} |
910
|
|
|
|
911
|
|
|
/** |
912
|
|
|
* Extract the secret key from a crypto_box keypair. |
913
|
|
|
* |
914
|
|
|
* @param string $keypair |
915
|
|
|
* @return string Your crypto_box secret key |
916
|
|
|
* @throws Error |
917
|
|
|
* @throws TypeError |
918
|
|
|
*/ |
919
|
|
View Code Duplication |
public static function crypto_box_secretkey($keypair) |
|
|
|
|
920
|
|
|
{ |
921
|
|
|
/* Type checks: */ |
922
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); |
923
|
|
|
|
924
|
|
|
/* Input validation: */ |
925
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { |
926
|
|
|
throw new Error('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); |
927
|
|
|
} |
928
|
|
|
|
929
|
|
|
if (self::isPhp72OrGreater()) { |
930
|
|
|
return sodium_crypto_box_secretkey($keypair); |
931
|
|
|
} |
932
|
|
|
if (self::use_fallback('crypto_box_secretkey')) { |
933
|
|
|
return call_user_func('\\Sodium\\crypto_box_secretkey', $keypair); |
934
|
|
|
} |
935
|
|
|
if (PHP_INT_SIZE === 4) { |
936
|
|
|
return ParagonIE_Sodium_Crypto32::box_secretkey($keypair); |
937
|
|
|
} |
938
|
|
|
return ParagonIE_Sodium_Crypto::box_secretkey($keypair); |
939
|
|
|
} |
940
|
|
|
|
941
|
|
|
/** |
942
|
|
|
* Generate an X25519 keypair from a seed. |
943
|
|
|
* |
944
|
|
|
* @param string $seed |
945
|
|
|
* @return string |
946
|
|
|
*/ |
947
|
|
View Code Duplication |
public static function crypto_box_seed_keypair($seed) |
|
|
|
|
948
|
|
|
{ |
949
|
|
|
/* Type checks: */ |
950
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1); |
951
|
|
|
|
952
|
|
|
if (self::isPhp72OrGreater()) { |
953
|
|
|
return sodium_crypto_box_seed_keypair($seed); |
954
|
|
|
} |
955
|
|
|
if (self::use_fallback('crypto_box_seed_keypair')) { |
956
|
|
|
return call_user_func('\\Sodium\\crypto_box_seed_keypair', $seed); |
957
|
|
|
} |
958
|
|
|
return ParagonIE_Sodium_Crypto::box_seed_keypair($seed); |
959
|
|
|
} |
960
|
|
|
|
961
|
|
|
/** |
962
|
|
|
* Calculates a BLAKE2b hash, with an optional key. |
963
|
|
|
* |
964
|
|
|
* @param string $message The message to be hashed |
965
|
|
|
* @param string $key If specified, must be a string between 16 and 64 |
966
|
|
|
* bytes long |
967
|
|
|
* @param int $length Output length in bytes; must be between 16 and 64 |
968
|
|
|
* (default = 32) |
969
|
|
|
* @return string Raw binary |
970
|
|
|
* @throws Error |
971
|
|
|
* @throws TypeError |
972
|
|
|
*/ |
973
|
|
|
public static function crypto_generichash($message, $key = '', $length = self::CRYPTO_GENERICHASH_BYTES) |
974
|
|
|
{ |
975
|
|
|
/* Type checks: */ |
976
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); |
977
|
|
|
if (is_null($key)) { |
978
|
|
|
$key = ''; |
979
|
|
|
} |
980
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); |
981
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 3); |
982
|
|
|
|
983
|
|
|
/* Input validation: */ |
984
|
|
View Code Duplication |
if (!empty($key)) { |
|
|
|
|
985
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { |
986
|
|
|
throw new Error('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); |
987
|
|
|
} |
988
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { |
989
|
|
|
throw new Error('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); |
990
|
|
|
} |
991
|
|
|
} |
992
|
|
|
|
993
|
|
|
if (self::isPhp72OrGreater()) { |
994
|
|
|
return sodium_crypto_generichash($message, $key, $length); |
995
|
|
|
} |
996
|
|
|
if (self::use_fallback('crypto_generichash')) { |
997
|
|
|
return call_user_func('\\Sodium\\crypto_generichash', $message, $key, $length); |
998
|
|
|
} |
999
|
|
|
if (PHP_INT_SIZE === 4) { |
1000
|
|
|
return ParagonIE_Sodium_Crypto32::generichash($message, $key, $length); |
1001
|
|
|
} |
1002
|
|
|
return ParagonIE_Sodium_Crypto::generichash($message, $key, $length); |
1003
|
|
|
} |
1004
|
|
|
|
1005
|
|
|
/** |
1006
|
|
|
* Get the final BLAKE2b hash output for a given context. |
1007
|
|
|
* |
1008
|
|
|
* @param string &$ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). |
1009
|
|
|
* @param int $length Hash output size. |
1010
|
|
|
* @return string Final BLAKE2b hash. |
1011
|
|
|
* @throws Error |
1012
|
|
|
* @throws TypeError |
1013
|
|
|
*/ |
1014
|
|
|
public static function crypto_generichash_final(&$ctx, $length = self::CRYPTO_GENERICHASH_BYTES) |
1015
|
|
|
{ |
1016
|
|
|
/* Type checks: */ |
1017
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1); |
1018
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2); |
1019
|
|
|
|
1020
|
|
|
if (self::isPhp72OrGreater()) { |
1021
|
|
|
return sodium_crypto_generichash_final($ctx, $length); |
1022
|
|
|
} |
1023
|
|
|
if (self::use_fallback('crypto_generichash_final')) { |
1024
|
|
|
$func = '\\Sodium\\crypto_generichash_final'; |
1025
|
|
|
return $func($ctx, $length); |
1026
|
|
|
} |
1027
|
|
|
if (PHP_INT_SIZE === 4) { |
1028
|
|
|
$result = ParagonIE_Sodium_Crypto32::generichash_final($ctx, $length); |
1029
|
|
|
} else { |
1030
|
|
|
$result = ParagonIE_Sodium_Crypto::generichash_final($ctx, $length); |
1031
|
|
|
} |
1032
|
|
|
try { |
1033
|
|
|
self::memzero($ctx); |
1034
|
|
|
} catch (Error $ex) { |
|
|
|
|
1035
|
|
|
unset($ctx); |
1036
|
|
|
} |
1037
|
|
|
return $result; |
1038
|
|
|
} |
1039
|
|
|
|
1040
|
|
|
/** |
1041
|
|
|
* Initialize a BLAKE2b hashing context, for use in a streaming interface. |
1042
|
|
|
* |
1043
|
|
|
* @param string $key If specified must be a string between 16 and 64 bytes |
1044
|
|
|
* @param int $length The size of the desired hash output |
1045
|
|
|
* @return string A BLAKE2 hashing context, encoded as a string |
1046
|
|
|
* (To be 100% compatible with ext/libsodium) |
1047
|
|
|
* @throws Error |
1048
|
|
|
* @throws TypeError |
1049
|
|
|
*/ |
1050
|
|
|
public static function crypto_generichash_init($key = '', $length = self::CRYPTO_GENERICHASH_BYTES) |
1051
|
|
|
{ |
1052
|
|
|
/* Type checks: */ |
1053
|
|
|
if (is_null($key)) { |
1054
|
|
|
$key = ''; |
1055
|
|
|
} |
1056
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1); |
1057
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2); |
1058
|
|
|
|
1059
|
|
|
/* Input validation: */ |
1060
|
|
View Code Duplication |
if (!empty($key)) { |
|
|
|
|
1061
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { |
1062
|
|
|
throw new Error('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); |
1063
|
|
|
} |
1064
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { |
1065
|
|
|
throw new Error('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); |
1066
|
|
|
} |
1067
|
|
|
} |
1068
|
|
|
|
1069
|
|
|
if (self::isPhp72OrGreater()) { |
1070
|
|
|
return sodium_crypto_generichash_init($key, $length); |
1071
|
|
|
} |
1072
|
|
|
if (self::use_fallback('crypto_generichash_init')) { |
1073
|
|
|
return call_user_func('\\Sodium\\crypto_generichash_init', $key, $length); |
1074
|
|
|
} |
1075
|
|
|
if (PHP_INT_SIZE === 4) { |
1076
|
|
|
return ParagonIE_Sodium_Crypto32::generichash_init($key, $length); |
1077
|
|
|
} |
1078
|
|
|
return ParagonIE_Sodium_Crypto::generichash_init($key, $length); |
1079
|
|
|
} |
1080
|
|
|
|
1081
|
|
|
/** |
1082
|
|
|
* Update a BLAKE2b hashing context with additional data. |
1083
|
|
|
* |
1084
|
|
|
* @param string &$ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). |
1085
|
|
|
* $ctx is passed by reference and gets updated in-place. |
1086
|
|
|
* @param string $message The message to append to the existing hash state. |
1087
|
|
|
* @return void |
1088
|
|
|
* @throws TypeError |
1089
|
|
|
*/ |
1090
|
|
View Code Duplication |
public static function crypto_generichash_update(&$ctx, $message) |
|
|
|
|
1091
|
|
|
{ |
1092
|
|
|
/* Type checks: */ |
1093
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1); |
1094
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); |
1095
|
|
|
|
1096
|
|
|
if (self::isPhp72OrGreater()) { |
1097
|
|
|
sodium_crypto_generichash_update($ctx, $message); |
1098
|
|
|
return; |
1099
|
|
|
} |
1100
|
|
|
if (self::use_fallback('crypto_generichash_update')) { |
1101
|
|
|
$func = '\\Sodium\\crypto_generichash_update'; |
1102
|
|
|
$func($ctx, $message); |
1103
|
|
|
return; |
1104
|
|
|
} |
1105
|
|
|
if (PHP_INT_SIZE === 4) { |
1106
|
|
|
$ctx = ParagonIE_Sodium_Crypto32::generichash_update($ctx, $message); |
1107
|
|
|
} else { |
1108
|
|
|
$ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx, $message); |
1109
|
|
|
} |
1110
|
|
|
} |
1111
|
|
|
|
1112
|
|
|
/** |
1113
|
|
|
* Perform a key exchange, between a designated client and a server. |
1114
|
|
|
* |
1115
|
|
|
* Typically, you would designate one machine to be the client and the |
1116
|
|
|
* other to be the server. The first two keys are what you'd expect for |
1117
|
|
|
* scalarmult() below, but the latter two public keys don't swap places. |
1118
|
|
|
* |
1119
|
|
|
* | ALICE | BOB | |
1120
|
|
|
* | Client | Server | |
1121
|
|
|
* |--------------------------------|-------------------------------------| |
1122
|
|
|
* | shared = crypto_kx( | shared = crypto_kx( | |
1123
|
|
|
* | alice_sk, | bob_sk, | <- contextual |
1124
|
|
|
* | bob_pk, | alice_pk, | <- contextual |
1125
|
|
|
* | alice_pk, | alice_pk, | <----- static |
1126
|
|
|
* | bob_pk | bob_pk | <----- static |
1127
|
|
|
* | ) | ) | |
1128
|
|
|
* |
1129
|
|
|
* They are used along with the scalarmult product to generate a 256-bit |
1130
|
|
|
* BLAKE2b hash unique to the client and server keys. |
1131
|
|
|
* |
1132
|
|
|
* @param string $my_secret |
1133
|
|
|
* @param string $their_public |
1134
|
|
|
* @param string $client_public |
1135
|
|
|
* @param string $server_public |
1136
|
|
|
* @return string |
1137
|
|
|
* @throws Error |
1138
|
|
|
* @throws TypeError |
1139
|
|
|
*/ |
1140
|
|
|
public static function crypto_kx($my_secret, $their_public, $client_public, $server_public) |
1141
|
|
|
{ |
1142
|
|
|
/* Type checks: */ |
1143
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($my_secret, 'string', 1); |
1144
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($their_public, 'string', 2); |
1145
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($client_public, 'string', 3); |
1146
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($server_public, 'string', 4); |
1147
|
|
|
|
1148
|
|
|
/* Input validation: */ |
1149
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !== self::CRYPTO_BOX_SECRETKEYBYTES) { |
1150
|
|
|
throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); |
1151
|
|
|
} |
1152
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($their_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { |
1153
|
|
|
throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); |
1154
|
|
|
} |
1155
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($client_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { |
1156
|
|
|
throw new Error('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); |
1157
|
|
|
} |
1158
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($server_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { |
1159
|
|
|
throw new Error('Argument 4 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); |
1160
|
|
|
} |
1161
|
|
|
|
1162
|
|
|
if (self::isPhp72OrGreater()) { |
1163
|
|
|
if (is_callable('sodium_crypto_kx')) { |
1164
|
|
|
return sodium_crypto_kx( |
1165
|
|
|
$my_secret, |
1166
|
|
|
$their_public, |
1167
|
|
|
$client_public, |
1168
|
|
|
$server_public |
1169
|
|
|
); |
1170
|
|
|
} |
1171
|
|
|
} |
1172
|
|
|
if (self::use_fallback('crypto_kx')) { |
1173
|
|
|
return call_user_func( |
1174
|
|
|
'\\Sodium\\crypto_kx', |
1175
|
|
|
$my_secret, |
1176
|
|
|
$their_public, |
1177
|
|
|
$client_public, |
1178
|
|
|
$server_public |
1179
|
|
|
); |
1180
|
|
|
} |
1181
|
|
|
if (PHP_INT_SIZE === 4) { |
1182
|
|
|
return ParagonIE_Sodium_Crypto32::keyExchange( |
1183
|
|
|
$my_secret, |
1184
|
|
|
$their_public, |
1185
|
|
|
$client_public, |
1186
|
|
|
$server_public |
1187
|
|
|
); |
1188
|
|
|
} |
1189
|
|
|
return ParagonIE_Sodium_Crypto::keyExchange( |
1190
|
|
|
$my_secret, |
1191
|
|
|
$their_public, |
1192
|
|
|
$client_public, |
1193
|
|
|
$server_public |
1194
|
|
|
); |
1195
|
|
|
} |
1196
|
|
|
|
1197
|
|
|
/** |
1198
|
|
|
* @param int $outlen |
1199
|
|
|
* @param string $passwd |
1200
|
|
|
* @param string $salt |
1201
|
|
|
* @param int $opslimit |
1202
|
|
|
* @param int $memlimit |
1203
|
|
|
* @return string |
1204
|
|
|
* @throws Error |
1205
|
|
|
*/ |
1206
|
|
View Code Duplication |
public static function crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit) |
|
|
|
|
1207
|
|
|
{ |
1208
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1); |
1209
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2); |
1210
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3); |
1211
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4); |
1212
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5); |
1213
|
|
|
|
1214
|
|
|
if (self::isPhp72OrGreater()) { |
1215
|
|
|
return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit); |
1216
|
|
|
} |
1217
|
|
|
if (self::use_fallback('crypto_pwhash')) { |
1218
|
|
|
return call_user_func('\\Sodium\\crypto_pwhash', $outlen, $passwd, $salt, $opslimit, $memlimit); |
1219
|
|
|
} |
1220
|
|
|
// This is the best we can do. |
1221
|
|
|
throw new Error( |
1222
|
|
|
'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' |
1223
|
|
|
); |
1224
|
|
|
} |
1225
|
|
|
|
1226
|
|
|
/** |
1227
|
|
|
* @param string $passwd |
1228
|
|
|
* @param int $opslimit |
1229
|
|
|
* @param int $memlimit |
1230
|
|
|
* @return string |
1231
|
|
|
* @throws Error |
1232
|
|
|
*/ |
1233
|
|
View Code Duplication |
public static function crypto_pwhash_str($passwd, $opslimit, $memlimit) |
|
|
|
|
1234
|
|
|
{ |
1235
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); |
1236
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2); |
1237
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3); |
1238
|
|
|
|
1239
|
|
|
if (self::isPhp72OrGreater()) { |
1240
|
|
|
return sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit); |
1241
|
|
|
} |
1242
|
|
|
if (self::use_fallback('crypto_pwhash_str')) { |
1243
|
|
|
return call_user_func('\\Sodium\\crypto_pwhash_str', $passwd, $opslimit, $memlimit); |
1244
|
|
|
} |
1245
|
|
|
// This is the best we can do. |
1246
|
|
|
throw new Error( |
1247
|
|
|
'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' |
1248
|
|
|
); |
1249
|
|
|
} |
1250
|
|
|
|
1251
|
|
|
/** |
1252
|
|
|
* @param string $passwd |
1253
|
|
|
* @param string $hash |
1254
|
|
|
* @return bool |
1255
|
|
|
* @throws Error |
1256
|
|
|
*/ |
1257
|
|
View Code Duplication |
public static function crypto_pwhash_str_verify($passwd, $hash) |
|
|
|
|
1258
|
|
|
{ |
1259
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); |
1260
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2); |
1261
|
|
|
|
1262
|
|
|
if (self::isPhp72OrGreater()) { |
1263
|
|
|
return sodium_crypto_pwhash_str_verify($passwd, $hash); |
1264
|
|
|
} |
1265
|
|
|
if (self::use_fallback('crypto_pwhash_str_verify')) { |
1266
|
|
|
return call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd, $hash); |
1267
|
|
|
} |
1268
|
|
|
// This is the best we can do. |
1269
|
|
|
throw new Error( |
1270
|
|
|
'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' |
1271
|
|
|
); |
1272
|
|
|
} |
1273
|
|
|
|
1274
|
|
|
/** |
1275
|
|
|
* @param int $outlen |
1276
|
|
|
* @param string $passwd |
1277
|
|
|
* @param string $salt |
1278
|
|
|
* @param int $opslimit |
1279
|
|
|
* @param int $memlimit |
1280
|
|
|
* @return string |
1281
|
|
|
* @throws Error |
1282
|
|
|
*/ |
1283
|
|
View Code Duplication |
public static function crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit) |
|
|
|
|
1284
|
|
|
{ |
1285
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1); |
1286
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2); |
1287
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3); |
1288
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4); |
1289
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5); |
1290
|
|
|
|
1291
|
|
|
if (self::isPhp72OrGreater()) { |
1292
|
|
|
return sodium_crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit); |
1293
|
|
|
} |
1294
|
|
|
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) { |
1295
|
|
|
return call_user_func('\\Sodium\\crypto_pwhash_scryptsalsa208sha256', $outlen, $passwd, $salt, $opslimit, $memlimit); |
1296
|
|
|
} |
1297
|
|
|
// This is the best we can do. |
1298
|
|
|
throw new Error( |
1299
|
|
|
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' |
1300
|
|
|
); |
1301
|
|
|
} |
1302
|
|
|
|
1303
|
|
|
/** |
1304
|
|
|
* @param string $passwd |
1305
|
|
|
* @param int $opslimit |
1306
|
|
|
* @param int $memlimit |
1307
|
|
|
* @return string |
1308
|
|
|
* @throws Error |
1309
|
|
|
*/ |
1310
|
|
View Code Duplication |
public static function crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit) |
|
|
|
|
1311
|
|
|
{ |
1312
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); |
1313
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2); |
1314
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3); |
1315
|
|
|
|
1316
|
|
|
if (self::isPhp72OrGreater()) { |
1317
|
|
|
return sodium_crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit); |
1318
|
|
|
} |
1319
|
|
|
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) { |
1320
|
|
|
return call_user_func('\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str', $passwd, $opslimit, $memlimit); |
1321
|
|
|
} |
1322
|
|
|
// This is the best we can do. |
1323
|
|
|
throw new Error( |
1324
|
|
|
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' |
1325
|
|
|
); |
1326
|
|
|
} |
1327
|
|
|
|
1328
|
|
|
/** |
1329
|
|
|
* @param string $passwd |
1330
|
|
|
* @param string $hash |
1331
|
|
|
* @return bool |
1332
|
|
|
* @throws Error |
1333
|
|
|
*/ |
1334
|
|
View Code Duplication |
public static function crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash) |
|
|
|
|
1335
|
|
|
{ |
1336
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); |
1337
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2); |
1338
|
|
|
|
1339
|
|
|
if (self::isPhp72OrGreater()) { |
1340
|
|
|
return sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash); |
1341
|
|
|
} |
1342
|
|
|
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify')) { |
1343
|
|
|
return call_user_func('\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify', $passwd, $hash); |
1344
|
|
|
} |
1345
|
|
|
// This is the best we can do. |
1346
|
|
|
throw new Error( |
1347
|
|
|
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' |
1348
|
|
|
); |
1349
|
|
|
} |
1350
|
|
|
|
1351
|
|
|
/** |
1352
|
|
|
* Calculate the shared secret between your secret key and your |
1353
|
|
|
* recipient's public key. |
1354
|
|
|
* |
1355
|
|
|
* Algorithm: X25519 (ECDH over Curve25519) |
1356
|
|
|
* |
1357
|
|
|
* @param string $secretKey |
1358
|
|
|
* @param string $publicKey |
1359
|
|
|
* @return string |
1360
|
|
|
* @throws Error |
1361
|
|
|
* @throws TypeError |
1362
|
|
|
*/ |
1363
|
|
|
public static function crypto_scalarmult($secretKey, $publicKey) |
1364
|
|
|
{ |
1365
|
|
|
/* Type checks: */ |
1366
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); |
1367
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); |
1368
|
|
|
|
1369
|
|
|
/* Input validation: */ |
1370
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { |
1371
|
|
|
throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); |
1372
|
|
|
} |
1373
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { |
1374
|
|
|
throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); |
1375
|
|
|
} |
1376
|
|
|
|
1377
|
|
|
if (self::isPhp72OrGreater()) { |
1378
|
|
|
return sodium_crypto_scalarmult($secretKey, $publicKey); |
1379
|
|
|
} |
1380
|
|
|
if (self::use_fallback('crypto_scalarmult')) { |
1381
|
|
|
return call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey); |
1382
|
|
|
} |
1383
|
|
|
|
1384
|
|
|
/* Output validation: Forbid all-zero keys */ |
1385
|
|
|
if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { |
1386
|
|
|
throw new Error('Zero secret key is not allowed'); |
1387
|
|
|
} |
1388
|
|
|
if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) { |
1389
|
|
|
throw new Error('Zero public key is not allowed'); |
1390
|
|
|
} |
1391
|
|
|
if (PHP_INT_SIZE === 4) { |
1392
|
|
|
return ParagonIE_Sodium_Crypto32::scalarmult($secretKey, $publicKey); |
1393
|
|
|
} |
1394
|
|
|
return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey); |
1395
|
|
|
} |
1396
|
|
|
|
1397
|
|
|
/** |
1398
|
|
|
* Calculate an X25519 public key from an X25519 secret key. |
1399
|
|
|
* |
1400
|
|
|
* @param string $secretKey |
1401
|
|
|
* @return string |
1402
|
|
|
* @throws Error |
1403
|
|
|
* @throws TypeError |
1404
|
|
|
*/ |
1405
|
|
|
public static function crypto_scalarmult_base($secretKey) |
1406
|
|
|
{ |
1407
|
|
|
/* Type checks: */ |
1408
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); |
1409
|
|
|
|
1410
|
|
|
/* Input validation: */ |
1411
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { |
1412
|
|
|
throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); |
1413
|
|
|
} |
1414
|
|
|
|
1415
|
|
|
if (self::isPhp72OrGreater()) { |
1416
|
|
|
return sodium_crypto_scalarmult_base($secretKey); |
1417
|
|
|
} |
1418
|
|
|
if (self::use_fallback('crypto_scalarmult_base')) { |
1419
|
|
|
return call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey); |
1420
|
|
|
} |
1421
|
|
|
if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { |
1422
|
|
|
throw new Error('Zero secret key is not allowed'); |
1423
|
|
|
} |
1424
|
|
|
if (PHP_INT_SIZE === 4) { |
1425
|
|
|
return ParagonIE_Sodium_Crypto32::scalarmult_base($secretKey); |
1426
|
|
|
} |
1427
|
|
|
return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey); |
1428
|
|
|
} |
1429
|
|
|
|
1430
|
|
|
/** |
1431
|
|
|
* Authenticated symmetric-key encryption. |
1432
|
|
|
* |
1433
|
|
|
* Algorithm: XSalsa20-Poly1305 |
1434
|
|
|
* |
1435
|
|
|
* @param string $plaintext The message you're encrypting |
1436
|
|
|
* @param string $nonce A Number to be used Once; must be 24 bytes |
1437
|
|
|
* @param string $key Symmetric encryption key |
1438
|
|
|
* @return string Ciphertext with Poly1305 MAC |
1439
|
|
|
* @throws Error |
1440
|
|
|
* @throws TypeError |
1441
|
|
|
*/ |
1442
|
|
View Code Duplication |
public static function crypto_secretbox($plaintext, $nonce, $key) |
|
|
|
|
1443
|
|
|
{ |
1444
|
|
|
/* Type checks: */ |
1445
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); |
1446
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); |
1447
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); |
1448
|
|
|
|
1449
|
|
|
/* Input validation: */ |
1450
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { |
1451
|
|
|
throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); |
1452
|
|
|
} |
1453
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { |
1454
|
|
|
throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); |
1455
|
|
|
} |
1456
|
|
|
|
1457
|
|
|
if (self::isPhp72OrGreater()) { |
1458
|
|
|
return sodium_crypto_secretbox($plaintext, $nonce, $key); |
1459
|
|
|
} |
1460
|
|
|
if (self::use_fallback('crypto_secretbox')) { |
1461
|
|
|
return call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key); |
1462
|
|
|
} |
1463
|
|
|
if (PHP_INT_SIZE === 4) { |
1464
|
|
|
return ParagonIE_Sodium_Crypto32::secretbox($plaintext, $nonce, $key); |
1465
|
|
|
} |
1466
|
|
|
return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key); |
1467
|
|
|
} |
1468
|
|
|
|
1469
|
|
|
/** |
1470
|
|
|
* Decrypts a message previously encrypted with crypto_secretbox(). |
1471
|
|
|
* |
1472
|
|
|
* @param string $ciphertext Ciphertext with Poly1305 MAC |
1473
|
|
|
* @param string $nonce A Number to be used Once; must be 24 bytes |
1474
|
|
|
* @param string $key Symmetric encryption key |
1475
|
|
|
* @return string Original plaintext message |
1476
|
|
|
* @throws Error |
1477
|
|
|
* @throws TypeError |
1478
|
|
|
*/ |
1479
|
|
View Code Duplication |
public static function crypto_secretbox_open($ciphertext, $nonce, $key) |
|
|
|
|
1480
|
|
|
{ |
1481
|
|
|
/* Type checks: */ |
1482
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); |
1483
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); |
1484
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); |
1485
|
|
|
|
1486
|
|
|
/* Input validation: */ |
1487
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { |
1488
|
|
|
throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); |
1489
|
|
|
} |
1490
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { |
1491
|
|
|
throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); |
1492
|
|
|
} |
1493
|
|
|
|
1494
|
|
|
if (self::isPhp72OrGreater()) { |
1495
|
|
|
return sodium_crypto_secretbox_open($ciphertext, $nonce, $key); |
1496
|
|
|
} |
1497
|
|
|
if (self::use_fallback('crypto_secretbox_open')) { |
1498
|
|
|
return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key); |
1499
|
|
|
} |
1500
|
|
|
if (PHP_INT_SIZE === 4) { |
1501
|
|
|
return ParagonIE_Sodium_Crypto32::secretbox_open($ciphertext, $nonce, $key); |
1502
|
|
|
} |
1503
|
|
|
return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key); |
1504
|
|
|
} |
1505
|
|
|
|
1506
|
|
|
/** |
1507
|
|
|
* Authenticated symmetric-key encryption. |
1508
|
|
|
* |
1509
|
|
|
* Algorithm: XChaCha20-Poly1305 |
1510
|
|
|
* |
1511
|
|
|
* @param string $plaintext The message you're encrypting |
1512
|
|
|
* @param string $nonce A Number to be used Once; must be 24 bytes |
1513
|
|
|
* @param string $key Symmetric encryption key |
1514
|
|
|
* @return string Ciphertext with Poly1305 MAC |
1515
|
|
|
* @throws Error |
1516
|
|
|
* @throws TypeError |
1517
|
|
|
*/ |
1518
|
|
View Code Duplication |
public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key) |
|
|
|
|
1519
|
|
|
{ |
1520
|
|
|
/* Type checks: */ |
1521
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); |
1522
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); |
1523
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); |
1524
|
|
|
|
1525
|
|
|
/* Input validation: */ |
1526
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { |
1527
|
|
|
throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); |
1528
|
|
|
} |
1529
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { |
1530
|
|
|
throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); |
1531
|
|
|
} |
1532
|
|
|
if (PHP_INT_SIZE === 4) { |
1533
|
|
|
return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305($plaintext, $nonce, $key); |
1534
|
|
|
} |
1535
|
|
|
return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key); |
1536
|
|
|
} |
1537
|
|
|
/** |
1538
|
|
|
* Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305(). |
1539
|
|
|
* |
1540
|
|
|
* @param string $ciphertext Ciphertext with Poly1305 MAC |
1541
|
|
|
* @param string $nonce A Number to be used Once; must be 24 bytes |
1542
|
|
|
* @param string $key Symmetric encryption key |
1543
|
|
|
* @return string Original plaintext message |
1544
|
|
|
* @throws Error |
1545
|
|
|
* @throws TypeError |
1546
|
|
|
*/ |
1547
|
|
View Code Duplication |
public static function crypto_secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) |
|
|
|
|
1548
|
|
|
{ |
1549
|
|
|
/* Type checks: */ |
1550
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); |
1551
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); |
1552
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); |
1553
|
|
|
|
1554
|
|
|
/* Input validation: */ |
1555
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { |
1556
|
|
|
throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); |
1557
|
|
|
} |
1558
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { |
1559
|
|
|
throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); |
1560
|
|
|
} |
1561
|
|
|
|
1562
|
|
|
if (PHP_INT_SIZE === 4) { |
1563
|
|
|
return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key); |
1564
|
|
|
} |
1565
|
|
|
return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key); |
1566
|
|
|
} |
1567
|
|
|
|
1568
|
|
|
/** |
1569
|
|
|
* Calculates a SipHash-2-4 hash of a message for a given key. |
1570
|
|
|
* |
1571
|
|
|
* @param string $message Input message |
1572
|
|
|
* @param string $key SipHash-2-4 key |
1573
|
|
|
* @return string Hash |
1574
|
|
|
* @throws Error |
1575
|
|
|
* @throws TypeError |
1576
|
|
|
*/ |
1577
|
|
View Code Duplication |
public static function crypto_shorthash($message, $key) |
|
|
|
|
1578
|
|
|
{ |
1579
|
|
|
/* Type checks: */ |
1580
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); |
1581
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); |
1582
|
|
|
|
1583
|
|
|
/* Input validation: */ |
1584
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SHORTHASH_KEYBYTES) { |
1585
|
|
|
throw new Error('Argument 2 must be CRYPTO_SHORTHASH_KEYBYTES long.'); |
1586
|
|
|
} |
1587
|
|
|
|
1588
|
|
|
if (self::isPhp72OrGreater()) { |
1589
|
|
|
return sodium_crypto_shorthash($message, $key); |
1590
|
|
|
} |
1591
|
|
|
if (self::use_fallback('crypto_shorthash')) { |
1592
|
|
|
return call_user_func('\\Sodium\\crypto_shorthash', $message, $key); |
1593
|
|
|
} |
1594
|
|
|
if (PHP_INT_SIZE === 4) { |
1595
|
|
|
return ParagonIE_Sodium_Core32_SipHash::sipHash24($message, $key); |
1596
|
|
|
} |
1597
|
|
|
return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key); |
1598
|
|
|
} |
1599
|
|
|
|
1600
|
|
|
/** |
1601
|
|
|
* Expand a key and nonce into a keystream of pseudorandom bytes. |
1602
|
|
|
* |
1603
|
|
|
* @param int $len Number of bytes desired |
1604
|
|
|
* @param string $nonce Number to be used Once; must be 24 bytes |
1605
|
|
|
* @param string $key XSalsa20 key |
1606
|
|
|
* @return string Pseudorandom stream that can be XORed with messages |
1607
|
|
|
* to provide encryption (but not authentication; see |
1608
|
|
|
* Poly1305 or crypto_auth() for that, which is not |
1609
|
|
|
* optional for security) |
1610
|
|
|
* @throws Error |
1611
|
|
|
* @throws TypeError |
1612
|
|
|
*/ |
1613
|
|
View Code Duplication |
public static function crypto_stream($len, $nonce, $key) |
|
|
|
|
1614
|
|
|
{ |
1615
|
|
|
/* Type checks: */ |
1616
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1); |
1617
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); |
1618
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); |
1619
|
|
|
|
1620
|
|
|
/* Input validation: */ |
1621
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { |
1622
|
|
|
throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); |
1623
|
|
|
} |
1624
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { |
1625
|
|
|
throw new Error('Argument 3 must be CRYPTO_STREAM_KEYBYTES long.'); |
1626
|
|
|
} |
1627
|
|
|
|
1628
|
|
|
if (self::isPhp72OrGreater()) { |
1629
|
|
|
return sodium_crypto_stream($len, $nonce, $key); |
1630
|
|
|
} |
1631
|
|
|
if (self::use_fallback('crypto_stream')) { |
1632
|
|
|
return call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key); |
1633
|
|
|
} |
1634
|
|
|
if (PHP_INT_SIZE === 4) { |
1635
|
|
|
return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20($len, $nonce, $key); |
1636
|
|
|
} |
1637
|
|
|
return ParagonIE_Sodium_Core_XSalsa20::xsalsa20($len, $nonce, $key); |
1638
|
|
|
} |
1639
|
|
|
|
1640
|
|
|
/** |
1641
|
|
|
* DANGER! UNAUTHENTICATED ENCRYPTION! |
1642
|
|
|
* |
1643
|
|
|
* Unless you are following expert advice, do not used this feature. |
1644
|
|
|
* |
1645
|
|
|
* Algorithm: XSalsa20 |
1646
|
|
|
* |
1647
|
|
|
* This DOES NOT provide ciphertext integrity. |
1648
|
|
|
* |
1649
|
|
|
* @param string $message Plaintext message |
1650
|
|
|
* @param string $nonce Number to be used Once; must be 24 bytes |
1651
|
|
|
* @param string $key Encryption key |
1652
|
|
|
* @return string Encrypted text which is vulnerable to chosen- |
1653
|
|
|
* ciphertext attacks unless you implement some |
1654
|
|
|
* other mitigation to the ciphertext (i.e. |
1655
|
|
|
* Encrypt then MAC) |
1656
|
|
|
* @throws Error |
1657
|
|
|
* @throws TypeError |
1658
|
|
|
*/ |
1659
|
|
View Code Duplication |
public static function crypto_stream_xor($message, $nonce, $key) |
|
|
|
|
1660
|
|
|
{ |
1661
|
|
|
/* Type checks: */ |
1662
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); |
1663
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); |
1664
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); |
1665
|
|
|
|
1666
|
|
|
/* Input validation: */ |
1667
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { |
1668
|
|
|
throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); |
1669
|
|
|
} |
1670
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { |
1671
|
|
|
throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); |
1672
|
|
|
} |
1673
|
|
|
|
1674
|
|
|
if (self::isPhp72OrGreater()) { |
1675
|
|
|
return sodium_crypto_stream_xor($message, $nonce, $key); |
1676
|
|
|
} |
1677
|
|
|
if (self::use_fallback('crypto_stream_xor')) { |
1678
|
|
|
return call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce, $key); |
1679
|
|
|
} |
1680
|
|
|
if (PHP_INT_SIZE === 4) { |
1681
|
|
|
return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20_xor($message, $nonce, $key); |
1682
|
|
|
} |
1683
|
|
|
return ParagonIE_Sodium_Core_XSalsa20::xsalsa20_xor($message, $nonce, $key); |
1684
|
|
|
} |
1685
|
|
|
|
1686
|
|
|
/** |
1687
|
|
|
* Returns a signed message. You probably want crypto_sign_detached() |
1688
|
|
|
* instead, which only returns the signature. |
1689
|
|
|
* |
1690
|
|
|
* Algorithm: Ed25519 (EdDSA over Curve25519) |
1691
|
|
|
* |
1692
|
|
|
* @param string $message Message to be signed. |
1693
|
|
|
* @param string $secretKey Secret signing key. |
1694
|
|
|
* @return string Signed message (signature is prefixed). |
1695
|
|
|
* @throws Error |
1696
|
|
|
* @throws TypeError |
1697
|
|
|
*/ |
1698
|
|
View Code Duplication |
public static function crypto_sign($message, $secretKey) |
|
|
|
|
1699
|
|
|
{ |
1700
|
|
|
/* Type checks: */ |
1701
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); |
1702
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2); |
1703
|
|
|
|
1704
|
|
|
/* Input validation: */ |
1705
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { |
1706
|
|
|
throw new Error('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); |
1707
|
|
|
} |
1708
|
|
|
|
1709
|
|
|
if (self::isPhp72OrGreater()) { |
1710
|
|
|
return sodium_crypto_sign($message, $secretKey); |
1711
|
|
|
} |
1712
|
|
|
if (self::use_fallback('crypto_sign')) { |
1713
|
|
|
return call_user_func('\\Sodium\\crypto_sign', $message, $secretKey); |
1714
|
|
|
} |
1715
|
|
|
if (PHP_INT_SIZE === 4) { |
1716
|
|
|
return ParagonIE_Sodium_Crypto32::sign($message, $secretKey); |
1717
|
|
|
} |
1718
|
|
|
return ParagonIE_Sodium_Crypto::sign($message, $secretKey); |
1719
|
|
|
} |
1720
|
|
|
|
1721
|
|
|
/** |
1722
|
|
|
* Validates a signed message then returns the message. |
1723
|
|
|
* |
1724
|
|
|
* @param string $signedMessage A signed message |
1725
|
|
|
* @param string $publicKey A public key |
1726
|
|
|
* @return string The original message (if the signature is |
1727
|
|
|
* valid for this public key) |
1728
|
|
|
* @throws Error |
1729
|
|
|
* @throws TypeError |
1730
|
|
|
*/ |
1731
|
|
View Code Duplication |
public static function crypto_sign_open($signedMessage, $publicKey) |
|
|
|
|
1732
|
|
|
{ |
1733
|
|
|
/* Type checks: */ |
1734
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($signedMessage, 'string', 1); |
1735
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); |
1736
|
|
|
|
1737
|
|
|
/* Input validation: */ |
1738
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) < self::CRYPTO_SIGN_BYTES) { |
1739
|
|
|
throw new Error('Argument 1 must be at least CRYPTO_SIGN_BYTES long.'); |
1740
|
|
|
} |
1741
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { |
1742
|
|
|
throw new Error('Argument 2 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); |
1743
|
|
|
} |
1744
|
|
|
|
1745
|
|
|
if (self::isPhp72OrGreater()) { |
1746
|
|
|
return sodium_crypto_sign_open($signedMessage, $publicKey); |
1747
|
|
|
} |
1748
|
|
|
if (self::use_fallback('crypto_sign_open')) { |
1749
|
|
|
return call_user_func('\\Sodium\\crypto_sign_open', $signedMessage, $publicKey); |
1750
|
|
|
} |
1751
|
|
|
if (PHP_INT_SIZE === 4) { |
1752
|
|
|
return ParagonIE_Sodium_Crypto32::sign_open($signedMessage, $publicKey); |
1753
|
|
|
} |
1754
|
|
|
return ParagonIE_Sodium_Crypto::sign_open($signedMessage, $publicKey); |
1755
|
|
|
} |
1756
|
|
|
|
1757
|
|
|
/** |
1758
|
|
|
* Generate a new random Ed25519 keypair. |
1759
|
|
|
* |
1760
|
|
|
* @return string |
1761
|
|
|
*/ |
1762
|
|
|
public static function crypto_sign_keypair() |
1763
|
|
|
{ |
1764
|
|
|
if (self::isPhp72OrGreater()) { |
1765
|
|
|
return sodium_crypto_sign_keypair(); |
1766
|
|
|
} |
1767
|
|
|
if (self::use_fallback('crypto_sign_keypair')) { |
1768
|
|
|
return call_user_func( |
1769
|
|
|
'\\Sodium\\crypto_sign_keypair' |
1770
|
|
|
); |
1771
|
|
|
} |
1772
|
|
|
if (PHP_INT_SIZE === 4) { |
1773
|
|
|
return ParagonIE_Sodium_Core32_Ed25519::keypair(); |
1774
|
|
|
} |
1775
|
|
|
return ParagonIE_Sodium_Core_Ed25519::keypair(); |
1776
|
|
|
} |
1777
|
|
|
|
1778
|
|
|
/** |
1779
|
|
|
* Generate an Ed25519 keypair from a seed. |
1780
|
|
|
* |
1781
|
|
|
* @param string $seed Input seed |
1782
|
|
|
* @return string Keypair |
1783
|
|
|
*/ |
1784
|
|
View Code Duplication |
public static function crypto_sign_seed_keypair($seed) |
|
|
|
|
1785
|
|
|
{ |
1786
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1); |
1787
|
|
|
|
1788
|
|
|
if (self::isPhp72OrGreater()) { |
1789
|
|
|
return sodium_crypto_sign_seed_keypair($seed); |
1790
|
|
|
} |
1791
|
|
|
if (self::use_fallback('crypto_sign_keypair')) { |
1792
|
|
|
return call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed); |
1793
|
|
|
} |
1794
|
|
|
$publicKey = ''; |
1795
|
|
|
$secretKey = ''; |
1796
|
|
|
if (PHP_INT_SIZE === 4) { |
1797
|
|
|
ParagonIE_Sodium_Core32_Ed25519::seed_keypair($publicKey, $secretKey, $seed); |
1798
|
|
|
} else { |
1799
|
|
|
ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey, $secretKey, $seed); |
1800
|
|
|
} |
1801
|
|
|
return $secretKey . $publicKey; |
1802
|
|
|
} |
1803
|
|
|
|
1804
|
|
|
/** |
1805
|
|
|
* Extract an Ed25519 public key from an Ed25519 keypair. |
1806
|
|
|
* |
1807
|
|
|
* @param string $keypair Keypair |
1808
|
|
|
* @return string Public key |
1809
|
|
|
* @throws Error |
1810
|
|
|
* @throws TypeError |
1811
|
|
|
*/ |
1812
|
|
View Code Duplication |
public static function crypto_sign_publickey($keypair) |
|
|
|
|
1813
|
|
|
{ |
1814
|
|
|
/* Type checks: */ |
1815
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); |
1816
|
|
|
|
1817
|
|
|
/* Input validation: */ |
1818
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { |
1819
|
|
|
throw new Error('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); |
1820
|
|
|
} |
1821
|
|
|
|
1822
|
|
|
if (self::isPhp72OrGreater()) { |
1823
|
|
|
return sodium_crypto_sign_publickey($keypair); |
1824
|
|
|
} |
1825
|
|
|
if (self::use_fallback('crypto_sign_publickey')) { |
1826
|
|
|
return call_user_func('\\Sodium\\crypto_sign_publickey', $keypair); |
1827
|
|
|
} |
1828
|
|
|
if (PHP_INT_SIZE === 4) { |
1829
|
|
|
return ParagonIE_Sodium_Core32_Ed25519::publickey($keypair); |
1830
|
|
|
} |
1831
|
|
|
return ParagonIE_Sodium_Core_Ed25519::publickey($keypair); |
1832
|
|
|
} |
1833
|
|
|
|
1834
|
|
|
/** |
1835
|
|
|
* Calculate an Ed25519 public key from an Ed25519 secret key. |
1836
|
|
|
* |
1837
|
|
|
* @param string $secretKey Your Ed25519 secret key |
1838
|
|
|
* @return string The corresponding Ed25519 public key |
1839
|
|
|
* @throws Error |
1840
|
|
|
* @throws TypeError |
1841
|
|
|
*/ |
1842
|
|
View Code Duplication |
public static function crypto_sign_publickey_from_secretkey($secretKey) |
|
|
|
|
1843
|
|
|
{ |
1844
|
|
|
/* Type checks: */ |
1845
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); |
1846
|
|
|
|
1847
|
|
|
/* Input validation: */ |
1848
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { |
1849
|
|
|
throw new Error('Argument 1 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); |
1850
|
|
|
} |
1851
|
|
|
|
1852
|
|
|
if (self::isPhp72OrGreater()) { |
1853
|
|
|
return sodium_crypto_sign_publickey_from_secretkey($secretKey); |
1854
|
|
|
} |
1855
|
|
|
if (self::use_fallback('crypto_sign_publickey_from_secretkey')) { |
1856
|
|
|
return call_user_func('\\Sodium\\crypto_sign_publickey_from_secretkey', $secretKey); |
1857
|
|
|
} |
1858
|
|
|
if (PHP_INT_SIZE === 4) { |
1859
|
|
|
return ParagonIE_Sodium_Core32_Ed25519::publickey_from_secretkey($secretKey); |
1860
|
|
|
} |
1861
|
|
|
return ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey); |
1862
|
|
|
} |
1863
|
|
|
|
1864
|
|
|
/** |
1865
|
|
|
* Extract an Ed25519 secret key from an Ed25519 keypair. |
1866
|
|
|
* |
1867
|
|
|
* @param string $keypair Keypair |
1868
|
|
|
* @return string Secret key |
1869
|
|
|
* @throws Error |
1870
|
|
|
* @throws TypeError |
1871
|
|
|
*/ |
1872
|
|
View Code Duplication |
public static function crypto_sign_secretkey($keypair) |
|
|
|
|
1873
|
|
|
{ |
1874
|
|
|
/* Type checks: */ |
1875
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); |
1876
|
|
|
|
1877
|
|
|
/* Input validation: */ |
1878
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { |
1879
|
|
|
throw new Error('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); |
1880
|
|
|
} |
1881
|
|
|
|
1882
|
|
|
if (self::isPhp72OrGreater()) { |
1883
|
|
|
return sodium_crypto_sign_secretkey($keypair); |
1884
|
|
|
} |
1885
|
|
|
if (self::use_fallback('crypto_sign_secretkey')) { |
1886
|
|
|
return call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair); |
1887
|
|
|
} |
1888
|
|
|
if (PHP_INT_SIZE === 4) { |
1889
|
|
|
return ParagonIE_Sodium_Core32_Ed25519::secretkey($keypair); |
1890
|
|
|
} |
1891
|
|
|
return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair); |
1892
|
|
|
} |
1893
|
|
|
|
1894
|
|
|
/** |
1895
|
|
|
* Calculate the Ed25519 signature of a message and return ONLY the signature. |
1896
|
|
|
* |
1897
|
|
|
* Algorithm: Ed25519 (EdDSA over Curve25519) |
1898
|
|
|
* |
1899
|
|
|
* @param string $message Message to be signed |
1900
|
|
|
* @param string $secretKey Secret signing key |
1901
|
|
|
* @return string Digital signature |
1902
|
|
|
* @throws Error |
1903
|
|
|
* @throws TypeError |
1904
|
|
|
*/ |
1905
|
|
View Code Duplication |
public static function crypto_sign_detached($message, $secretKey) |
|
|
|
|
1906
|
|
|
{ |
1907
|
|
|
/* Type checks: */ |
1908
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); |
1909
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2); |
1910
|
|
|
|
1911
|
|
|
/* Input validation: */ |
1912
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { |
1913
|
|
|
throw new Error('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); |
1914
|
|
|
} |
1915
|
|
|
|
1916
|
|
|
if (self::isPhp72OrGreater()) { |
1917
|
|
|
return sodium_crypto_sign_detached($message, $secretKey); |
1918
|
|
|
} |
1919
|
|
|
if (self::use_fallback('crypto_sign_detached')) { |
1920
|
|
|
return call_user_func('\\Sodium\\crypto_sign_detached', $message, $secretKey); |
1921
|
|
|
} |
1922
|
|
|
if (PHP_INT_SIZE === 4) { |
1923
|
|
|
return ParagonIE_Sodium_Crypto32::sign_detached($message, $secretKey); |
1924
|
|
|
} |
1925
|
|
|
return ParagonIE_Sodium_Crypto::sign_detached($message, $secretKey); |
1926
|
|
|
} |
1927
|
|
|
|
1928
|
|
|
/** |
1929
|
|
|
* Verify the Ed25519 signature of a message. |
1930
|
|
|
* |
1931
|
|
|
* @param string $signature Digital sginature |
1932
|
|
|
* @param string $message Message to be verified |
1933
|
|
|
* @param string $publicKey Public key |
1934
|
|
|
* @return bool TRUE if this signature is good for this public key; |
1935
|
|
|
* FALSE otherwise |
1936
|
|
|
* @throws Error |
1937
|
|
|
* @throws TypeError |
1938
|
|
|
*/ |
1939
|
|
View Code Duplication |
public static function crypto_sign_verify_detached($signature, $message, $publicKey) |
|
|
|
|
1940
|
|
|
{ |
1941
|
|
|
/* Type checks: */ |
1942
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($signature, 'string', 1); |
1943
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); |
1944
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 3); |
1945
|
|
|
|
1946
|
|
|
/* Input validation: */ |
1947
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($signature) !== self::CRYPTO_SIGN_BYTES) { |
1948
|
|
|
throw new Error('Argument 1 must be CRYPTO_SIGN_BYTES long.'); |
1949
|
|
|
} |
1950
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { |
1951
|
|
|
throw new Error('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); |
1952
|
|
|
} |
1953
|
|
|
|
1954
|
|
|
if (self::isPhp72OrGreater()) { |
1955
|
|
|
return sodium_crypto_sign_verify_detached($signature, $message, $publicKey); |
1956
|
|
|
} |
1957
|
|
|
if (self::use_fallback('crypto_sign_verify_detached')) { |
1958
|
|
|
return call_user_func('\\Sodium\\crypto_sign_verify_detached', $signature, $message, $publicKey); |
1959
|
|
|
} |
1960
|
|
|
if (PHP_INT_SIZE === 4) { |
1961
|
|
|
return ParagonIE_Sodium_Crypto32::sign_verify_detached($signature, $message, $publicKey); |
1962
|
|
|
} |
1963
|
|
|
return ParagonIE_Sodium_Crypto::sign_verify_detached($signature, $message, $publicKey); |
1964
|
|
|
} |
1965
|
|
|
|
1966
|
|
|
/** |
1967
|
|
|
* Convert an Ed25519 secret key to a Curve25519 secret key |
1968
|
|
|
* |
1969
|
|
|
* @param string $sk |
1970
|
|
|
* @return string |
1971
|
|
|
* @throws Error |
1972
|
|
|
*/ |
1973
|
|
|
public static function crypto_sign_ed25519_sk_to_curve25519($sk) |
1974
|
|
|
{ |
1975
|
|
|
/* Type checks: */ |
1976
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1); |
1977
|
|
|
|
1978
|
|
|
/* Input validation: */ |
1979
|
|
|
if (ParagonIE_Sodium_Core_Util::strlen($sk) < self::CRYPTO_SIGN_SEEDBYTES) { |
1980
|
|
|
throw new Error('Argument 1 must be at least CRYPTO_SIGN_SEEDBYTES long.'); |
1981
|
|
|
} |
1982
|
|
|
if (self::isPhp72OrGreater()) { |
1983
|
|
|
if (is_callable('crypto_sign_ed25519_sk_to_curve25519')) { |
1984
|
|
|
return sodium_crypto_sign_ed25519_sk_to_curve25519($sk); |
1985
|
|
|
} |
1986
|
|
|
} |
1987
|
|
|
if (self::use_fallback('crypto_sign_ed25519_sk_to_curve25519')) { |
1988
|
|
|
return call_user_func('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519', $sk); |
1989
|
|
|
} |
1990
|
|
|
|
1991
|
|
|
$h = hash('sha512', ParagonIE_Sodium_Core_Util::substr($sk, 0, 32), true); |
1992
|
|
|
$h[0] = ParagonIE_Sodium_Core_Util::intToChr( |
1993
|
|
|
ParagonIE_Sodium_Core_Util::chrToInt($h[0]) & 248 |
1994
|
|
|
); |
1995
|
|
|
$h[31] = ParagonIE_Sodium_Core_Util::intToChr( |
1996
|
|
|
(ParagonIE_Sodium_Core_Util::chrToInt($h[31]) & 127) | 64 |
1997
|
|
|
); |
1998
|
|
|
return ParagonIE_Sodium_Core_Util::substr($h, 0, 32); |
1999
|
|
|
} |
2000
|
|
|
|
2001
|
|
|
/** |
2002
|
|
|
* Cache-timing-safe implementation of hex2bin(). |
2003
|
|
|
* |
2004
|
|
|
* @param string $string Hexadecimal string |
2005
|
|
|
* @return string Raw binary string |
2006
|
|
|
* @throws TypeError |
2007
|
|
|
*/ |
2008
|
|
View Code Duplication |
public static function hex2bin($string) |
|
|
|
|
2009
|
|
|
{ |
2010
|
|
|
/* Type checks: */ |
2011
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1); |
2012
|
|
|
|
2013
|
|
|
if (self::isPhp72OrGreater()) { |
2014
|
|
|
return sodium_hex2bin($string); |
2015
|
|
|
} |
2016
|
|
|
if (self::use_fallback('hex2bin')) { |
2017
|
|
|
return call_user_func('\\Sodium\\hex2bin', $string); |
2018
|
|
|
} |
2019
|
|
|
return ParagonIE_Sodium_Core_Util::hex2bin($string); |
2020
|
|
|
} |
2021
|
|
|
|
2022
|
|
|
/** |
2023
|
|
|
* Increase a string (little endian) |
2024
|
|
|
* |
2025
|
|
|
* @param string $var |
2026
|
|
|
* |
2027
|
|
|
* @return void |
2028
|
|
|
* @throws Error (Unless libsodium is installed) |
2029
|
|
|
*/ |
2030
|
|
|
public static function increment(&$var) |
2031
|
|
|
{ |
2032
|
|
|
/* Type checks: */ |
2033
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1); |
2034
|
|
|
|
2035
|
|
|
if (self::isPhp72OrGreater()) { |
2036
|
|
|
sodium_increment($var); |
2037
|
|
|
return; |
2038
|
|
|
} |
2039
|
|
|
if (self::use_fallback('increment')) { |
2040
|
|
|
@call_user_func('\\Sodium\\increment', $var); |
|
|
|
|
2041
|
|
|
return; |
2042
|
|
|
} |
2043
|
|
|
|
2044
|
|
|
$len = ParagonIE_Sodium_Core_Util::strlen($var); |
2045
|
|
|
$c = 1; |
2046
|
|
|
$copy = ''; |
2047
|
|
|
for ($i = 0; $i < $len; ++$i) { |
2048
|
|
|
$c += ParagonIE_Sodium_Core_Util::chrToInt( |
2049
|
|
|
ParagonIE_Sodium_Core_Util::substr($var, $i, 1) |
2050
|
|
|
); |
2051
|
|
|
$copy .= ParagonIE_Sodium_Core_Util::intToChr($c); |
2052
|
|
|
$c >>= 8; |
2053
|
|
|
} |
2054
|
|
|
$var = $copy; |
2055
|
|
|
} |
2056
|
|
|
|
2057
|
|
|
/** |
2058
|
|
|
* The equivalent to the libsodium minor version we aim to be compatible |
2059
|
|
|
* with (sans pwhash and memzero). |
2060
|
|
|
* |
2061
|
|
|
* @return int |
2062
|
|
|
*/ |
2063
|
|
|
public static function library_version_major() |
2064
|
|
|
{ |
2065
|
|
|
if (self::isPhp72OrGreater()) { |
2066
|
|
|
return sodium_library_version_major(); |
2067
|
|
|
} |
2068
|
|
|
if (self::use_fallback('library_version_major')) { |
2069
|
|
|
return (int) call_user_func('\\Sodium\\library_version_major'); |
2070
|
|
|
} |
2071
|
|
|
return self::LIBRARY_VERSION_MAJOR; |
2072
|
|
|
} |
2073
|
|
|
|
2074
|
|
|
/** |
2075
|
|
|
* The equivalent to the libsodium minor version we aim to be compatible |
2076
|
|
|
* with (sans pwhash and memzero). |
2077
|
|
|
* |
2078
|
|
|
* @return int |
2079
|
|
|
*/ |
2080
|
|
|
public static function library_version_minor() |
2081
|
|
|
{ |
2082
|
|
|
if (self::isPhp72OrGreater()) { |
2083
|
|
|
return sodium_library_version_minor(); |
2084
|
|
|
} |
2085
|
|
|
if (self::use_fallback('library_version_minor')) { |
2086
|
|
|
return (int) call_user_func('\\Sodium\\library_version_minor'); |
2087
|
|
|
} |
2088
|
|
|
return self::LIBRARY_VERSION_MINOR; |
2089
|
|
|
} |
2090
|
|
|
|
2091
|
|
|
/** |
2092
|
|
|
* Compare two strings. |
2093
|
|
|
* |
2094
|
|
|
* @param string $left |
2095
|
|
|
* @param string $right |
2096
|
|
|
* @return int |
2097
|
|
|
* @throws TypeError |
2098
|
|
|
*/ |
2099
|
|
|
public static function memcmp($left, $right) |
2100
|
|
|
{ |
2101
|
|
|
/* Type checks: */ |
2102
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1); |
2103
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2); |
2104
|
|
|
|
2105
|
|
|
if (self::use_fallback('memcmp')) { |
2106
|
|
|
return call_user_func('\\Sodium\\memcmp', $left, $right); |
2107
|
|
|
} |
2108
|
|
|
return ParagonIE_Sodium_Core_Util::memcmp($left, $right); |
2109
|
|
|
} |
2110
|
|
|
|
2111
|
|
|
/** |
2112
|
|
|
* It's actually not possible to zero memory buffers in PHP. You need the |
2113
|
|
|
* native library for that. |
2114
|
|
|
* |
2115
|
|
|
* @param string|null $var |
2116
|
|
|
* |
2117
|
|
|
* @return void |
2118
|
|
|
* @throws Error (Unless libsodium is installed) |
2119
|
|
|
*/ |
2120
|
|
View Code Duplication |
public static function memzero(&$var) |
|
|
|
|
2121
|
|
|
{ |
2122
|
|
|
/* Type checks: */ |
2123
|
|
|
ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1); |
2124
|
|
|
|
2125
|
|
|
if (self::isPhp72OrGreater()) { |
2126
|
|
|
sodium_memzero($var); |
2127
|
|
|
return; |
2128
|
|
|
} |
2129
|
|
|
if (self::use_fallback('memzero')) { |
2130
|
|
|
@call_user_func('\\Sodium\\memzero', $var); |
|
|
|
|
2131
|
|
|
return; |
2132
|
|
|
} |
2133
|
|
|
// This is the best we can do. |
2134
|
|
|
throw new Error( |
2135
|
|
|
'This is not implemented, as it is not possible to securely wipe memory from PHP' |
2136
|
|
|
); |
2137
|
|
|
} |
2138
|
|
|
|
2139
|
|
|
/** |
2140
|
|
|
* Generate a string of bytes from the kernel's CSPRNG. |
2141
|
|
|
* Proudly uses /dev/urandom (if getrandom(2) is not available). |
2142
|
|
|
* |
2143
|
|
|
* @param int $numBytes |
2144
|
|
|
* @return string |
2145
|
|
|
* @throws TypeError |
2146
|
|
|
*/ |
2147
|
|
View Code Duplication |
public static function randombytes_buf($numBytes) |
|
|
|
|
2148
|
|
|
{ |
2149
|
|
|
/* Type checks: */ |
2150
|
|
|
if (!is_int($numBytes)) { |
2151
|
|
|
if (is_numeric($numBytes)) { |
2152
|
|
|
$numBytes = (int)$numBytes; |
2153
|
|
|
} else { |
2154
|
|
|
throw new TypeError('Argument 1 must be an integer, ' . gettype($numBytes) . ' given.'); |
2155
|
|
|
} |
2156
|
|
|
} |
2157
|
|
|
if (self::use_fallback('randombytes_buf')) { |
2158
|
|
|
return call_user_func('\\Sodium\\randombytes_buf', $numBytes); |
2159
|
|
|
} |
2160
|
|
|
return random_bytes($numBytes); |
2161
|
|
|
} |
2162
|
|
|
|
2163
|
|
|
/** |
2164
|
|
|
* Generate an integer between 0 and $range (non-inclusive). |
2165
|
|
|
* |
2166
|
|
|
* @param int $range |
2167
|
|
|
* @return int |
2168
|
|
|
* @throws TypeError |
2169
|
|
|
*/ |
2170
|
|
View Code Duplication |
public static function randombytes_uniform($range) |
|
|
|
|
2171
|
|
|
{ |
2172
|
|
|
/* Type checks: */ |
2173
|
|
|
if (!is_int($range)) { |
2174
|
|
|
if (is_numeric($range)) { |
2175
|
|
|
$range = (int)$range; |
2176
|
|
|
} else { |
2177
|
|
|
throw new TypeError('Argument 1 must be an integer, ' . gettype($range) . ' given.'); |
2178
|
|
|
} |
2179
|
|
|
} |
2180
|
|
|
if (self::use_fallback('randombytes_uniform')) { |
2181
|
|
|
return (int) call_user_func('\\Sodium\\randombytes_uniform', $range); |
2182
|
|
|
} |
2183
|
|
|
return random_int(0, $range - 1); |
2184
|
|
|
} |
2185
|
|
|
|
2186
|
|
|
/** |
2187
|
|
|
* Generate a random 16-bit integer. |
2188
|
|
|
* |
2189
|
|
|
* @return int |
2190
|
|
|
*/ |
2191
|
|
|
public static function randombytes_random16() |
2192
|
|
|
{ |
2193
|
|
|
if (self::use_fallback('randombytes_random16')) { |
2194
|
|
|
return (int) call_user_func('\\Sodium\\randombytes_random16'); |
2195
|
|
|
} |
2196
|
|
|
return random_int(0, 65535); |
2197
|
|
|
} |
2198
|
|
|
|
2199
|
|
|
/** |
2200
|
|
|
* This emulates libsodium's version_string() function, except ours is |
2201
|
|
|
* prefixed with 'polyfill-'. |
2202
|
|
|
* |
2203
|
|
|
* @return string |
2204
|
|
|
*/ |
2205
|
|
|
public static function version_string() |
2206
|
|
|
{ |
2207
|
|
|
if (self::isPhp72OrGreater()) { |
2208
|
|
|
return sodium_version_string(); |
2209
|
|
|
} |
2210
|
|
|
if (self::use_fallback('version_string')) { |
2211
|
|
|
return (string) call_user_func('\\Sodium\\version_string'); |
2212
|
|
|
} |
2213
|
|
|
return self::VERSION_STRING; |
2214
|
|
|
} |
2215
|
|
|
|
2216
|
|
|
/** |
2217
|
|
|
* Should we use the libsodium core function instead? |
2218
|
|
|
* This is always a good idea, if it's available. (Unless we're in the |
2219
|
|
|
* middle of running our unit test suite.) |
2220
|
|
|
* |
2221
|
|
|
* If ext/libsodium is available, use it. Return TRUE. |
2222
|
|
|
* Otherwise, we have to use the code provided herein. Return FALSE. |
2223
|
|
|
* |
2224
|
|
|
* @param string $sodium_func_name |
2225
|
|
|
* |
2226
|
|
|
* @return bool |
2227
|
|
|
*/ |
2228
|
|
|
protected static function use_fallback($sodium_func_name = '') |
2229
|
|
|
{ |
2230
|
|
|
static $res = null; |
2231
|
|
|
if ($res === null) { |
2232
|
|
|
$res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300; |
2233
|
|
|
} |
2234
|
|
|
if (PHP_INT_SIZE === 4) { |
2235
|
|
|
if ($res && is_callable('\\Sodium\\' . $sodium_func_name)) { |
2236
|
|
|
// We can safely just offload to the PECL extension |
2237
|
|
|
return true; |
2238
|
|
|
} |
2239
|
|
|
/* |
|
|
|
|
2240
|
|
|
if (DIRECTORY_SEPARATOR === '\\' && PHP_VERSION_ID < 70000) { |
2241
|
|
|
throw new RuntimeException( |
2242
|
|
|
'Sodium_compat produces incorrect results on systems that do not support 64-bit integers. ' . |
2243
|
|
|
'Please upgrade to PHP 7 or newer for Windows x64 support.' |
2244
|
|
|
); |
2245
|
|
|
} |
2246
|
|
|
throw new RuntimeException( |
2247
|
|
|
'Sodium_compat produces incorrect results on systems that do not support 64-bit integers.' |
2248
|
|
|
); |
2249
|
|
|
*/ |
2250
|
|
|
} |
2251
|
|
|
if ($res === false) { |
2252
|
|
|
// No libsodium installed |
2253
|
|
|
return false; |
2254
|
|
|
} |
2255
|
|
|
if (self::$disableFallbackForUnitTests) { |
2256
|
|
|
// Don't fallback. Use the PHP implementation. |
2257
|
|
|
return false; |
2258
|
|
|
} |
2259
|
|
|
if (!empty($sodium_func_name)) { |
2260
|
|
|
return is_callable('\\Sodium\\' . $sodium_func_name); |
2261
|
|
|
} |
2262
|
|
|
return true; |
2263
|
|
|
} |
2264
|
|
|
|
2265
|
|
|
/** |
2266
|
|
|
* Libsodium as implemented in PHP 7.2 |
2267
|
|
|
* |
2268
|
|
|
* @ref https://wiki.php.net/rfc/libsodium |
2269
|
|
|
* @return bool |
|
|
|
|
2270
|
|
|
*/ |
2271
|
|
|
protected static function isPhp72OrGreater() |
2272
|
|
|
{ |
2273
|
|
|
static $res = null; |
2274
|
|
|
if ($res === null) { |
2275
|
|
|
$res = PHP_VERSION_ID >= 70200 && extension_loaded('sodium'); |
2276
|
|
|
} |
2277
|
|
|
if (self::$disableFallbackForUnitTests) { |
2278
|
|
|
// Don't fallback. Use the PHP implementation. |
2279
|
|
|
return false; |
2280
|
|
|
} |
2281
|
|
|
return $res; |
2282
|
|
|
} |
2283
|
|
|
} |
2284
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.