Code Duplication    Length = 155-180 lines in 3 locations

install/js/crypt/aesctr.class.php 1 location

@@ 8-162 (lines=155) @@
5
/*    form is offered.                                                                            */
6
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
7
8
class AesCtr extends Aes
9
{
10
    /**
11
     * Encrypt a text using AES encryption in Counter mode of operation
12
     *  - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
13
     *
14
     * Unicode multi-byte character safe
15
     *
16
     * @param plaintext source text to be encrypted
17
     * @param password  the password to use to generate a key
18
     * @param nBits     number of bits to be used in the key (128, 192, or 256)
19
     * @return          string text
20
     */
21
    public static function encrypt($plaintext, $password, $nBits)
22
    {
23
    $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
24
    if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) {
25
        return '';
26
    }
27
    // standard allows 128/192/256 bit keys
28
    // note PHP (5) gives us plaintext and password in UTF8 encoding!
29
30
    // use AES itself to encrypt password to get cipher key (using plain password as source for
31
    // key expansion) - gives us well encrypted key
32
    $nBytes = $nBits / 8; // no bytes in key
33
    $pwBytes = array();
34
    for ($i = 0; $i < $nBytes; $i++) {
35
        $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
36
    }
37
    $key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
38
    $key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
39
40
    // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in
41
    // 1st 8 bytes, block counter in 2nd 8 bytes
42
    $counterBlock = array();
43
    $nonce = floor(microtime(true) * 1000); // timestamp: milliseconds since 1-Jan-1970
44
    $nonceSec = floor($nonce / 1000);
45
    $nonceMs = $nonce % 1000;
46
    // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes
47
    for ($i = 0; $i < 4; $i++) {
48
        $counterBlock[$i] = self::urs($nonceSec, $i * 8) & 0xff;
49
    }
50
    for ($i = 0; $i < 4; $i++) {
51
        $counterBlock[$i + 4] = $nonceMs & 0xff;
52
    }
53
    // and convert it to a string to go on the front of the ciphertext
54
    $ctrTxt = '';
55
    for ($i = 0; $i < 8; $i++) {
56
        $ctrTxt .= chr($counterBlock[$i]);
57
    }
58
59
    // generate key schedule - an expansion of the key into distinct Key Rounds for each round
60
    $keySchedule = Aes::keyExpansion($key);
61
    //print_r($keySchedule);
62
63
    $blockCount = ceil(strlen($plaintext) / $blockSize);
64
    $ciphertxt = array(); // ciphertext as array of strings
65
66
    for ($b = 0; $b < $blockCount; $b++) {
67
        // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
68
        // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
69
        for ($c = 0; $c < 4; $c++) {
70
            $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
71
        }
72
        for ($c = 0; $c < 4; $c++) {
73
            $counterBlock[15 - $c - 4] = self::urs($b / 0x100000000, $c * 8);
74
        }
75
76
        $cipherCntr = Aes::cipher($counterBlock, $keySchedule); // -- encrypt counter block --
77
78
        // block size is reduced on final block
79
        $blockLength = $b < $blockCount - 1 ? $blockSize : (strlen($plaintext) - 1) % $blockSize + 1;
80
        $cipherByte = array();
81
82
        for ($i = 0; $i < $blockLength; $i++) {  // -- xor plaintext with ciphered counter byte-by-byte --
83
        $cipherByte[$i] = $cipherCntr[$i] ^ ord(substr($plaintext, $b * $blockSize + $i, 1));
84
        $cipherByte[$i] = chr($cipherByte[$i]);
85
        }
86
        $ciphertxt[$b] = implode('', $cipherByte); // escape troublesome characters in ciphertext
87
    }
88
89
    // implode is more efficient than repeated string concatenation
90
    $ciphertext = $ctrTxt.implode('', $ciphertxt);
91
    $ciphertext = base64_encode($ciphertext);
92
93
    return $ciphertext;
94
    }
95
96
    /**
97
     * Decrypt a text encrypted by AES in counter mode of operation
98
     *
99
     * @param ciphertext source text to be decrypted
100
     * @param password   the password to use to generate a key
101
     * @param nBits      number of bits to be used in the key (128, 192, or 256)
102
     * @return           string text
103
     */
104
    public static function decrypt($ciphertext, $password, $nBits)
105
    {
106
    $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
107
    if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) {
108
        return '';
109
    }
110
    // standard allows 128/192/256 bit keys
