Skip to content

Commit 1fe7ca8

Browse files
authored
Add Base64UrlSafe utility and refactor code references (#576)
* Add Base64UrlSafe utility and refactor code references This commit adds the utility `Base64UrlSafe` to provide methods for encoding and decoding in Base64UrlSafe format. Simultaneously, the commit also updates multiple files across the library to use this utility instead of the previously used `ParagonIE\ConstantTime\Base64UrlSafe`. This change will ensure consistent use of this utility throughout the project, promoting maintainability and ease of updating in the future, if required.
1 parent 4a05eb0 commit 1fe7ca8

File tree

73 files changed

+581
-85
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+581
-85
lines changed

phpstan-baseline.neon

+294-14
Large diffs are not rendered by default.

src/Experimental/KeyEncryption/AESCTR.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
use InvalidArgumentException;
88
use Jose\Component\Core\JWK;
9+
use Jose\Component\Core\Util\Base64UrlSafe;
910
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyEncryption;
10-
use ParagonIE\ConstantTime\Base64UrlSafe;
1111
use RuntimeException;
1212
use function in_array;
1313
use function is_string;

src/Experimental/KeyEncryption/Chacha20Poly1305.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
use InvalidArgumentException;
88
use Jose\Component\Core\JWK;
9+
use Jose\Component\Core\Util\Base64UrlSafe;
910
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyEncryption;
1011
use LogicException;
11-
use ParagonIE\ConstantTime\Base64UrlSafe;
1212
use RuntimeException;
1313
use function in_array;
1414
use function is_string;

src/Experimental/Signature/Blake2b.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
use InvalidArgumentException;
88
use Jose\Component\Core\JWK;
9+
use Jose\Component\Core\Util\Base64UrlSafe;
910
use Jose\Component\Signature\Algorithm\MacAlgorithm;
10-
use ParagonIE\ConstantTime\Base64UrlSafe;
1111
use RuntimeException;
1212
use function extension_loaded;
1313
use function in_array;

src/Library/Console/GeneratorCommand.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace Jose\Component\Console;
66

77
use InvalidArgumentException;
8+
use Jose\Component\Core\Util\Base64UrlSafe;
89
use Jose\Component\KeyManagement\JWKFactory;
9-
use ParagonIE\ConstantTime\Base64UrlSafe;
1010
use Symfony\Component\Console\Input\InputInterface;
1111
use Symfony\Component\Console\Input\InputOption;
1212
use function is_bool;

src/Library/Core/JWK.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace Jose\Component\Core;
66

77
use InvalidArgumentException;
8+
use Jose\Component\Core\Util\Base64UrlSafe;
89
use JsonSerializable;
9-
use ParagonIE\ConstantTime\Base64UrlSafe;
1010
use function array_key_exists;
1111
use function in_array;
1212
use function is_array;
+218
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jose\Component\Core\Util;
6+
7+
/**
8+
* Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
9+
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
10+
*
11+
* Permission is hereby granted, free of charge, to any person obtaining a copy
12+
* of this software and associated documentation files (the "Software"), to deal
13+
* in the Software without restriction, including without limitation the rights
14+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15+
* copies of the Software, and to permit persons to whom the Software is
16+
* furnished to do so, subject to the following conditions:
17+
*
18+
* The above copyright notice and this permission notice shall be included in all
19+
* copies or substantial portions of the Software.
20+
*
21+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27+
* SOFTWARE.
28+
*/
29+
30+
/**
31+
* @readonly
32+
*/
33+
final class Base64UrlSafe
34+
{
35+
public static function encode(string $binString): string
36+
{
37+
return static::doEncode($binString, true);
38+
}
39+
40+
public static function encodeUnpadded(string $src): string
41+
{
42+
return static::doEncode($src, false);
43+
}
44+
45+
public static function decode(string $encodedString, bool $strictPadding = false): string
46+
{
47+
$srcLen = self::safeStrlen($encodedString);
48+
if ($srcLen === 0) {
49+
return '';
50+
}
51+
52+
if ($strictPadding) {
53+
if (($srcLen & 3) === 0) {
54+
if ($encodedString[$srcLen - 1] === '=') {
55+
$srcLen--;
56+
if ($encodedString[$srcLen - 1] === '=') {
57+
$srcLen--;
58+
}
59+
}
60+
}
61+
if (($srcLen & 3) === 1) {
62+
throw new RangeException('Incorrect padding');
63+
}
64+
if ($encodedString[$srcLen - 1] === '=') {
65+
throw new RangeException('Incorrect padding');
66+
}
67+
} else {
68+
$encodedString = rtrim($encodedString, '=');
69+
$srcLen = self::safeStrlen($encodedString);
70+
}
71+
72+
$err = 0;
73+
$dest = '';
74+
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
75+
/** @var array<int, int> $chunk */
76+
$chunk = unpack('C*', self::safeSubstr($encodedString, $i, 4));
77+
$c0 = static::decode6Bits($chunk[1]);
78+
$c1 = static::decode6Bits($chunk[2]);
79+
$c2 = static::decode6Bits($chunk[3]);
80+
$c3 = static::decode6Bits($chunk[4]);
81+
82+
$dest .= pack(
83+
'CCC',
84+
((($c0 << 2) | ($c1 >> 4)) & 0xff),
85+
((($c1 << 4) | ($c2 >> 2)) & 0xff),
86+
((($c2 << 6) | $c3) & 0xff)
87+
);
88+
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
89+
}
90+
91+
if ($i < $srcLen) {
92+
/** @var array<int, int> $chunk */
93+
$chunk = unpack('C*', self::safeSubstr($encodedString, $i, $srcLen - $i));
94+
$c0 = static::decode6Bits($chunk[1]);
95+
96+
if ($i + 2 < $srcLen) {
97+
$c1 = static::decode6Bits($chunk[2]);
98+
$c2 = static::decode6Bits($chunk[3]);
99+
$dest .= pack('CC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff));
100+
$err |= ($c0 | $c1 | $c2) >> 8;
101+
if ($strictPadding) {
102+
$err |= ($c2 << 6) & 0xff;
103+
}
104+
} elseif ($i + 1 < $srcLen) {
105+
$c1 = static::decode6Bits($chunk[2]);
106+
$dest .= pack('C', ((($c0 << 2) | ($c1 >> 4)) & 0xff));
107+
$err |= ($c0 | $c1) >> 8;
108+
if ($strictPadding) {
109+
$err |= ($c1 << 4) & 0xff;
110+
}
111+
} elseif ($strictPadding) {
112+
$err |= 1;
113+
}
114+
}
115+
$check = ($err === 0);
116+
if (! $check) {
117+
throw new RangeException('Base64::decode() only expects characters in the correct base64 alphabet');
118+
}
119+
return $dest;
120+
}
121+
122+
public static function decodeNoPadding(string $encodedString): string
123+
{
124+
$srcLen = self::safeStrlen($encodedString);
125+
if ($srcLen === 0) {
126+
return '';
127+
}
128+
if (($srcLen & 3) === 0) {
129+
if ($encodedString[$srcLen - 1] === '=') {
130+
throw new InvalidArgumentException("decodeNoPadding() doesn't tolerate padding");
131+
}
132+
if (($srcLen & 3) > 1) {
133+
if ($encodedString[$srcLen - 2] === '=') {
134+
throw new InvalidArgumentException("decodeNoPadding() doesn't tolerate padding");
135+
}
136+
}
137+
}
138+
return static::decode($encodedString, true);
139+
}
140+
141+
private static function doEncode(string $src, bool $pad = true): string
142+
{
143+
$dest = '';
144+
$srcLen = self::safeStrlen($src);
145+
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
146+
/** @var array<int, int> $chunk */
147+
$chunk = unpack('C*', self::safeSubstr($src, $i, 3));
148+
$b0 = $chunk[1];
149+
$b1 = $chunk[2];
150+
$b2 = $chunk[3];
151+
152+
$dest .=
153+
static::encode6Bits($b0 >> 2) .
154+
static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
155+
static::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
156+
static::encode6Bits($b2 & 63);
157+
}
158+
159+
if ($i < $srcLen) {
160+
/** @var array<int, int> $chunk */
161+
$chunk = unpack('C*', self::safeSubstr($src, $i, $srcLen - $i));
162+
$b0 = $chunk[1];
163+
if ($i + 1 < $srcLen) {
164+
$b1 = $chunk[2];
165+
$dest .=
166+
static::encode6Bits($b0 >> 2) .
167+
static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
168+
static::encode6Bits(($b1 << 2) & 63);
169+
if ($pad) {
170+
$dest .= '=';
171+
}
172+
} else {
173+
$dest .=
174+
static::encode6Bits($b0 >> 2) .
175+
static::encode6Bits(($b0 << 4) & 63);
176+
if ($pad) {
177+
$dest .= '==';
178+
}
179+
}
180+
}
181+
return $dest;
182+
}
183+
184+
private static function decode6Bits(int $src): int
185+
{
186+
$ret = -1;
187+
$ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
188+
$ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);
189+
$ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);
190+
$ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63;
191+
192+
return $ret + ((((0x5e - $src) & ($src - 0x60)) >> 8) & 64);
193+
}
194+
195+
private static function encode6Bits(int $src): string
196+
{
197+
$diff = 0x41;
198+
$diff += ((25 - $src) >> 8) & 6;
199+
$diff -= ((51 - $src) >> 8) & 75;
200+
$diff -= ((61 - $src) >> 8) & 13;
201+
$diff += ((62 - $src) >> 8) & 49;
202+
203+
return pack('C', $src + $diff);
204+
}
205+
206+
private static function safeStrlen(string $str): int
207+
{
208+
return mb_strlen($str, '8bit');
209+
}
210+
211+
private static function safeSubstr(string $str, int $start = 0, $length = null): string
212+
{
213+
if ($length === 0) {
214+
return '';
215+
}
216+
return mb_substr($str, $start, $length, '8bit');
217+
}
218+
}

