IPB
ЛогинПароль:

> Внимание!

1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Блочное шифрование данных, алгоритм ГОСТ 28147-89
сообщение
Сообщение #1


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Здравствуйте!
Требуется реализовать алгоритм блочного шифрования ГОСТ 28147-89 в следующих режимах
шифрования: режим простой замены; режим гаммирования; режим гаммирования с обратной связью.
Программа должна запрашивать имя входного и выходного файлов,
ключ, вектор инициализации (синхропосылку), режим работы
(зашифрование или расшифрование), режим шифрования.

У меня прежде всего вопрос по организации данных..
В соответствии с алгоритмом

размер блока – 64 бита;
- размер ключа – 256 бит. Ключ представляется как массив из
восьми 32-битных подключей K={K0,K1,…,K7};
- количество S-блоков – 8. Каждый S-блок (в терминах стандарта –
узел замены) содержит 16 четырехбитных значений, представляющих
собой произвольную перестановку чисел от 0 до 15. Совокупность всех
S-блоков можно представить в виде матрицы (таблицы замен) размером 8 на 16.

Скажите пожалуйста, какие типы правильнее использовать для массива ключей и таблицы замен?


 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гость






Цитата
какие типы правильнее использовать для массива ключей и таблицы замен?
Язык - С++, как видно? Тогда тебе нельзя привязываться к размеру конкретного типа, а единственный тип, который имеет одинаковый размер везде - это char. Там что или описывай все в байтах:
    typedef unsigned char Tsubkey[4]; // 32 bit
typedef Tsubkey Tkey[8]; // 8 * 32 bit
, или делай так:
    typedef bool Tsubkey[32];
typedef Tsubkey Tkey[8];
(представляй каждый элемент типа Tsubkey отдельным битом...) В первом случае будет меньше размер, занимаемый данными. Во втором - размер (возможно) будет больше (если компилятор не оптимизирует), но зато будет очень быстрый доступ к битам, причем можно будет элементарно "убрать" разницу между little-endian и big-endian.

Все вышесказанное можешь не принимать во внимание, если твоя задача - реализовать это под строго заданным компилятором и под одной аппаратной платформой. Тогда можешь выбирать, что тебе больше нравится - работать с битами внутри байта, или работать с bool-ами и потом "собирать" байты из них. Я бы все-таки выбрал второй вариант...

Аналогично и с узлами замены.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 3.03.2009 21:57) *

    
typedef bool Tsubkey[32];
typedef Tsubkey Tkey[8];




Ой..Забыла указать, да, язык С++ (Builder C++ 6)..
Скажи пожалуйста, если действовать таким образом, то как ключ вводить (одним числом или нет)? И как заполнять Tsubkey?

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гость






Цитата
как ключ вводить (одним числом или нет)?
Строкой... Все вводится строкой. Если длина ключа - 256 бит, то длина строки должна быть = 256/8 = 32 символа. Ввела 32-символьную строку, "перевела" ее в биты, и работай дальше. Вот пример "перевода" строки в последовательность бит, и обработки ПОДключа:
typedef bool Tsubkey[32];
typedef Tsubkey Tkey[8];

void print_subkey(const Tsubkey& sk) {
AnsiString s = "";
for(int i = 0; i < 32; i++) {
s += (sk[i] == true ? ("T") : ("F"));
}
Form1->Memo1->Lines->Add(s);
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
bool key[256] = {false};
int curr = 255;

AnsiString s = "the test";
for(int i = s.Length(); i > 0; i--) {
unsigned char ch = s[i];
for(int j = 0; j < 8; j++) {
key[curr--] = (ch & 0x01) ? true : false;
ch >>= 1;
}
}
Tsubkey *ps = (Tsubkey*)&key;
for(int i = 0; i < 8; i++) {
print_subkey( *ps++ );
}
}
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Мне не очень понятно, как поступить с таблицей замен..Каждая из 8-ми строк там содержит 4-хбитные числа от 0 до 15..Преподаватель несколько упростил задачу: предложил самостоятельно её составить, хранить соответственно в файле..
Объясните мне пожалуйста, как тогда добиться при её считывании в некотором смысле единообразия с тем, как поступаем с ключом?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Вот что у меня получилось при формировании таблицы замен:


wchar_t blokS[8][16];
char *fileS;
//....
void __fastcall TFormMain::ButBeginClick(TObject *Sender)
{
FILE *f;
wchar_t c;
fileS=OpenDialog2->FileName.c_str();
f=fopen(fileS,"r");
int j;
int i=0;
while (i<8)
{
j=0;
while ((!feof(f))&&(j<15))
{
fread(&c,sizeof(wchar_t),1,f);
if (c!=' ') //не пробел
{
blokS[i][j]=c;
j++;
}
}
i++;
}
//....
}


Но я не уверена, правильно ли задавать таблицу как wchar_t в моём случае..Или есть более удачный вариант?

Сообщение отредактировано: 18192123 -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Пока не могу добиться нормального считывания из файла...
если содержимое файла такое 15 0 3 12....
то считываются числа порядка 13617 и в таком духе..
Помогите, пожалуйста, разобраться с этим..!
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гость






Файл текстовый? Двоичный? Здесь не форум телепатов, если ты хочешь, чтоб тебе помогли - приводи информацию, которая будет полезна, а не какие-то обрывки...

Если файл текстовый - почему открыт без "rt", и зачем читаешь из него fread-ом? Если двоичный - почему открыт без "rb"? Пример файла приведи (запакуй его и присоедини).
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Таблица замен в текстовом файле..Ниже его содержимое


Прикрепленные файлы
Прикрепленный файл  1.txt ( 310 байт ) Кол-во скачиваний: 283
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Гость






Ну, раз текстовый, то:
wchar_t blokS[8][16];

void __fastcall TForm1::Button10Click(TObject *Sender)
{
wchar_t c;
if(OpenDialog2->Execute()) {
FILE *f = fopen(OpenDialog2->FileName.c_str(),"rt");
int i = 0;
while(i < 8) {
int j = 0;
int code;
while((!feof(f)) && (j < 16)) { // читаем 16 значений, а не 15 !!!
fscanf(f, "%d", &code);
blokS[i][j++] = (wchar_t)code;
}
i++;
}

}
}
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


У меня ещё вопрос по считыванию блока текста (текст в текстовом файле)..По алгоритму размер такого блока 64 бита..
Здесь снова использовать fscanf или можно и fread?
Пробовала и то, и то - в результате считывается что-то странное, а не то, что представлено в файле..

int N1,N2;
__int64 N;
f=fopen(fileIn,"rt");
while (!feof(f))
{
fscanf(f, "%s", &N);
//fread(&N,sizeof(__int64),1,f);
}




Кроме того, входной блок должен быть разбит на правую и левую части (соответственно по 32 бита). Объясните пожалуйста, как это производится?

Сообщение отредактировано: 18192123 -


Прикрепленные файлы
Прикрепленный файл  2.txt ( 8 байт ) Кол-во скачиваний: 248
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Гость






Зачем ты заталкиваешь это в __int64? Ты хочешь получить битовое представление строки в переменной типа __int64? Тогда так:
	__int64 value64;
char str[sizeof(__int64) + 1] = {0};

if(OpenDialog2->Execute()) {
FILE *f = fopen(OpenDialog2->FileName.c_str(),"rt");

// Можно предварительно создать форматную строку, чтоб не привязываться
// к "магическому числу" 8, вместо использования sizeof(__int64)
fscanf(f, "%8s", str);
}
value64 = *(__int64*)(&str[0]); // копируем содержимое строки как __int64

В общем, выше показано, как прочитать блок символов определенной длины из текстового файла. Дальше делай с ним, что тебе надо...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 15.03.2009 15:33) *

	__int64 value64;
//...
value64 = *(__int64*)(&str[0]);



Значит получили входной блок..
А как теперь разбить его на правую (младшую) и левую (старшую) половины?

Сообщение отредактировано: 18192123 -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #14


Гость






Вот 2 способа:
	union Convertor {
__int64 value64;
__int32 LR[2];
};
Convertor value;

char str[sizeof(__int64) + 1] = {0};

if(OpenDialog2->Execute()) {
FILE *f = fopen(OpenDialog2->FileName.c_str(),"rt");
fscanf(f, "%8s", str);
}
value.value64 = *(__int64*)(&str[0]);
__int32 L = value.LR[1];
__int32 R = value.LR[0];

__int32 myL = (value.value64 & 0xFFFFFFFF00000000) >> 32;
__int32 myR = (value.value64 & 0x00000000FFFFFFFF);