111
    $ciphertext = base64_decode($ciphertext);
112
113
    // use AES to encrypt password (mirroring encrypt routine)
114
    $nBytes = $nBits / 8; // no bytes in key
115
    $pwBytes = array();
116
    for ($i = 0; $i < $nBytes; $i++) {
117
        $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
118
    }
119
    $key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
120
    $key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
121
122
    // recover nonce from 1st element of ciphertext
123
    $counterBlock = array();
124
    $ctrTxt = substr($ciphertext, 0, 8);
125
    for ($i = 0; $i < 8; $i++) {
126
        $counterBlock[$i] = ord(substr($ctrTxt, $i, 1));
127
    }
128
129
    // generate key schedule
130
    $keySchedule = Aes::keyExpansion($key);
131
132
    // separate ciphertext into blocks (skipping past initial 8 bytes)
133
    $nBlocks = ceil((strlen($ciphertext) - 8) / $blockSize);
134
    $ct = array();
135
    for ($b = 0; $b < $nBlocks; $b++) {
136
        $ct[$b] = substr($ciphertext, 8 + $b * $blockSize, 16);
137
    }
138
    $ciphertext = $ct; // ciphertext is now array of block-length strings
139
140
    // plaintext will get generated block-by-block into array of block-length strings
141
    $plaintxt = array();
142
143
    for ($b = 0; $b < $nBlocks; $b++) {
144
        // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
145
        for ($c = 0; $c < 4; $c++) {
146
            $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
147
        }
148
        for ($c = 0; $c < 4; $c++) {
149
            $counterBlock[15 - $c - 4] = self::urs(($b + 1) / 0x100000000 - 1, $c * 8) & 0xff;
150
        }
151
152
        $cipherCntr = Aes::cipher($counterBlock, $keySchedule); // encrypt counter block
153
154
        $plaintxtByte = array();
155
        for ($i = 0; $i < strlen($ciphertext[$b]); $i++) {
156
        // -- xor plaintext with ciphered counter byte-by-byte --
157
        $plaintxtByte[$i] = $cipherCntr[$i] ^ ord(substr($ciphertext[$b], $i, 1));
158
        $plaintxtByte[$i] = chr($plaintxtByte[$i]);
159
160
        }
161
        $plaintxt[$b] = implode('', $plaintxtByte);
162
    }
163
164
    // join array of blocks into single plaintext string
165
    $plaintext = implode('', $plaintxt);

includes/libraries/Encryption/Crypt/aesctr.php 1 location

@@ 226-405 (lines=180) @@
223
224
}
225
226
class aesctr extends Aes
227
{
228
229
    /**
230
     * Encrypt a text using AES encryption in Counter mode of operation
231
     *  - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
232
     *
233
     * Unicode multi-byte character safe
234
     *
235
     * @param plaintext string text to be encrypted
236
     * @param password  the password to use to generate a key
237
     * @param nBits     integer of bits to be used in the key (128, 192, or 256)
238
     * @return          string text
239
     */
240
    public static function encrypt($plaintext, $password, $nBits)
241
    {
242
        $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
243
        if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) {
244
            return ''; // standard allows 128/192/256 bit keys
245
        }
246
        // note PHP (5) gives us plaintext and password in UTF8 encoding!
247
248
        // use AES itself to encrypt password to get cipher key (using plain password as source for
249
        // key expansion) - gives us well encrypted key
250
        $nBytes = $nBits / 8; // no bytes in key
251
        $pwBytes = array();
252
        for ($i = 0; $i < $nBytes; $i++) {
253
            $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
254
        }
255
        $key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
256
        $key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
257
258
        // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in
259
        // 1st 8 bytes, block counter in 2nd 8 bytes
260
        $counterBlock = array();
261
        $nonce = floor(microtime(true) * 1000); // timestamp: milliseconds since 1-Jan-1970
262
        $nonceSec = floor($nonce / 1000);
263
        $nonceMs = $nonce % 1000;
264
        // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes
265
        for ($i = 0; $i < 4; $i++) {
266
            $counterBlock[$i] = self::urs($nonceSec, $i * 8) & 0xff;
267
        }
268
        for ($i = 0; $i < 4; $i++) {
269
            $counterBlock[$i + 4] = $nonceMs & 0xff;
270
        }
271
        // and convert it to a string to go on the front of the ciphertext
272
        $ctrTxt = '';
273
        for ($i = 0; $i < 8; $i++) {
274
            $ctrTxt .= chr($counterBlock[$i]);
275
        }
276
277
        // generate key schedule - an expansion of the key into distinct Key Rounds for each round
278
        $keySchedule = Aes::keyExpansion($key);
279
280
        $blockCount = ceil(strlen($plaintext) / $blockSize);
281
        $ciphertxt = array(); // ciphertext as array of strings
282
283
        for ($b = 0; $b < $blockCount; $b++) {
284
            // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
285
            // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
286
            for ($c = 0; $c < 4; $c++) {
287
                $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
288
            }
289
            for ($c = 0; $c < 4; $c++) {
290
                $counterBlock[15 - $c - 4] = self::urs($b / 0x100000000, $c * 8);
291
            }
292
293
            $cipherCntr = Aes::cipher($counterBlock, $keySchedule); // -- encrypt counter block --
294
295
            // block size is reduced on final block
296
            $blockLength = $b < $blockCount - 1 ? $blockSize : (strlen($plaintext) - 1) % $blockSize + 1;
297
            $cipherByte = array();
298
299
            for ($i = 0; $i < $blockLength; $i++) {  // -- xor plaintext with ciphered counter byte-by-byte --
300
                $cipherByte[$i] = $cipherCntr[$i] ^ ord(substr($plaintext, $b * $blockSize + $i, 1));
301
                $cipherByte[$i] = chr($cipherByte[$i]);
302
            }
303
            $ciphertxt[$b] = implode('', $cipherByte); // escape troublesome characters in ciphertext
304
        }
305
306
        // implode is more efficient than repeated string concatenation
307
        $ciphertext = $ctrTxt.implode('', $ciphertxt);
308
        $ciphertext = base64_encode($ciphertext);
309
310
        return $ciphertext;
311
    }