src/Library/Core/Util/ECKey.php

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use InvalidArgumentException;
88
use Jose\Component\Core\JWK;
9-
use ParagonIE\ConstantTime\Base64UrlSafe;
109
use RuntimeException;
1110
use function extension_loaded;
1211
use function is_array;

src/Library/Core/Util/RSAKey.php

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use InvalidArgumentException;
88
use Jose\Component\Core\JWK;
9-
use ParagonIE\ConstantTime\Base64UrlSafe;
109
use RuntimeException;
1110
use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence;
1211
use SpomkyLabs\Pki\ASN1\Type\Primitive\BitString;

src/Library/Encryption/Algorithm/ContentEncryption/AESCBCHS.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
66

7+
use Jose\Component\Core\Util\Base64UrlSafe;
78
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
8-
use ParagonIE\ConstantTime\Base64UrlSafe;
99
use RuntimeException;
1010
use function extension_loaded;
1111
use const OPENSSL_RAW_DATA;

src/Library/Encryption/Algorithm/ContentEncryption/AESGCM.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
66

7+
use Jose\Component\Core\Util\Base64UrlSafe;
78
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
8-
use ParagonIE\ConstantTime\Base64UrlSafe;
99
use RuntimeException;
1010
use function extension_loaded;
1111
use const OPENSSL_RAW_DATA;