, выбирай, какое тебе удобнее... Значения L и myL должны совпадать, R и myR - тоже.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #15


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Итак..далее..
У меня будет функция (выступающая в качестве основного шага криптопреобразования) по преобразованию очередного 64-битного блока текста (его и будет возвращать ф-ция), в которую помимо этого блока необходимо передавать подключи в таком порядке: К0К1К2К3К4К5К6К7К0К1К2К3К4К5К6К7К0К1К2К3К4К5К6К7К7К6К
5К4К3К2К1К0..
Вызов функции с такой последовательностью ключей обеспечивает шифрование блока открытого текста в режиме простой замены..
И мне не понятно, как передать определённый подключ в функцию..
Объясните пожалуйста..!

p.s. привожу статью, на которую опираюсь (пункты 1.3, 1.4, 1.5)


Прикрепленные файлы
Прикрепленный файл  28147_89.rar ( 143.15 килобайт ) Кол-во скачиваний: 223
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #16


Гость






Цитата
мне не понятно, как передать определённый подключ в функцию..
Я ж тебе в четвертом посте показывал, как работать с под-ключами, как "выдирать" их из ключа в любом порядке...

У тебя есть документы, которые содержат все необходимые тебе преобразования. Продумай, наконец, систему типов программы. Продумай систему преобразований типов (явных или неявных, может, будет проще написать небольшой класс, может, будет проще работать с массивами bool-ов, может - со строками, может - с __int64, я не знаю, у меня информация об алгоритме только очень отрывочная), а то так и будешь плавать в ненужных наворотах от одной задачи к другой. Я не буду делать все задание за тебя. Это мне не интересно (кстати, я сомневаюсь, что программная реализация стандарта шифрования ГОСТ 28147-89 вообще законна, у меня есть документ, однозначно утверждающий: "приведенный ниже материал не должен ни при каких условиях использоваться для программной или аппаратной реализации алгоритма криптографического преобразования" (С), так что можно ли вообще делать то, что ты делаешь - еще очень большой вопрос)
 К началу страницы 
+ Ответить 
сообщение
Сообщение #17


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 15.03.2009 18:44) *

...так что можно ли вообще делать то, что ты делаешь - еще очень большой вопрос)

Ну поскольку учебная программа предполагает, то почему нельзя?)
И к тому же, программа-то не предназначена для использования вне учебных целей)

Вообщем реализовала я основной шаг криптопреобразования, шифрование-дешифрование в режиме простой замены..
Вот только в процессе зашифрования получаю идентичный исходному текст...

int blokS[8][16];
__int32 Keys[8];
char *fileS,*fileIn,*fileOut;
//основной шаг
__int64 BaseStep(__int64 N,__int32 Key)
{
__int32 L,R,S,helpS=0;
int i,Sm;
R = (N & 0x00000000FFFFFFFF);
L = (N & 0xFFFFFFFF00000000) >> 32;
S = (R+Key)%0xffffffff;
for (i=0;i<8;i++) //замена с использование таблицы замен
{
Sm=(S&0xf);
S=S>>4;
helpS=(helpS|blokS[i][Sm])<<4;
}
helpS=helpS<<11;
helpS=helpS^L;
//меняем половины местами и получаем преобразованный блок
L=R;
R=helpS;
N=0;
N=(N|L)<<32;
N=N|R;
return N;
}

__int64 emcryption(__int64 n)
{
int k,j;
__int32 l;
for (k=0; k<3; k++)
for (j=0; j<8; j++)
n=BaseStep(n,Keys[j]);
for (j=7; j>=0; j--)
n=BaseStep(n,Keys[j]);
l = (n & 0xFFFFFFFF00000000) >> 32;
n=(n & 0x00000000FFFFFFFF)<<32;
n=n|l;
return n;
}

__int64 decryption(__int64 n)
{
int k,j;
__int32 l;
for (j=0; j<8; j++)
n=BaseStep(n,Keys[j]);
for (k=0; k<3; k++)
for (j=7; j>=0; j--)
n=BaseStep(n,Keys[j]);
l = (n & 0xFFFFFFFF00000000) >> 32;
n=(n & 0x00000000FFFFFFFF)<<32;
n=n|l;
return n;
}

