Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace ParagonIE\ConstantTime;
3
 
4
/**
5
 *  Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
6
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
7
 *
8
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
9
 *  of this software and associated documentation files (the "Software"), to deal
10
 *  in the Software without restriction, including without limitation the rights
11
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 *  copies of the Software, and to permit persons to whom the Software is
13
 *  furnished to do so, subject to the following conditions:
14
 *
15
 *  The above copyright notice and this permission notice shall be included in all
16
 *  copies or substantial portions of the Software.
17
 *
18
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
 *  SOFTWARE.
25
 */
26
 
27
/**
28
 * Class Base32
29
 * [A-Z][2-7]
30
 *
31
 * @package ParagonIE\ConstantTime
32
 */
33
abstract class Base32 implements EncoderInterface
34
{
35
    /**
36
     * Decode a Base32-encoded string into raw binary
37
     *
38
     * @param string $src
39
     * @param bool $strictPadding
40
     * @return string
41
     */
42
    public static function decode($src, $strictPadding = \false)
43
    {
44
        return static::doDecode($src, \false, $strictPadding);
45
    }
46
 
47
    /**
48
     * Decode an uppercase Base32-encoded string into raw binary
49
     *
50
     * @param string $src
51
     * @param bool $strictPadding
52
     * @return string
53
     */
54
    public static function decodeUpper($src, $strictPadding = \false)
55
    {
56
        return static::doDecode($src, \true, $strictPadding);
57
    }
58
 
59
    /**
60
     * Encode into Base32 (RFC 4648)
61
     *
62
     * @param string $src
63
     * @return string
64
     */
65
    public static function encode($src)
66
    {
67
        return static::doEncode($src, \false);
68
    }
69
 
70
    /**
71
     * Encode into Base32 (RFC 4648)
72
     *
73
     * @param string $src
74
     * @return string
75
     * @throws \TypeError
76
     */
77
    public static function encodeUnpadded($src)
78
    {
79
        return static::doEncode($src, false, false);
80
    }
81
 
82
    /**
83
     * Encode into uppercase Base32 (RFC 4648)
84
     *
85
     * @param string $src
86
     * @return string
87
     */
88
    public static function encodeUpper($src)
89
    {
90
        return static::doEncode($src, \true);
91
    }
92
 
93
    /**
94
     * Encode into uppercase Base32 (RFC 4648)
95
     *
96
     * @param string $src
97
     * @return string
98
     * @throws \TypeError
99
     */
100
    public static function encodeUpperUnpadded($src)
101
    {
102
        return static::doEncode($src, true, false);
103
    }
104
 
105
    /**
106
     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
107
     * into 8-bit integers.
108
     *
109
     * @param int $src
110
     * @return int
111
     */
112
    protected static function decode5Bits($src)
113
    {
114
        $ret = -1;
115
 
116
        // if ($src > 96 && $src < 123) $ret += $src - 97 + 1; // -64
117
        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 96);
118
 
119
        // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
120
        $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23);
121
 
122
        return $ret;
123
    }
124
 
125
    /**
126
     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
127
     * into 8-bit integers.
128
     *
129
     * Uppercase variant.
130
     *
131
     * @param int $src
132
     * @return int
133
     */
134
    protected static function decode5BitsUpper($src)
135
    {
136
        $ret = -1;
137
 
138
        // if ($src > 64 && $src < 91) $ret += $src - 65 + 1; // -64
139
        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
140
 
141
        // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
142
        $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23);
143
 
144
        return $ret;
145
    }
146
 
147
    /**
148
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
149
     * into 5-bit integers.
150
     *
151
     * @param int $src
152
     * @return string
153
     */
154
    protected static function encode5Bits($src)
155
    {
156
        $diff = 0x61;
157
 
158
        // if ($src > 25) $ret -= 72;
159
        $diff -= ((25 - $src) >> 8) & 73;
160
 
161
        return \pack('C', $src + $diff);
162
    }
163
 
164
    /**
165
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
166
     * into 5-bit integers.
167
     *
168
     * Uppercase variant.
169
     *
170
     * @param int $src
171
     * @return string
172
     */
173
    protected static function encode5BitsUpper($src)
174
    {
175
        $diff = 0x41;
176
 
177
        // if ($src > 25) $ret -= 40;
178
        $diff -= ((25 - $src) >> 8) & 41;
179
 
180
        return \pack('C', $src + $diff);
181
    }
