Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
1

OPENSsl RSA не расшифровывает зашифрованное сообщение

11.10.2019, 17:09. Показов 3349. Ответов 30

Author24 — интернет-сервис помощи студентам
Всем привет. Уже несколько дней бьюсь над зашифровкой и расшифровкой текста через RSA шифрование. В интернете пытался найти в чем проблема, но так и не нашел. Почти у каждого кода, который я находил, примерно такая же реализация шифрования и расшифровки текста. Текст вроде и шифрует, но расшифровать он его не может( Мой код может и плохой, но это для меня как пример, чтобы понять сам механизм работы RSA шифрования. Так что за goto не ругайте)) Пишу в visual studio 2017. Помогите, пожалуйста.
C++
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
#define _CRT_SECURE_NO_WARNINGS
 
#include <iostream>
#include <conio.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
 
using namespace std;
void GenKeys();
void Enc();
void Dec();
void GenKeysMenu();
void EncryptMenu();
void DecryptMenu();
 
void main() {
    setlocale(LC_ALL, "Russian");
    char key;
StartMenu:
    system("cls");
    cout << "-------------- Шифрование RSA --------------" << endl << endl;
    cout << "  1. Получение ключей" << endl;
    cout << "  2. Зашифровать содержимое файла" << endl;
    cout << "  3. Дешифровать содержимое файла" << endl << endl;
    cout << "Ваш выбор: ";
    cin >> key;
    switch (key) {
    case '1': GenKeysMenu(); goto StartMenu;
    case '2': EncryptMenu(); goto StartMenu;
    case '3': DecryptMenu(); goto StartMenu;
    default: goto StartMenu;
    }
}
 
void GenKeys() {
    /* указатель на структуру для хранения ключей */
    RSA * rsa = NULL;
    unsigned long bits = 1024; /* длина ключа в битах */
    BIO* privKey_file = NULL, *pubKey_file = NULL;
    /*Создаем файлы ключей*/
    privKey_file = BIO_new_file("private.pem", "w+");
    pubKey_file = BIO_new_file("public.pem", "w+");
    /* Генерируем ключи */
    rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
    // Получаем из структуры rsa открытый и секретный ключи и сохраняем в файлах.
    PEM_write_bio_RSAPublicKey(pubKey_file, rsa);
    PEM_write_bio_RSAPrivateKey(privKey_file, rsa, NULL, NULL, 0, NULL, NULL);
    
    /* Освобождаем память, выделенную под структуру rsa */
    RSA_free(rsa);
    BIO_free_all(privKey_file);
    BIO_free_all(pubKey_file);
    cout << "Ключи сгенерированы и помещены в папку с исполняемым файлом" << endl;
}
 
void Encrypt() {
    /* структура для хранения открытого ключа */
    RSA * pubKey = NULL;
    BIO * pubKey_file = BIO_new_file("public.pem", "r");
    unsigned char *ctext, *ptext;
    int inlen, outlen;
    /* Считываем открытый ключ */
    //fopen_s(&pubKey_file, "public.pem", "rb");
    if (pubKey_file == NULL)
    {
        cout << "Файл не открыт." << endl;
        return;
    }
    pubKey = PEM_read_bio_RSAPublicKey(pubKey_file, NULL, NULL, NULL);
    //fclose(pubKey_file);
    /* Определяем длину ключа */
    int key_size = RSA_size(pubKey);
    ctext = (unsigned char *)malloc(key_size);
    ptext = (unsigned char *)malloc(key_size);
    OpenSSL_add_all_algorithms();
 
    int out = _open("rsa.file", O_CREAT | O_TRUNC | O_RDWR, 0600);
    int in = _open("in.txt", O_RDWR);
    /* Шифруем содержимое входного файла */
    while (1) {
        inlen = _read(in, ptext, key_size-11);
        if (inlen <= 0) break;
        outlen = RSA_public_encrypt(inlen, ptext, ctext, pubKey, RSA_PKCS1_PADDING);
        if (outlen != RSA_size(pubKey)) exit(-1);
        _write(out, ctext, outlen);
    }
    cout << "Содержимое файла in.txt было зашифровано и помещено в файл rsa.file" << endl;
}
 