312
313
    /**
314
     * Decrypt a text encrypted by AES in counter mode of operation
315
     *
316
     * @param ciphertext source text to be decrypted
317
     * @param password   the password to use to generate a key
318
     * @param nBits      integer of bits to be used in the key (128, 192, or 256)
319
     * @return           string text
320
     */
321
    public static function decrypt($ciphertext, $password, $nBits)
322
    {
323
        $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
324
        if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) {
325
            return ''; // standard allows 128/192/256 bit keys
326
        }
327
        $ciphertext = base64_decode($ciphertext);
328
329
        // use AES to encrypt password (mirroring encrypt routine)
330
        $nBytes = $nBits / 8; // no bytes in key
331
        $pwBytes = array();
332
        for ($i = 0; $i < $nBytes; $i++) {
333
            $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
334
        }
335
        $key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
336
        $key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
337
338
        // recover nonce from 1st element of ciphertext
339
        $counterBlock = array();
340
        $ctrTxt = substr($ciphertext, 0, 8);
341
        for ($i = 0; $i < 8; $i++) {
342
            $counterBlock[$i] = ord(substr($ctrTxt, $i, 1));
343
        }
344
345
        // generate key schedule
346
        $keySchedule = Aes::keyExpansion($key);
347
348
        // separate ciphertext into blocks (skipping past initial 8 bytes)
349
        $nBlocks = ceil((strlen($ciphertext) - 8) / $blockSize);
350
        $ct = array();
351
        for ($b = 0; $b < $nBlocks; $b++) {
352
            $ct[$b] = substr($ciphertext, 8 + $b * $blockSize, 16);
353
        }
354
        $ciphertext = $ct; // ciphertext is now array of block-length strings
355
356
        // plaintext will get generated block-by-block into array of block-length strings
357
        $plaintxt = array();
358
359
        for ($b = 0; $b < $nBlocks; $b++) {
360
            // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
361
            for ($c = 0; $c < 4; $c++) {
362
                $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
363
            }
364
            for ($c = 0; $c < 4; $c++) {
365
                $counterBlock[15 - $c - 4] = self::urs(($b + 1) / 0x100000000 - 1, $c * 8) & 0xff;
366
            }
367
368
            $cipherCntr = Aes::cipher($counterBlock, $keySchedule); // encrypt counter block
369
370
            $plaintxtByte = array();
371
            for ($i = 0; $i < strlen($ciphertext[$b]); $i++) {
372
                // -- xor plaintext with ciphered counter byte-by-byte --
373
                $plaintxtByte[$i] = $cipherCntr[$i] ^ ord(substr($ciphertext[$b], $i, 1));
374
                $plaintxtByte[$i] = chr($plaintxtByte[$i]);
375
            }
376
            $plaintxt[$b] = implode('', $plaintxtByte);
377
        }