182
 
183
 
184
    /**
185
     * Base32 decoding
186
     *
187
     * @param string $src
188
     * @param bool $upper
189
     * @param bool $strictPadding
190
     * @return string
191
     */
192
    protected static function doDecode($src, $upper = \false, $strictPadding = \true)
193
    {
194
        // We do this to reduce code duplication:
195
        $method = $upper
196
            ? 'decode5BitsUpper'
197
            : 'decode5Bits';
198
 
199
        // Remove padding
200
        $srcLen = Binary::safeStrlen($src);
201
        if ($srcLen === 0) {
202
            return '';
203
        }
204
        if ($strictPadding) {
205
            if (($srcLen & 7) === 0) {
206
                for ($j = 0; $j < 7; ++$j) {
207
                    if ($src[$srcLen - 1] === '=') {
208
                        $srcLen--;
209
                    } else {
210
                        break;
211
                    }
212
                }
213
            }
214
            if (($srcLen & 7) === 1) {
215
                throw new \RangeException(
216
                    'Incorrect padding'
217
                );
218
            }
219
        } else {
220
            $src = \rtrim($src, '=');
221
            $srcLen = Binary::safeStrlen($src);
222
        }
223
 
224
        $err = 0;
225
        $dest = '';
226
        // Main loop (no padding):
227
        for ($i = 0; $i + 8 <= $srcLen; $i += 8) {
228
            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 8));
229
            $c0 = static::$method($chunk[1]);
230
            $c1 = static::$method($chunk[2]);
231
            $c2 = static::$method($chunk[3]);
232
            $c3 = static::$method($chunk[4]);
233
            $c4 = static::$method($chunk[5]);
234
            $c5 = static::$method($chunk[6]);
235
            $c6 = static::$method($chunk[7]);
236
            $c7 = static::$method($chunk[8]);
237
 
238
            $dest .= \pack(
239
                'CCCCC',
240
                (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
241
                (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
242
                (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
243
                (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff,
244
                (($c6 << 5) | ($c7     )             ) & 0xff
245
            );
246
            $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6 | $c7) >> 8;
247
        }
248
        // The last chunk, which may have padding:
249
        if ($i < $srcLen) {
250
            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
251
            $c0 = static::$method($chunk[1]);
252
 
253
            if ($i + 6 < $srcLen) {
254
                $c1 = static::$method($chunk[2]);
255
                $c2 = static::$method($chunk[3]);
256
                $c3 = static::$method($chunk[4]);
257
                $c4 = static::$method($chunk[5]);
258
                $c5 = static::$method($chunk[6]);
259
                $c6 = static::$method($chunk[7]);
260
 
261
                $dest .= \pack(
262
                    'CCCC',
263
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
264
                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
265
                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
266
                    (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff
267
                );
268
                $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8;
269
            } elseif ($i + 5 < $srcLen) {
270
                $c1 = static::$method($chunk[2]);
271
                $c2 = static::$method($chunk[3]);
272
                $c3 = static::$method($chunk[4]);
273
                $c4 = static::$method($chunk[5]);
274
                $c5 = static::$method($chunk[6]);
275
 
276
                $dest .= \pack(
277
                    'CCCC',
278
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
279
                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
280
                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
281
                    (($c4 << 7) | ($c5 << 2)             ) & 0xff
282
                );
283
                $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5) >> 8;
284
            } elseif ($i + 4 < $srcLen) {
285
                $c1 = static::$method($chunk[2]);
286
                $c2 = static::$method($chunk[3]);
287
                $c3 = static::$method($chunk[4]);
288
                $c4 = static::$method($chunk[5]);
289
 
290
                $dest .= \pack(
291
                    'CCC',
292
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
293
                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
294
                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff
295
                );
296
                $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8;
297
            } elseif ($i + 3 < $srcLen) {
298
                $c1 = static::$method($chunk[2]);
299
                $c2 = static::$method($chunk[3]);
300
                $c3 = static::$method($chunk[4]);
301
 
302
                $dest .= \pack(
303
                    'CC',
304
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
305
                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff
306
                );
307
                $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
308
            } elseif ($i + 2 < $srcLen) {
309
                $c1 = static::$method($chunk[2]);
310
                $c2 = static::$method($chunk[3]);
311
 
312
                $dest .= \pack(
313
                    'CC',
314
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
315
                    (($c1 << 6) | ($c2 << 1)             ) & 0xff
316
                );
317
                $err |= ($c0 | $c1 | $c2) >> 8;
318
            } elseif ($i + 1 < $srcLen) {
319
                $c1 = static::$method($chunk[2]);
320
 
321
                $dest .= \pack(
322
                    'C',
323
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff
324
                );
325
                $err |= ($c0 | $c1) >> 8;
326
            } else {
327
                $dest .= \pack(
328
                    'C',
329
                    (($c0 << 3)                          ) & 0xff
330
                );
331
                $err |= ($c0) >> 8;
332
            }
333
        }
334
        if ($err !== 0) {
335
            throw new \RangeException(
336
                'Base32::doDecode() only expects characters in the correct base32 alphabet'
337
            );
338
        }
339
        return $dest;
340
    }
341
 
342
    /**
343
     * Base32 Decoding
344
     *
345
     * @param string $src
346
     * @param bool $upper
347
     * @param bool $pad
348
     * @return string
349
     */
350
    protected static function doEncode($src, $upper = \false, $pad = \true)
351
    {
352
        // We do this to reduce code duplication:
353
        $method = $upper
354
            ? 'encode5BitsUpper'
355
            : 'encode5Bits';
356
 
357
        $dest = '';
358
        $srcLen = Binary::safeStrlen($src);
359
 
360
        // Main loop (no padding):
361
        for ($i = 0; $i + 5 <= $srcLen; $i += 5) {
362
            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 5));
363
            $b0 = $chunk[1];
364
            $b1 = $chunk[2];
365
            $b2 = $chunk[3];
366
            $b3 = $chunk[4];
367
            $b4 = $chunk[5];
368
            $dest .=
369
                static::$method(              ($b0 >> 3)  & 31) .
370
                static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
371
                static::$method((($b1 >> 1)             ) & 31) .
372
                static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
373
                static::$method((($b2 << 1) | ($b3 >> 7)) & 31) .
374
                static::$method((($b3 >> 2)             ) & 31) .
375
                static::$method((($b3 << 3) | ($b4 >> 5)) & 31) .
376
                static::$method(  $b4                     & 31);
377
        }
