· 5 years ago · Sep 20, 2020, 04:20 PM
1/*Программе передается аргумент - пароль.
2На стандартый поток ввода подаются данные, зашифрованные алгоритмом AES-256-CBC с солью. Для получения начального вектора и ключа из пароля и соли используется алгоритм SHA-256.
3
4Необходимо расшифровать данные и вывести их на стандартый поток вывода.
5
6Используйте API OpenSSL/LibreSSL. Запуск сторонних команд через fork+exec запрещен.
7
8Отправляйте только исходный файл Си-программы с решением.
9*/
10
11#include <stdio.h>
12#include <string.h>
13#include <unistd.h>
14#include <openssl/evp.h>
15
16
17static const size_t KEY_SIZE = 32;
18static const size_t DATA_SIZE = 1024;
19static const size_t IV_SIZE = 16;
20static const size_t SALT_SIZE = 8;
21
22
23int main(int argc, char **argv) {
24 char* password = argv[1];
25
26 //созданеи контекста
27 //переменная, которая хранит состояние шифрующего автомата.
28 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
29
30
31 unsigned char data[SALT_SIZE];
32 unsigned char salt[SALT_SIZE];
33
34 read(STDIN_FILENO, data, SALT_SIZE);
35 read(STDIN_FILENO, salt, SALT_SIZE);
36
37 unsigned char iv[IV_SIZE];
38 unsigned char key[KEY_SIZE];
39
40// Генерация ключа и начального вектора из
41// пароля произвольной длины и 8-байтной соли
42 EVP_BytesToKey(
43 EVP_aes_256_cbc(), // алгоритм шифрования
44 EVP_sha256(), // алгоритм хеширования пароля
45 salt, // соль
46 password, strlen(password), // пароль
47 1, // количество итераций хеширования
48 key, // результат: ключ нужной длины
49 iv // результат: начальный вектор нужной длины
50 );
51
52 // Начальная стадия: инициализация
53 EVP_DecryptInit(
54 ctx, // контекст для хранения состояния
55 EVP_aes_256_cbc(), // алгоритм шифрования
56 key, // ключ нужного размера
57 iv // начальное значение нужного размера
58 );
59 unsigned char input[DATA_SIZE];
60 unsigned char output[DATA_SIZE + IV_SIZE];
61
62
63 int updated_size = 0;
64 ssize_t read_cnt = read(STDIN_FILENO, input, sizeof(input));
65 while (read_cnt > 0) {
66 EVP_DecryptUpdate(ctx, output, &updated_size, input, read_cnt); //Добавление очередной порции данных
67 write(STDOUT_FILENO, output, updated_size);
68 read_cnt = read(STDIN_FILENO, input, sizeof(input));
69 }
70
71 EVP_DecryptFinal(ctx, output, &updated_size);
72 write(STDOUT_FILENO, output, updated_size);
73
74 EVP_CIPHER_CTX_free(ctx);
75 return 0;
76}