378
379
        // join array of blocks into single plaintext string
380
        $plaintext = implode('', $plaintxt);
381
382
        return $plaintext;
383
    }
384
385
    /*
386
    * Unsigned right shift function, since PHP has neither >>> operator nor unsigned ints
387
    *
388
    * @param a  number to be shifted (32-bit integer)
389
    * @param b  number of bits to shift a to the right (0..31)
390
    * @return   a right-shifted and zero-filled by b bits
391
    */
392
    private static function urs($a, $b)
393
    {
394
        $a &= 0xffffffff;
395
        $b &= 0x1f; // (bounds check)
396
        if ($a & 0x80000000 && $b > 0) {   // if left-most bit set
397
            $a = ($a >> 1) & 0x7fffffff; //   right-shift one bit & clear left-most bit
398
            $a = $a >> ($b - 1); //   remaining right-shifts
399
        } else {                       // otherwise
400
            $a = ($a >> $b); //   use normal right-shift
401
        }
402
403
        return $a;
404
    }
405
}
406
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
407

install/libs/aesctr.php 1 location

@@ 226-405 (lines=180) @@
223
224
}
225
226
class aesctr extends Aes
227
{
228
229
    /**
230
     * Encrypt a text using AES encryption in Counter mode of operation
231
     *  - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
232
     *
233
     * Unicode multi-byte character safe
234
     *
235
     * @param plaintext string text to be encrypted
236
     * @param password  the password to use to generate a key
237
     * @param nBits     integer of bits to be used in the key (128, 192, or 256)
238
     * @return          string text
239
     */
240
    public static function encrypt($plaintext, $password, $nBits)
241
    {
242
        $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
243
        if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) {
244
            return ''; // standard allows 128/192/256 bit keys
245
        }
246
        // note PHP (5) gives us plaintext and password in UTF8 encoding!
247
248
        // use AES itself to encrypt password to get cipher key (using plain password as source for
249
        // key expansion) - gives us well encrypted key
250
        $nBytes = $nBits / 8; // no bytes in key
251
        $pwBytes = array();
252
        for ($i = 0; $i < $nBytes; $i++) {
253
            $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
254
        }
255
        $key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
256
        $key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
257
258
        // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in
259
        // 1st 8 bytes, block counter in 2nd 8 bytes
260
        $counterBlock = array();
261
        $nonce = floor(microtime(true) * 1000); // timestamp: milliseconds since 1-Jan-1970
262
        $nonceSec = floor($nonce / 1000);
263
        $nonceMs = $nonce % 1000;
264
        // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes
265
        for ($i = 0; $i < 4; $i++) {
266
            $counterBlock[$i] = self::urs($nonceSec, $i * 8) & 0xff;
267
        }
268
        for ($i = 0; $i < 4; $i++) {
269
            $counterBlock[$i + 4] = $nonceMs & 0xff;
270
        }
271
        // and convert it to a string to go on the front of the ciphertext
272
        $ctrTxt = '';
273
        for ($i = 0; $i < 8; $i++) {
274
            $ctrTxt .= chr($counterBlock[$i]);
275
        }
276
277
        // generate key schedule - an expansion of the key into distinct Key Rounds for each round
278
        $keySchedule = Aes::keyExpansion($key);
279
280
        $blockCount = ceil(strlen($plaintext) / $blockSize);
281
        $ciphertxt = array(); // ciphertext as array of strings
282
283
        for ($b = 0; $b < $blockCount; $b++) {
284
            // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
285
            // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
286
            for ($c = 0; $c < 4; $c++) {
287
                $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
288
            }
289
            for ($c = 0; $c < 4; $c++) {
290
                $counterBlock[15 - $c - 4] = self::urs($b / 0x100000000, $c * 8);
291
            }
292
293
            $cipherCntr = Aes::cipher($counterBlock, $keySchedule); // -- encrypt counter block --
294
295
            // block size is reduced on final block
296
            $blockLength = $b < $blockCount - 1 ? $blockSize : (strlen($plaintext) - 1) % $blockSize + 1;
297
            $cipherByte = array();
298
299
            for ($i = 0; $i < $blockLength; $i++) {  // -- xor plaintext with ciphered counter byte-by-byte --
300
                $cipherByte[$i] = $cipherCntr[$i] ^ ord(substr($plaintext, $b * $blockSize + $i, 1));
301
                $cipherByte[$i] = chr($cipherByte[$i]);
302
            }
303
            $ciphertxt[$b] = implode('', $cipherByte); // escape troublesome characters in ciphertext
304
        }
305
306
        // implode is more efficient than repeated string concatenation
307
        $ciphertext = $ctrTxt.implode('', $ciphertxt);
308
        $ciphertext = base64_encode($ciphertext);
309
310
        return $ciphertext;
311
    }
