Rev 827 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 827 | Rev 874 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | <?php |
1 | <?php |
2 | declare(strict_types=1); |
2 | declare(strict_types=1); |
3 | namespace ParagonIE\ConstantTime; |
3 | namespace ParagonIE\ConstantTime; |
4 | 4 | ||
- | 5 | use InvalidArgumentException; |
|
- | 6 | use RangeException; |
|
- | 7 | use TypeError; |
|
- | 8 | ||
5 | /** |
9 | /** |
6 | * Copyright (c) 2016 - 2018 Paragon Initiative Enterprises. |
10 | * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. |
7 | * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) |
11 | * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) |
8 | * |
12 | * |
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | * of this software and associated documentation files (the "Software"), to deal |
14 | * of this software and associated documentation files (the "Software"), to deal |
11 | * in the Software without restriction, including without limitation the rights |
15 | * in the Software without restriction, including without limitation the rights |
Line 60... | Line 64... | ||
60 | /** |
64 | /** |
61 | * Encode into Base32 (RFC 4648) |
65 | * Encode into Base32 (RFC 4648) |
62 | * |
66 | * |
63 | * @param string $binString |
67 | * @param string $binString |
64 | * @return string |
68 | * @return string |
65 | * @throws \TypeError |
69 | * @throws TypeError |
66 | */ |
70 | */ |
67 | public static function encode(string $binString): string |
71 | public static function encode(string $binString): string |
68 | { |
72 | { |
69 | return static::doEncode($binString, false, true); |
73 | return static::doEncode($binString, false, true); |
70 | } |
74 | } |
71 | /** |
75 | /** |
72 | * Encode into Base32 (RFC 4648) |
76 | * Encode into Base32 (RFC 4648) |
73 | * |
77 | * |
74 | * @param string $src |
78 | * @param string $src |
75 | * @return string |
79 | * @return string |
76 | * @throws \TypeError |
80 | * @throws TypeError |
77 | */ |
81 | */ |
78 | public static function encodeUnpadded(string $src): string |
82 | public static function encodeUnpadded(string $src): string |
79 | { |
83 | { |
80 | return static::doEncode($src, false, false); |
84 | return static::doEncode($src, false, false); |
81 | } |
85 | } |
Line 83... | Line 87... | ||
83 | /** |
87 | /** |
84 | * Encode into uppercase Base32 (RFC 4648) |
88 | * Encode into uppercase Base32 (RFC 4648) |
85 | * |
89 | * |
86 | * @param string $src |
90 | * @param string $src |
87 | * @return string |
91 | * @return string |
88 | * @throws \TypeError |
92 | * @throws TypeError |
89 | */ |
93 | */ |
90 | public static function encodeUpper(string $src): string |
94 | public static function encodeUpper(string $src): string |
91 | { |
95 | { |
92 | return static::doEncode($src, true, true); |
96 | return static::doEncode($src, true, true); |
93 | } |
97 | } |
Line 95... | Line 99... | ||
95 | /** |
99 | /** |
96 | * Encode into uppercase Base32 (RFC 4648) |
100 | * Encode into uppercase Base32 (RFC 4648) |
97 | * |
101 | * |
98 | * @param string $src |
102 | * @param string $src |
99 | * @return string |
103 | * @return string |
100 | * @throws \TypeError |
104 | * @throws TypeError |
101 | */ |
105 | */ |
102 | public static function encodeUpperUnpadded(string $src): string |
106 | public static function encodeUpperUnpadded(string $src): string |
103 | { |
107 | { |
104 | return static::doEncode($src, true, false); |
108 | return static::doEncode($src, true, false); |
105 | } |
109 | } |
Line 180... | Line 184... | ||
180 | $diff -= ((25 - $src) >> 8) & 41; |
184 | $diff -= ((25 - $src) >> 8) & 41; |
181 | 185 | ||
182 | return \pack('C', $src + $diff); |
186 | return \pack('C', $src + $diff); |
183 | } |
187 | } |
184 | 188 | ||
- | 189 | /** |
|
- | 190 | * @param string $encodedString |
|
- | 191 | * @param bool $upper |
|
- | 192 | * @return string |
|
- | 193 | */ |
|
- | 194 | public static function decodeNoPadding(string $encodedString, bool $upper = false): string |
|
- | 195 | { |
|
- | 196 | $srcLen = Binary::safeStrlen($encodedString); |
|
- | 197 | if ($srcLen === 0) { |
|
- | 198 | return ''; |
|
- | 199 | } |
|
- | 200 | if (($srcLen & 7) === 0) { |
|
- | 201 | for ($j = 0; $j < 7 && $j < $srcLen; ++$j) { |
|
- | 202 | if ($encodedString[$srcLen - $j - 1] === '=') { |
|
- | 203 | throw new InvalidArgumentException( |
|
- | 204 | "decodeNoPadding() doesn't tolerate padding" |
|
- | 205 | ); |
|
- | 206 | } |
|
- | 207 | } |
|
- | 208 | } |
|
- | 209 | return static::doDecode( |
|
- | 210 | $encodedString, |
|
- | 211 | $upper, |
|
- | 212 | true |
|
- | 213 | ); |
|
- | 214 | } |
|
185 | 215 | ||
186 | /** |
216 | /** |
187 | * Base32 decoding |
217 | * Base32 decoding |
188 | * |
218 | * |
189 | * @param string $src |
219 | * @param string $src |
190 | * @param bool $upper |
220 | * @param bool $upper |
191 | * @param bool $strictPadding |
221 | * @param bool $strictPadding |
192 | * @return string |
222 | * @return string |
- | 223 | * |
|
193 | * @throws \TypeError |
224 | * @throws TypeError |
194 | * @psalm-suppress RedundantCondition |
225 | * @psalm-suppress RedundantCondition |
195 | */ |
226 | */ |
196 | protected static function doDecode(string $src, bool $upper = false, bool $strictPadding = false): string |
227 | protected static function doDecode( |
- | 228 | string $src, |
|
- | 229 | bool $upper = false, |
|
- | 230 | bool $strictPadding = false |
|
197 | { |
231 | ): string { |
198 | // We do this to reduce code duplication: |
232 | // We do this to reduce code duplication: |
199 | $method = $upper |
233 | $method = $upper |
200 | ? 'decode5BitsUpper' |
234 | ? 'decode5BitsUpper' |
201 | : 'decode5Bits'; |
235 | : 'decode5Bits'; |
202 | 236 | ||
Line 214... | Line 248... | ||
214 | break; |
248 | break; |
215 | } |
249 | } |
216 | } |
250 | } |
217 | } |
251 | } |
218 | if (($srcLen & 7) === 1) { |
252 | if (($srcLen & 7) === 1) { |
219 | throw new \RangeException( |
253 | throw new RangeException( |
220 | 'Incorrect padding' |
254 | 'Incorrect padding' |
221 | ); |
255 | ); |
222 | } |
256 | } |
223 | } else { |
257 | } else { |
224 | $src = \rtrim($src, '='); |
258 | $src = \rtrim($src, '='); |
Line 285... | Line 319... | ||
285 | (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, |
319 | (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, |
286 | (($c3 << 4) | ($c4 >> 1) ) & 0xff, |
320 | (($c3 << 4) | ($c4 >> 1) ) & 0xff, |
287 | (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff |
321 | (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff |
288 | ); |
322 | ); |
289 | $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8; |
323 | $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8; |
- | 324 | if ($strictPadding) { |
|
- | 325 | $err |= ($c6 << 5) & 0xff; |
|
- | 326 | } |
|
290 | } elseif ($i + 5 < $srcLen) { |
327 | } elseif ($i + 5 < $srcLen) { |
291 | /** @var int $c1 */ |
328 | /** @var int $c1 */ |
292 | $c1 = static::$method($chunk[2]); |
329 | $c1 = static::$method($chunk[2]); |
293 | /** @var int $c2 */ |
330 | /** @var int $c2 */ |
294 | $c2 = static::$method($chunk[3]); |
331 | $c2 = static::$method($chunk[3]); |
Line 322... | Line 359... | ||
322 | (($c0 << 3) | ($c1 >> 2) ) & 0xff, |
359 | (($c0 << 3) | ($c1 >> 2) ) & 0xff, |
323 | (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, |
360 | (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, |
324 | (($c3 << 4) | ($c4 >> 1) ) & 0xff |
361 | (($c3 << 4) | ($c4 >> 1) ) & 0xff |
325 | ); |
362 | ); |
326 | $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8; |
363 | $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8; |
- | 364 | if ($strictPadding) { |
|
- | 365 | $err |= ($c4 << 7) & 0xff; |
|
- | 366 | } |
|
327 | } elseif ($i + 3 < $srcLen) { |
367 | } elseif ($i + 3 < $srcLen) { |
328 | /** @var int $c1 */ |
368 | /** @var int $c1 */ |
329 | $c1 = static::$method($chunk[2]); |
369 | $c1 = static::$method($chunk[2]); |
330 | /** @var int $c2 */ |
370 | /** @var int $c2 */ |
331 | $c2 = static::$method($chunk[3]); |
371 | $c2 = static::$method($chunk[3]); |
Line 336... | Line 376... | ||
336 | 'CC', |
376 | 'CC', |
337 | (($c0 << 3) | ($c1 >> 2) ) & 0xff, |
377 | (($c0 << 3) | ($c1 >> 2) ) & 0xff, |
338 | (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff |
378 | (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff |
339 | ); |
379 | ); |
340 | $err |= ($c0 | $c1 | $c2 | $c3) >> 8; |
380 | $err |= ($c0 | $c1 | $c2 | $c3) >> 8; |
- | 381 | if ($strictPadding) { |
|
- | 382 | $err |= ($c3 << 4) & 0xff; |
|
- | 383 | } |
|
341 | } elseif ($i + 2 < $srcLen) { |
384 | } elseif ($i + 2 < $srcLen) { |
342 | /** @var int $c1 */ |
385 | /** @var int $c1 */ |
343 | $c1 = static::$method($chunk[2]); |
386 | $c1 = static::$method($chunk[2]); |
344 | /** @var int $c2 */ |
387 | /** @var int $c2 */ |
345 | $c2 = static::$method($chunk[3]); |
388 | $c2 = static::$method($chunk[3]); |
Line 348... | Line 391... | ||
348 | 'CC', |
391 | 'CC', |
349 | (($c0 << 3) | ($c1 >> 2) ) & 0xff, |
392 | (($c0 << 3) | ($c1 >> 2) ) & 0xff, |
350 | (($c1 << 6) | ($c2 << 1) ) & 0xff |
393 | (($c1 << 6) | ($c2 << 1) ) & 0xff |
351 | ); |
394 | ); |
352 | $err |= ($c0 | $c1 | $c2) >> 8; |
395 | $err |= ($c0 | $c1 | $c2) >> 8; |
- | 396 | if ($strictPadding) { |
|
- | 397 | $err |= ($c2 << 6) & 0xff; |
|
- | 398 | } |
|
353 | } elseif ($i + 1 < $srcLen) { |
399 | } elseif ($i + 1 < $srcLen) { |
354 | /** @var int $c1 */ |
400 | /** @var int $c1 */ |
355 | $c1 = static::$method($chunk[2]); |
401 | $c1 = static::$method($chunk[2]); |
356 | 402 | ||
357 | $dest .= \pack( |
403 | $dest .= \pack( |
358 | 'C', |
404 | 'C', |
359 | (($c0 << 3) | ($c1 >> 2) ) & 0xff |
405 | (($c0 << 3) | ($c1 >> 2) ) & 0xff |
360 | ); |
406 | ); |
361 | $err |= ($c0 | $c1) >> 8; |
407 | $err |= ($c0 | $c1) >> 8; |
- | 408 | if ($strictPadding) { |
|
- | 409 | $err |= ($c1 << 6) & 0xff; |
|
- | 410 | } |
|
362 | } else { |
411 | } else { |
363 | $dest .= \pack( |
412 | $dest .= \pack( |
364 | 'C', |
413 | 'C', |
365 | (($c0 << 3) ) & 0xff |
414 | (($c0 << 3) ) & 0xff |
366 | ); |
415 | ); |
367 | $err |= ($c0) >> 8; |
416 | $err |= ($c0) >> 8; |
368 | } |
417 | } |
369 | } |
418 | } |
370 | $check = ($err === 0); |
419 | $check = ($err === 0); |
371 | if (!$check) { |
420 | if (!$check) { |
372 | throw new \RangeException( |
421 | throw new RangeException( |
373 | 'Base32::doDecode() only expects characters in the correct base32 alphabet' |
422 | 'Base32::doDecode() only expects characters in the correct base32 alphabet' |
374 | ); |
423 | ); |
375 | } |
424 | } |
376 | return $dest; |
425 | return $dest; |
377 | } |
426 | } |
Line 381... | Line 430... | ||
381 | * |
430 | * |
382 | * @param string $src |
431 | * @param string $src |
383 | * @param bool $upper |
432 | * @param bool $upper |
384 | * @param bool $pad |
433 | * @param bool $pad |
385 | * @return string |
434 | * @return string |
386 | * @throws \TypeError |
435 | * @throws TypeError |
387 | */ |
436 | */ |
388 | protected static function doEncode(string $src, bool $upper = false, $pad = true): string |
437 | protected static function doEncode(string $src, bool $upper = false, $pad = true): string |
389 | { |
438 | { |
390 | // We do this to reduce code duplication: |
439 | // We do this to reduce code duplication: |
391 | $method = $upper |
440 | $method = $upper |