void __fastcall TFormMain::ButBeginClick(TObject *Sender)
{
int i;
//Ключ
for (i=0;i<8;i++)
Keys[i]=StrToInt(MemoKey->Lines->Strings[i]);

//таблица замен
FILE *f = fopen(OpenDialog2->FileName.c_str(),"rt");
i = 0;
while(i < 8)
{
int j = 0;
int code;
while((!feof(f)) && (j < 16))
{
fscanf(f, "%d", &code);
blokS[i][j++] = (int)code;
}
i++;
}
fclose(f);
//
__int64 N,masN[100];
f=fopen(fileIn,"rt");
FILE *fOut;
fOut=fopen(fileOut,"w");
__int32 L,R;
while (!feof(f))
{
char str[sizeof(__int64) + 1] = {0};
fscanf(f, "%8s", str);
N = *(__int64*)(&str[0]);
N=emcryption(N);
//N=decryption(N);
fwrite(&N,sizeof(__int64),1,fOut);
}
fclose(fOut);
}




Думаю, что в основном шаге напутала чего-нибудь... Помогите пожалуйста разобраться, что не так..?
Текст по-прежнему в текстовом файле..

Сообщение отредактировано: 18192123 -


Прикрепленные файлы
Прикрепленный файл  2.txt ( 8 байт ) Кол-во скачиваний: 272
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #18


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(18192123 @ 15.03.2009 23:31) *


//...
N=emcryption(N);
//N=decryption(N);
fwrite(&N,sizeof(__int64),1,fOut);
//...



Поправила вызов функций зашифрования-расшифрования...
Приведённый выше файл удалось зашифровать..Но результат расшифрования не совпал с исходным текстом...
Зашифрование-расшифрование проводилось с ключом (1;2;3;4;5;6;7;8) - вводится в Memo..

Сообщение отредактировано: 18192123 -


Прикрепленные файлы
Прикрепленный файл  emcryption.txt ( 8 байт ) Кол-во скачиваний: 259
Прикрепленный файл  decryption.txt ( 8 байт ) Кол-во скачиваний: 278
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #19


Гость






Все-таки что-то не так в функции decryption(): если сделать точку останова и посмотреть, какое значение получилось после прочтения исходного текста в N (еще до encryption), а потом сравнить его со значением N после decryption, то выясняется, что после decryption значение N = -1. Хотя в самом начале было совсем другое значения.

Это первое. Второе: ты все запутала окончательно. Смотри... Ты читаешь изначальный текст из файла 2.txt, значит, входной файл у тебя там, перед шифрованием, должен открываться как "rt", а выходной (поскольку записываешь ты в него __int64) должен открываться как "wb"... Не просто "w", а именно "wb"... ТЕперь обратный процесс: ты читаешь данные для дешифрования из бинарного файла, т.е., открываться должен как "rb", а пишешь в decrypted.txt - как в текстовый - значит, вот так:

// шифрование:
f = fopen("2.txt","rt");
FILE *fOut;
fOut=fopen(fileIn,"wb"); // encrypted.txt
__int32 L,R;
while (!feof(f))
{
char str[sizeof(__int64) + 1] = {0};
fscanf(f, "%8s", str); // читаешь как строку из txt-файла
N = *(__int64*)(&str[0]);
N=emcryption(N);
fwrite(&N,sizeof(__int64),1,fOut); // пишешь в бинарный файл как значение __int64
}
fclose(fOut);

// дешифрование
f=fopen(fileIn,"rb"); // encrypted.txt
FILE *fOut;
fOut=fopen(fileOut,"wt"); // decrypted.txt
__int32 L,R;
while (!feof(f))
{
char str[sizeof(__int64) + 1] = {0};
fread(&N, sizeof(__int64), 1, f); // читаешь значение __int64
N=decryption(N); // шифруешь это значение N. Но тут почему-то получается (-1)
fprintf(fOut, "%8s\0", (char*)(&N)); // а вот пишешь - уже строку
}
fclose(fOut);

Понимаешь, о чем я?

В самой функции decryption не разбирался...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #20


Гость






Так... А вот теперь я разбирался со всеми функциями. И вот что удалось сделать:

1) не работай со знаковыми __int64, везде придется поменять этот тип на unsigned __int64...
2) в некоторых местах я убрал заведомо лишние действия, и добавил явные приведения типов там, где без них могут быть проблемы...
3) самое главное: в функции BaseStep ты делаешь:
Цитата
 helpS=helpS<<11;
- это совершенно неверно. В твоем документа ясно сказано, что сдвиг должен быть циклическим, т.е., выталкиваемый слева бит становится крайним справа. Это тоже поправил...
4) Ну, по мелочам: сделал локальные переменные в циклах, убрал неиспользуемые массивы и переменные, при чтении из зашифрованного файла проверяю значение, возвращаемое fread, иначе в расшифрованный файл записывается 8 байт мусора. Вот что получилось в итоге:
unsigned __int32 blokS[8][16];
unsigned __int32 Keys[8];
char *fileS,*fileIn="encrypted.txt",*fileOut="decrypted.txt";