312
313
    /**
314
     * Decrypt a text encrypted by AES in counter mode of operation
315
     *
316
     * @param ciphertext source text to be decrypted
317
     * @param password   the password to use to generate a key
318
     * @param nBits      integer of bits to be used in the key (128, 192, or 256)
319
     * @return           string text
320
     */
321
    public static function decrypt($ciphertext, $password, $nBits)
322
    {
323
        $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
324
        if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) {
325
            return ''; // standard allows 128/192/256 bit keys
326
        }
327
        $ciphertext = base64_decode($ciphertext);
328
329
        // use AES to encrypt password (mirroring encrypt routine)
330
        $nBytes = $nBits / 8; // no bytes in key
331
        $pwBytes = array();
332
        for ($i = 0; $i < $nBytes; $i++) {
333
            $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
334
        }
335
        $key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
336
        $key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
337
338
        // recover nonce from 1st element of ciphertext
339
        $counterBlock = array();
340
        $ctrTxt = substr($ciphertext, 0, 8);
341
        for ($i = 0; $i < 8; $i++) {
342
            $counterBlock[$i] = ord(substr($ctrTxt, $i, 1));
343
        }
344
345
        // generate key schedule
346
        $keySchedule = Aes::keyExpansion($key);
347
348
        // separate ciphertext into blocks (skipping past initial 8 bytes)
349
        $nBlocks = ceil((strlen($ciphertext) - 8) / $blockSize);
350
        $ct = array();
351
        for ($b = 0; $b < $nBlocks; $b++) {
352
            $ct[$b] = substr($ciphertext, 8 + $b * $blockSize, 16);
353
        }
354
        $ciphertext = $ct; // ciphertext is now array of block-length strings
355
356
        // plaintext will get generated block-by-block into array of block-length strings
357
        $plaintxt = array();
358
359
        for ($b = 0; $b < $nBlocks; $b++) {
360
            // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
361
            for ($c = 0; $c < 4; $c++) {
362
                $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
363
            }
364
            for ($c = 0; $c < 4; $c++) {
365
                $counterBlock[15 - $c - 4] = self::urs(($b + 1) / 0x100000000 - 1, $c * 8) & 0xff;
366
            }
367
368
            $cipherCntr = Aes::cipher($counterBlock, $keySchedule); // encrypt counter block
369
370
            $plaintxtByte = array();
371
            for ($i = 0; $i < strlen($ciphertext[$b]); $i++) {
372
                // -- xor plaintext with ciphered counter byte-by-byte --
373
                $plaintxtByte[$i] = $cipherCntr[$i] ^ ord(substr($ciphertext[$b], $i, 1));
374
                $plaintxtByte[$i] = chr($plaintxtByte[$i]);
375
            }
376
            $plaintxt[$b] = implode('', $plaintxtByte);
377
        }
378
379
        // join array of blocks into single plaintext string
380
        $plaintext = implode('', $plaintxt);
381
382
        return $plaintext;
383
    }
384
385
    /*
386
    * Unsigned right shift function, since PHP has neither >>> operator nor unsigned ints
387
    *
388
    * @param a  number to be shifted (32-bit integer)
389
    * @param b  number of bits to shift a to the right (0..31)
390
    * @return   a right-shifted and zero-filled by b bits
391
    */
392
    private static function urs($a, $b)
393
    {
394
        $a &= 0xffffffff;
395
        $b &= 0x1f; // (bounds check)
396
        if ($a & 0x80000000 && $b > 0) {   // if left-most bit set
397
            $a = ($a >> 1) & 0x7fffffff; //   right-shift one bit & clear left-most bit
398
            $a = $a >> ($b - 1); //   remaining right-shifts
399
        } else {                       // otherwise
400
            $a = ($a >> $b); //   use normal right-shift
401
        }
402
403
        return $a;
404
    }
405
}
406
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
407