Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Crypto api RC2 
V
    Опции темы
frying
Дата 2.5.2012, 20:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 17.10.2011

Репутация: нет
Всего: нет



Доброго времени суток!
Проблема такая: почему-то зашифрованные данные ничем не отличаются от исходных. В чём ошибка не понятно.
Код

#define _WIN32_WINNT 0x0400

#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <Windows.h>
#include <WinCrypt.h>
#pragma comment(lib, "advapi32.lib")

using namespace std;

int main(){
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hSessionKey = 0;

    // Получение контекста криптопровайдера
    if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
      cout << "CryptAcquireContext Error";
      cin.get();
      //return 1;
    } else {
        std::cout << "Cryptographic provider initialized" << std::endl;
    }
    // Генерация сессионного ключа
    if (!CryptGenKey(hProv, CALG_RC2, 40<<16, &hSessionKey)) {
      cout << "CryptGenKey Error";
      cin.get();
      //return 1;
    } else {
        std::cout << "Session key generated" << std::endl;
        std::cout << &hSessionKey << std::endl;
    }

    ifstream ifs;
    ifs.open("out.txt");
    ofstream ofs;
    ofs.open("in.txt");
    if (!ifs.is_open() || !ofs.is_open()) {
        cout << "File is not exist" << endl;
    } else {
        while (!ifs.eof())
        {
            const size_t buf3_size = 5;
            char buf3[buf3_size] = { 0 };
            DWORD count3 = strlen(buf3);
            ifs.read(buf3, buf3_size);
            bool flag = ifs.eof();
            // Шифрование данных
            if (!CryptEncrypt(hSessionKey, 0, flag, 0, (BYTE*)buf3, &count3, 40)) {
                cout << "CryptEncrypt Error";
                cin.get();
                return 1;
            } else {
                for (size_t i = 0; i < ifs.gcount(); ++i)
                {
                    ofs << buf3[i];
                }
            }
        }
        ifs.close();
        ofs.close();
    }
    cin.get();
}


Проверялось на Visual C++.
PM MAIL   Вверх
feodorv
Дата 2.5.2012, 22:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



А это что такое:
Цитата(frying @  2.5.2012,  21:13 Найти цитируемый пост)
            char buf3[buf3_size] = { 0 };
            DWORD count3 = strlen(buf3);

Почему strlen? Как это вообще могло работать???


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
GremlinProg
Дата 3.5.2012, 06:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(feodorv @  3.5.2012,  00:36 Найти цитируемый пост)
Как это вообще могло работать???

в принципе, могло бы:
Цитата(frying @  2.5.2012,  22:13 Найти цитируемый пост)
const size_t buf3_size = 5;

а вот здесь, думаю есть ошибка:
Цитата(frying @  2.5.2012,  22:13 Найти цитируемый пост)
for (size_t i = 0; i < ifs.gcount(); ++i)

CryptEncrypt возвращает чсисло зашифрованных байт в count3,
так что если там 0, вполне возможно, что данные на выходе остались неизменными,
наверное, что-то не так с логикой: флаги, порядок вызовов API и т.п.


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
frying
Дата 3.5.2012, 06:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 17.10.2011

Репутация: нет
Всего: нет



Попробовал сделать так:
Код

for (size_t i = 0; i < count3; ++i)
{
    cout << count3 << endl;
    ofs << buf3[i];
}

На экране всё время выводится 8.
Насчёт флагов - ведь там сейчас всего один действующий flag, который показывает последний блок из файла или нет будет передан.
PM MAIL   Вверх
GremlinProg
Дата 3.5.2012, 06:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(frying @  2.5.2012,  22:13 Найти цитируемый пост)
CryptEncrypt(hSessionKey, 0, flag, 0, (BYTE*)buf3, &count3, 40)

флаг тут может быть только 0 либо CRYPT_OAEP, ничего другого быть не должно,
а последний параметр должен принимать размер буфера buf3 в байтах,
ни где не вижу, чтобы он был распределен на 40 байт,

чтобы определить необходимый размер буфера, который требуется выделить для CryptEncrypt, необходимо вызвать его с pbData=NULL, тогда размер буфера будет возвращен в параметре pdwDataLen

документация: http://msdn.microsoft.com/en-us/library/wi...4(v=vs.85).aspx


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
feodorv
Дата 3.5.2012, 17:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(GremlinProg @  3.5.2012,  07:27 Найти цитируемый пост)
CryptEncrypt возвращает чсисло зашифрованных байт в count3,

Я, в сущности, к тому, что CryptEncrypt и принимает число приготовленных байт для шифрования тоже в count3, а если там 0?

Вот сколько байт считано из файла:
Цитата(frying @  2.5.2012,  21:13 Найти цитируемый пост)
ifs.read(buf3, buf3_size);


