@@ -27,19 +27,19 @@ class Encryption
27
27
* @return string padded payload (plaintext)
28
28
* @throws \ErrorException
29
29
*/
30
- public static function padPayload (string $ payload , int $ maxLengthToPad , string $ contentEncoding ): string
30
+ public static function padPayload (string $ payload , int $ maxLengthToPad , ContentEncoding $ contentEncoding ): string
31
31
{
32
32
$ payloadLen = Utils::safeStrlen ($ payload );
33
33
$ padLen = $ maxLengthToPad ? $ maxLengthToPad - $ payloadLen : 0 ;
34
34
35
- if ($ contentEncoding === " aesgcm " ) {
35
+ if ($ contentEncoding === ContentEncoding:: aesgcm) {
36
36
return pack ('n* ' , $ padLen ).str_pad ($ payload , $ padLen + $ payloadLen , chr (0 ), STR_PAD_LEFT );
37
37
}
38
- if ($ contentEncoding === " aes128gcm " ) {
38
+ if ($ contentEncoding === ContentEncoding:: aes128gcm) {
39
39
return str_pad ($ payload .chr (2 ), $ padLen + $ payloadLen , chr (0 ), STR_PAD_RIGHT );
40
40
}
41
41
42
- throw new \ErrorException ("This content encoding is not supported: " . $ contentEncoding );
42
+ throw new \ErrorException ("This content encoding is not implemented. " );
43
43
}
44
44
45
45
/**
@@ -49,7 +49,7 @@ public static function padPayload(string $payload, int $maxLengthToPad, string $
49
49
*
50
50
* @throws \ErrorException
51
51
*/
52
- public static function encrypt (string $ payload , string $ userPublicKey , string $ userAuthToken , string $ contentEncoding ): array
52
+ public static function encrypt (string $ payload , string $ userPublicKey , string $ userAuthToken , ContentEncoding $ contentEncoding ): array
53
53
{
54
54
return self ::deterministicEncrypt (
55
55
$ payload ,
@@ -64,8 +64,14 @@ public static function encrypt(string $payload, string $userPublicKey, string $u
64
64
/**
65
65
* @throws \RuntimeException
66
66
*/
67
- public static function deterministicEncrypt (string $ payload , string $ userPublicKey , string $ userAuthToken , string $ contentEncoding , array $ localKeyObject , string $ salt ): array
68
- {
67
+ public static function deterministicEncrypt (
68
+ string $ payload ,
69
+ string $ userPublicKey ,
70
+ string $ userAuthToken ,
71
+ ContentEncoding $ contentEncoding ,
72
+ array $ localKeyObject ,
73
+ string $ salt
74
+ ): array {
69
75
$ userPublicKey = Base64Url::decode ($ userPublicKey );
70
76
$ userAuthToken = Base64Url::decode ($ userAuthToken );
71
77
@@ -112,7 +118,7 @@ public static function deterministicEncrypt(string $payload, string $userPublicK
112
118
$ context = self ::createContext ($ userPublicKey , $ localPublicKey , $ contentEncoding );
113
119
114
120
// derive the Content Encryption Key
115
- $ contentEncryptionKeyInfo = self ::createInfo ($ contentEncoding , $ context , $ contentEncoding );
121
+ $ contentEncryptionKeyInfo = self ::createInfo ($ contentEncoding-> value , $ context , $ contentEncoding );
116
122
$ contentEncryptionKey = self ::hkdf ($ salt , $ ikm , $ contentEncryptionKeyInfo , 16 );
117
123
118
124
// section 3.3, derive the nonce
@@ -132,16 +138,19 @@ public static function deterministicEncrypt(string $payload, string $userPublicK
132
138
];
133
139
}
134
140
135
- public static function getContentCodingHeader (string $ salt , string $ localPublicKey , string $ contentEncoding ): string
141
+ public static function getContentCodingHeader (string $ salt , string $ localPublicKey , ContentEncoding $ contentEncoding ): string
136
142
{
137
- if ($ contentEncoding === "aes128gcm " ) {
143
+ if ($ contentEncoding === ContentEncoding::aesgcm) {
144
+ return "" ;
145
+ }
146
+ if ($ contentEncoding === ContentEncoding::aes128gcm) {
138
147
return $ salt
139
148
.pack ('N* ' , 4096 )
140
149
.pack ('C* ' , Utils::safeStrlen ($ localPublicKey ))
141
150
.$ localPublicKey ;
142
151
}
143
152
144
- return "" ;
153
+ throw new \ ValueError ( " This content encoding is not implemented. " ) ;
145
154
}
146
155
147
156
/**
@@ -182,19 +191,19 @@ private static function hkdf(string $salt, string $ikm, string $info, int $lengt
182
191
*
183
192
* @throws \ErrorException
184
193
*/
185
- private static function createContext (string $ clientPublicKey , string $ serverPublicKey , string $ contentEncoding ): ?string
194
+ private static function createContext (string $ clientPublicKey , string $ serverPublicKey , ContentEncoding $ contentEncoding ): ?string
186
195
{
187
- if ($ contentEncoding === " aes128gcm " ) {
196
+ if ($ contentEncoding === ContentEncoding:: aes128gcm) {
188
197
return null ;
189
198
}
190
199
191
200
if (Utils::safeStrlen ($ clientPublicKey ) !== 65 ) {
192
- throw new \ErrorException ('Invalid client public key length ' );
201
+ throw new \ErrorException ('Invalid client public key length. ' );
193
202
}
194
203
195
204
// This one should never happen, because it's our code that generates the key
196
205
if (Utils::safeStrlen ($ serverPublicKey ) !== 65 ) {
197
- throw new \ErrorException ('Invalid server public key length ' );
206
+ throw new \ErrorException ('Invalid server public key length. ' );
198
207
}
199
208
200
209
$ len = chr (0 ).'A ' ; // 65 as Uint16BE
@@ -212,25 +221,25 @@ private static function createContext(string $clientPublicKey, string $serverPub
212
221
*
213
222
* @throws \ErrorException
214
223
*/
215
- private static function createInfo (string $ type , ?string $ context , string $ contentEncoding ): string
224
+ private static function createInfo (string $ type , ?string $ context , ContentEncoding $ contentEncoding ): string
216
225
{
217
- if ($ contentEncoding === " aesgcm " ) {
226
+ if ($ contentEncoding === ContentEncoding:: aesgcm) {
218
227
if (!$ context ) {
219
- throw new \ErrorException ('Context must exist ' );
228
+ throw new \ValueError ('Context must exist. ' );
220
229
}
221
230
222
231
if (Utils::safeStrlen ($ context ) !== 135 ) {
223
- throw new \ErrorException ('Context argument has invalid size ' );
232
+ throw new \ValueError ('Context argument has invalid size. ' );
224
233
}
225
234
226
235
return 'Content-Encoding: ' .$ type .chr (0 ).'P-256 ' .$ context ;
227
236
}
228
237
229
- if ($ contentEncoding === " aes128gcm " ) {
238
+ if ($ contentEncoding === ContentEncoding:: aes128gcm) {
230
239
return 'Content-Encoding: ' .$ type .chr (0 );
231
240
}
232
241
233
- throw new \ErrorException ('This content encoding is not supported . ' );
242
+ throw new \ErrorException ('This content encoding is not implemented . ' );
234
243
}
235
244
236
245
private static function createLocalKeyObject (): array
@@ -262,17 +271,18 @@ private static function createLocalKeyObject(): array
262
271
/**
263
272
* @throws \ValueError
264
273
*/
265
- private static function getIKM (string $ userAuthToken , string $ userPublicKey , string $ localPublicKey , string $ sharedSecret , string $ contentEncoding ): string
274
+ private static function getIKM (string $ userAuthToken , string $ userPublicKey , string $ localPublicKey , string $ sharedSecret , ContentEncoding $ contentEncoding ): string
266
275
{
267
276
if (empty ($ userAuthToken )) {
268
277
return $ sharedSecret ;
269
278
}
270
- if ($ contentEncoding === "aesgcm " ) {
279
+
280
+ if ($ contentEncoding === ContentEncoding::aesgcm) {
271
281
$ info = 'Content-Encoding: auth ' .chr (0 );
272
- } elseif ($ contentEncoding === " aes128gcm " ) {
282
+ } elseif ($ contentEncoding === ContentEncoding:: aes128gcm) {
273
283
$ info = "WebPush: info " .chr (0 ).$ userPublicKey .$ localPublicKey ;
274
284
} else {
275
- throw new \ValueError ("This content encoding is not supported . " );
285
+ throw new \ValueError ("This content encoding is not implemented . " );
276
286
}
277
287
278
288
return self ::hkdf ($ userAuthToken , $ sharedSecret , $ info , 32 );
0 commit comments