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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Кто работал с CryptoAPI Помогите 
:(
    Опции темы
Art2
Дата 22.5.2014, 18:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Разбираюсь с  CryptoAPI шифровать и дешифровать научился. А вот экспортировать и импортировать сессионный ключ не могу. Весь интернет излазил сорцы с ошибками, кто работал с  CryptoAPI помогите изучить шифрование файлов.
PM MAIL   Вверх
feodorv
Дата 22.5.2014, 18:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Посмотрите здесь smile 


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


Новичок



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

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



Спасибо я эту тему смотрел. И заметил терпение у Вас огромное)). А по делу представленный там код экспорта и импорта у меня не хочет работать почему то. Вот собранный мною код шифрует и дешифрует и записывает в файл, но только сразу не выключаясь может  взглянув на код что нибудь подскажите. Помогите сделать что то вроде Вашей концепции в той теме на последней странице.
Код

#include <iostream>
#include <vector>
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <fstream>
#include <cstdio>
 
 
#define BLOCK_SIZE 256

 using namespace std;
 
int main () {
    
    HCRYPTPROV hProv;
    HCRYPTHASH hHash;
    HCRYPTKEY hSessionKey;
    HCRYPTPROV            hCryptProv;
    HCRYPTKEY            hCryptKey;
    BOOL                bRes;
    
    
    //получаем контекст
    if(CryptAcquireContext(
                &hCryptProv, 
                NULL, 
                MS_DEF_PROV, 
                PROV_RSA_FULL, 
                CRYPT_VERIFYCONTEXT)) 
    {
        printf("CryptAcquireContext complete. \n");
    }
    else
    {
        printf("Acquisition of context failed.\n");
        exit(1);
    }
    
    // сгенерируем сессионный ключ 
   if(CryptGenKey(
                    hCryptProv, 
                    CALG_RC4, 
                    CRYPT_ENCRYPT, 
                    &hSessionKey))
    {
        printf("CryptGenKey complete. \n"  );
    }
    else
    {
        printf("Acquisition of context failed.\n");
        exit(1);
    }
    
    
    FILE * fin, * fout, *fou ;
    char buf[BLOCK_SIZE];
    ssize_t ret;
    

    
    
    //открываем нужные файлы
    if ( ( fin = fopen("qwerty.jpg", "rb") ) == NULL ){
        fprintf(stderr, "%s: can't open file %s for input!\n",  "qwerty.jpg");
        exit(1);
    }
    
    if ( ( fout = fopen("qwerty7.jpg", "wb+") ) == NULL ){
        fprintf(stderr, "%s: can't open file %s for output!\n", "qwerty7.jpg");
        fclose(fin);
        exit(1);
    }
    if ( ( fou = fopen("qwerty6.jpg", "wb+") ) == NULL ){
        fprintf(stderr, "%s: can't open file %s for output!\n", "qwerty7.jpg");
        fclose(fin);
        exit(1);
    }
    // считываем часть данных в буфер
    while ( ( ret = fread(&buf, sizeof(char), BLOCK_SIZE, fin) ) > 0 ){
        
        
            std::cout
                   << "Prochel yes" 
                   << std::endl; 
        
           DWORD len=  sizeof ( buf);
            
            //шифруем блок данных
             if (CryptEncrypt(hSessionKey, 0, true, 0, (BYTE*)buf, 
                     &len, sizeof ( buf)))
                { 
                   std::cout
                   << "Crypt yes" 
                   << std::endl;
                }
            else
                {
                   printf("Acquisition of context failed.\n");
                   exit(1);
                }
        
        // запись шифрованных данных
        if ( fwrite(&buf, sizeof(char), ret, fout) < 0 ){
            fprintf(stderr, "%s: can't write to file %s\n",  "qwerty7.jpg");
            fclose(fin);
            fclose(fout);
            exit(1);
        } else {
            std::cout
                   << "Zapis yes" 
                   << std::endl; }
    
            
           //дешифруем блок данных 
             if (CryptDecrypt(hSessionKey, 0, true, 0, (BYTE*)buf, &len))
                { 
                   std::cout
                   << "DECrypt yes" 
                   << std::endl;
                }
            else
                {
                   printf("Acquisition of context failed.\n");
                   exit(1);
                }
        
        // запись шифрованных данных
        if ( fwrite(&buf, sizeof(char), ret, fou) < 0 ){
            fprintf(stderr, "%s: can't write to file %s\n",  "qwerty7.jpg");
            fclose(fin);
            fclose(fout);
            exit(1);
        } else {
            std::cout
                   << "Zapis yes" 
                   << std::endl; }
    }
    
    fclose(fout);
    fclose(fin);
    
    getchar();
    return 0;
}

 
PM MAIL   Вверх
feodorv
Дата 23.5.2014, 00:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Art2 @  22.5.2014,  22:28 Найти цитируемый пост)
не хочет работать почему то