src/Library/Encryption/Algorithm/KeyEncryption/AESGCMKW.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use AESKW\Wrapper as WrapperInterface;
88
use InvalidArgumentException;
99
use Jose\Component\Core\JWK;
10-
use ParagonIE\ConstantTime\Base64UrlSafe;
10+
use Jose\Component\Core\Util\Base64UrlSafe;
1111
use RuntimeException;
1212
use function extension_loaded;
1313
use function in_array;

src/Library/Encryption/Algorithm/KeyEncryption/AESKW.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use AESKW\Wrapper as WrapperInterface;
88
use InvalidArgumentException;
99
use Jose\Component\Core\JWK;
10-
use ParagonIE\ConstantTime\Base64UrlSafe;
10+
use Jose\Component\Core\Util\Base64UrlSafe;
1111
use RuntimeException;
1212
use function in_array;
1313
use function is_string;

src/Library/Encryption/Algorithm/KeyEncryption/AbstractECDH.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
use Brick\Math\BigInteger;
88
use InvalidArgumentException;
99
use Jose\Component\Core\JWK;
10+
use Jose\Component\Core\Util\Base64UrlSafe;
1011
use Jose\Component\Core\Util\Ecc\Curve;
1112
use Jose\Component\Core\Util\Ecc\EcDH;
1213
use Jose\Component\Core\Util\Ecc\NistCurve;
1314
use Jose\Component\Core\Util\Ecc\PrivateKey;
1415
use Jose\Component\Core\Util\ECKey;
1516
use Jose\Component\Encryption\Algorithm\KeyEncryption\Util\ConcatKDF;
16-
use ParagonIE\ConstantTime\Base64UrlSafe;
1717
use RuntimeException;
1818
use Throwable;
1919
use function array_key_exists;