void Decrypt() {
    RSA * privKey = NULL;
    BIO * privKey_file = BIO_new_file("private.pem", "r");
    unsigned char *ptext, *ctext;
    int inlen, outlen;
 
    /* Открываем ключевой файл и считываем секретный ключ */
    OpenSSL_add_all_algorithms();
    //privKey_file = fopen("private.pem", "rb");
    privKey = PEM_read_bio_RSAPrivateKey(privKey_file, NULL, NULL, NULL);
 
    /* Определяем размер ключа */
    int key_size = RSA_size(privKey);
    ptext = (unsigned char *)malloc(key_size);
    ctext = (unsigned char *)malloc(key_size);
 
    int out = _open("out.txt", O_CREAT | O_TRUNC | O_RDWR, 0600);
    int in = _open("rsa.file", O_RDWR);
 
    /* Дешифруем файл */
    while (1) {
        inlen = _read(in, ctext, key_size);
        if (inlen <= 0) break;
        outlen = RSA_private_decrypt(inlen, ctext, ptext, privKey, RSA_PKCS1_PADDING);
        if (outlen < 0) exit(0);
        _write(out, ptext, outlen);
    }
    cout << "Содержимое файла rsa.file было дешифровано и помещено в файл out.txt" << endl;
 
}
void GenKeysMenu() {
    system("cls");
    cout << "-------------- Шифрование RSA --------------" << endl << endl;
    GenKeys();
    cout << "Нажмите любую кнопку для возврата в меню...";
    _getch();
}
void EncryptMenu() {
    system("cls");
    cout << "-------------- Шифрование RSA --------------" << endl << endl;
    Encrypt();
    cout << "Нажмите любую кнопку для возврата в меню...";
    _getch();
}
void DecryptMenu() {
    char secret[] = "";
    system("cls");
    cout << "-------------- Шифрование RSA --------------" << endl << endl;
    Decrypt();
    cout << "Нажмите любую кнопку для возврата в меню...";
    _getch();
}
Добавлено через 1 час 27 минут
Путем экспериментов выяснил, что программа прикрепленная ниже работает на пятый раз. Т.е. я запускаю ее, выбираю шифрование, потом расшифровку (после этого программа завершается с ошибкой). Запускаем еще раз и повторяем эту же процедуру 4 раза. На 5 раз программа не завершается с ошибкой, а расшифровывает текст. В чем может быть проблема?
C++
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
#include "pch.h"
#define _CRT_SECURE_NO_WARNINGS
 
#include <iostream>
#include <conio.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
 
using namespace std;
void GenKeys();
void Enc();
void Dec();
void GenKeysMenu();
void EncryptMenu();
void DecryptMenu();
 
void main() {
    setlocale(LC_ALL, "Russian");
    char key;
StartMenu:
    system("cls");
    cout << "-------------- Шифрование RSA --------------" << endl << endl;
    cout << "  1. Получение ключей" << endl;
    cout << "  2. Зашифровать содержимое файла" << endl;
    cout << "  3. Дешифровать содержимое файла" << endl << endl;
    cout << "Ваш выбор: ";
    cin >> key;
    switch (key) {
    case '1': GenKeysMenu(); goto StartMenu;
    case '2': EncryptMenu(); goto StartMenu;
    case '3': DecryptMenu(); goto StartMenu;
    default: goto StartMenu;
    }
}
 
void GenKeys() {
    /* указатель на структуру для хранения ключей */
    RSA*    rsa = 0;
    BIGNUM* bignum = 0;
    const int bits = 2048;
    const BN_ULONG e = RSA_F4;
    int result = 0;
 
    //генерация ключей, заполнение структуры RSA
    bignum = BN_new();
    result = BN_set_word(bignum, e);
    if (result != 1)return;
 
    rsa = RSA_new();
    result = RSA_generate_key_ex(rsa, bits, bignum, 0);
    BIO* privKey_file = NULL, *pubKey_file = NULL;
    /*Создаем файлы ключей*/
    privKey_file = BIO_new_file("private.pem", "w+");
    pubKey_file = BIO_new_file("public.pem", "w+");
    // Получаем из структуры rsa открытый и секретный ключи и сохраняем в файлах.
    PEM_write_bio_RSA_PUBKEY(pubKey_file, rsa);
    PEM_write_bio_RSAPrivateKey(privKey_file, rsa, NULL, NULL, 0, NULL, NULL);
    
    /* Освобождаем память, выделенную под структуру rsa */
    RSA_free(rsa);
    BIO_free_all(privKey_file);
    BIO_free_all(pubKey_file);
    cout << "Ключи сгенерированы и помещены в папку с исполняемым файлом" << endl;
}
 