вот столько и надо определять в count3:
Цитата(frying @  2.5.2012,  21:13 Найти цитируемый пост)
            if (!CryptEncrypt(hSessionKey, 0, flag, 0, (BYTE*)buf3, &count3, 40)) {

на каждом шаге цикла чтения из файла.


Цитата(GremlinProg @  3.5.2012,  07:53 Найти цитируемый пост)
ни где не вижу, чтобы он был распределен на 40 байт,

+1



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
frying
Дата 4.5.2012, 07:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 17.10.2011

Репутация: нет
Всего: нет



GremlinProg, флаг нужен, в спецификации он называется Final.
Пробую получить размер буфера:
Код

const int buf3_size = 8;
char buf3[buf3_size] = { 0 };
DWORD pdwDataLen;
CryptEncrypt(hSessionKey, 0, true, 0, 0, &pdwDataLen , buf3_size);
cout << pdwDataLen  << endl;


Но pdwDataLen  всегда 0. Почему?
PM MAIL   Вверх
GremlinProg
Дата 4.5.2012, 07:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(frying @  4.5.2012,  09:01 Найти цитируемый пост)
GremlinProg, флаг нужен, в спецификации он называется Final

извиняюсь smile, спутал с dwFlags, след. параметр  


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
feodorv
Дата 4.5.2012, 09:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(frying @  4.5.2012,  08:01 Найти цитируемый пост)
Но pdwDataLen  всегда 0. Почему? 

А чем оно инициализируется?
Цитата(frying @  4.5.2012,  08:01 Найти цитируемый пост)
DWORD pdwDataLen; // <-- ничем...
CryptEncrypt(hSessionKey, 0, true, 0, 0, &pdwDataLen , buf3_size);

Скорее всего, там 0, что в купе с true даёт 0 в pdwDataLen...

Добавлено через 3 минуты и 47 секунд
Цитата

pdwDataLen 
[in, out] Pointer to a DWORD value holding the length of the data buffer. Before calling this function, the DWORD value is set to the number of bytes to be encrypted. Upon return, the DWORD value contains the number of bytes needed to hold the encrypted data

Кстати, переменную лучше назвать как dwDataLen, так как p... намекает на указатель smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
frying
Дата 4.5.2012, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 17.10.2011

Репутация: нет
Всего: нет



feodorv спасибо за совет, но я думал, что если dwDataLen будет всё равно инициализироваться в функции, зачем задавать начальное значение. Сейчас, если инициализирую нулём, то функция с флагом final = true даёт значение 8, если же final = false, то значение 0.
Посмотрите, пожалуйста, переделанный код
Код

#define _WIN32_WINNT 0x0400

#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <Windows.h>
#include <WinCrypt.h>
#pragma comment(lib, "advapi32.lib")
#include <WinError.h>

using namespace std;

HCRYPTKEY getSessionKey()
{
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hSessionKey = 0;

    // Получение контекста криптопровайдера
    if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
      cout << "CryptAcquireContext Error";
      cin.get();
      //return 1;
    } else {
        std::cout << "Cryptographic provider initialized" << std::endl;
    }
    // Генерация сессионного ключа
    if (!CryptGenKey(hProv, CALG_RC2, 64<<16, &hSessionKey)) {
      cout << "CryptGenKey Error";
      cin.get();
      //return 1;
    } else {
        std::cout << "Session key generated" << std::endl;
        std::cout << hSessionKey << std::endl;
    }
    return hSessionKey;
}

int errorReturn()
{
    cout << GetLastError() << endl;
    cin.get();
    return 1;
}

int main(){

    HCRYPTKEY hSessionKey = getSessionKey();
    std::cout << hSessionKey << std::endl;

    ifstream ifs;
    ifs.open("out.txt", ios::in | ios::binary);
    ofstream ofs;
    ofs.open("in.txt", ios::out | ios::binary);
    ofstream ofs1;
    ofs1.open("in1.txt", ios::out | ios::binary);
    //Если удалось открыть файл для чтения и для записи.
    if (!ifs.is_open() || !ofs.is_open()) {
        cout << "File is not exist" << endl;
    } else {
        const int buf3_size = 8;
        char buf3[buf3_size] = { 0 };
        DWORD dwDataLen = 0;
        CryptEncrypt(hSessionKey, 0, true, 0, 0, &dwDataLen , buf3_size);
        while (!ifs.eof())
        {
            ifs.read(buf3, buf3_size);
            bool flag = ifs.eof();

            cout << "Plain Text is ";
            for (int i = 0; i < buf3_size; ++i)
            {
                cout << buf3[i];
            }
            cout << endl;

            // Шифрование данных
            cout << dwDataLen  << endl;
            if (!CryptEncrypt(hSessionKey, 0, flag, 0, (BYTE*)buf3, &dwDataLen , buf3_size)) {
                ifs.close();
                ofs.close();
                ofs1.close();
                cout << "CryptEncrypt Error" << endl;
                return errorReturn();
            } else {
                cout << "Encrypted text is ";
                for (size_t i = 0; i < dwDataLen; ++i)
                {
                    cout << buf3[i];
                }
                ofs.write(buf3, dwDataLen);
                cout << endl;
            }

            // Дешифрование данных
            if (!CryptDecrypt(hSessionKey, 0, flag, 0, (BYTE*)buf3, &dwDataLen )) {
                ifs.close();
                ofs.close();
                ofs1.close();
                cout << "CryptDecrypt Error";
                return errorReturn();
            }
            cout << "Decrypted text is ";
            for (int i = 0; i < buf3_size ; ++i)
            {
                cout << buf3[i];
            }
            ofs1.write(buf3, dwDataLen);
            cout << endl;
        }
        ifs.close();
        ofs.close();
        ofs1.close();
    }
    cin.get();
}


