JWT Framework
Search…
Custom Algorithm
This framework provides dozens of signature or encryption algorithms. If your application uses a custom algorithm or if another algorithm has been recently approved in the JWT context, it may be interesting to use it with this framework.
Hopefully, this is very easy. In the following example, we will create a class to use the ChaCha20 + Poly 1305 (IETF variant) encryption algorithm as a Key Encryption Algorithm.
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Acme\Algorithm;
6
7
use Base64Url\Base64Url;
8
use Jose\Component\Core\JWK;
9
use const Sodium\CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES;
10
11
/**
12
* This algorithm is a custom algorithm that use the ChaCha20 + Poly 1305 with a 192 bits nonce (IETF variant).
13
*/
14
final class ChaCha20Poly1305IETF implements KeyEncryption //The algorithm acts as a Key Encryption algorithm
15
{
16
/**
17
* {@inheritdoc}
18
*/
19
public function name(): string
20
{
21
return 'ChaCha20+Poly1305+IETF'; // The name of our algorithm. This name will be used in our JWE headers
22
}
23
24
/**
25
* {@inheritdoc}
26
*/
27
public function allowedKeyTypes(): array
28
{
29
return ['oct']; // Key types for this algorithm are octet keys
30
}
31
32
/**
33
* {@inheritdoc}
34
*/
35
public function encryptKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string
36
{
37
$this->checkKey($key); // We check the key
38
$kek = Base64Url::decode($key->get('k')); // We retrieve the secret
39
$nonce = random_bytes(CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES); // We create a nonce
40
$additionalHeader['nonce'] = Base64Url::encode($nonce); // We add the nonce to the header
41
42
return sodium_crypto_aead_chacha20poly1305_ietf_encrypt($cek, '', $nonce, $kek); // We return the encrypted CEK
43
}
44
45
/**
46
* {@inheritdoc}
47
*/
48
public function decryptKey(JWK $key, string $encrypted_cek, array $header): string
49
{
50
$this->checkKey($key); // We check the key
51
$this->checkAdditionalParameters($header); // We verify the nonce is in the headers
52
$nonce = Base64Url::decode($header['nonce']); // We retrieve the nonce
53
$kek = Base64Url::decode($key->get('k')); // an the secret
54
55
$decrypted = sodium_crypto_aead_chacha20poly1305_ietf_decrypt($encrypted_cek, '', $nonce, $kek); // We try to decrypt the CEK
56
if (false === $decrypted) { // If it fails we throw an exception
57
throw new \RuntimeException('Unable to decrypt.');
58
}
59
60
return $decrypted; // Otherwise we return the decrypted CEK
61
}
62
63
/**
64
* @param JWK $key
65
*/
66
protected function checkKey(JWK $key)
67
{
68
if (!in_array($key->get('kty'), $this->allowedKeyTypes())) {
69
throw new \InvalidArgumentException('Wrong key type.');
70
}
71
if (!$key->has('k')) {
72
throw new \InvalidArgumentException('The key parameter "k" is missing.');
73
}
74
}
75
76
/**
77
* @param array $header
78
*/
79
protected function checkAdditionalParameters(array $header)
80
{
81
foreach (['nonce'] as $k) {
82
if (!array_key_exists($k, $header)) {
83
throw new \InvalidArgumentException(sprintf('Parameter "%s" is missing.', $k));
84
}
85
}
86
}
87
88
/**
89
* {@inheritdoc}
90
*/
91
public function getKeyManagementMode(): string
92
{
93
return self::MODE_ENCRYPT; //Key Management Mode is 'enc'.
94
}
95
}
Copied!
Last modified 3yr ago
Copy link