Давайте пока не про CryptoAPI.
  • Это небрежность в кодировании, я пониманию, но всё же:
    Цитата(Art2 @  22.5.2014,  22:28 Найти цитируемый пост)
        if ( ( fou = fopen("qwerty6.jpg", "wb+") ) == NULL ){
            fprintf(stderr, "%s: can't open file %s for output!\n", "qwerty7.jpg");
            fclose(fin);
            exit(1);
        }
    Здесь при выдаче ошибки печатается неверное имя файла. И раз уж Вы делаете fclose(fin), то почему бы не сделать fclose(fout))))
  • Здесь уже всё серьёзней. fread принимает в качестве аргумента адрес массива байт, а не адрес адреса массива байт (хотя для данного случая они и совпадают))):
    Цитата(Art2 @  22.5.2014,  22:28 Найти цитируемый пост)
       while ( ( ret = fread(&buf, sizeof(char), BLOCK_SIZE, fin) ) > 0 ){
    Кроме того, Вы не учитываете возвращённое значение ret, означающее число считанных из файла байт. Ниже в коде Вы почему-то считаете, что их sizeof ( buf), хотя их только ret (при чтении конца файла ret может отличаться от sizeof ( buf)).
  • Соответственно, нужно следить за теми величинами, которые возвращают CryptEncrypt и CryptDecrypt (а они не обязаны совпадать с ret, которое Вы передаёте в fwrite).
  • Проверяли правильность форматной строки fprintf?
    Цитата(Art2 @  22.5.2014,  22:28 Найти цитируемый пост)
                fprintf(stderr, "%s: can't write to file %s\n",  "qwerty7.jpg");
  • Тексты ошибок совпадают для разных ошибочных ситуаций.
  • Некрасивая смесь cout и printf, << и read/write (уж что-нибудь одно).
По поводу CryptAPI. Почему у Вас в CryptDecrypt и CryptDecrypt аргумент Final всегда true? По мысли создателей CryptAPI этот аргумент может стать true только для последней порции данных, когда feof(fin). Более того, в CryptAPI существует такое понятие, как состояние ключа. При каждой шифровке или расшифровке состояние ключа меняется. Иными словами, Вы не можете использовать такой код:
Цитата(Art2 @  22.5.2014,  22:28 Найти цитируемый пост)
             if (CryptEncrypt(hSessionKey, 0, true, 0, (BYTE*)buf, &len, sizeof ( buf)))
...
            if (CryptDecrypt(hSessionKey, 0, true, 0, (BYTE*)buf, &len))
...
ибо ключ при шифровке и расшифровке находится в разных состояниях (а для правильной шифровке/расшифровке ключ должен быть в одном и том же состоянии!!!). Здесь можно продублировать изначальный ключ, зашифровывать изначальным ключом, а расшифровывать копией, тогда всё должно получиться  smile 


Это сообщение отредактировал(а) feodorv - 23.5.2014, 00:38


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


Новичок



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

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



Из приведенных ошибок да совершенно верно 1-я  по невнимательности, а во второй сделал так 
Код

 while ( ( ret = fread(&buf, sizeof(char), BLOCK_SIZE, fin) ) > 0 ){
        
               printf( "Prochel yes \n" );
                  
        
           DWORD len=  sizeof ( ret);
            
            //шифруем блок данных
             if (CryptEncrypt(hSessionKey, 0, true, 0, (BYTE*)buf, 
                     &len, sizeof ( ret)))
                { 

Про вывод ошибок не совсем в курсе как исправить. От "cout" избавился. А в 
Код

if (CryptEncrypt(hSessionKey, 0, true, 0, (BYTE*)buf, &len, sizeof ( buf)))
...
            if (CryptDecrypt(hSessionKey, 0, true, 0, (BYTE*)buf, &len))
 поменяв true на  false программа прекратила расшифровывать данные из буфера. 

Поэтому теперь объясните пожалуйста про:
 
Цитата

Здесь можно продублировать изначальный ключ, зашифровывать изначальным ключом, а расшифровывать копией, тогда всё должно получиться 


Это сообщение отредактировал(а) Art2 - 23.5.2014, 20:11
PM MAIL   Вверх
Art2
Дата 26.5.2014, 16:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



feodorv  помогите пожалуйста вот изменил код  экспорта ключей из Вашего поста, убрал пароль, вычисление хеша и теперь экспортируется оба ключа. Можете посмотреть правильность 
Код

#include <Windows.h>
#include <WinCrypt.h>
#include <stdio.h>
#pragma comment (lib, "advapi32.lib")
#define KEYSET_NAME "Movable"
#define FILE_NAME "priv.rsa"
#define FILE_NAM "publ.rsa"
BOOL _ExportKey()
{
  HCRYPTPROV hProv;
  HCRYPTKEY hKey = 0, hPrivKey = 0;
  HCRYPTHASH hHash = 0;
  BOOL isOld = FALSE, success = TRUE;
  
  if( CryptAcquireContext( &hProv, KEYSET_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, 0) )
    isOld = TRUE;
  else if( !CryptAcquireContext( &hProv, KEYSET_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET) )
  {
    printf( "Не удается создать контекст\n" );
    return FALSE;
  }
 
  
  
  
  if( success && isOld && !CryptGetUserKey( hProv, AT_KEYEXCHANGE, &hPrivKey) )
  {
    printf( "Не удается получить приватный ключ из контейнера\n" );
    success = FALSE;
  }
  if( success && !isOld && !CryptGenKey( hProv, AT_KEYEXCHANGE, 1024<<16 | CRYPT_EXPORTABLE, &hPrivKey) )
  {
    printf( "Не удается создать ключ RSA для обмена\n" );
    success = FALSE;
  }
  {
  if( success )
  {
    DWORD dwLen = 0;
   
    if( !CryptExportKey( hPrivKey, hKey, PRIVATEKEYBLOB, 0, NULL, &dwLen) )
      success = FALSE;
      
      BYTE* key = static_cast<BYTE*>(malloc(dwLen));
ZeroMemory(key, dwLen);
    
    if( !CryptExportKey( hPrivKey, hKey, PRIVATEKEYBLOB, 0, key, &dwLen) )
      success = FALSE;
    if( !success )
      printf( "Не удается экспортировать приватный ключ RSA для обмена\n" );
    else
    {
      HANDLE hFile;
      if( (hFile = CreateFileA( FILE_NAME, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE )
      {
        if( !WriteFile( hFile, key, dwLen, &dwLen, NULL))
          printf( "Не удается сохранить публичный ключ RSA для обмена в файл\n" );
        CloseHandle( hFile );
      }
      else
      {
        printf( "Не удается создать файл %s\n", FILE_NAME);
        success = FALSE;
      }
    }
    if( key != NULL ) free( key );
  }
  
    DWORD dwLen = 0;
   
    if( !CryptExportKey( hPrivKey, hKey, PUBLICKEYBLOB, 0, NULL, &dwLen) )
      success = FALSE;
      
      BYTE* key = static_cast<BYTE*>(malloc(dwLen));
ZeroMemory(key, dwLen);
    
    if( !CryptExportKey( hPrivKey, hKey, PUBLICKEYBLOB, 0, key, &dwLen) )
      success = FALSE;
    if( !success )
      printf( "Не удается экспортировать приватный ключ RSA для обмена\n" );
    else
    {
      HANDLE hFile;
      if( (hFile = CreateFileA( FILE_NAM, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE )
      {
        if( !WriteFile( hFile, key, dwLen, &dwLen, NULL))
          printf( "Не удается сохранить публичный ключ RSA для обмена в файл\n" );
        CloseHandle( hFile );
      }
      else
      {
        printf( "Не удается создать файл %s\n", FILE_NAM);
        success = FALSE;
      }
    }
    if( key != NULL ) free( key );
  }

  
  
  if( hKey != 0 ) CryptDestroyKey( hKey );
  if( hPrivKey != 0 ) CryptDestroyKey( hPrivKey );
  if( hHash != 0 ) CryptDestroyHash( hHash );
  CryptReleaseContext( hProv, 0);
  if( success ) printf( "Приватный ключ экспортирован успешно1\n" );
  
   getchar();
   
  return success;
}
int main()
{
  return _ExportKey() ? 0 : -1;
}



по окончанию работы кода создается два файла приват ключ весит 596 байт, открытый ключ 148 байт. Только не могу импортировать открытый ключ. Можете мне помощь?
PM MAIL   Вверх
feodorv
Дата 26.5.2014, 22:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Art2, я очень прошу прощения, безумно занят, почему не ответил на Ваш предыдущий постинг, с ним ещё нужно разобраться.

Цитата(Art2 @  26.5.2014,  17:44 Найти цитируемый пост)
Только не могу импортировать открытый ключ. Можете мне помощь? 

Не отрабатывает CryptImportKey? Какую ошибку (GetLastError()) пишет? 


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


Новичок



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

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



Нечего страшного))  Код ошибки 57 я поискал вроде аппаратная ошибка.
Может я чего то не до понимаю в работе CriptoAPI я пытаюсь сделать отдельно генератор ключей(секретного и открытого) с сохранением в виде файла, и отдельно шифратор файлов который генерирует сессионный ключ шифрует нужный файл, импортирует открытый ключ шифрует сессионный и  сохраняет также в виде файла. И дешифратор импортирует секретный ключ находит файл сессионного расшифровывает его и дальше   расшифровывает нужный файл. Мне осталось научиться экспорту и импорту ключей.
PM MAIL   Вверх
feodorv
Дата 27.5.2014, 00:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Art2 @  26.5.2014,  17:44 Найти цитируемый пост)
убрал пароль

Насколько я помню, PRIVATEKEYBLOB обязан быть с паролем, иначе CryptImportKey не отработает:
Цитата
For all but the public key, the key or key pair is encrypted.
Соответственно, PUBLICKEYBLOB обязан быть без пароля.


Цитата(Art2 @  27.5.2014,  00:27 Найти цитируемый пост)
Код ошибки 57 я поискал вроде аппаратная ошибка.

Реально, ERROR_ADAP_HDW_ERR? Нет рабочей сетевой платы? В принципе, сетевая плата для CryptAPI нужна, оттуда берётся уникальный (предположительно уникальный))) MAC-адрес. Но что-то мне не верится...


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


Новичок



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

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



Да error 57. Это тот который я изменял немного. После прочтения Вашего поста удалил все что пытался сделать опять скопировал с  того    поста сначала в экспорте компилятор ругался на эту строку  выдавал " invalid conversion from `void*' to `BYTE*' "
Код

 if( success && (key =  malloc( dwLen )) == NULL )
    {
      printf( "Ошибка выделения памяти\n" );
      success = FALSE;
    }
 изменил его на это и заработало 
Код

 if( success && (key =static_cast<BYTE*> ( malloc( dwLen ))) == NULL )
    {
      printf( "Ошибка выделения памяти\n" );
      success = FALSE;
    }

 и в импорте тоже вот на эту строку выдавал " invalid conversion from `char*' to `unsigned char*' "
Код

if( success && (content = (char *) malloc( dwLen )) == NULL )
  {
    printf( "Ошибка выделения памяти\n" );
    success = FALSE;
  }
 изменил его так 
Код

if( success && (content = static_cast< unsigned char*>(malloc( dwLen ))) == NULL )
  {
    printf( "Ошибка выделения памяти\n" );
    success = FALSE;
  }
 теперь просто пишет "Ошибка выделения памяти"
Если будет хоть какой то  рабочий пример экспорта и импорта ключей дальше я сам разберусь, просто мало информации в сети именно про экспорт и импорт.

Это сообщение отредактировал(а) Art2 - 27.5.2014, 19:39
PM MAIL   Вверх
feodorv
Дата 27.5.2014, 23:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Art2 @  27.5.2014,  18:12 Найти цитируемый пост)
теперь просто пишет "Ошибка выделения памяти"

Чему равно dwLen?


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


Эксперт
****


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

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



Цитата(feodorv @  28.5.2014,  00:17 Найти цитируемый пост)
Чему равно dwLen? 

Не помню я, что я правил, но куда-то пропало:
Цитата(feodorv @  11.2.2012,  01:21 Найти цитируемый пост)
      dwLen = *plength = info.nFileSizeLow;




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


Новичок



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

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



Большое спасибо все работает. Очень помогли. Теперь меняю  пробую и изучаю. Еще одна просьба где можно по лучше прочитать про "CryptDeriveKey" функция которая при одинаковых входных данных генерирует один и тот же пароль. 
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.

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


 




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


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

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