void Encrypt() {
    /* структура для хранения открытого ключа */
    RSA * pubKey = NULL;
    BIO * pubKey_file = BIO_new_file("public.pem", "r");
    unsigned char *ctext, *ptext;
    int inlen, outlen;
    /* Считываем открытый ключ */
    //fopen_s(&pubKey_file, "public.pem", "rb");
    if (pubKey_file == NULL)
    {
        cout << "Файл не открыт." << endl;
        return;
    }
    pubKey = PEM_read_bio_RSA_PUBKEY(pubKey_file, NULL, NULL, NULL);
    //fclose(pubKey_file);
    /* Определяем длину ключа */
    int key_size = RSA_size(pubKey);
    ctext = (unsigned char *)malloc(key_size);
    ptext = (unsigned char *)malloc(key_size);
    OpenSSL_add_all_algorithms();
 
    int out = _open("rsa.file", O_CREAT | O_TRUNC | O_RDWR, 0600);
    int in = _open("in.txt", O_RDWR);
    /* Шифруем содержимое входного файла */
    while (1) {
        inlen = _read(in, ptext, key_size-42);
        if (inlen <= 0) break;
        outlen = RSA_public_encrypt(inlen, ptext, ctext, pubKey, RSA_PKCS1_OAEP_PADDING);
        if (outlen != RSA_size(pubKey)) exit(-1);
        _write(out, ctext, outlen);
    }
    BIO_free_all(pubKey_file);
    _close(out);
    _close(in);
    cout << "Содержимое файла in.txt было зашифровано и помещено в файл rsa.file" << endl;
}
 
