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
| using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(" При вводе для разделения разрядов можно использовать пробел и подчёркивание.");
Console.WriteLine(" Остальные символы не предусмотренные системой счисления приводят к ошибке.");
Console.WriteLine(" Для шестнадцатеричной системы регистр значения не имеет.");
Console.WriteLine(" Разряды вводятся от старших к младшим");
Console.WriteLine(" Для шестнадцатеричной системы количество разрядов долно быть 16");
Console.WriteLine(" Для десятичной системы количество разрядов долно быть 20");
Console.WriteLine(" Для двоичной системы количество разрядов долно быть 64");
Console.WriteLine();
Cl_Register64 _reg;
string TextInput;
{
FileStream _key_file = new FileStream("key.bin", FileMode.OpenOrCreate); // Попытка открытия файла ключа
do
{
Console.Write(" Введите шестнадцатеричный ключ (пустая строка - ключ буден прочитан из файла \"key.bin\":\n ");
TextInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(TextInput))
{
Console.Write(" Ключ будет прочитан из файла");
if (_key_file.Length != 8) // Если в файле ключа 8 байт, то создание регистра
{ Console.Write(" Нет файла ключа"); _reg = null; }
else
{
_reg = Cl_Register64.Create(new BinaryReader(_key_file).ReadUInt64());
}
}
else { _reg = Cl_Register64.CreateFromString(TextInput, Cl_Register64.TypeStringEnum.Hex); }
} while (_reg == null);
Console.WriteLine($" Ключ в двоичном коде - {_reg.ToStringBinary()} ;\n в шестнадцатеричном коде {_reg.ToStringHex()} .");
Console.WriteLine();
Console.WriteLine(" Ключ сохранён в \"key.bin\" ");
_key_file.Seek(0, SeekOrigin.Begin); // Установка указателя на начало файла
new BinaryWriter(_key_file).Write(_reg.InitialValue);
_key_file.Close(); // Закрытие файла ключа
}
Console.Write(" Введите текст для шифрования (пустая строка - текст буден прочитан из файла \"text.bin\":\n ");
do
{
TextInput = Console.ReadLine();
if (string.IsNullOrEmpty(TextInput))
{
Console.Write(" Попытка чтения текста из файла.");
try
{
Stream _text_file = new FileStream("text.bin", FileMode.OpenOrCreate); // Попытка открытия файла текста
TextInput = new BinaryReader(_text_file).ReadString();
_text_file.Close();
}
catch (Exception) { Console.Write(" В файле нет текста."); }
}
if (string.IsNullOrEmpty(TextInput))
Console.Write(" Нет текста для шифрования: строка: он пустой или состоит из пробелов.");
} while (string.IsNullOrEmpty(TextInput));
{
Stream _text_file = new FileStream("text.bin", FileMode.Create); // Создание файла текста
BinaryWriter _text_stream = new BinaryWriter(_text_file); // Создание двоичного потока записи
_text_stream.Write(TextInput); // Запись в файл текста
Console.WriteLine($" Текст для шифрования \"{TextInput}\" ;\n " +
$"в шестнадцатеричном коде {StreamToString(_text_file)} .");
TextInput = null;
MemoryStream _text_coding_stream = _reg.Encrypt(_text_file); // Получение зашифрованного текста
_text_file.Close(); _text_file = null; // Закрытие потока и файла текста
Stream _text_coding_file = new FileStream("text_coding.bin", FileMode.Create);
_text_coding_stream.WriteTo(_text_coding_file);
Console.WriteLine("\n Зашифрованный текст запомнен в файле \"text_coding.bin\"\n " +
$" в шестнадцатеричном коде {StreamToString(_text_coding_stream)} .");
_text_coding_file.Close(); _text_coding_file = null;
}
{
Console.WriteLine("\n Зашифрованный текст читается из файла \"text_coding.bin\"\n ");
Stream _text_coding_file = new FileStream("text_coding.bin", FileMode.Open);
Console.WriteLine("\n Расшифровка текста\"\n ");
MemoryStream _text_decoding_stream = _reg.Encrypt(_text_coding_file); // Получение расшифрованного текста
_text_coding_file.Close();
_text_decoding_stream.Seek(0, SeekOrigin.Begin);
TextInput = new BinaryReader(_text_decoding_stream).ReadString(); // Чтение расшифрованного текста
}
{
Console.WriteLine("\n Запись расшифрованного текста в файл \"text_decoding.bin\"\n ");
Stream _text_file = new FileStream("text_decoding.bin", FileMode.Create); // Создание файла расшифрованного текста
BinaryWriter _text_decoding_stream = new BinaryWriter(_text_file); // Создание двоичного потока записи
_text_decoding_stream.Write(TextInput); // Запись в файл текста
Console.WriteLine("\n Расшифрованный текст запомнен в файле \"text_decoding.bin\"\n " +
$" Текст \"{TextInput}\"" +
$"\n в шестнадцатеричном коде {StreamToString(_text_file)} .");
_text_file.Close();
}
Console.Write("Для выхода нажмите любую клавишу..... "); Console.ReadKey();
}
static string StreamToString(Stream stream)
{
stream.Seek(0, SeekOrigin.Begin);
BinaryReader stream_bin = new BinaryReader(stream);
string _ret = "";
while (stream.Position < stream.Length)
{
_ret += Convert.ToString(stream_bin.ReadByte(), 16);
if (stream.Position % 2 == 0)
{
if (stream.Position % 4 == 0)
{ _ret += " "; }
else
{ _ret += "_"; }
}
}
return _ret;
}
}
}
class Cl_Register
{
private byte[] _initialValue;
private byte[] _currentValue;
/// <summary>Возвращает начальное значение регистра</summary>
public byte[] InitialValue { get => _initialValue; private set { _initialValue = value; CurrentValue = InitialValue; } }
/// <summary>Возвращает суммарный сдвиг регистра</summary>
public long TotalShift { get; private set; }
/// <summary>Возвращает текущее значение регистра</summary>
public byte[] CurrentValue { get => _currentValue; private set { _currentValue = (byte[])value.Clone(); TotalShift = 0; } }
/// <summary>Сокрытие конструктора по умолчанию</summary>
private Cl_Register() { }
/// <summary>Создание нового регистра</summary>
/// <param name="NewValue">Массив байтов для начального значения регистра</param>
/// <returns>Новый объект Cl_Register</returns>
static public Cl_Register Create(byte[] NewValue) => new Cl_Register() { InitialValue = NewValue };
/// <summary>Перечислитель для типов строки</summary>
public enum TypeStringEnum { Bynary = 0, Hex = 1, Decimal = 3 }
/// <summary>Создание нового регистра из строковых данных для начального значения</summary>
/// <param name="NewValue">Строка символов от младшего к старшему разряду</param>
/// <param name="Type">Тип данных в строке</param>
static public Cl_Register CreateFromString(string NewValue, TypeStringEnum Type)
{
NewValue = NewValue.Replace(" ", ""); // Удаляет из строки все пробелы
switch (Type)
{
case TypeStringEnum.Bynary:
// Количество двоичных символов в исходной строке
int Count_char = NewValue.Count(_char => _char == '0' || _char == '1');
if (Count_char != NewValue.Length || Count_char % 8 != 0) // Определение некорректных данных
{
Console.WriteLine("Ошибка!\nПолученные данные для двоичного преобразования некорректны!");
return null;
}
// Подготовка массива для данных
byte[] retValue = new byte[NewValue.Length / 8];
for (int IndByte = 0; IndByte < retValue.Length; IndByte++) // Цикл по байтам
{
retValue[IndByte] = Convert.ToByte(new string(NewValue.Substring(IndByte * 8, 8).Reverse().ToArray()), 2);
}
return Create(retValue);
case TypeStringEnum.Hex:
NewValue = NewValue.ToUpper(); // Перевод строки в верхний регистр
// Ссылка на перебор шестнацатиричных символов в исходной строке
Count_char = NewValue.Count(_char => _char >= '0' && _char <= '9' || _char >= 'A' && _char <= 'F');
if (Count_char != NewValue.Length || Count_char % 2 != 0) // Определение некорректных данных
{
Console.WriteLine("Ошибка!\nПолученные данные для шестнадцатеричного преобразования некорректны!");
return null;
}
// Подготовка массива для данных
retValue = new byte[NewValue.Length / 2];
for (int IndByte = 0; IndByte < retValue.Length; IndByte++) // Цикл по байтам
{
int begChar = IndByte * 2; // Номер первого символа для байта
retValue[IndByte] = Convert.ToByte(new string(NewValue.Substring(IndByte * 2, 2).Reverse().ToArray()), 16);
}
return Create(retValue);
case TypeStringEnum.Decimal:
// Реализация требует преобразования сначала в десятичное число, потом в двоичное, потом в массив байтов
// Требует работы с числами большого размера > 128
// Из-за сложности для учебного примера нет смысла в реализации
return null;
default:
return null;
}
}
/// <summary>Метод возвращающий строковое двоичное представление регистра</summary>
public string ToStringBinary()
{
string _str = "";
for (int IndByte = CurrentValue.Length - 1; IndByte >= 0; IndByte--) // Цикл по байтам в обратном порядке - от старших к младшим
{
// Преобразуемый байт CurrentValue[IndByte];
_str += new string(Convert.ToString(CurrentValue[IndByte], 2).PadLeft(8, '0').Reverse().ToArray()) + " ";
}
return _str;
}
/// <summary>Метод возвращающий строковое шестнадцатеричное представление регистра</summary>
public string ToStringHex()
{
string _str = "";
for (int IndByte = CurrentValue.Length - 1; IndByte >= 0; IndByte--) // Цикл по байтам в обратном порядке - от старших к младшим
{
// Преобразуемый байт CurrentValue[IndByte];
_str += new string(CurrentValue[IndByte].ToString("X").PadLeft(2, '0').Reverse().ToArray()) + " ";
}
return _str;
}
/// <summary>Метод возвращающий младший бит регистра</summary>
public byte LowBit() => (byte)(CurrentValue[0] & 0b1);
/// <summary>Метод возвращающий старший бит регистра</summary>
public byte MostBit() => (byte)(CurrentValue[CurrentValue.Length - 1] & 0b1000_0000 >> 7);
/// <summary>Метод возвращающий младший байт регистра</summary>
public byte LowByte() => CurrentValue[0];
/// <summary>Метод возвращающий старший байт регистра</summary>
public byte MostByte() => CurrentValue[CurrentValue.Length - 1];
/// <summary>Метод возвращающий бит обратной связи (X^n + X^n-1 + X^1 + 1)</summary>
public byte FeedbackBit()
=> (byte)((CurrentValue[0] & 0b1) ^ (CurrentValue[0] & 0b10) >> 1
^ ((CurrentValue[CurrentValue.Length - 1] & 0b0100_0000) >> 6) ^ ((CurrentValue[CurrentValue.Length - 1] & 0b1000_0000) >> 7)
);
/// <summary>Метод сдвигающий регистр на один бит в сторону младших разрядов</summary>
public void Step()
{
// Старший бит для заполнения байта. Инициализирован битом обратной связи
byte _bit = FeedbackBit();
for (int IndByte = CurrentValue.Length - 1; IndByte >= 0; IndByte--) // Цикл по байтам в обратном порядке - от старших к младшим
{
byte buf_byte = CurrentValue[IndByte]; // Запоминание текущего байта
CurrentValue[IndByte] >>= 1; // Сдвиг текущего байта к младшим битам. В старшем бите 0.
_bit <<= 7; // Сдвиг сохранённого бита из младшего в старший. Остальные биты = 0
CurrentValue[IndByte] |= _bit; // Запись старшего бита в байт
_bit = buf_byte; // Сохранение бита сдвига для следующего байта
}
TotalShift++; // Увелечение счётчика сдвигов
}
/// <summary>Метод сдвигающий регистр на один байт в сторону младших разрядов</summary>
public void StepByte() { for (int Ind = 0; Ind < 8; Ind++) Step(); }
/// <summary>Метод возвращающий зашифрованный поток</summary>
public MemoryStream Encrypt(MemoryStream stream)
{
MemoryStream stream_ret = new MemoryStream();
stream.Seek(0, SeekOrigin.Begin);
Init();
for (long Ind = 0; Ind < stream.Length; Ind++)
{
StepByte();
stream_ret.WriteByte((byte)(stream.ReadByte() ^ MostByte()));
}
return stream_ret;
}
/// <summary>Метод сбрасывающий сдвиги</summary>
public void Init() { CurrentValue = InitialValue; }
/// <summary>Метод возвращающий True, если текущее значение регистра равно начальному</summary>
public bool ReturnedToBeginning()
{
for (int IndByte = 0; IndByte < _currentValue.Length; IndByte++)
{
if (_currentValue[IndByte] != _initialValue[IndByte])
return false;
}
return true;
}
}
/// <summary>Класс 64-разрядного регистра с обратной связью</summary>
class Cl_Register64
{
private ulong _initialValue; // Поле для начального состояния регистра
private ulong _currentValue; // Поле для текущего состояния регистра
/// <summary>Возвращает начальное значение регистра</summary>
public ulong InitialValue { get => _initialValue; private set { _initialValue = value; CurrentValue = InitialValue; } }
/// <summary>Возвращает суммарный сдвиг регистра</summary>
public long TotalShift { get; private set; }
/// <summary>Возвращает текущее значение регистра</summary>
public ulong CurrentValue { get => _currentValue; private set { _currentValue = value; TotalShift = 0; } }
/// <summary>Возвращает делегат функции обратной связи регистра</summary>
public delegateFeedbackFunction FeedbackFunction { get; private set; }
/// <summary>Сокрытие конструктора по умолчанию</summary>
private Cl_Register64() { }
/// Делегат для функкции обратной связи. Должна возвращать в старшем бите связь от состояния параметра.
public delegate ulong delegateFeedbackFunction(ulong Register);
/// <summary>Создание нового регистра</summary>
/// <param name="NewValue">Начальное значение регистра</param>
/// <param name="FeedbackFunction">Функция обратной связи</param>
/// <returns>Новый объект Cl_Register</returns>
static public Cl_Register64 Create(ulong NewValue, delegateFeedbackFunction FeedbackFunction = null)
=> new Cl_Register64() { InitialValue = NewValue, FeedbackFunction = FeedbackFunction == null ? FeedbackBit : FeedbackFunction };
/// <summary>Перечислитель для типов строки</summary>
public enum TypeStringEnum { Bynary = 0, Hex = 1, Decimal = 3 }
/// <summary>Создание нового регистра из строковых данных для начального значения</summary>
/// <param name="NewValue">Строка символов от младшего к старшему разряду</param>
/// <param name="Type">Тип данных в строке</param>
static public Cl_Register64 CreateFromString(string NewValue, TypeStringEnum Type, delegateFeedbackFunction FeedbackFunction = null)
{
if (FeedbackFunction == null) FeedbackFunction = FeedbackBit;
NewValue = NewValue.Replace(" ", "").Replace("_", ""); // Удаляет из строки все пробелы и подчёркивания
switch (Type)
{
case TypeStringEnum.Bynary:
// Количество двоичных символов в исходной строке
int Count_char = NewValue.Count(_char => _char == '0' || _char == '1');
if (Count_char != NewValue.Length || Count_char != 64) // Определение некорректных данных
{
Console.WriteLine("Ошибка!\nПолученные данные для двоичного преобразования некорректны!");
return null;
}
// Конвертация из двоичной строки в ulong
return Create(Convert.ToUInt64(NewValue, 2), FeedbackFunction);
case TypeStringEnum.Hex:
NewValue = NewValue.ToUpper(); // Перевод строки в верхний регистр
// Подсчёт количества допустимых символов
Count_char = NewValue.Count(_char => _char >= '0' && _char <= '9' || _char >= 'A' && _char <= 'F');
if (Count_char != NewValue.Length || Count_char != 16) // Определение некорректных данных
{
Console.WriteLine("Ошибка!\nПолученные данные для шестнадцатеричного преобразования некорректны!");
return null;
}
// Конвертация из шестнадцатеричной строки в ulong
return Create(Convert.ToUInt64(NewValue, 16), FeedbackFunction);
case TypeStringEnum.Decimal:
Count_char = NewValue.Count(_char => _char >= '0' && _char <= '9');
if (Count_char != NewValue.Length || Count_char != 20 || !UInt64.TryParse(NewValue, out ulong _ret)) // Определение некорректных данных
{
Console.WriteLine("Ошибка!\nПолученные данные для шестнадцатеричного преобразования некорректны!");
return null;
}
// Конвертация из шестнадцатеричной строки в ulong
return Create(_ret, FeedbackFunction);
default:
return null;
}
}
/// <summary>Метод возвращающий строковое двоичное представление регистра</summary>
public string ToStringBinary()
{
string _str = Convert.ToString((Int64)CurrentValue, 2).PadLeft(64, '0');
string _ret = "";
for (int IndChar = 0; IndChar < _str.Length; IndChar += 8) // Цикл по 8 символов
{ // "Красивый" формат двоичного вывода
_ret += " " + _str.Substring(IndChar, 4) + "_" + _str.Substring(IndChar + 4, 4);
}
return _ret;
}
/// <summary>Метод возвращающий строковое шестнадцатеричное представление регистра</summary>
public string ToStringHex()
{
string _str = Convert.ToString((Int64)CurrentValue, 16).PadLeft(16, '0');
string _ret = "";
for (int IndChar = 0; IndChar < _str.Length; IndChar += 4) // Цикл по 8 символов
{ // "Красивый" формат двоичного вывода
_ret += " " + _str.Substring(IndChar, 2) + "_" + _str.Substring(IndChar + 2, 2);
}
return _ret;
}
/// <summary>Метод возвращающий младший бит регистра</summary>
public ulong LowBit() => CurrentValue & 0b1;
/// <summary>Метод возвращающий старший бит регистра</summary>
public ulong MostBit() => CurrentValue & 0x8000_0000_0000_0000;
/// <summary>Метод возвращающий младший байт регистра</summary>
public byte LowByte() => (byte)(CurrentValue & 0x0000_0000_0000_00FF);
/// <summary>Метод возвращающий старший байт регистра</summary>
public byte MostByte() => (byte)(CurrentValue & 0xFF00_0000_0000_0000);
/// <summary>Метод для функции обратной связи по умолчанию (X^63 + X^62 + X^1 + X^0)</summary>
static public ulong FeedbackBit(ulong Register)
=> ((Register & 0b1) << 63 ^ (Register & 0b10) << 62
^ ((Register & 0x4000_0000_0000_0000) << 1) ^ (Register & 0x8000_0000_0000_0000)
);
/// <summary>Метод сдвигающий регистр на один бит в сторону младших разрядов</summary>
public void Step()
{
ulong _bit = FeedbackBit(CurrentValue);// Старший бит обратной связи
CurrentValue >>= 1; // Сдвиг к младшим на 1 разряд
CurrentValue |= _bit; // Запись в старший бита обратной связи
TotalShift++; // Увелечение счётчика сдвигов
}
/// <summary>Метод сдвигающий регистр на один байт в сторону младших разрядов</summary>
public void StepByte() { for (int Ind = 0; Ind < 8; Ind++) Step(); }
/// <summary>Метод сдвигающий регистр на один 16 бит в сторону младших разрядов</summary>
public void StepUInt16() { StepByte(); StepByte(); }
/// <summary>Метод сдвигающий регистр на один 32 бита в сторону младших разрядов</summary>
public void StepUInt32() { StepUInt16(); StepUInt16(); }
/// <summary>Метод сдвигающий регистр на один 64 бита в сторону младших разрядов</summary>
public void StepUInt64() { StepUInt32(); StepUInt32(); }
/// <summary>Метод возвращающий зашифрованный поток</summary>
public MemoryStream Encrypt(Stream stream)
{
stream.Seek(0, SeekOrigin.Begin); // Смещение указателя в начало потока
Init(); // Установка регистра в начальное состояние
MemoryStream stream_ret = new MemoryStream(); // Создание выходного потока в память
BinaryWriter stream_ret_bin = new BinaryWriter(stream_ret); // Создание двоичного вывода в поток
BinaryReader stream_out_bin = new BinaryReader(stream); // Создание двоичного ввода из потока
while (stream.Position + 8 < stream.Length) // Определение есть или нет 8 байт до конца потока
{
StepUInt64(); // Изменение состояния регистра на 64 бита
stream_ret_bin.Write(stream_out_bin.ReadUInt64() ^ CurrentValue); // Считывание, шифрование и запись по 8 байт (64 бита)
}
while (stream.Position < stream.Length) // Определение есть или байт до конца потока
{
StepByte(); // Изменение состояния регистра на 8 битов
stream_ret_bin.Write((byte)(stream_out_bin.ReadByte() ^ LowByte())); // Считывание, шифрование и запись по 1 байту (8 битов)
}
return stream_ret;
}
/// <summary>Метод сбрасывающий сдвиги</summary>
public void Init() { CurrentValue = InitialValue; }
/// <summary>Метод возвращающий True, если текущее значение регистра равно начальному</summary>
public bool ReturnedToBeginning() => _currentValue == _initialValue;
} |