View difference between Paste ID: U3jtbRbq and bH8c8jha
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
}