void Decrypt() {
    RSA * privKey = NULL;
    BIO * privKey_file = BIO_new_file("private.pem", "r");
    unsigned char *ptext, *ctext;
    int inlen, outlen;
 
    /* Открываем ключевой файл и считываем секретный ключ */
    OpenSSL_add_all_algorithms();
    //privKey_file = fopen("private.pem", "rb");
    privKey = PEM_read_bio_RSAPrivateKey(privKey_file, NULL, NULL, NULL);
 
    /* Определяем размер ключа */
    int key_size = RSA_size(privKey);
    ptext = (unsigned char *)malloc(key_size);
    ctext = (unsigned char *)malloc(key_size);
 
    int out = _open("out.txt", O_CREAT | O_TRUNC | O_RDWR, 0600);
    int in = _open("rsa.file", O_RDWR);
 
    /* Дешифруем файл */
    while (1) {
        inlen = _read(in, ctext, key_size);
        if (inlen <= 0) break;
        outlen = RSA_private_decrypt(key_size, ctext, ptext, privKey, RSA_PKCS1_OAEP_PADDING);
        if (outlen < 0) exit(0);
        _write(out, ptext, outlen);
    }
    BIO_free_all(privKey_file);
    _close(out);
    _close(in);
    cout << "Содержимое файла rsa.file было дешифровано и помещено в файл out.txt" << endl;
 
}
void GenKeysMenu() {
    system("cls");
    cout << "-------------- Шифрование RSA --------------" << endl << endl;
    GenKeys();
    cout << "Нажмите любую кнопку для возврата в меню...";
    _getch();
}
void EncryptMenu() {
    system("cls");
    cout << "-------------- Шифрование RSA --------------" << endl << endl;
    Encrypt();
    cout << "Нажмите любую кнопку для возврата в меню...";
    _getch();
}
void DecryptMenu() {
    char secret[] = "";
    system("cls");
    cout << "-------------- Шифрование RSA --------------" << endl << endl;
    Decrypt();
    cout << "Нажмите любую кнопку для возврата в меню...";
    _getch();
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.10.2019, 17:09
Ответы с готовыми решениями:

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

Зашифрованное число RSA меньше изначального шифруемого?
Всегда ли зашифрованное с помощью RSA число меньше чем изначальное шифруемое?

Реализация RSA в OpenSSL
В приложении на C++ нужно реализовать поддержку RSA, но поскольку на C++ у меня нет вообще никакого...

Есть ли для Аndroid класс реализации OpenSSL алгоритмом RSA ?
Вообще, нужно зашифровывать/расшифровывать строку в Java, C++ и в perl. Есть ли для android...

30
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
11.10.2019, 17:12 2
Цитата Сообщение от Rideslow Посмотреть сообщение
завершается с ошибкой
с какой?
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
11.10.2019, 17:22  [ТС] 3
возможно я не правильно выразился, не совсем ошибка. строка 129 возвращает "-1" и строка 130 завершает программу. После этого я запускаю программу еще раз и повторяю те же действия, и на 2-6 запуск программа все таки расшифрует текст.

Добавлено через 5 минут
Цитата Сообщение от Avaddon74 Посмотреть сообщение
с какой?
возможно я не правильно выразился, не совсем ошибка. строка 129 возвращает "-1" и строка 130 завершает программу. После этого я запускаю программу еще раз и повторяю те же действия, и на 2-6 запуск программа все таки расшифрует текст.
0
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
11.10.2019, 17:33 4
Rideslow, Запустите программу по F5 и отслеживайте изменения переменных, сделайте вывод промежуточных значений и найдете ошибку
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
11.10.2019, 17:41  [ТС] 5
Цитата Сообщение от Avaddon74 Посмотреть сообщение
Rideslow, Запустите программу по F5 и отслеживайте изменения переменных, сделайте вывод промежуточных значений и найдете ошибку
Пробовал, но что-то все равно ладу дать не могу с ней.
0
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
11.10.2019, 17:47 6
Цитата Сообщение от Rideslow Посмотреть сообщение
Пробовал, но что-то все равно ладу дать не могу с ней
Могу предположить, что плохо старались
Когда ошибка возникает постоянно, то проще всего её найти, сложнее найти когда наоборот, и сотни запусков 1 привод к неверному.
Повторюсь, оформите логи и вывод промежуточных значений, и будет вам счастье
0
Любитель чаепитий
3742 / 1798 / 566
Регистрация: 24.08.2014
Сообщений: 6,016
Записей в блоге: 1
12.10.2019, 05:50 7
Цитата Сообщение от Rideslow Посмотреть сообщение
возможно я не правильно выразился, не совсем ошибка. строка 129 возвращает "-1" и строка 130 завершает программу. После этого я запускаю программу еще раз и повторяю те же действия, и на 2-6 запуск программа все таки расшифрует текст.
после того, как функция возвращает -1, проверьте ERR_get_error.
https://www.openssl.org/docs/m... error.html
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
12.10.2019, 06:50  [ТС] 8
Цитата Сообщение от GbaLog- Посмотреть сообщение
после того, как функция возвращает -1, проверьте ERR_get_error.
https://www.openssl.org/docs/m... error.html
err_get_error вернул "67768441"
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
12.10.2019, 18:22  [ТС] 9
Цитата Сообщение от GbaLog- Посмотреть сообщение
после того, как функция возвращает -1, проверьте ERR_get_error.
https://www.openssl.org/docs/m... error.html
после добавления кусочка кода, удалось выяснить, что возвращаются 2 ошибки:
1) error:040A1079:lib(4):func(161):reason(121)
2) error:04065072:lib(4):func(101):reason(114)