//основной шаг
unsigned __int64 BaseStep(unsigned __int64 N, unsigned __int32 Key) {
unsigned __int32 L, R, S, helpS = 0;
R = (unsigned __int32)(N & 0x00000000FFFFFFFF);
L = (unsigned __int32)((N & 0xFFFFFFFF00000000) >> 32);

S = (R + Key) % 0xffffffff;
for(int i = 0; i < 8; i++) { // замена с использованием таблицы замен
int Sm = (S & 0xf);
S = S >> 4;
helpS = (helpS | blokS[i][Sm]) << 4;
}
for(int i = 0; i < 11; i++) { // циклический сдвиг !!!
bool b = (helpS & 0x80000000) ? true : false;
helpS <<= 1;
if(b) {
helpS |= 0x1;
}
}
helpS = helpS ^ L;
// меняем половины местами и получаем преобразованный блок
L = R;
R = helpS;
N = ((unsigned __int64)L << 32) | (unsigned __int64)R;
return N;
}

unsigned __int64 emcryption(unsigned __int64 n) {
unsigned __int32 l;
for(int k = 0; k < 3; k++) {
for(int j = 0; j < 8; j++) {
n = BaseStep(n, Keys[j]);
}
}
for(int j = 7; j >= 0; j--) {
n = BaseStep(n, Keys[j]);
}
l = n >> 32;
n = (n << 32) | l;
return n;
}

unsigned __int64 decryption(unsigned __int64 n) {
unsigned __int32 l;
for(int j = 0; j < 8; j++) {
n = BaseStep(n, Keys[j]);
}
for(int k = 0; k < 3; k++) {
for(int j = 7; j >= 0; j--) {
n = BaseStep(n, Keys[j]);
}
}
l = n >> 32;
n = (n << 32) | l;
return n;
}

// Шифрование
void __fastcall TForm1::Button11Click(TObject *Sender)
{
// Ключ
for(int i = 0; i < 8; i++) {
Keys[i] = StrToInt(Memo1->Lines->Strings[i]);
}

if(OpenDialog2->Execute()){
// таблица замен
FILE *f = fopen(OpenDialog2->FileName.c_str(),"rt");
int i = 0;
while(i < 8) {
int j = 0;
int code;
while((!feof(f)) && (j < 16)) {
fscanf(f, "%d", &code);
blokS[i][j++] = (int)code;
}
i++;
}
fclose(f);

unsigned __int64 N;
f = fopen("2.txt","rt");
FILE *fOut = fopen(fileIn, "wb"); // encrypted.txt
while(!feof(f)) {
char str[sizeof(unsigned __int64) + 1] = {0};
fscanf(f, "%8s", str);
N = *(__int64*)(&str[0]);
N = emcryption(N);
fwrite(&N, sizeof(unsigned __int64), 1, fOut);
}
fclose(fOut);
}
}
//---------------------------------------------------------------------------

// Дешифрование
void __fastcall TForm1::Button12Click(TObject *Sender)
{
// Ключ
for(int i = 0; i < 8; i++) {
Keys[i] = StrToInt(Memo1->Lines->Strings[i]);
}

// таблица замен
if(OpenDialog2->Execute()) {
FILE *f = fopen(OpenDialog2->FileName.c_str(),"rt");
int i = 0;
while(i < 8) {
int j = 0;
int code;
while((!feof(f)) && (j < 16)) {
fscanf(f, "%d", &code);
blokS[i][j++] = (int)code;
}
i++;
}
fclose(f);
//

unsigned __int64 N;
f = fopen(fileIn, "rb"); // encrypted.txt
FILE *fOut = fopen(fileOut,"wt");
while(!feof(f)) {
char str[sizeof(unsigned __int64) + 1] = {0};
if(fread(&N, sizeof(unsigned __int64), 1, f)) {
N = decryption(N);
char result[9] = {0};
strncpy(result, (char *)&N, 8);
fprintf(fOut, "%s", result);
}
}
fclose(fOut);
}
}


Исходный и расшифрованный текст (те самые 8 байт: "qwertyui") полностью идентичны.
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 19.04.2024 20:52
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name