1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the tmilos/jose-jwt package. |
5
|
|
|
* |
6
|
|
|
* (c) Milos Tomic <[email protected]> |
7
|
|
|
* |
8
|
|
|
* This source file is subject to the MIT license that is bundled |
9
|
|
|
* with this source code in the file LICENSE. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Tmilos\JoseJwt\Jwe; |
13
|
|
|
|
14
|
|
|
use Tmilos\JoseJwt\Error\JoseJwtException; |
15
|
|
|
use Tmilos\JoseJwt\Random\RandomGenerator; |
16
|
|
|
use Tmilos\JoseJwt\Util\StringUtils; |
17
|
|
|
|
18
|
|
|
class AesKeyWrapAlgorithm implements JweAlgorithm |
19
|
|
|
{ |
20
|
|
|
/** @var int */ |
21
|
|
|
private $kekLengthBits; |
22
|
|
|
|
23
|
|
|
/** @var string */ |
24
|
|
|
private $wrapperClass; |
25
|
|
|
|
26
|
|
|
/** @var array */ |
27
|
|
|
private static $wrapperMap = [ |
28
|
|
|
128 => 'AESKW\A128KW', |
29
|
|
|
192 => 'AESKW\A192KW', |
30
|
|
|
256 => 'AESKW\A256KW', |
31
|
|
|
]; |
32
|
|
|
|
33
|
|
|
/** @var RandomGenerator */ |
34
|
|
|
private $randomGenerator; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @param int $keySize |
38
|
|
|
* @param RandomGenerator $randomGenerator |
39
|
|
|
*/ |
40
|
|
|
public function __construct($keySize, RandomGenerator $randomGenerator) |
41
|
|
|
{ |
42
|
|
|
$this->randomGenerator = $randomGenerator; |
43
|
|
|
$this->kekLengthBits = $keySize; |
44
|
|
|
if (false === array_key_exists($keySize, self::$wrapperMap)) { |
45
|
|
|
throw new JoseJwtException(sprintf('Invalid kek key size "%s"', $keySize)); |
46
|
|
|
} else { |
47
|
|
|
$this->wrapperClass = self::$wrapperMap[$keySize]; |
48
|
|
|
} |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @param int $cekSizeBits |
53
|
|
|
* @param string|resource $kek |
54
|
|
|
* @param array $header |
55
|
|
|
* |
56
|
|
|
* @return array [cek, encryptedCek] |
57
|
|
|
*/ |
58
|
|
|
public function wrapNewKey($cekSizeBits, $kek, array $header) |
59
|
|
|
{ |
60
|
|
|
$kekLen = StringUtils::length($kek); |
|
|
|
|
61
|
|
View Code Duplication |
if ($kekLen * 8 != $this->kekLengthBits) { |
|
|
|
|
62
|
|
|
throw new JoseJwtException(sprintf('AesKeyWrap management algorithm expected key of size %s bits, but was given %s bits', $this->kekLengthBits, $kekLen * 8)); |
63
|
|
|
} |
64
|
|
|
if ($cekSizeBits % 8 != 0) { |
65
|
|
|
throw new JoseJwtException('CekSizeBits must be divisible by 8'); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
$cek = $this->randomGenerator->get($cekSizeBits / 8); |
69
|
|
|
|
70
|
|
|
$encryptedCek = $this->aesWrap($kek, $cek); |
|
|
|
|
71
|
|
|
|
72
|
|
|
return [$cek, $encryptedCek]; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @param string $encryptedCek |
77
|
|
|
* @param string $kek |
78
|
|
|
* @param int $cekSizeBits |
79
|
|
|
* @param array $header |
80
|
|
|
* |
81
|
|
|
* @return string |
82
|
|
|
*/ |
83
|
|
|
public function unwrap($encryptedCek, $kek, $cekSizeBits, array $header) |
84
|
|
|
{ |
85
|
|
|
$kekLen = StringUtils::length($kek); |
86
|
|
View Code Duplication |
if ($kekLen * 8 != $this->kekLengthBits) { |
|
|
|
|
87
|
|
|
throw new JoseJwtException(sprintf('AesKeyWrap management algorithm expected key of size %s bits, but was given %s bits', $this->kekLengthBits, $kekLen * 8)); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
return $this->aesUnwrap($kek, $encryptedCek); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @param string $kek |
95
|
|
|
* @param string $key |
96
|
|
|
* |
97
|
|
|
* @return string |
98
|
|
|
*/ |
99
|
|
|
private function aesWrap($kek, $key) |
100
|
|
|
{ |
101
|
|
|
return call_user_func([$this->wrapperClass, 'wrap'], $kek, $key); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* @param string $kek |
106
|
|
|
* @param string $wrappedKey |
107
|
|
|
* |
108
|
|
|
* @return string |
109
|
|
|
*/ |
110
|
|
|
private function aesUnwrap($kek, $wrappedKey) |
111
|
|
|
{ |
112
|
|
|
return call_user_func([$this->wrapperClass, 'unwrap'], $kek, $wrappedKey); |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.