SHOW:
|
|
- or go back to the newest paste.
1 | <?php | |
2 | ||
3 | /** Êëàññ îñóùåñòâëÿþùèé ðàáîòó ñ øèôðîì ÃÎÑÒ 28147-89 (øèôðîâàíèå/äåøèôðîâàííèå äàííûõ) | |
4 | * | |
5 | * @author IntSys | |
6 | * @copyright Copyright (c) 2011-2013, IntSys, intsystem.org | |
7 | */ | |
8 | class ClassGost{ | |
9 | /** Êîëè÷åñòî èòòåðàöèé îñíîâíîãî øàãà êðèïòîîáðàçîâàíèÿ | |
10 | */ | |
11 | const CNT_MAIN_STEP=32; | |
12 | ||
13 | /** Òàáëèöà çàìåí | |
14 | * | |
15 | * @var array | |
16 | */ | |
17 | protected $s_block=array( | |
18 | array(6,12,7,1,5,15,13,8,4,10,9,14,0,3,11,2), | |
19 | array(14,11,4,12,6,13,15,10,2,3,8,1,0,7,5,9), | |
20 | array(13,11,4,1,3,15,5,9,0,10,14,7,6,8,2,12), | |
21 | array(7,13,10,1,0,8,9,15,14,4,6,12,11,2,5,3), | |
22 | array(1,15,13,0,5,7,10,4,9,2,3,14,6,11,8,12), | |
23 | array(4,10,9,2,13,8,0,14,6,11,1,12,7,15,5,3), | |
24 | array(4,11,10,0,7,2,1,13,3,6,8,5,9,12,15,14), | |
25 | array(5,8,1,13,10,3,4,2,14,15,12,7,6,0,9,11), | |
26 | ||
27 | ); | |
28 | ||
29 | /** Êëþ÷ | |
30 | * | |
31 | * @var array | |
32 | */ | |
33 | protected $k_block=array ( | |
34 | 0x00000000, | |
35 | 0x00000000, | |
36 | 0x00000000, | |
37 | 0x00000000, | |
38 | 0x00000000, | |
39 | 0x00000000, | |
40 | 0x00000000, | |
41 | 0x00000000, | |
42 | ); | |
43 | ||
44 | ||
45 | /** Çàøèôðîâàòü äàííûå | |
46 | * | |
47 | * @param string $data äàííûå äëÿ øèôðîâàíèÿ | |
48 | * @param mixed $key êëþ÷ øèôðîâàíèÿ | |
49 | * @param array $table òàáëèöà çàìåí | |
50 | * @return mixed âîçâðàùàåò çàøèôðîâàííóþ ñòðîêó, èëè false â ñëó÷àå íåóäà÷è | |
51 | */ | |
52 | function Encode($data, $key=null, $table=null){ | |
53 | if(!is_null($key)){ | |
54 | if(!$this->SetKey($key)){ | |
55 | return false; | |
56 | } | |
57 | } | |
58 | ||
59 | if(!is_null($table)){ | |
60 | if(!$this->SetTableReplace($table)){ | |
61 | return false; | |
62 | } | |
63 | } | |
64 | ||
65 | $blocks=$this->LoadData2Blocks($data); | |
66 | $keys=$this->LoadKeysArray(self::CNT_MAIN_STEP); | |
67 | ||
68 | $result=''; | |
69 | ||
70 | foreach($blocks as $block){ | |
71 | $result.=$this->Global_MainStep($block, $keys); | |
72 | ||
73 | } | |
74 | ||
75 | return $result; | |
76 | } | |
77 | ||
78 | /** Ðàñøèôðîâàòü äàííûå | |
79 | * | |
80 | * @param string $data çàøèôðîâàííûå äàííûå | |
81 | * @param mixed $key êëþ÷ øèôðîâàíèÿ | |
82 | * @param array $table òàáëèöà çàìåí | |
83 | * @return mixed âîçâðàùàåò èñõîäíûå äàííûå, èëè false â ñëó÷àå íåóäà÷è | |
84 | */ | |
85 | function Decode($data, $key=null, $table=null){ | |
86 | if(!is_null($key)){ | |
87 | if(!$this->SetKey($key)){ | |
88 | return false; | |
89 | } | |
90 | } | |
91 | ||
92 | if(!is_null($table)){ | |
93 | if(!$this->SetTableReplace($table)){ | |
94 | return false; | |
95 | } | |
96 | } | |
97 | ||
98 | $blocks=$this->LoadData2Blocks($data); | |
99 | $keys=array_reverse($this->LoadKeysArray(self::CNT_MAIN_STEP)); | |
100 | ||
101 | $result=''; | |
102 | foreach($blocks as $block){ | |
103 | $result.=$this->Global_MainStep($block, $keys); | |
104 | } | |
105 | ||
106 | return $result; | |
107 | } | |
108 | ||
109 | /** Óñòàíîâèòü êëþ÷ øèôðîâàíèÿ<br><br> | |
110 | * Âîçìîæíî óêàçàòü êëþ÷ â äâóõ ôîðìàòàõ:<br> | |
111 | * - Ñòðîêà äëèííîé â 32 áàéòà<br> | |
112 | * - Ìàññèâ èç 8 ýëåìåíòîâ, ãäå êàæäûé ýëåìåíò - 4 áàéòîâîå ÷èñëî integer<br><br> | |
113 | * Ïðè ýòîì ëþáîå îòêëîíåíèå îò äàííûõ ôîðìàòîâ áóäåò âûçûâàòü îøèáêó | |
114 | * | |
115 | * @param mixed $key êëþ÷ øèôðîâàíèÿ | |
116 | * @return boolen âîçâðàùàåò true åñëè óäàëîñü óñòàíîâèòü êëþ÷ øèôðîâàíèÿ, false - åñëè ïðîèçîøëà îøèáêà | |
117 | */ | |
118 | function SetKey($key){ | |
119 | if(is_string($key)){ | |
120 | if(strlen($key)!==32){ | |
121 | trigger_error(__METHOD__.': "$key" length must be equal to 256 bits (32 bytes)', E_USER_WARNING); | |
122 | return false; | |
123 | } | |
124 | ||
125 | $new_key=array(); | |
126 | for($i=0; $i<32; $i+=4){ | |
127 | // $tmp=(int)hexdec(bin2hex(substr($key, ($i*4), 4))); | |
128 | $tmp=(int)hexdec(bin2hex(substr($key, ($i), 4))); | |
129 | $new_key[]=$tmp; | |
130 | } | |
131 | ||
132 | $this->k_block=$new_key; | |
133 | return true; | |
134 | }elseif(is_array($key)){ | |
135 | if(count($key)!=8){ | |
136 | trigger_error(__METHOD__.': count of elements in the array "$key" must be equal to 8', E_USER_WARNING); | |
137 | return false; | |
138 | } | |
139 | $new_key=array(); | |
140 | foreach($key as $k => $val){ | |
141 | if(!is_integer($val)){ | |
142 | trigger_error(__METHOD__.': every element of the array "$key" must be integer. The array element "$table['.htmlspecialchars($k).']" is not an integer.', E_USER_WARNING); | |
143 | return false; | |
144 | } | |
145 | ||
146 | $new_key[]=$val; | |
147 | } | |
148 | ||
149 | $this->k_block=$new_key; | |
150 | return true; | |
151 | }else{ | |
152 | trigger_error(__METHOD__.': unknown "$Key" format. "$key" must be array[8] of integer or 32-bytes string.', E_USER_WARNING); | |
153 | return false; | |
154 | } | |
155 | } | |
156 | ||
157 | /** Óñòàíîâèòü òàáëèöó çàìåí.<br> | |
158 | * Ôîðìàò òàáëèöû çàìåí - ìàòðèöà ðàçìåðíîñòüþ 8x16, | |
159 | * êàæäûé åå ýëåìåíò áîëüøå ëèáî ðàâåí 0 è ìåíüøå ëèáî ðàâåí 15, | |
160 | * ïðè ýòîì â êàæäîé ñòðîêå íå äîëæíî áûòü ïîâòîðÿþùèõñÿ çíà÷åíèé.<br><br> | |
161 | * Òàêæå îáðàòèòå âíèìàíèå ÷òî íåïðàâèëüíûé âûáîð òàáëèöû çàìåí, ìîæåò | |
162 | * ïðèâåñòè ê ñíèæåíèþ ñòîéêîñòè øèôðà. | |
163 | * | |
164 | * @example | |
165 | * Ïðèìåð òàáëèöû:<br> | |
166 | * array(6 ,12,7 ,1 ,5 ,15,13,8 ,4 ,10,9 ,14,0 ,3 ,11,2 ),<br> | |
167 | * array(14,11,4 ,12,6 ,13,15,10,2 ,3 ,8 ,1 ,0 ,7 ,5 ,9 ),<br> | |
168 | * array(13,11,4 ,1 ,3 ,15,5 ,9 ,0 ,10,14,7 ,6 ,8 ,2 ,12),<br> | |
169 | * array(7 ,13,10,1 ,0 ,8 ,9 ,15,14,4 ,6 ,12,11,2 ,5 ,3 ),<br> | |
170 | * array(1 ,15,13,0 ,5 ,7 ,10,4 ,9 ,2 ,3 ,14,6 ,11,8 ,12),<br> | |
171 | * array(4 ,10,9 ,2 ,13,8 ,0 ,14,6 ,11,1 ,12,7 ,15,5 ,3 ),<br> | |
172 | * array(4 ,11,10,0 ,7 ,2 ,1 ,13,3 ,6 ,8 ,5 ,9 ,12,15,14),<br> | |
173 | * array(5 ,8 ,1 ,13,10,3 ,4 ,2 ,14,15,12,7 ,6 ,0 ,9 ,11),<br> | |
174 | * | |
175 | * @param array $table òàáëèöà çàìåí | |
176 | * @return boolean âîçâðàùàåò true åñëè óäàëîñü óñòàíîâèòü òàáëèöó çàìåí, false- åñëè ïðîèçîøëà îøèáêà | |
177 | */ | |
178 | function SetTableReplace($table){ | |
179 | if(!is_array($table)){ | |
180 | trigger_error(__METHOD__.': "$table" must be array', E_USER_WARNING); | |
181 | return false; | |
182 | } | |
183 | ||
184 | if(count($table)!=8){ | |
185 | trigger_error(__METHOD__.': count of elements in the array "$table" must be equal to 8', E_USER_WARNING); | |
186 | return false; | |
187 | } | |
188 | ||
189 | $i=0; | |
190 | $new_array=array(); | |
191 | foreach($table as $key => $val){ | |
192 | if(!is_array($val)){ | |
193 | trigger_error(__METHOD__.': $table['.htmlspecialchars($key).'] must be array', E_USER_WARNING); | |
194 | return false; | |
195 | } | |
196 | ||
197 | if(count($val)!=16){ | |
198 | trigger_error(__METHOD__.': count of elements in the array "$table['.htmlspecialchars($key).']" must be equal to 16', E_USER_WARNING); | |
199 | return false; | |
200 | } | |
201 | ||
202 | ||
203 | $new_val=array(); | |
204 | foreach($val as $int_key => $int_val){ | |
205 | if(!is_integer($int_val)){ | |
206 | trigger_error(__METHOD__.': every element of the array "$table['.htmlspecialchars($key).']" must be integer. The array element "$table['.htmlspecialchars($key).']['.htmlspecialchars($int_key).']" is not an integer.', E_USER_WARNING); | |
207 | return false; | |
208 | } | |
209 | ||
210 | if($int_val>15 || $int_val<0){ | |
211 | trigger_error(__METHOD__.': every element of the array "$table['.htmlspecialchars($key).']" must be greater than or equal to 0 and less than or equal to 15. The array element "$table['.htmlspecialchars($key).']['.htmlspecialchars($int_key).']" is not in this range.', E_USER_WARNING); | |
212 | return false; | |
213 | } | |
214 | $new_val[]=$int_val; | |
215 | } | |
216 | ||
217 | $new_array[$i]=$new_val; | |
218 | $i++; | |
219 | } | |
220 | ||
221 | ||
222 | $this->s_block=$new_array; | |
223 | return true; | |
224 | } | |
225 | ||
226 | /** Îñíîâíîé øàã øèôðîîáðàçîâàíèÿ | |
227 | * | |
228 | * @param string $block øèôðóåìûé áëîê | |
229 | * @param array $keys ïîäãîòîâëåííûé ìàññèâ ñ êëþ÷àìè | |
230 | * @param intger $cnt_repeat [îïöèîíàëüíî] êîëè÷åñòâî ïðåîáðàçîâàíèé | |
231 | * @return string | |
232 | */ | |
233 | protected function Global_MainStep($block, $keys, $cnt_repeat=self::CNT_MAIN_STEP){ | |
234 | $this->Global_BlockExplode($block, $n1, $n2); | |
235 | ||
236 | if(count($keys)<$cnt_repeat){ | |
237 | $cnt_repeat=count($keys); | |
238 | } | |
239 | ||
240 | for($i=0; $i<$cnt_repeat; $i++){ | |
241 | $val=$this->Global_SummMod32($n1, $keys[$i]); | |
242 | ||
243 | $val=$this->Global_BlockReplace($val); | |
244 | ||
245 | $val=$this->Global_BlockCycleShift($val, 21); | |
246 | ||
247 | $val=$val ^ $n2; | |
248 | ||
249 | $n2=$n1; | |
250 | $n1=$val; | |
251 | } | |
252 | ||
253 | $this->Global_BlockImplode($block, $n2, $n1); | |
254 | return $block; | |
255 | } | |
256 | ||
257 | /** Ôóíêöèÿ öèêëè÷íîãî ïîáèòîâîãî ñäâèãà âïðàâî | |
258 | * | |
259 | * @param integer $block | |
260 | * @param integer $bits êîëè÷åñòâî áèòîâ äëÿ ñäâèãà | |
261 | * @return integer | |
262 | */ | |
263 | protected function Global_BlockCycleShift($block, $bits){ | |
264 | if($bits>0){ | |
265 | $a=$bits; | |
266 | $b=32-$a; | |
267 | $block=(($block >> $a) & ~(-pow(2,$b)))^($block << $b); | |
268 | } | |
269 | return $block; | |
270 | } | |
271 | ||
272 | /** Çàìåíà ïî òàáëèöå çàìåí | |
273 | * | |
274 | * @param integer $block òåêóùèé áëîê äëÿ çàìåíû | |
275 | * @return integer | |
276 | */ | |
277 | protected function Global_BlockReplace($block){ | |
278 | $new_block=0; | |
279 | ||
280 | for($i=0; $i<8; $i++){ | |
281 | //Âû÷ëåíÿåì íóæíûå 4 áèòà ïîä çàìåíó | |
282 | $rem=$block>>(4*($i+1)); | |
283 | $rem=$rem<<(4*($i+1)); | |
284 | ||
285 | if($i==7){ | |
286 | $hex=$rem; | |
287 | }else{ | |
288 | $hex=$block-$rem; | |
289 | $block=$rem; | |
290 | } | |
291 | ||
292 | $hex=$this->Global_BlockCycleShift($hex,(4*$i)); | |
293 | ||
294 | //Íàõîäèì íà êàêîå ÷èñëî åãî çàìåíÿòü ïî òàáëèöå çàìåí | |
295 | $replace=$this->s_block[$i][$hex]; | |
296 | ||
297 | //Çàìåíÿåì | |
298 | $new_block=$new_block + (pow(16, $i)*$replace); | |
299 | } | |
300 | ||
301 | return $new_block; | |
302 | } | |
303 | ||
304 | /** Ñóììèðîâàíèå äâóõ ÷èñåë ïî ìîäóëþ 32 | |
305 | * | |
306 | * @param integer $bin1 ÷èñëî (4 áàéòà) | |
307 | * @param integer $bin2 ÷èñëî (4 áàéòà) | |
308 | * @return integer ðåçóëüòàò âû÷èñëåíèÿ (4 áàéòà) | |
309 | */ | |
310 | protected function Global_SummMod32($bin1, $bin2){ | |
311 | $summ=$this->NormalizeInteger32(intval($bin1 + $bin2)); | |
312 | ||
313 | return $summ; | |
314 | } | |
315 | ||
316 | /** Ðàçáèåíèå áëîêà íà "ïðàâóþ" è "ëåâóþ" ÷àñòü | |
317 | * | |
318 | * @param string $block âõîäíîé áëîê (8 áàéò) | |
319 | * @param &integer $left ëåâàÿ ÷àñòü (íàêîïèòåëü N1) (4 áàéòà) | |
320 | * @param &integer $right ïðàâàÿ ÷àñòü (íàêîïèòåëü N2) (4 áàéòà) | |
321 | */ | |
322 | protected function Global_BlockExplode($block, &$left, &$right){ | |
323 | $left=''; | |
324 | $right=''; | |
325 | ||
326 | $left=substr($block, 0, 4); | |
327 | $right=substr($block, 4, 4); | |
328 | ||
329 | $left =hexdec(bin2hex($left )); | |
330 | $right=hexdec(bin2hex($right)); | |
331 | } | |
332 | ||
333 | /** Ðàçáèåíèå áëîêà íà "ïðàâóþ" è "ëåâóþ" ÷àñòü | |
334 | * | |
335 | * @param &string $block âõîäíîé áëîê (8 áàéò) | |
336 | * @param integer $left ëåâàÿ ÷àñòü (íàêîïèòåëü N1) (4 áàéòà) | |
337 | * @param integer $right ïðàâàÿ ÷àñòü (íàêîïèòåëü N2) (4 áàéòà) | |
338 | */ | |
339 | protected function Global_BlockImplode(&$block, $left, $right){ | |
340 | $left =sprintf("%08x", $left ); | |
341 | $right=sprintf("%08x", $right); | |
342 | ||
343 | $block=''; | |
344 | ||
345 | $arr=str_split($left, 2); | |
346 | foreach($arr as $hex){ | |
347 | $block.=chr(hexdec($hex)); | |
348 | } | |
349 | ||
350 | $arr=str_split($right, 2); | |
351 | foreach($arr as $hex){ | |
352 | $block.=chr(hexdec($hex)); | |
353 | } | |
354 | } | |
355 | ||
356 | /** Ãåíåðèðóåì ìàññèâ ñ êëþ÷àìè | |
357 | * | |
358 | * @param integer $cnt_repeat êîëè÷åñòâî êëþ÷åé | |
359 | * @return array | |
360 | */ | |
361 | protected function LoadKeysArray($cnt_repeat=self::CNT_MAIN_STEP){ | |
362 | $key_block=array(); | |
363 | for($i=0; $i<$cnt_repeat; $i++){ | |
364 | if($i<($cnt_repeat-8)){ | |
365 | $x=$i % 8; | |
366 | }else{ | |
367 | $x=7 - ($i % 8); | |
368 | } | |
369 | $key_block[]=$this->k_block[$x]; | |
370 | } | |
371 | ||
372 | return $key_block; | |
373 | } | |
374 | ||
375 | /** Ðàçáèâàåì äàííûå íà áëîêè ïî 64 áèòà (8 áàéò) | |
376 | * | |
377 | * @param string $data âõîäíûå äàííûå | |
378 | * @param integer $block_size [îïöèîíàëüíî] (64 - äåôîëò) ðàçìåðíîñòü áëîêîâ | |
379 | * @return array âûõîäíîé ìàññèâ ñ áëîêàìè | |
380 | */ | |
381 | protected function LoadData2Blocks($data, $block_size=64){ | |
382 | $blocks=array(); | |
383 | ||
384 | $block_len=(int)$block_size / 8; | |
385 | ||
386 | for($i=0, $x=(ceil(strlen($data)/$block_len)); $i<$x; $i++){ | |
387 | $blocks[$i]=substr($data, ($i*$block_len), $block_len); | |
388 | ||
389 | if($i==($x-1)){ | |
390 | //Åñëè ïîñëåäíèé áëîê íå ïîëîí, òî äîïîëíÿåì åãî íóëÿìè | |
391 | $blocks[$i]=str_pad($blocks[$i], $block_len, chr(0), STR_PAD_RIGHT); | |
392 | ||
393 | } | |
394 | } | |
395 | ||
396 | return $blocks; | |
397 | } | |
398 | ||
399 | /** Ïðåâåäåíèå 64áèòíîãî integer ê "32áèòíîìó" íà 64áèòíûõ ñèñòåìàõ | |
400 | * | |
401 | * @param integer $number | |
402 | */ | |
403 | private function NormalizeInteger32($number){ | |
404 | static $is_64bit=null; | |
405 | ||
406 | $number=intval($number); | |
407 | ||
408 | if(is_null($is_64bit)){ | |
409 | if(intval(2147483647+1)>0){ | |
410 | $is_64bit=true; | |
411 | }else{ | |
412 | $is_64bit=false; | |
413 | } | |
414 | } | |
415 | ||
416 | if($is_64bit){ | |
417 | static $int=null; | |
418 | ||
419 | if(is_null($int)){ | |
420 | $int=0; | |
421 | ||
422 | //Ãåíåðèðóåì ÷èñëî ó êîòîðîãî â äâîè÷íîì ïðåäñòàâëåíèè ìëàäøèå 32 áèòà - åäèíèöû, îñòàëüíûå - íóëè | |
423 | // | |
424 | // 32-áèòíûõ ñèñòåìàõ ýòî ÷èñëî "-1" | |
425 | //Â 64-áèòíûõ - "4294967295" | |
426 | for($i=0; $i<32; $i++){ | |
427 | $int=$int | (1<<$i); | |
428 | } | |
429 | } | |
430 | ||
431 | //Ïîáèòîâîå AND | |
432 | $number=intval($number & $int); | |
433 | } | |
434 | ||
435 | return $number; | |
436 | } | |
437 | } |