6
6
7
7
use InvalidArgumentException ;
8
8
use RangeException ;
9
+ use SensitiveParameter ;
10
+ use SodiumException ;
11
+ use function extension_loaded ;
12
+ use function pack ;
13
+ use function rtrim ;
9
14
use function strlen ;
15
+ use function substr ;
16
+ use function unpack ;
17
+ use function sodium_base642bin ;
18
+ use function sodium_bin2base64 ;
19
+ use const SODIUM_BASE64_VARIANT_URLSAFE ;
20
+ use const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING ;
10
21
11
22
/**
12
23
* Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
33
44
34
45
final readonly class Base64UrlSafe
35
46
{
36
- public static function encode (string $ binString ): string
37
- {
47
+ public static function encode (
48
+ #[SensitiveParameter]
49
+ string $ binString
50
+ ): string {
51
+ if (extension_loaded ('sodium ' )) {
52
+ try {
53
+ return sodium_bin2base64 ($ binString , SODIUM_BASE64_VARIANT_URLSAFE );
54
+ } catch (SodiumException $ ex ) {
55
+ throw new RangeException ($ ex ->getMessage (), $ ex ->getCode (), $ ex );
56
+ }
57
+ }
38
58
return static ::doEncode ($ binString , true );
39
59
}
40
60
41
- public static function encodeUnpadded (string $ src ): string
42
- {
61
+ public static function encodeUnpadded (
62
+ #[SensitiveParameter]
63
+ string $ src
64
+ ): string {
65
+ if (extension_loaded ('sodium ' )) {
66
+ try {
67
+ return sodium_bin2base64 ($ src , SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING );
68
+ } catch (SodiumException $ ex ) {
69
+ throw new RangeException ($ ex ->getMessage (), $ ex ->getCode (), $ ex );
70
+ }
71
+ }
43
72
return static ::doEncode ($ src , false );
44
73
}
45
74
46
- public static function decode (string $ encodedString , bool $ strictPadding = false ): string
47
- {
75
+ public static function decode (
76
+ #[SensitiveParameter]
77
+ string $ encodedString ,
78
+ bool $ strictPadding = false
79
+ ): string {
48
80
$ srcLen = self ::safeStrlen ($ encodedString );
49
81
if ($ srcLen === 0 ) {
50
82
return '' ;
@@ -65,6 +97,13 @@ public static function decode(string $encodedString, bool $strictPadding = false
65
97
if ($ encodedString [$ srcLen - 1 ] === '= ' ) {
66
98
throw new RangeException ('Incorrect padding ' );
67
99
}
100
+ if (extension_loaded ('sodium ' )) {
101
+ try {
102
+ return sodium_base642bin (self ::safeSubstr ($ encodedString , 0 , $ srcLen ), SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING );
103
+ } catch (SodiumException $ ex ) {
104
+ throw new RangeException ($ ex ->getMessage (), $ ex ->getCode (), $ ex );
105
+ }
106
+ }
68
107
} else {
69
108
$ encodedString = rtrim ($ encodedString , '= ' );
70
109
$ srcLen = self ::safeStrlen ($ encodedString );
@@ -120,27 +159,27 @@ public static function decode(string $encodedString, bool $strictPadding = false
120
159
return $ dest ;
121
160
}
122
161
123
- public static function decodeNoPadding (string $ encodedString ): string
124
- {
162
+ public static function decodeNoPadding (
163
+ #[SensitiveParameter]
164
+ string $ encodedString
165
+ ): string {
125
166
$ srcLen = self ::safeStrlen ($ encodedString );
126
167
if ($ srcLen === 0 ) {
127
168
return '' ;
128
169
}
129
170
if (($ srcLen & 3 ) === 0 ) {
130
- if ($ encodedString [$ srcLen - 1 ] === '= ' ) {
171
+ if ($ encodedString [$ srcLen - 1 ] === '= ' || $ encodedString [ $ srcLen - 2 ] === ' = ' ) {
131
172
throw new InvalidArgumentException ("decodeNoPadding() doesn't tolerate padding " );
132
173
}
133
- if (($ srcLen & 3 ) > 1 ) {
134
- if ($ encodedString [$ srcLen - 2 ] === '= ' ) {
135
- throw new InvalidArgumentException ("decodeNoPadding() doesn't tolerate padding " );
136
- }
137
- }
138
174
}
139
175
return static ::decode ($ encodedString , true );
140
176
}
141
177
142
- private static function doEncode (string $ src , bool $ pad = true ): string
143
- {
178
+ private static function doEncode (
179
+ #[SensitiveParameter]
180
+ string $ src ,
181
+ bool $ pad = true
182
+ ): string {
144
183
$ dest = '' ;
145
184
$ srcLen = self ::safeStrlen ($ src );
146
185
for ($ i = 0 ; $ i + 3 <= $ srcLen ; $ i += 3 ) {
@@ -204,13 +243,19 @@ private static function encode6Bits(int $src): string
204
243
return pack ('C ' , $ src + $ diff );
205
244
}
206
245
207
- private static function safeStrlen (string $ str ): int
208
- {
246
+ private static function safeStrlen (
247
+ #[SensitiveParameter]
248
+ string $ str
249
+ ): int {
209
250
return strlen ($ str );
210
251
}
211
252
212
- private static function safeSubstr (string $ str , int $ start = 0 , $ length = null ): string
213
- {
253
+ private static function safeSubstr (
254
+ #[SensitiveParameter]
255
+ string $ str ,
256
+ int $ start = 0 ,
257
+ $ length = null
258
+ ): string {
214
259
if ($ length === 0 ) {
215
260
return '' ;
216
261
}
0 commit comments