3
3
namespace Firebase \JWT ;
4
4
5
5
use DomainException ;
6
+ use Exception ;
6
7
use InvalidArgumentException ;
7
8
use UnexpectedValueException ;
8
9
use DateTime ;
@@ -50,6 +51,7 @@ class JWT
50
51
'RS256 ' => array ('openssl ' , 'SHA256 ' ),
51
52
'RS384 ' => array ('openssl ' , 'SHA384 ' ),
52
53
'RS512 ' => array ('openssl ' , 'SHA512 ' ),
54
+ 'EdDSA ' => array ('sodium_crypto ' , 'EdDSA ' ),
53
55
);
54
56
55
57
/**
@@ -198,7 +200,7 @@ public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $he
198
200
*
199
201
* @return string An encrypted message
200
202
*
201
- * @throws DomainException Unsupported algorithm was specified
203
+ * @throws DomainException Unsupported algorithm or bad key was specified
202
204
*/
203
205
public static function sign ($ msg , $ key , $ alg = 'HS256 ' )
204
206
{
@@ -214,14 +216,24 @@ public static function sign($msg, $key, $alg = 'HS256')
214
216
$ success = \openssl_sign ($ msg , $ signature , $ key , $ algorithm );
215
217
if (!$ success ) {
216
218
throw new DomainException ("OpenSSL unable to sign data " );
217
- } else {
218
- if ($ alg === 'ES256 ' ) {
219
- $ signature = self ::signatureFromDER ($ signature , 256 );
220
- }
221
- if ($ alg === 'ES384 ' ) {
222
- $ signature = self ::signatureFromDER ($ signature , 384 );
223
- }
224
- return $ signature ;
219
+ }
220
+ if ($ alg === 'ES256 ' ) {
221
+ $ signature = self ::signatureFromDER ($ signature , 256 );
222
+ } elseif ($ alg === 'ES384 ' ) {
223
+ $ signature = self ::signatureFromDER ($ signature , 384 );
224
+ }
225
+ return $ signature ;
226
+ case 'sodium_crypto ' :
227
+ if (!function_exists ('sodium_crypto_sign_detached ' )) {
228
+ throw new DomainException ('libsodium is not available ' );
229
+ }
230
+ try {
231
+ // The last non-empty line is used as the key.
232
+ $ lines = array_filter (explode ("\n" , $ key ));
233
+ $ key = base64_decode (end ($ lines ));
234
+ return sodium_crypto_sign_detached ($ msg , $ key );
235
+ } catch (Exception $ e ) {
236
+ throw new DomainException ($ e ->getMessage (), 0 , $ e );
225
237
}
226
238
}
227
239
}
@@ -237,7 +249,7 @@ public static function sign($msg, $key, $alg = 'HS256')
237
249
*
238
250
* @return bool
239
251
*
240
- * @throws DomainException Invalid Algorithm or OpenSSL failure
252
+ * @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure
241
253
*/
242
254
private static function verify ($ msg , $ signature , $ key , $ alg )
243
255
{
@@ -258,6 +270,18 @@ private static function verify($msg, $signature, $key, $alg)
258
270
throw new DomainException (
259
271
'OpenSSL error: ' . \openssl_error_string ()
260
272
);
273
+ case 'sodium_crypto ' :
274
+ if (!function_exists ('sodium_crypto_sign_verify_detached ' )) {
275
+ throw new DomainException ('libsodium is not available ' );
276
+ }
277
+ try {
278
+ // The last non-empty line is used as the key.
279
+ $ lines = array_filter (explode ("\n" , $ key ));
280
+ $ key = base64_decode (end ($ lines ));
281
+ return sodium_crypto_sign_verify_detached ($ signature , $ msg , $ key );
282
+ } catch (Exception $ e ) {
283
+ throw new DomainException ($ e ->getMessage (), 0 , $ e );
284
+ }
261
285
case 'hash_hmac ' :
262
286
default :
263
287
$ hash = \hash_hmac ($ algorithm , $ msg , $ key , true );
0 commit comments