378
        // The last chunk, which may have padding:
379
        if ($i < $srcLen) {
380
            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
381
            $b0 = $chunk[1];
382
            if ($i + 3 < $srcLen) {
383
                $b1 = $chunk[2];
384
                $b2 = $chunk[3];
385
                $b3 = $chunk[4];
386
                $dest .=
387
                    static::$method(              ($b0 >> 3)  & 31) .
388
                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
389
                    static::$method((($b1 >> 1)             ) & 31) .
390
                    static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
391
                    static::$method((($b2 << 1) | ($b3 >> 7)) & 31) .
392
                    static::$method((($b3 >> 2)             ) & 31) .
393
                    static::$method((($b3 << 3)             ) & 31);
394
                if ($pad) {
395
                    $dest .= '=';
396
                }
397
            } elseif ($i + 2 < $srcLen) {
398
                $b1 = $chunk[2];
399
                $b2 = $chunk[3];
400
                $dest .=
401
                    static::$method(              ($b0 >> 3)  & 31) .
402
                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
403
                    static::$method((($b1 >> 1)             ) & 31) .
404
                    static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
405
                    static::$method((($b2 << 1)             ) & 31);
406
                if ($pad) {
407
                    $dest .= '===';
408
                }
409
            } elseif ($i + 1 < $srcLen) {
410
                $b1 = $chunk[2];
411
                $dest .=
412
                    static::$method(              ($b0 >> 3)  & 31) .
413
                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
414
                    static::$method((($b1 >> 1)             ) & 31) .
415
                    static::$method((($b1 << 4)             ) & 31);
416
                if ($pad) {
417
                    $dest .= '====';
418
                }
419
            } else {
420
                $dest .=
421
                    static::$method(              ($b0 >> 3)  & 31) .
422
                    static::$method( ($b0 << 2)               & 31);
423
                if ($pad) {
424
                    $dest .= '======';
425
                }
426
            }
427
        }
428
        return $dest;
429
    }
430
}