Cheetah
Jwt.php
Go to the documentation of this file.
1 <?php
2 
3 namespace OAuth2\Encryption;
4 
9 class Jwt implements EncryptionInterface
10 {
11  public function encode($payload, $key, $algo = 'HS256')
12  {
13  $header = $this->generateJwtHeader($payload, $algo);
14 
15  $segments = array(
16  $this->urlSafeB64Encode(json_encode($header)),
17  $this->urlSafeB64Encode(json_encode($payload))
18  );
19 
20  $signing_input = implode('.', $segments);
21 
22  $signature = $this->sign($signing_input, $key, $algo);
23  $segments[] = $this->urlsafeB64Encode($signature);
24 
25  return implode('.', $segments);
26  }
27 
28  public function decode($jwt, $key = null, $allowedAlgorithms = true)
29  {
30  if (!strpos($jwt, '.')) {
31  return false;
32  }
33 
34  $tks = explode('.', $jwt);
35 
36  if (count($tks) != 3) {
37  return false;
38  }
39 
40  list($headb64, $payloadb64, $cryptob64) = $tks;
41 
42  if (null === ($header = json_decode($this->urlSafeB64Decode($headb64), true))) {
43  return false;
44  }
45 
46  if (null === $payload = json_decode($this->urlSafeB64Decode($payloadb64), true)) {
47  return false;
48  }
49 
50  $sig = $this->urlSafeB64Decode($cryptob64);
51 
52  if ((bool) $allowedAlgorithms) {
53  if (!isset($header['alg'])) {
54  return false;
55  }
56 
57  // check if bool arg supplied here to maintain BC
58  if (is_array($allowedAlgorithms) && !in_array($header['alg'], $allowedAlgorithms)) {
59  return false;
60  }
61 
62  if (!$this->verifySignature($sig, "$headb64.$payloadb64", $key, $header['alg'])) {
63  return false;
64  }
65  }
66 
67  return $payload;
68  }
69 
70  private function verifySignature($signature, $input, $key, $algo = 'HS256')
71  {
72  // use constants when possible, for HipHop support
73  switch ($algo) {
74  case'HS256':
75  case'HS384':
76  case'HS512':
77  return $this->hash_equals(
78  $this->sign($input, $key, $algo),
79  $signature
80  );
81 
82  case 'RS256':
83  return openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256') === 1;
84 
85  case 'RS384':
86  return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384') === 1;
87 
88  case 'RS512':
89  return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1;
90 
91  default:
92  throw new \InvalidArgumentException("Unsupported or invalid signing algorithm.");
93  }
94  }
95 
96  private function sign($input, $key, $algo = 'HS256')
97  {
98  switch ($algo) {
99  case 'HS256':
100  return hash_hmac('sha256', $input, $key, true);
101 
102  case 'HS384':
103  return hash_hmac('sha384', $input, $key, true);
104 
105  case 'HS512':
106  return hash_hmac('sha512', $input, $key, true);
107 
108  case 'RS256':
109  return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256');
110 
111  case 'RS384':
112  return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384');
113 
114  case 'RS512':
115  return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512');
116 
117  default:
118  throw new \Exception("Unsupported or invalid signing algorithm.");
119  }
120  }
121 
122  private function generateRSASignature($input, $key, $algo)
123  {
124  if (!openssl_sign($input, $signature, $key, $algo)) {
125  throw new \Exception("Unable to sign data.");
126  }
127 
128  return $signature;
129  }
130 
131  public function urlSafeB64Encode($data)
132  {
133  $b64 = base64_encode($data);
134  $b64 = str_replace(array('+', '/', "\r", "\n", '='),
135  array('-', '_'),
136  $b64);
137 
138  return $b64;
139  }
140 
141  public function urlSafeB64Decode($b64)
142  {
143  $b64 = str_replace(array('-', '_'),
144  array('+', '/'),
145  $b64);
146 
147  return base64_decode($b64);
148  }
149 
153  protected function generateJwtHeader($payload, $algorithm)
154  {
155  return array(
156  'typ' => 'JWT',
157  'alg' => $algorithm,
158  );
159  }
160 
161  protected function hash_equals($a, $b)
162  {
163  if (function_exists('hash_equals')) {
164  return hash_equals($a, $b);
165  }
166  $diff = strlen($a) ^ strlen($b);
167  for ($i = 0; $i < strlen($a) && $i < strlen($b); $i++) {
168  $diff |= ord($a[$i]) ^ ord($b[$i]);
169  }
170 
171  return $diff === 0;
172  }
173 }
OAuth2\Encryption\Jwt\urlSafeB64Encode
urlSafeB64Encode($data)
Definition: Jwt.php:131
OAuth2\Encryption
Definition: EncryptionInterface.php:3
OAuth2\Encryption\Jwt\encode
encode($payload, $key, $algo='HS256')
Definition: Jwt.php:11
php
OAuth2\Encryption\Jwt
Definition: Jwt.php:10
OAuth2\Encryption\Jwt\generateJwtHeader
generateJwtHeader($payload, $algorithm)
Definition: Jwt.php:153
OAuth2\Encryption\Jwt\decode
decode($jwt, $key=null, $allowedAlgorithms=true)
Definition: Jwt.php:28
OAuth2\Encryption\Jwt\urlSafeB64Decode
urlSafeB64Decode($b64)
Definition: Jwt.php:141
OAuth2\Encryption\Jwt\hash_equals
hash_equals($a, $b)
Definition: Jwt.php:161
OAuth2\Encryption\EncryptionInterface
Definition: EncryptionInterface.php:6