код, как нашел их прикрепил
C++
1
2
char buf[256]; 
strcpy(ERR_error_string(ERR_get_error(), buf), buf);
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
12.10.2019, 19:53 10
Rideslow, не уверен, что это поможет, но файлы, которые ты окрываешь через _open, нужно открывать в бинарном режиме, т.е. с флагом _O_BINARY.
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
12.10.2019, 21:07  [ТС] 11
Цитата Сообщение от nonedark2008 Посмотреть сообщение
Rideslow, не уверен, что это поможет, но файлы, которые ты окрываешь через _open, нужно открывать в бинарном режиме, т.е. с флагом _O_BINARY.
Не помогло, но спасибо за попытку помочь
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
12.10.2019, 21:47 12
Цитата Сообщение от Rideslow Посмотреть сообщение
Не помогло, но спасибо за попытку помочь
Собрал у себя твой код с предложенными мной исправлениями. Файл размером в мегабайт без всяких проблем шифруется и дешифруется. Правда openssl я взял, видимо, поновее.
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
12.10.2019, 22:03  [ТС] 13
Цитата Сообщение от nonedark2008 Посмотреть сообщение
Собрал у себя твой код с предложенными мной исправлениями. Файл размером в мегабайт без всяких проблем шифруется и дешифруется. Правда openssl я взял, видимо, поновее.
несколько запусков хорошо дешифрует? а то у меня раз через 5 дешифрует, а потом опять ломается.
Не могли бы вы скинуть свой openssl? у меня версия 1.0.1
0
фрилансер
5499 / 5095 / 1047
Регистрация: 11.10.2019
Сообщений: 13,346
12.10.2019, 22:10 14
Rideslow, а что за волшебная восьмеричная константа 0600 ?
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
12.10.2019, 22:17  [ТС] 15
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Rideslow, а что за волшебная восьмеричная константа 0600 ?
правами доступа 0600 (чтение и запись для пользователя).
0
фрилансер
5499 / 5095 / 1047
Регистрация: 11.10.2019
Сообщений: 13,346
12.10.2019, 22:21 16
Rideslow, я код у себя опробовал - рабочий, ни разу не ломается. Вот версию библиотеки не знаю, я себе только нужные файлы как-то оставил, с версией потерялись ))

а goto можешь так убрать

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    while(1)
    {
        system("cls");
        cout << "-------------- Шифрование RSA --------------" << endl << endl;
        cout << "  1. Получение ключей" << endl;
        cout << "  2. Зашифровать содержимое файла" << endl;
        cout << "  3. Дешифровать содержимое файла" << endl << endl;
        cout << "Ваш выбор: ";
        cin >> key;
        switch (key)
        {
            case '1': GenKeysMenu(); continue;
            case '2': EncryptMenu(); continue;
            case '3': DecryptMenu(); continue;
        }
    }
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
12.10.2019, 22:24  [ТС] 17
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Rideslow, я код у себя опробовал - рабочий, ни разу не ломается. Вот версию библиотеки не знаю, я себе только нужные файлы как-то оставил, с версией потерялись ))
Спасибо, что проверили, значит буду с версией openssl копаться, неужели я потерял несколько дней из-за версии?
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
12.10.2019, 22:31 18
Цитата Сообщение от Rideslow Посмотреть сообщение
Не могли бы вы скинуть свой openssl?
Ставил версию 1.1.1, бинарники от которой скачал отсюда.

Добавлено через 1 минуту
Цитата Сообщение от Rideslow Посмотреть сообщение
несколько запусков хорошо дешифрует?
Да, раз 5 подряд.
0
0 / 0 / 0
Регистрация: 11.10.2019
Сообщений: 14
12.10.2019, 22:34  [ТС] 19
Цитата Сообщение от nonedark2008 Посмотреть сообщение
Ставил версию 1.1.1, бинарники от которой скачал отсюда.
Спасибо, завтра попробую поставить и скомпилировать еще раз.
0
фрилансер
5499 / 5095 / 1047
Регистрация: 11.10.2019
Сообщений: 13,346
12.10.2019, 22:46 20
Rideslow, я порылся насчёт магической константы (не люблю такие вещи )

вот тут есть сорс
https://unix.superglobalmegaco... tat.h.html

в нём есть определение этих констант
C++
1
2
3
4
#define S_IRWXU 0000700         /* RWX mask for owner */
#define S_IRUSR 0000400         /* R for owner */
#define S_IWUSR 0000200         /* W for owner */
#define S_IXUSR 0000100         /* X for owner */
в итоге 0600 == (S_IRUSR|S_IWUSR)

удивило, что восьмеричные. Оригинальный подход
0
12.10.2019, 22:46
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
12.10.2019, 22:46
Помогаю со студенческими работами здесь

Расшифровать сообщение, зашифрованное шифром Цезаря
Написать программу, которая расшифровывает сообщение, зашифрованное шифром Цезаря, перебором всех...

Как написать шифрование RSA на python без import RSA
Нужнен код без использование RSA библиотеки. Буду блогодарен!

Зашифровать сообщение имеющимся публичным ключом (RSA)
Господа, нуждаюсь в вашей помощи. Вопрос по RSA: Есть сгенерированный публичный ключ...

Зашифровывает, но не расшифровывает
HELP public void Button1Click(object sender, EventArgs e) { for(int j=0; j&lt;count2;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru