-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
798 lines (741 loc) · 65.5 KB
/
Copy pathindex.html
File metadata and controls
798 lines (741 loc) · 65.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
<!DOCTYPE html>
<html lang="bg">
<head>
<meta charset="utf-8" />
<title>Разлики при криптиране, хеширане и посоляване</title>
<link rel="stylesheet" href="css/styles.css" />
<link rel="stylesheet" href="css/playgrounds.css" />
</head>
<body>
<article>
<section class="content">
<h1>Разлики при криптиране, хеширане и посоляване</h1>
<h2>Въведение</h2>
<p>
Всеки човек, използващ интернет, се е сблъсквал с процесите по
криптиране и хеширане на информация, но може би единствено изучените
програмисти знаят какви процеси стоят зад тези сложни термини.
</p>
<p>
<strong class="blue">Криптирането</strong> е основен процес при
сигурния <mark class="orange">трансфер на данни</mark>, използван в
комуникацията между повечето модерни устройства. Предаваната
информация се криптира така, че единствено желаният получател да може
да разтълкува съдържанието й. Така зловредни опити за разчитане на
информацията при процеса на трансфер са напрактика безполезни. Пример
за това би било при плащане с банкова карта, външно лице да се опита
да извлече банковата ни информация, като проследява криптираните данни
от транзакцията.
</p>
<p>
При <strong class="blue">хеширането</strong> основният проблем, който
се разрешава, е проверката за
<mark class="orange">интегритет на данни</mark>. Стойността получена
при хеширането на дадени данни е уникална, като всяка малка промяна в
данните води до напълно различна хеш стойност. Освен това хеширането
не е обратим процес за разлика от криптирането т.е. при наличие на хеш
стойността не можем да възстановим първоначалния вид на данните. Така
например безопасно могат да се съхраняват пароли чрез тяхната уникална
хеш стойност без притеснения, че хакер, получил достъп до базата, ще
получи достъп и до акаунтите на потребителите
</p>
<p>
Но какво ще стане, ако хакерът в горния пример забележи, че в базата с
хешираните пароли има еднакви стойности? Това би подсказало на хакера,
че съответните потребители използват често срещани пароли. Всеки
уважаващ себе си хакер би успял да разбие тези лесни пароли за
отрицателно време. За да се предотврати този проблем, повечето модерни
приложения използват техниката посоляване.
<strong class="blue">Посоляването</strong> е процесът по прибавяне на
допълнителна последователност от символи към потребителската парола
преди процеса на хеширане. Постига се
<mark class="orange">усложняване на потребителската парола</mark>.
Така двама потребители с еднаква парола, ще имат различни хеш
стойности в базата данни, което значително усложнява работата на
злонамерените хакери.
</p>
<p>Нека разгледаме по-подробно гореописаните понятия.</p>
<h2>Криптиране</h2>
<p>
Криптирането не е процес, който навлиза в употреба с появата на
компютрите. Исторически данни показват, че още древните египтяни са
използвали система за промяна текстове си, така че само избрани лица
от аристокрацията да разберат значението им.<sup><a href="#references_1">[1]</a></sup>
</p>
<h3>Шифърът на Цезар</h3>
<p>
Един от най-известните ранни шифри е този използван от римския
император Юлий Цезар. Цезар е използвал примитивна версия на "Shift"
шифър, за да води скрита от враговете си кореспонденция. Шифърът на
Цезар взема дадено съобщение и заменя всяка самостоятелна буква в него
с буквата на <mark class="orange">3 позиции напред</mark> в азбуката.
</p>
<p>
Например в криптирано съобщение думата
<mark class="significant blue">ВОЙНА</mark> ще бъде заменена с
<mark class="significant green">ЕСМРГ</mark>, тъй като на буквата
<em>В</em> отговаря буквата <em>Е</em>, на <em>О</em> – <em>С</em> и т.н.
Когато получателят види криптираното съобщение той трябва да използва
обратния процес декриптиране, за да разбере съдържанието му. Това
изисква предварителна "уговорка" между двете лица, тоест криптиращия
участник трябва да сподели метода на декриптиране на своя събеседник
преди започване на криптираната комуникация.
</p>
<p>
В нашия пример съобщението <em>ЕСМРГ</em> ще бъде декодирано, като за
всяка негова буква бъде заменена с тази на 3 позиция преди нея в
азбуката. Това е обратният процес на операцията по кодиране. С
по-математически термини, ако представим буквите от азбуката чрез
числата от 0 до 29 (<em>A</em> е 0, <em>Б</em> е 1, ..., <em>Я</em> е 29),
то функцията на кодиране е <em>Fn(x) = (x + n) mod 30</em>, където
<em>n</em> е броят измествания надясно (при Цезаровия шифър
<em>n = 3</em>). Функцията за Декориране
<em>Gn(x) = (x – n) mod 30</em>.<sup><a href="#references_2">[2]</a></sup>
</p>
<section class="ceaserShiftContainer playground">
<h4>Цезаров шифър в действие</h4>
<section>
<label for="alphabetSelect">Азбука на съобщението:</label>
<select id="alphabetSelect" onchange="updateShift()">
<option value="cyrillic" selected>Кирилица</option>
<option value="latin">Латиница</option>
</select>
</section>
<section>
<label for="textInput">Съобщение за кодиране:</label>
<input type="text" id="textInput" class="inputBox"
placeholder="Въведете текст, състоящ се от главни букви..." oninput="updateShift()" />
</section>
<section>
<section>Стойност на преместването: <mark id="shiftValue" class="orange">0</mark></section>
<input type="range" id="shiftRange" oninput="updateShift()" />
</section>
<section>
<label for="originalLettersContainer">Шифър:</label>
<section class="letters-container">
<section class="row" id="originalLettersContainer"></section>
<section class="row" id="encodedLettersContainer"> </section>
</section>
</section>
<section>
<label for="encodedText">Криптираното съобщение:</label>
<input type="text" id="encodedText" class="outputBox" readonly />
</section>
<script src="javascript/ceaser_shift.js"></script>
</section>
<h3>Разбиване на криптиращ алгоритъм</h3>
<p>
Ефективността на един шифър или алгоритъм за криптиране се определя
чрез времето нужно за разгадаването му – разбиването на ключа.
Алгоритъмът на Цезар, колкото и примитивен да изглежда, е бил разгадан
едва след 9 века от арабски учен.<sup><a href="#references_2">[2]</a></sup>
Въпреки това, ако е известен методът – изместване на азбуката с дадено
число, то са нужни 30 на брой опита, за да се разгадае ключа, равен на
3.
</p>
<p>
Съществуват различни вариации на шифъра на Цезар, които се опитват да
увеличат сложността на алгоритъма. Ако се използва индивидуално
подреждане, такова че всяка буква отговаря на произволна друга
възможните комбинации за ключ стават <em>30!</em>. Това е число с 32
нули, което би довело читателя до мисълта, че този шифър би бил
неразбиваем. Това ще е вярно, ако се използва наивен
<em class="orange">brute force</em> метод за
решаването на проблема.<sup><a href="#references_6">[6]</a></sup>
</p>
<p>
При анализирането на даден криптиращ алгоритъм повече на брой ключове,
не винаги значи по-сигурен алгоритъм. Съществуват техники като
<mark class="orange">семантичния анализ</mark>, които
лесно разбиват семейството от шифри, произлизащи от Цезаровия.
Семантичният анализ проверява колко често се среща всяка буква в
шифрованото съобщение. Това носи изключително много информация за
възможните ключове, тъй като най-срещаните букви в езика, ще отговарят
на най-срещаните букви в криптираното съобщение.<sup><a href="#references_3">[3]</a></sup>
</p>
<p>
Например петте най-често срещаните букви в българския език са
<em>А</em>, <em>И</em>, <em>О</em>, <em>Е</em> и <em>Н</em>.<sup><a href="#references_4">[4]</a></sup>
Нека си представим как сме шпиони, които са се добрали до кодираното
съобщение
<mark class="significant green">ЧА КУЕ ЖЧРЮДЗ ЖЧ ИЮЛЖЧЬЮКЮЛ ОБДЦЬЖЧ ЧЙЕБЦ Б ИУЛМЩЧЕ ГУЕ ЩЧК</mark>
и искаме да го разгадаем. Ако анализираме броя срещания на всяка буква
ще забележим, че най-често срещана в съобщението е буквата <em>Ч</em>,
следвана от <em>Е</em>, <em>Ж</em>, <em>Ю</em>. Много по-вероятно е
кодираната буква <em>Ч</em> да отговаря на <em>А</em> в реалното
съобщение, отколкото на буквата <em>Щ</em> например.
</p>
<p>
Съобщението е:
<mark class="significant blue">АЗ СЪМ НАЧЕЛО НА ПЕТНАДЕСЕТ ХИЛЯДНА АРМИЯ И ПЪТУВАМ КЪМ ВАС</mark>
</p>
<section class="frequencyAnalyzerContainer playground">
<h4>Анализатор на честотата на символите</h4>
<section><label for="inputText">Съобщение:</label>
<input type="text" id="inputText" class="inputBox"
placeholder="Въведете текст за анализиране тук..."></input>
</section>
<section id="results">
<table id="frequencyTable">
<thead>
<tr>
<th id="tableSymbol">Символ</th>
<th id="tableFrequency">Честота</th>
</tr>
</thead>
<tbody></tbody>
</table>
</section>
<script src="javascript/frequency_analyzer.js"></script>
</section>
<h3>Криптиращи ключове</h3>
<p>
Друг примерен вариант е
<mark class="orange">шифърът на Виженер</mark>. Нека си представим
ключа на обикновения шифър на Цезар, като една буква – примерно ключ
<em>Г</em>. Това ще означава, че местим всяка буква от оригиналното
съобщение с 3 позиции напред, тъй като буквата <em>Г</em> е третата
буква в азбуката, ако започнем броенето от 0. Горният вариант на
шифър, където всяка буква сочи към друга буква, има ключ с дължина 30
– на всяка буква от азбуката показваме с колко да се измести чрез
друга буква от азбуката. Тогава шифърът на Виженер може да има ключ с
произволна дължина.<sup><a href="#references_3">[3]</a></sup>
</p>
<p>
Например ключа <mark class="significant orange">ГБК</mark> означава,
че първата буква в нашето съобщение ще бъде преместена с 3 позиции
напред, тъй като <em>Г</em> е третата буква от азбуката, като започнем
от 0. Следващата буква в нашето съобщение ще бъде криптирана чрез
изместването й на 1 позиция напред в азбуката (<em>Б = 1</em>). Третата
буква в нашето съобщение ще бъде изместена с 10 позиции напред (<em>К = 10</em>). След това повтаряме
процеса по криптиране, като започваме от
четвъртата буква на съобщението и първия символ на ключа.
</p>
<p>
Нека криптираме съобщението
<mark class="significant blue">ЗАПОЧВАМЕ ВОЙНА</mark> с ключа
<mark class="significant orange">ГБК</mark>. Това се получава, като
заместим <em>З</em> с буквата 3 позиции напред – <em>К</em>, поради ключа
<em>Г</em>, после <em>А</em> с <em>Б</em> заради <em>Б</em>, <em>П</em> с
<em>Щ</em> заради <em>К</em>, <em>О</em> със <em>С</em> заради <em>Г</em> и т.н.
Крайният резултат от криптиращия алгоритъм е низът
<mark class="significant green">КБЩСШМГНП ЕПУРБ</mark>.
</p>
<p>
Шифърът на Виженер на пръв поглед се справя с проблема с често
повтарящите се букви. В зависимост от дължината на ключа един път
буквата <em>А</em> може да се превърне в <em>Б</em>, друг път в <em>С</em>.
Така семантичният анализ изглежда няма да помогне при анализиране на
криптиращия алгоритъм. Това обаче не е напълно вярно. Съществуват
множество алгоритми, чрез които може да се определи дължината на
ключа. Когато веднъж знаем дължината на ключа, разбиването на шифъра
на Виженер се свежда до това да разбием няколко на брой последователни
Цезарови шифъра. Като дори тогава можем да използваме семантично
изследване във всеки един отделен шифър.<sup><a href="#references_3">[3]</a></sup>
</p>
<section class="ceaserKeyContainer playground">
<h4>Криптиране с ключ</h4>
<section>
<label for="alphabetSelectKey">Азбука на съобщението:</label>
<select id="alphabetSelectKey" onchange="encryptKey()">
<option value="cyrillic" selected>Кирилица</option>
<option value="latin">Латиница</option>
</select>
</section>
<section>
<label for="messageInputKey">Съобщение:</label>
<input type="text" class="inputBox" id="messageInputKey"
placeholder="Въведете съобщение за криптиране..." oninput="encryptKey()"></input>
</section>
<section> <label for="messageInputKey">Ключ с букви:</label>
<input type="text" class="keyBox" id="keyInputKey"
placeholder="Въведете ключ, показващ отместването в азбуката..." oninput="encryptKey()" />
</section>
<section>
<label for="resultKey">Криптирано съобщение:</label>
<input type="text" class="outputBox" id="resultKey" , readonly></input>
</section>
<script src="javascript/ceaser_key.js"></script>
</section>
<h3>128/256-битови ключове</h3>
<p>
Модерните ключове представляват поредица от нули и единици обикновено
с дължина 128 или 256 символа. Известни са още като 128-битови или
256-битови ключове. Възможните ключове с дължина 128 бита са 2 на
степен 128 или число с 38 нули. Това е така, защото на всеки бит
избираме дали да е 0 или 1. Имаме 128 избора или
<em>2*2*2...*2 = 2<sup>128</sup></em>
възможни комбинации. Ако отгатвате по 1 милиард възможни ключа в
секунда и сте започнали при самото създаването на Вселената, няма все
още да сте минали 1 процент от всички възможни комбинации.
</p>
<p>
Цялата информация, която се предава в интернет пространството може да
се представи като поредица от нули и единици. За простота ще
използваме <mark class="orange">ASCII таблицата</mark>. Тя показва как
можем да представим текст чрез поредица от числа, като заменим всеки
символ с дадено число. Например малката латинска буква <em>a</em> се
представя чрез числото 97, малкото <em>b</em> с <em>98</em>, малкото
<em>z</em> с <em>122</em>, голямото <em>A</em> със <em>65</em>, <em>B</em> с
<em>66</em>, <em>Z</em> с <em>90</em>. Всъщност се извършва вид кодиране –
всеки символ се кодира със зададено в таблицата число. Имаме кодиране
на компютърната азбука, състояща се от 256 символа в числата от 0 до
255. Така думата <mark class="significant blue">ball</mark> ще бъде
преведена до числата
<mark class="significant green">98, 97, 108, 108</mark>. Какво общо
имат тези числа с битовете?
</p>
<h3>Кодиране с 4-битов ключ</h3>
<p>
За да отговорим на този въпрос, трябва да разбираме как се преминава
от десетична бройна система в двоична бройна система. Записът на
числото 108 в десетична бройна система показва, че имаме 1 стотица, 0
десетици и 8 единици. Можем да запишем числото 108 като
<em>100 * 1 + 10 * 0 + 1 * 8</em>. Ако заменим със степени на десетката,
получаваме
<em>(10<sup>2</sup>) * 1 + (10<sup>1</sup>) * 0 + (10<sup>0</sup>) *
8</em>. Така числото 101 в двоична бройна система означава, че имаме
<em>(2<sup>2</sup>) * 1 + (2<sup>1</sup>) * 0 + (2<sup>0</sup>) * 1 = 4
* 1 + 2 * 0 + 1 * 1 = 5</em>. Така всеки бит показва дали ще включим съответна степен на двойката
при получаване на финалното число или не. Числото 101 показва –
включваме 4, не включваме 2, включваме 1, получаваме 5 след сумиране.
Същото е и при числото 108 в десетична бройна система – нулата
показва, че нямаме десетици, но имаме 1 стотица и 8 единици. Числото
<mark class="significant blue">108</mark> в двоична бройна система е
<mark class="significant green">01101100</mark> или
<em>(2<sup>7</sup>) * 0 + (2<sup>6</sup>) * 1 + (2<sup>5</sup>) * 1 +
(2<sup>4</sup>) * 0 + (2<sup>3</sup>) * 1 + (2<sup>2</sup>) * 1 +
(2<sup>1</sup>) * 0 + (2<sup>0</sup>) * 0 = 128 * 0 + 64 * 1 + 32 *
1 + 16 * 0 + 8 * 1 + 4 * 1 + 2* 0 + 1 * 0 = 108</em>.
</p>
<p>
Вече знаем, че думата <em>ball</em> се кодира до последователните числа
<em>98, 97, 108, 108</em>, които в двоична бройна система се изписват
така: <em>01100010, 01100001, 01101100, 01101100</em>. Първата нула е
използвана за уеднаквяване на дължината на символите – така знаем, че
първите 8 бита са 1 символ, следващите 8 бита са втория символ и т.н.
Сега спокойно можем да представим низа <em>ball</em> като
последователността от 32 бита
<mark class="significant blue">01100010011000010110110001101100</mark>. Ще използваме 4-битовия ключ
<mark class="significant orange">1100</mark> за кодиране на горната
последователност. Самият ключ не ни е достатъчен да кодираме
съобщението – трябва ни функция на кодирането.
</p>
<p>
Ще използваме операцията <em>побитово или</em>, изписвана още "|".
Функцията приема два бита и връща резултат 0, ако и двата бита с 0 или
1 във всички останали случаи. Започваме да криптираме всички групички
от 4 бита в първоначалното съобщение като използваме ключа и
дефинираната функция. От първата група <em>0110 | 1100</em> получаваме
<em>1110</em> с финален резултат
<mark class="significant green">11101110111011011110110011101100</mark>. След това можем да превърнем
криптираната поредица от битове в
четири числа в десетична бройна система, които пък да превърнем в
последователност от символи чрез ASCII таблицата.
</p>
<p>
Така криптирано съобщение с 4-битовия ни ключ изглежда по този начин:
<mark class="significant green">îíìì</mark>
</p>
<section class="bitKeyContainer playground">
<h4>Криптиране с битов ключ</h4>
<section>
<label for="bitKeyInputText">Съобщение на английски:</label>
<input type="text" id="bitKeyInputText" class="inputBox"
placeholder="Въведете съобщение на английски език..." oninput="updateSteps()"></input>
</section>
<section>
<label for="textToASCII">Текст към ASCII:</label>
<input type="text" class="outputBox" id="textToASCII" readonly>
</section>
<section>
<label for="ASCIIToBinary">ASCII към Двоичен запис:</label>
<input type="text" class="outputBox" id="ASCIIToBinary" readonly>
</section>
<section>
<label for="bitKeyKey">Битов ключ (низ от единици и нули):</label>
<input type="text" id="bitKeyKey" class="keyBox" placeholder="Въведете ключ за криптиране..."
oninput="updateSteps()" />
</section>
<section>
<label for="encryptedBinary">Криптиран Двоичен запис:</label>
<input type="text" class="outputBox" id="encryptedBinary" readonly>
</section>
<section>
<label for="encryptedASCII">Криптиран ASCII:</label>
<input type="text" class="outputBox" id="encryptedASCII" readonly>
</section>
<section>
<label for="encryptedText">Криптиран Текст:</label>
<input type="text" class="outputBox" id="encryptedText" readonly>
</section>
<script src="javascript/bit_key.js"></script>
</section>
<h3>Симетрично криптиране</h3>
<p>
Симетричното криптиране използва
<mark class="orange">един ключ за криптиране и декриптиране</mark>
на данните. Процесът по криптиране на данните със споделен ключ не
изисква големи количества изчислителна мощ. Освен това създаването на
такива ключове е сравнително бърза операция. Основният проблем свързан
със симетричното криптиране е споделянето на ключа. За да си
комуникират двете страни, те трябва предварително да знаят ключа. В
миналото са се извършвали операции по дискретно доставяне на физически
ключове до важните организации в света, което е било изключително скъп
процес, но и опасен. Бъде ли прихванат ключа, цялата комуникация може
да бъде подслушвана. Така се налага ключа, изпращан до човека, с който
искаме да комуникираме, също да бъде криптиран с друг алгоритъм. Но
какъв ще е ключа за новия криптиращ алгоритъм и как ще бъде
предварително споделен?
</p>
<h3>Асиметрично криптиране</h3>
<p>
В решаване на този проблем през 70-те години на 20-ти век се
разработва асиметричното криптиране. То използва
<mark class="orange">два ключа – публичен и частен</mark>.
Публичният ключ е известен на всички страни в комуникацията и се
използва за криптирането на данните. Изпратените криптирани данни
обаче не могат да се декодират с друго освен частния ключ. Частният
ключ се знае само от страната получател. Така всеки друг прихванал
данните не може да разбере техния смисъл.
</p>
<p>
Нека разгледаме примера как Ани и Борко ще осъществят поверителна
комуникация чрез асиметрично криптиране. Всеки участник в
комуникацията притежава частен ключ. Частният ключ е разработен така,
че само той да декодира данните от друг ключ – публичния. Ани споделя
своя разработен публичен ключ със света. Борко желае да изпрати
съобщение на Ани. Той вижда споделения публичен ключ на Ани, използва
го да криптира своето съобщение и го изпраща на Ани. Ани получава
криптираното съобщение. Само тя знае какъв е нейния частен ключ – само
той може да декодира получените съобщения. Ани използва своя таен ключ
и разбира съобщението на Борко. Така, ако някой трети човек – Иван,
проследи съобщението и има достъп до публичния ключ на Ани, не може да
разбере информацията, която Борко ѝ е пратил.<sup><a href="#references_5">[5]</a></sup>
</p>
<h3>Функция капан</h3>
<p>
От по-научна гледна точка асиметричното криптиране използва така
наречените <em>функции капан</em>. Ако <em>f</em> е функция капан и
<em>y = f(x)</em> е лесно за пресмятане, то
<em>x = f<sup> -1</sup>(y)</em> изисква огромно количество изчислителна
мощ за пресмятане, освен ако не се знае допълнително, помощно число –
<em>k</em>, с което пресмятането на <em>x = f<sup> -1</sup>(y, k)</em> е
тривиално. Така криптирането на дадено съобщение <em>x</em> с публичния
ключ, пресмятането на <em>y</em>, е бърза операция, но декриптирането –
пресмятането на първоначалното съобщение <em>x</em> чрез криптираното
<em>y</em> е почти невъзможно. Но ако човек знае частния ключ –
<em>k</em>, възстановяването на <em>x</em> е мигновен процес.<sup><a href="#references_9">[9]</a></sup>
</p>
<p>
Примерна <em>функция капан</em> е
<mark class="orange">процесът по умножаване на две прости числа</mark>
– <em>p</em> и <em>q</em>. Лесно можем да изчислим колко е тяхното
произведение – лесно се смята <em>y = f(p, q)</em>. Но обратният въпрос
– от дадено <em>y</em> да кажем кои две прости числа са били умножени за
получаването на <em>y</em> отнема огромно количество време. Например,
трудно ще определим <em>p</em> и <em>q</em>, ако е дадено
<em>y = 6895601</em>. Трябва да минем през всяко едно просто число,
докато не получим един от делители на <em>y</em>. Но ако получим
информация, че <em>p = 1931</em>, то веднага можем да кажем чрез деление
колко е другото просто число <em>q</em>. Разбира се, модерните компютри
могат бързо да провървят всички прости числа и да намерят делителите
на 6895601, но с увеличаването на числото <em>y</em>, тази задача става
непосилна за тях.<sup><a href="#references_9">[9]</a></sup>
</p>
<h3>Хибридно криптиране</h3>
<p>
Асиметричното криптиране се извършва по-бавно, с повече ресурси
отколкото симетричното криптиране. При обмяната на големи количества
данни е подходящо да се използва споделен ключ, но как поверително да
обменим този ключ? В практиката се използва хибридна версия между
двете криптирания. Идеята е
<mark class="orange">споделеният ключ да бъде "договорен" чрез асиметрично
криптиране</mark>, като се използват частните и публични ключове на двете страни в
комуникацията. След като споделеният ключ е предаден тайно, може да се
премине към синхронно криптиране.<sup><a href="#references_5">[5]</a></sup>
</p>
<h2>Хеширане</h2>
<p>
Основната цел на процеса хеширане е да предостави метод за
удостоверяване на източника и интегритета на дадени данни. Това е
възможно поради функционалността на хеширането да превръща данни от
всякаква големина в низ с константна дължина. Низът, който се получава
се казва хеш стойност. Тъй като хеширането е така проектирано, че една
хеш стойност да не може да се получи от повече от една уникална
съвкупност от данни, то можем бързо да кажем дали съществува промяна в
дадени данни. За разлика от криптирането хеширането е
<mark class="orange">необратим процес</mark> – не може да се определи
стойността преди хеширане чрез хешираната стойност. Ако подаване
стойност <em>x</em> на хеширащата функция <em>f</em>, получаваме
хешираната стойност <em>y = f(x)</em>, но не можем да пресметнем
<em>x = f<sup> -1</sup>(y)</em>.
</p>
<h3>Проверка на интегритет</h3>
<p>
Нека разгледаме примера, където Борко изпраща съобщение на Ани – файл
с много на брой и изключително важни данни. Борко иска да е сигурен,
че Ани ще получи целия файл, без някоя информация да се изгуби в
процеса на предаване. Борко предварително изчислява хеш стойността на
файла и я праща заедно със самия файл. Така, след като Ани получи
файла, сама ще изчисли хеш стойността. Ако тя съвпада с тази изпратена
от Борко, файлът е бил предаден успешно, ако обаче двете стойности са
различни, то нещо се е объркало в процеса по трансфер на данните.
</p>
<p>
В горния пример ясно се наблюдава едно от основните свойства на
хеширането – способността да превръща огромно количество информация в
кратък уникален низ, идентифициращ информацията еднозначно. Ако
използваме известния алгоритъм <mark class="orange">SHA-256</mark> за
хеширане на даден низ, винаги ще получаваме стойност с дължина 256
бита. При хеширане на низа
<mark class="significant blue">Аз съм Цезар</mark> получаваме
<mark class="significant green">839d8fd51d6fceb3216d35ac8316999264f5d1d1ceb701eb7c488560112df79a</mark>.
След промяна на дори една
буква – <mark class="significant blue">Аз съм Сезар</mark>, получаваме
напълно различна хеш стойност –
<mark class="significant green">fc5494b9214f40f96eeb099d14c576962afba000f85c2af6d31a398c3c708121</mark>.
Така Ани е сигурна, че
съобщението е в пълния си вид, когато пристига до нея, и нищо във
файла не е било променяно по пътя. Но дали Ани трябва да е толкова
сигурна?
</p>
<p>
Какво ще се случи, ако някой прихване сигнала на Борко и промени
файла. След това пресметне новата хеш стойност и изпрати двата файла
на Ани. Ани ще провери хеш стойността на получения файл и няма да
разбере за подмяната. За да избегнат този проблем Ани и Борко ще
използват таен низ, който само те двамата знаят. Борко добавя тайната
дума в края на файла, изчислява новия хеш и изпраща първоначалния файл
с новата хеш стойност. Когато похитителят подмени файла на Иван и
изпрати фалшивите данни със своята хеш стойност, Ани ще забележи
подмяната. Когато Ани пресметне хеша на файла, като добави тайната
дума в края му, ще получи хеш различен от този на похитителя. Така Ани
ще знае, че оригиналният файл е бил подменен. А как Ани и Борко ще се
разберат поверително за тайната дума? Разбира се, ще използват
асиметрично криптиране.<sup><a href="#references_5">[5]</a></sup>
</p>
<section class="integrityHashContainer playground">
<h4>Хеширане с таен низ</h4>
<section>
<label for="integrityMessage">Съобщение:</label>
<input type="text" class="inputBox" id="integrityMessage" name="integrityMessage"
placeholder="Въведете съобщение..." oninput="calculateHashIntegrity()"></input>
</section>
<section>
<label for="integrityMessageHash">Хeш на съобщението:</label>
<input type="text" class="outputBox" id="integrityMessageHash" readonly>
</section>
<section>
<label for="integritySecret">Таен низ:</label>
<input type="text" class="keyBox" id="integritySecret" name="integritySecret"
placeholder="Въведете таен низ..." oninput="calculateHashIntegrity()">
</section>
<section>
<label for="integrityConcatenatedHash">Изпратен хеш на съобщението с тайния низ:</label>
<input type="text" class="outputBox" id="integrityConcatenatedHash" readonly>
</section>
<script src="javascript/integrity_hash.js"></script>
</section>
<h3>Съхранение на пароли</h3>
<p>
Способността на хеширането,
<mark class="orange">при малка промяна в първоначалното съдържание напълно да променя
хеш стойността</mark>
в резултата, е ключово свойство за съхранение на пароли. Освен това
хеширането не е обратима операция – не можем да разберем
първоначалната стойност чрез хешираната. Когато запаметяваме пароли в
базата ни от данни, удобно е те да са в хеширан вид. Така, ако хакери
получат достъп до базата, не могат да получат достъп до акаунтите на
потребителите.
</p>
<p>
Когато потребителят въведе паролата си за влизане, системата хешира
изпратения низ и проверява хешираната стойност, записана в базата. Тъй
като две пароли е почти сигурно, че нямат еднакъв хеш, при съвпадение
на хешираната стойност, потребителят получава достъп до акаунта си.
При въвеждане на хеш стойност в полето за парола, системата отново ще
хешира стойността, което ще доведе до нова, различна хеш стойност –
достъпът до акаунта ще бъде отказан.
</p>
<p>
Тъй като хеш стойността е уникална за всяка една парола, хакерите
могат да пробват различни пароли и да сравняват получения хеш с този в
базата данни. Ако се получи съвпадение, то паролата за акаунта е била
налучкана. Хеширането е бавен процес. Съществуват огромни таблици,
които съдържат хеш стойностите на статистически най-често използваните
пароли.<sup><a href="#references_8">[8]</a></sup> Това позволява на
киберпрестъпниците бързо да проверяват възможните пароли с реалните
хеш стойности. Генерирането на такива
<em class="orange">rainbow</em> таблици, включващи
всяка възможна комбинация за парола от даден вид, става все по-скъпо с
нарастване на дължината на паролата. За това е ключово, когато
избираме парола за онлайн система, тя да е дълга и да не съдържа
единствено думи.<sup><a href="#references_7">[7]</a></sup>
</p>
<h2>Посоляване</h2>
<h3>Проблемът със съхранение на хеширани пароли</h3>
<p>
Представете си, че вие сте хакерът, който е получил достъп до базата
от данни. Разглеждате хешираните стойности и забелязвате два акаунта,
на които отговаря един и същи хеш. Знаете, че две различни пароли
почти никога не генерират еднаква хеш стойност. Оттук лесно може да се
заключи, че повтарящият се хеш отговаря на често използвана парола –
последователност от цифри, любим отбор и т.н. Освен това повечето хора
използват пароли, които са кратки и лесни за запомняне. По-сигурните
пароли с множество символи и голяма дължина са рядко използвани.<sup><a
href="#references_7">[7]</a></sup>
</p>
<p>
За да се решат тези проблеми, модерните системи използват процеса
посоляване. Когато потребителят се регистрира в системата, тя създава
<mark class="orange">уникален за него низ от случайни символи</mark>.
Този низ, наречен <em class="orange">сол,</em> се
добавя в края на въведената от потребителя парола. След това
удължената парола се хешира от системата и се запаметява в базата
данни. Така две еднакви пароли ще генерират напълно различен хеш.
</p>
<h3>Добавяне на сол към парола</h3>
<p>
Нека си представим, че Ани и Борко се регистрират в сайт. И двамата
задават паролата за своят акаунт да е
<mark class="significant blue">123456</mark>. Хешът на тази парола с
известния <em>SHA-256</em> алгоритъм е
<mark class="significant green">b6cfefc9b41b1bd6940e8b023f391bd4ca684a28ab47f9fe86a70d40612e184e</mark>.
Системата обаче генерира
уникални низове за двата акаунта и ги добавя в края на паролите. За
Ани низът е <mark class="significant orange">@n1x</mark>, а за Борко –
<mark class="significant orange">b0b1</mark>. След това системата
хешира двата низа <mark class="significant blue">123456@n1x</mark> и
<mark class="significant blue">123456b0b1</mark>, получава двете хеш
стойности <mark
class="significant green">0914cd17fb5b89ce55b8b8794f537d446f2587f9b557a73cca01df9c1f4805d4</mark> и
<mark class="significant green">a8dd66908bf1c444510fd00a1b78a041f4823ffe4754b82b5e5fc991b28c2684</mark>
и ги запаметява в базата
данни. Посоляващите стойностите също се запаметяват в базата данни без
да се криптират или хешират. Защо?
</p>
<p>
Когато хакерите отворят базата данни, ще намерят двете хеш стойности и
съответните сол стойности. <em>Rainbow</em> таблиците им се оказват
безполезни, тъй като никоя от тях не използва добавената сол. Хакерите
решават да добавят към всяка популярна парола солта на Борко и
започват да пресмятат новите хеш стойности – генерират нова
<em>rainbow</em>
таблица, което е скъпа операция. Паролата на Борко бива разбита. Сега
обаче хакерите трябва да повторят същата операция, като използват
солта на Ани. В една система с милион потребители, този процес никога
не би бил ефективен.
</p>
<p>
Всъщност, процесът по посоляване на пароли, използва същата идея, която Ани и Борко приложиха, за да
гарантират интегритета на изпратени по мрежата данни – добавянето на таен низ в края на данните преди
пресмятането на хеш стойността.
</p>
<h3>Подлютяване</h3>
<p>
Солта се съхранява като обикновен текст в базите от данни. Това
видяхме, че не е проблем, тъй като всяка парола има уникална сол.
Сравнително лесно ще е да разбием един акаунт, но всички – невъзможно.
Ако солта беше една за всички акаунти, тогава процеса по разбиване на
паролата на Борко, ще разбие всички пароли в системата.
</p>
<p>
Подлютяването представлява стойност, която е
<mark class="orange">една за цялата система</mark> и се добавя в края
на всяка една парола. Важната разлика с посоляването е, че стойността
за подлютяване не се съхранява заедно с хешираната парола и солта.
Обикновено тя е в друг компонент, различен от базата данни. Така, ако
престъпниците получат достъп до базата данни, все още няма да имат
пълната информация, необходима за разбиването на паролите.<sup><a href="#references_10">[10]</a></sup>
</p>
<h2>Заключение</h2>
<p>
Криптирането и хеширането са два есенциални процеса за осигуряване на
сигурността в интернет пространството. Криптирането гарантира
поверителността и целостта на данните по време на предаване, докато
хеширането, особено когато се комбинира с посоляване, предоставя
сигурен начин за защита на критични данни като пароли. Чрез
използването на двете техники по подходящ начин се осигурява защита на
данните и се намалява риска от неоторизиран достъп.
</p>
<h2>Източници:</h2>
<section>
<ol id="references-ordered-list">
<li id="references_1">
The SSL Store, <em>The difference between Encryption, Hashing and
Salting</em>, публикувана на 19.12.2018г., [<a
href="https://www.thesslstore.com/blog/difference-encryption-hashing-salting/"
target="_blank">https://www.thesslstore.com/blog/difference-encryption-hashing-salting/</a>]
</li>
<li id="references_2">
Wikipedia, <em>Caesar cipher</em>, актуализирана последно на 30.04.2024г.,
[<a href="https://en.wikipedia.org/wiki/Caesar_cipher"
target="_blank">https://en.wikipedia.org/wiki/Caesar_cipher</a>]
</li>
<li id="references_3">
CSFG, <em>Coding - Encryption, Substitution ciphers</em>, посетена последно
на 14.05.2024г., [<a
href="https://www.csfieldguide.org.nz/en/chapters/coding-encryption/substitution-ciphers/"
target="_blank">https://www.csfieldguide.org.nz/en/chapters/coding-encryption/substitution-ciphers/</a>]
</li>
<li id="references_4">
Simia, <em>How often is which letter?</em>, публикувана на 04.11.2012г.,
[<a href="http://simia.net/letters/" target="_blank">http://simia.net/letters/</a>]
</li>
<li id="references_5">
Practical Networking, <em>Cryptography</em>, посетена последно на
14.05.2024г., [<a href="https://www.practicalnetworking.net/series/cryptography"
target="_blank">https://www.practicalnetworking.net/series/cryptography</a>]
</li>
<li id="references_6">
Google Cloud, <em>What is Encryption?</em>, посетена последно на
14.05.2024г., [<a href="https://cloud.google.com/learn/what-is-encryption"
target="_blank">https://cloud.google.com/learn/what-is-encryption</a>]
</li>
<li id="references_7">
Comparitech, <em>Encryption, hashing, salting - what's the
difference?</em>, актуализирана последно на 24.01.2024г., [<a
href="https://www.comparitech.com/blog/information-security/encryption-hashing-salting/"
target="_blank">https://www.comparitech.com/blog/information-security/encryption-hashing-salting/</a>
</li>
<li id="references_8">
Cybernews, <em>Hashing vs encryption vs salting: what's the
difference?</em>, актуализирана последно на 14.03.2022г., [<a
href="https://cybernews.com/security/hashing-vs-encryption/"
target="_blank">https://cybernews.com/security/hashing-vs-encryption/</a>]
</li>
<li id="references_9">
Wikipedia, <em>Trapdoor function</em>, актуализирана последно на
25.02.2024г., [<a href="https://en.wikipedia.org/wiki/Trapdoor_function"
target="_blank">https://en.wikipedia.org/wiki/Trapdoor_function</a>]
</li>
<li id="references_10">
Wikipedia, <em>Pepper (cryptography)</em>, актуализирана последно на
07.10.2023г., [<a href="https://en.m.wikipedia.org/wiki/Pepper_(cryptography)"
target="_blank">https://en.m.wikipedia.org/wiki/Pepper_(cryptography)</a>]
</li>
</ol>
</section>
<blockquote>
"ТС-ЗСДУИ ЦЙГФИР НУГМ, СХНСОНСХС ЦЙГФ ДИК НУГМ." ~ЩИКГУ
</blockquote>
</section>
<aside>
<h3>Автор</h3>
<img src="https://media.licdn.com/dms/image/D4D03AQEYS_DS2JhrDg/profile-displayphoto-shrink_800_800/0/1711764139912?e=1721260800&v=beta&t=LYYkQkD6mT5ApAWYxDLMALghXVNH7jA1-rrfudtVRI0"
alt="Снимка на автора, Теодор Костадинов." />
<ul>
<li><strong id="author-name">Теодор Костадинов</strong></li>
<li>Студент във Факултета по математика и информатика, СУ</li>
<li>
<a href="https://www.linkedin.com/in/teodor-kostadinov-685807301/" target="_blank">LinkedIn</a>
</li>
<li>
<a href="https://github.com/TeogopK" target="_blank">GitHub</a>
</li>
</ul>
</aside>
</article>
</body>
</html>