src/Library/Encryption/Algorithm/KeyEncryption/Dir.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use InvalidArgumentException;
88
use Jose\Component\Core\JWK;
9-
use ParagonIE\ConstantTime\Base64UrlSafe;
9+
use Jose\Component\Core\Util\Base64UrlSafe;
1010
use function in_array;
1111
use function is_string;
1212

src/Library/Encryption/Algorithm/KeyEncryption/PBES2AESKW.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use AESKW\Wrapper as WrapperInterface;
1111
use InvalidArgumentException;
1212
use Jose\Component\Core\JWK;
13-
use ParagonIE\ConstantTime\Base64UrlSafe;
13+
use Jose\Component\Core\Util\Base64UrlSafe;
1414
use RuntimeException;
1515
use function in_array;
1616
use function is_int;

src/Library/Encryption/Algorithm/KeyEncryption/Util/ConcatKDF.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Jose\Component\Encryption\Algorithm\KeyEncryption\Util;
66

77
use InvalidArgumentException;
8-
use ParagonIE\ConstantTime\Base64UrlSafe;
8+
use Jose\Component\Core\Util\Base64UrlSafe;
99
use const STR_PAD_LEFT;
1010

1111
/**

src/Library/Encryption/JWEBuilder.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use InvalidArgumentException;
88
use Jose\Component\Core\AlgorithmManager;
99
use Jose\Component\Core\JWK;
10+
use Jose\Component\Core\Util\Base64UrlSafe;
1011
use Jose\Component\Core\Util\JsonConverter;
1112
use Jose\Component\Core\Util\KeyChecker;
1213
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
@@ -19,7 +20,6 @@
1920
use Jose\Component\Encryption\Compression\CompressionMethod;
2021
use Jose\Component\Encryption\Compression\CompressionMethodManager;
2122
use LogicException;
22-
use ParagonIE\ConstantTime\Base64UrlSafe;
2323
use RuntimeException;
2424
use function array_key_exists;
2525
use function count;

src/Library/Encryption/Serializer/CompactSerializer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
namespace Jose\Component\Encryption\Serializer;
66

77
use InvalidArgumentException;
8+
use Jose\Component\Core\Util\Base64UrlSafe;
89
use Jose\Component\Core\Util\JsonConverter;
910
use Jose\Component\Encryption\JWE;
1011
use Jose\Component\Encryption\Recipient;
1112
use LogicException;
12-
use ParagonIE\ConstantTime\Base64UrlSafe;
1313
use Throwable;
1414
use function count;
1515
use function is_array;

0 commit comments

Comments
 (0)