GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 742f4d...25024f )
by Joni
05:42
created

AESGCMKWAlgorithm   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 12
c 1
b 0
f 1
lcom 1
cbo 9
dl 0
loc 163
ccs 41
cts 41
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
_getGCMCipher() 0 1 ?
_keySize() 0 1 ?
A _getGCM() 0 3 1
A __construct() 0 10 3
A fromJWK() 0 13 3
A fromKey() 0 4 1
A _encryptKey() 0 8 1
A _decryptKey() 0 10 2
A headerParameters() 0 5 1
1
<?php
2
3
namespace JWX\JWE\KeyAlgorithm;
4
5
use GCM\Cipher\Cipher;
6
use GCM\GCM;
7
use JWX\JWA\JWA;
8
use JWX\JWE\KeyAlgorithm\Feature\RandomCEK;
9
use JWX\JWE\KeyManagementAlgorithm;
10
use JWX\JWK\JWK;
11
use JWX\JWK\Symmetric\SymmetricKeyJWK;
12
use JWX\JWT\Header\Header;
13
use JWX\JWT\Parameter\AlgorithmParameter;
14
use JWX\JWT\Parameter\AuthenticationTagParameter;
15
use JWX\JWT\Parameter\InitializationVectorParameter;
16
use JWX\JWT\Parameter\JWTParameter;
17
18
19
/**
20
 * Base class for AES GCM key encryption algorithms.
21
 *
22
 * @link https://tools.ietf.org/html/rfc7518#section-4.7
23
 */
24
abstract class AESGCMKWAlgorithm extends KeyManagementAlgorithm
25
{
26
	use RandomCEK;
27
	
28
	/**
29
	 * Key encryption key.
30
	 *
31
	 * @var string $_kek
32
	 */
33
	protected $_kek;
34
	
35
	/**
36
	 * Initialization vector.
37
	 *
38
	 * @var string $_iv
39
	 */
40
	protected $_iv;
41
	
42
	/**
43
	 * Mapping from algorithm name to class name.
44
	 *
45
	 * @internal
46
	 *
47
	 * @var array
48
	 */
49
	const MAP_ALGO_TO_CLASS = array(
50
		/* @formatter:off */
51
		JWA::ALGO_A128GCMKW => A128GCMKWAlgorithm::class, 
52
		JWA::ALGO_A192GCMKW => A192GCMKWAlgorithm::class, 
53
		JWA::ALGO_A256GCMKW => A256GCMKWAlgorithm::class
54
		/* @formatter:on */
55
	);
56
	
57
	/**
58
	 * Required IV size in bytes.
59
	 *
60
	 * @var int
61
	 */
62
	const IV_SIZE = 12;
63
	
64
	/**
65
	 * Authentication tag size in bytes.
66
	 *
67
	 * @var int
68
	 */
69
	const AUTH_TAG_SIZE = 16;
70
	
71
	/**
72
	 * Get GCM Cipher instance.
73
	 *
74
	 * @return Cipher
75
	 */
76
	abstract protected function _getGCMCipher();
77
	
78
	/**
79
	 * Get the required key size.
80
	 *
81
	 * @return int
82
	 */
83
	abstract protected function _keySize();
84
	
85
	/**
86
	 * Get GCM instance.
87
	 *
88
	 * @return GCM
89
	 */
90 9
	final protected function _getGCM() {
91 9
		return new GCM($this->_getGCMCipher(), self::AUTH_TAG_SIZE);
92
	}
93
	
94
	/**
95
	 * Constructor
96
	 *
97
	 * @param string $kek Key encryption key
98
	 * @param string $iv Initialization vector
99
	 */
100 14
	public function __construct($kek, $iv) {
101 14
		if (strlen($kek) != $this->_keySize()) {
102 3
			throw new \LengthException("Invalid key size.");
103
		}
104 11
		if (strlen($iv) != self::IV_SIZE) {
105 1
			throw new \LengthException("Initialization vector must be 96 bits.");
106
		}
107 10
		$this->_kek = $kek;
108 10
		$this->_iv = $iv;
109 10
	}
110
	
111
	/**
112
	 *
113
	 * @param JWK $jwk
114
	 * @param Header $header
115
	 * @throws \UnexpectedValueException
116
	 * @return AESGCMKWAlgorithm
117
	 */
118 7
	public static function fromJWK(JWK $jwk, Header $header) {
119 7
		$jwk = SymmetricKeyJWK::fromJWK($jwk);
120 7
		if (!$header->hasInitializationVector()) {
121 1
			throw new \UnexpectedValueException("No initialization vector.");
122
		}
123 6
		$iv = $header->initializationVector()->initializationVector();
124 6
		$alg = JWA::deriveAlgorithmName($header, $jwk);
125 5
		if (!array_key_exists($alg, self::MAP_ALGO_TO_CLASS)) {
126 1
			throw new \UnexpectedValueException("Unsupported algorithm '$alg'.");
127
		}
128 4
		$cls = self::MAP_ALGO_TO_CLASS[$alg];
129 4
		return new $cls($jwk->key(), $iv);
130
	}
131
	
132
	/**
133
	 * Initialize from key encryption key with random IV.
134
	 *
135
	 * Key size must match the underlying cipher.
136
	 *
137
	 * @param string $key Key encryption key
138
	 * @return self
139
	 */
140 1
	public static function fromKey($key) {
141 1
		$iv = openssl_random_pseudo_bytes(self::IV_SIZE);
142 1
		return new static($key, $iv);
143
	}
144
	
145
	/**
146
	 *
147
	 * @see \JWX\JWE\KeyManagementAlgorithm::_encryptKey()
148
	 * @return string
149
	 */
150 5
	protected function _encryptKey($key, Header &$header) {
151 5
		list($ciphertext, $auth_tag) = $this->_getGCM()->encrypt($key, "", 
152 5
			$this->_kek, $this->_iv);
153
		// insert authentication tag to the header
154 5
		$header = $header->withParameters(
155 5
			AuthenticationTagParameter::fromString($auth_tag));
156 5
		return $ciphertext;
157
	}
158
	
159
	/**
160
	 *
161
	 * @see \JWX\JWE\KeyManagementAlgorithm::_decryptKey()
162
	 * @throws \RuntimeException For generic errors
163
	 * @return string
164
	 */
165 5
	protected function _decryptKey($ciphertext, Header $header) {
166 5
		if (!$header->hasAuthenticationTag()) {
167 1
			throw new \RuntimeException(
168 1
				"Header doesn't contain authentication tag.");
169
		}
170 4
		$auth_tag = $header->authenticationTag()->authenticationTag();
171 4
		$cek = $this->_getGCM()->decrypt($ciphertext, $auth_tag, "", 
172 4
			$this->_kek, $this->_iv);
173 4
		return $cek;
174
	}
175
	
176
	/**
177
	 *
178
	 * @see \JWX\JWE\KeyManagementAlgorithm::headerParameters()
179
	 * @return JWTParameter[]
180
	 */
181 2
	public function headerParameters() {
182 2
		return array_merge(parent::headerParameters(), 
183 2
			array(AlgorithmParameter::fromAlgorithm($this), 
184 2
				InitializationVectorParameter::fromString($this->_iv)));
185
	}
186
}
187