Несколько блоков отрабатывают нормально, потом выбрасывается 234 ошибка cryptencrypt. Скажите в чём ошибка.
PM MAIL   Вверх
feodorv
Дата 4.5.2012, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(frying @  4.5.2012,  16:53 Найти цитируемый пост)
я думал, что если dwDataLen будет всё равно инициализироваться в функции, зачем задавать начальное значение.

Нет, нет. Если в CryptEncrypt dwBufLen означает доступный размер буфера, то dwDataLen - число байт в буфере, которые нужно закриптовать. Дело в том, что для потоковых алгоритмов шифрование идёт байт в байт (хотя и в этом случае в конце в хвост зашифрованным данным могут быть записаны дополнительные байты), для блоковых (а CALG_RC2 - это блоковый алгоритм) шифрование осуществляется блоками бит (в Вашем случае - по 64 бита), поэтому если на входе будет, скажем, 2 байта, то на выходе уже 8! Соответственно, в этом случае до вызова CryptEncrypt устанавливаем dwDataLen в 2, а после вызова получаем значение 8. То есть dwDataLen - это аргумент функции, который как передаёт значение в функцию при её вызове, так и получает возвращаемое значение из функции. Поэтому dwDataLen нужно (правильно!) инициализировать до вызова CryptEncrypt

Код посмотрю, но попозже... Кстати, CryptAcquireContext в начале программы Вы делаете, а CryptReleaseContext в конце - нет.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
feodorv
Дата 4.5.2012, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Основное, что я вижу не так, это одновременное шифрование-дешифрование. Это очень плохо.

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

шифруем buf1
дешифруем buf1
шифруем buf2, финиш
дешифруем buf2, финиш

может отличаться от того, который получим при
Код

шифруем buf1
шифруем buf2, финиш

затем инициализируем ключ по-новой

дешифруем buf1
дешифруем buf2, финиш

В результате мы не сможем правильно дешифровать данные.

У Вас всё ещё хуже: Вы два раза подряд запрашиваете функции шифрования с finish, равной TRUE. При первом TRUE ключ уже невозвратимо искажается:
Цитата

The following extra actions are performed when Final is TRUE:

If the key is a block cipher key, the data is padded to a multiple of the block size of the cipher. To find the block size of a cipher, use CryptGetKeyParam to get the KP_BLOCKLEN value of the key. 
If the cipher is operating in a chaining mode, the next CryptEncrypt operation resets the cipher's feedback register to the KP_IV value of the key. 
If the cipher is a stream cipher, the next CryptEncrypt resets the cipher to its initial state. 

При втором TRUE ключ переиницилизирован, и CryptDecrypt дешифрует неизвестно что...

То есть: надо сначала (непрерывно) всё закриптовать (до финального TRUE) и уже потом всё разкриптовать (то же до финального TRUE).

Добавлено @ 18:28
Кстати:
Цитата
CryptEncrypt
If the buffer allocated for pbData is not large enough to hold the data, GetLastError returns ERROR_MORE_DATA and stores the required buffer size, in bytes, in the DWORD value pointed to by pdwDataLen.


Это сообщение отредактировал(а) feodorv - 4.5.2012, 19:45


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
feodorv
Дата 4.5.2012, 19:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(feodorv @  4.5.2012,  19:14 Найти цитируемый пост)
Кстати:

Есть небольшая тонкость: при финализировании данных, выровненных по границе блока, CryptEncrypt в конец буфера добавляет дополнительный блок в 8 байт. То есть буфер требуется большей длины (на те самые 8 байт). То есть:
Код

       char buf3[buf3_size+8] = { 0 };
       ...
       if (!CryptEncrypt(hSessionKey, 0, flag, 0, (BYTE*)buf3, &dwDataLen , buf3_size+8)) {


Но вообще, логику программы стоит переделать...

Это сообщение отредактировал(а) feodorv - 4.5.2012, 19:47


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
frying
Дата 9.5.2012, 13:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 17.10.2011

Репутация: нет
Всего: нет



feodorv,  большое спасибо за развёрнутый ответ.
Сделал сейчас по-другому: просто весь текст передаю одним блоком и шифрую. Основная моя ошибка была в том, что 
Цитата

Note that, depending on the algorithm used, the encrypted text can be larger than the original plaintext. In this case, the pbData buffer needs to be large enough to contain the encrypted text and any padding.

Т.е. для шифрованного теста буфер должен изначально подходить.

Это сообщение отредактировал(а) GremlinProg - 10.5.2012, 07:13
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0880 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.