Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
12 efrain 1
<?php
2
 
3
declare(strict_types=1);
4
 
5
 
6
class rsa {
7
    /**
8
     *
9
     * @var array
10
     */
11
    private $primes;
12
 
13
    /**
14
     *
15
     * @var int
16
     */
17
    private $maxprimes;
18
 
19
    /**
20
     *
21
     * @var Rsa
22
     */
23
    private static $_instance;
24
 
25
    /**
26
     *
27
     * @var int
28
     */
29
    private $n;
30
 
31
    /**
32
     *
33
     * @var int
34
     */
35
    private $e;
36
 
37
    /**
38
     *
39
     * @var int
40
     */
41
    private $d;
42
 
43
    public function __construct()
44
    {
45
        /*random generator seed */
46
        //mt_srand((double)microtime()*1000000);
47
        mt_srand((int)microtime()*1000000);
48
        /*
49
         * Prime numbers table
50
         * 570 prime numbers (Array can not be be enlarged)
51
         * 4507, 4513 is the smallest and 9521, 9533 is the largest pair
52
         * Still have no time to find why 9521, 9533 is the largest - sorry :)
53
         */
54
        $this->primes = array (4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597,
55
            4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751,
56
            4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931,
57
            4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051,
58
            5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227,
59
            5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399,
60
            5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521,
61
            5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683,
62
            5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839,
63
            5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007,
64
            6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151,
65
            6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301,
66
            6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451,
67
            6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637,
68
            6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791,
69
            6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949,
70
            6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103,
71
            7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253,
72
            7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477,
73
            7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589,
74
            7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741,
75
            7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919,
76
            7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093,
77
            8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263,
78
            8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429,
79
            8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609,
80
            8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741,
81
            8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893,
82
            8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059,
83
            9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227,
84
            9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397,
85
            9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533);
86
 
87
        $this->maxprimes = count($this->primes) - 1;
88
 
89
 
90
    }
91
 
92
    /**
93
     *
94
     * @param int $n
95
     * @param int $d
96
     * @param int $e
97
     */
98
    public function setKeys($n, $d, $e)
99
    {
100
        $this->n = $n;
101
        $this->d = $d;
102
        $this->e = $e;
103
    }
104
 
105
    /*
106
     Function for generating keys. Return array where
107
     $array[0] -> modulo N
108
     $array[1] ->  key E
109
     $array[2] ->  key D
110
     Public key pair is N and E
111
     Private key pair is N and D
112
     */
113
    public function generateKeys()
114
    {
115
        list($usec, $sec) = explode(' ', microtime());
116
        $seed = intval($sec + ((float) $usec * 100000));
117
        mt_srand($seed, MT_RAND_MT19937);
118
 
119
 
120
        $e = 0;
121
        $q = 0;
122
        $q = 0;
123
 
124
        //class-ify: global $primes, $maxprimes;
125
        while (empty($e) || empty($d)) {
126
            /* finding 2 small prime numbers $p and $q
127
             $p and $q must be different*/
128
            $p = $this->primes[mt_rand(0, $this->maxprimes)];
129
            while (empty($q) || ($p==$q)) {
130
                $q = $this->primes[mt_rand(0, $this->maxprimes)];
131
            }
132
            //second part of  and  pairs - N
133
            $n = $p*$q;
134
 
135
            //$pi (we need it to calculate D and E)
136
            $pi = ($p - 1) * ($q - 1);
137
 
138
            // Public key  E
139
            $e = $this->tofindE($pi, $p, $q);
140
 
141
            // Private key D
142
            $d = $this->extend($e, $pi);
143
 
144
            $keys = array ('n' => $n, 'd' => $d, 'e' => $e);
145
        }
146
        return $keys;
147
    }
148
 
149
    /* modulus function */
150
    private function mo($g, $l)
151
    {
152
        $result = $g - ($l * floor ($g/$l));
153
 
154
        return $result;
155
    }
156
 
157
    /*
158
     * Standard method of calculating D
159
     * D = E-1 (mod N)
160
     * It's presumed D will be found in less then 16 iterations
161
     */
162
    private function extend($Ee, $Epi) {
163
        $u1 = 1;
164
        $u2 = 0;
165
        $u3 = $Epi;
166
        $v1 = 0;
167
        $v2 = 1;
168
        $v3 = $Ee;
169
        while ($v3 != 0) {
170
            $qq = floor($u3/$v3);
171
            $t1 = $u1 - $qq * $v1;
172
            $t2 = $u2 - $qq * $v2;
173
            $t3 = $u3 - $qq * $v3;
174
            $u1 = $v1;
175
            $u2 = $v2;
176
            $u3 = $v3;
177
            $v1 = $t1;
178
            $v2 = $t2;
179
            $v3 = $t3;
180
            $z = 1;
181
        }
182
        $uu = $u1;
183
        $vv = $u2;
184
        if ($vv < 0) {
185
            $inverse = $vv + $Epi;
186
        } else {
187
            $inverse = $vv;
188
        }
189
        return $inverse;
190
    }
191
 
192
    /* This function return Greatest Common Divisor for $e and $pi numbers */
193
    private function GCD($e, $pi)
194
    {
195
        $y = $e;
196
        $x = $pi;
197
        while ($y != 0) {
198
            $w =  $this->mo($x , $y);
199
            $x = $y;
200
            $y = $w;
201
        }
202
        return $x;
203
    }
204
 
205
    /*function for calculating E under conditions:
206
     GCD(N, E) = 1 and 1<E<N
207
     If each test E is prime, there will be much less loops in that fuction
208
     and smaller E means less JS calculations on client side */
209
    /*
210
     * Calculating E under conditions:
211
     * GCD(N, E) = 1 and 1<E<N
212
     * If E is prime, there will be fewer loops in the function.
213
     * Smaller E also means reduced JS calculations on client side.
214
     */
215
    private function tofindE($pi)
216
    {
217
        //class-ify: global $primes, $maxprimes;
218
        $great = 0;
219
        $cc = mt_rand (0, $this->maxprimes);
220
        $startcc = $cc;
221
        while ($cc >= 0) {
222
            $se = $this->primes[$cc];
223
            $great = $this->GCD($se, $pi);
224
            $cc--;
225
            if ($great == 1) { break; }
226
        }
227
        if ($great == 0) {
228
            $cc = $startcc + 1;
229
            while ($cc <= $this->maxprimes) {
230
                $se = $this->primes[$cc];
231
                $great = $this->GCD($se, $pi);
232
                $cc++;
233
                if ($great == 1) { break; }
234
            }
235
        }
236
        return $se;
237
    }
238
 
239
    /*
240
     * ENCRYPT function returns
241
     *, X = M^E (mod N)
242
     * Please check http://www.ge.kochi-ct.ac.jp/cgi-bin-takagi/calcmodp
243
     * and Flash5 RSA .fla by R.Vijay <rveejay0 <at> hotmail <dot> com> at
244
     * http://www.digitalillusion.co.in/lab/rsaencyp.htm
245
     * It is one of the simplest examples for binary RSA calculations
246
     *
247
     * Each letter in the message is represented as its ASCII code number - 30
248
     * 3 letters in each block with 1 in the beginning and end.
249
     * For example string
250
     *, AAA
251
     * will become
252
     *, 13535351 (A = ASCII 65-30 = 35)
253
     * we can build these blocks because the smalest prime available is 4507
254
     *, 4507^2 = 20313049
255
     * This means that
256
     *, 1. Modulo N will always be < 19999991
257
     *, 2. Letters > ASCII 128 must not occur in plain text message
258
     */
259
 
260
    public function encrypt($m)
261
    {
262
        $m = strval($m);
263
 
264
        $asci = array ();
265
        for ($i=0, $max = strlen($m); $i<$max; $i+=3) {
266
            $tmpasci='1';
267
            for ($h=0; $h<3; $h++)
268
            {
269
                if ($i+$h <strlen($m)) {
270
                    $tmpstr = strval((ord (substr ($m, $i+$h, 1)) - 30));
271
                    if (strlen($tmpstr) < 2) {
272
                        $tmpstr ='0'.$tmpstr;
273
                    }
274
                } else {
275
                    break;
276
                }
277
                $tmpasci .=$tmpstr;
278
            }
279
            array_push($asci, $tmpasci.'1');
280
        }
281
        //Each number is then encrypted using the RSA formula: block ^E mod N
282
        $coded = null;
283
        for ($k=0, $max = count($asci) ; $k < $max; $k++)
284
        {
285
            $resultmod = $this->powmod($asci[$k], $this->e, $this->n);
286
            $coded .= $resultmod." ";
287
        }
288
        return strval($coded);
289
    }
290
 
291
    /*Russian Peasant method for exponentiation */
292
    private function powmod($base, $exp, $modulus)
293
    {
294
        $accum = 1;
295
        $i = 0;
296
        $basepow2 = $base;
297
        while (($exp >> $i)>0) {
298
            if ((($exp >> $i) & 1) == 1) {
299
                $accum = $this->mo(($accum * $basepow2) , $modulus);
300
            }
301
            $basepow2 = $this->mo(($basepow2 * $basepow2) , $modulus);
302
            $i++;
303
        }
304
        return $accum;
305
    }
306
 
307
    /*
308
     ENCRYPT function returns
309
     M = X^D (mod N)
310
     */
311
    public function decrypt($c) {
312
        $c = strval($c);
313
 
314
        //Strip the blank spaces from the ecrypted text and store it in an array
315
        $decryptarray = explode(' ', $c);
316
        for ($u=0; $u<count ($decryptarray); $u++)
317
        {
318
            if ($decryptarray[$u] == '') {
319
                array_splice($decryptarray, $u, 1);
320
            }
321
        }
322
        //Each number is then decrypted using the RSA formula: block ^D mod N
323
        $deencrypt = '';
324
        for ($u=0, $max = count($decryptarray); $u < $max; $u++)
325
        {
326
            $resultmod = strval($this->powmod($decryptarray[$u], $this->d, $this->n));
327
            //remove leading and trailing '1' digits
328
            $deencrypt.= substr ($resultmod, 1, strlen($resultmod)-2);
329
        }
330
        //Each ASCII code number + 30 in the message is represented as its letter
331
        $resultd = '';
332
        for ($u=0; $u<strlen($deencrypt); $u+=2) {
333
            $resultd .= chr(substr ($deencrypt, $u, 2) + 30);
334
        }
335
        return $resultd;
336
    }
337
}
338
 
339
?>