Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > cryptoapi CryptExportKey


Автор: frying 13.5.2012, 19:20
Доброго времени суток!
Мне нужно экспортировать ключ в файл. Использую для этого CryptExportKey. Вот код программы:
Код

#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>
#include <string>

using namespace std;

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

int main(int argc, char* argv[]){
    ofstream passOfs;
    passOfs.open("password");
    HCRYPTPROV hProv = 0;
    // Получение контекста криптопровайдера
    if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
        cout << "CryptAcquireContext Error";
        //cin.get();
        exit(1);
    }
    HCRYPTKEY hSessionKey = 0;
    // Генерация сессионного ключа
    if (!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hSessionKey)) {
        cout << "CryptGenKey Error";
        //cin.get();
        return 1;
    } else {
        std::cout << "Session key generated" << std::endl;
        std::cout << hSessionKey << std::endl;
    }

    HCRYPTKEY hPublicKey = NULL;
    HCRYPTHASH hPassHash = NULL;
    //Функция создающая хеш-объект, предназначенный для генерации хеш-значения данных.
    if (CryptCreateHash(hProv, CALG_MD5, NULL, 0, &hPassHash)) {
        cout << "Hash for public key generated" << endl;
        cout << hPassHash << endl;
    } else {
        cout << "Hash creation fail";
        exit(1);
    }
    //Основная функция хеширования данных.
    char password[] = "12345";
    if (!CryptHashData(hPassHash, (BYTE*) password, strlen(password), 0)) {
        cout<< "Error CryptHashData";
    } else {
        cout << "CryptHashData generated" << endl;
    }
    // Генерация сессионного ключа
    if (!CryptDeriveKey(hProv, CALG_3DES, hPassHash, CRYPT_EXPORTABLE, &hPublicKey)) {
        cout << "CryptDerKey Error";
        return 1;
    } else {
        std::cout << "Derive session key generated" << std::endl;
        std::cout << hPublicKey << std::endl;
    }

    DWORD count = 0;
    if (!CryptExportKey(hSessionKey, hPublicKey, SIMPLEBLOB, 0, NULL, &count)) {
        cout << "Error Initial of CryptExportKey: ";
        errorReturn();
        return 1;
    }
    cout << "count " << count << endl;

    BYTE* pdDataKey = new BYTE[count];
    if (!CryptExportKey(hSessionKey, hPublicKey, SIMPLEBLOB, 0, pdDataKey, &count)) {
        cout << "Error CryptExportKey: ";
        errorReturn();
        return 1;
    }
    cout << "data " << pdDataKey << endl;

    passOfs.write((char*) pdDataKey, count);
    passOfs.close();
}


На функции CryptExportKey программа выдаёт ошибку 80090003 (NTE_BAD_KEY), что, мол, непорядок с ключами. Почему, в чем ошибка? 

Автор: feodorv 14.5.2012, 01:05
http://www.microsoft-questions.com/microsoft/Platform-SDK-Security/35884723/ntebadkey-error-while-exporting-session-key-with-a-key-derived-from-password.aspx
Цитата

SIMPLEBLOB always encrypts with a PUBLIC key. ie. if you specify SIMPLEBLOB
in CryptExportKey, then the hExpKey parameter must be a public key. In your
code you generate a (derived) secret key. Since that key is not public key,
you get the NTE_BAD_KEY error.
You would need to use SYMMETRICWRAPKEYBLOB if you want to wrap your session
key with your derived key. (Another option is to export your session key in
plaintext format with PLAINTEXTKEYBLOB, then simply encrypt the key value
with your derived wrapper key.)

Автор: frying 14.5.2012, 14:46
feodorv,  спасибо, при SYMMETRICWRAPKEYBLOB  запись в файл прошла успешно, теперь пробую считать значение в файле используя CryptImportKey.  Просто добавил к коду выше ещё:
Код

ifstream passIfs;
passIfs.open("password");

DWORD dwDataLen = 0;
//Вычисляем длину входного файла.
passIfs.seekg(0, ios_base::end);
int bufLen = passIfs.tellg();
passIfs.seekg(0, ios_base::beg);
//Готовим буфер для чтения.
BYTE *bufAll = new BYTE[bufLen];
passIfs.read((char*) bufAll, bufLen);
cout << "bufLen " << bufLen << endl;
HCRYPTKEY readKey = 0;
if (!CryptImportKey(hProv, bufAll, bufLen, hPublicKey, 0, &readKey)) {
    cout << "Error CryptImportKey: ";
    errorReturn();
} else {
    cout << "readKey " << readKey << endl; 
}


Но ключ выводится не тот, или вообще выдается ошибка NTE_BAD_DATA.

Автор: feodorv 14.5.2012, 15:45
Цитата(frying @  14.5.2012,  15:46 Найти цитируемый пост)
Но ключ выводится не тот, или вообще выдается ошибка NTE_BAD_DATA. 

Цитата(frying @  14.5.2012,  15:46 Найти цитируемый пост)
if (!CryptImportKey(hProv, bufAll, bufLen, hPublicKey, 0, &readKey))

Создайте hPublicKey по-новой  smile А то Вы применяете уже юзаный ключ, состояние которого отлично от первоначального...

Автор: frying 14.5.2012, 17:11
Пробую сделать новый ключ: опять не подходит, что интересно, но даже CryptDeriveKey не совпадают. Добавил этот код в конце файла:
Код

//Теперь проверяем полученные значения.
    HCRYPTPROV hImportProv = 0;
    // Получение контекста криптопровайдера
    if (!CryptAcquireContext(&hImportProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
        cout << "CryptAcquireContext Error";
        exit(1);
    }
    HCRYPTKEY hPublicImportKey = NULL;
    HCRYPTHASH hPassImportHash = NULL;
    //Функция создающая хеш-объект, предназначенный для генерации хеш-значения данных.
    if (CryptCreateHash(hImportProv, CALG_MD5, NULL, 0, &hPassImportHash)) {
        cout << "Hash for import public key generated" << endl;
        //cout << hPassImportHash << endl;
    } else {
        cout << "Hash import creation fail";
        exit(1);
    }
    //Основная функция хеширования данных.
    char passwordNew[] = "12345";
    if (!CryptHashData(hPassImportHash, (BYTE*) passwordNew, strlen(passwordNew), 0)) {
        cout<< "Error CryptHashData for import";
    } else {
        cout << "CryptHashData for import generated" << endl;
    }
    // Генерация сессионного ключа
    if (!CryptDeriveKey(hImportProv, CALG_3DES, hPassImportHash, CRYPT_EXPORTABLE, &hPublicImportKey)) {
        cout << "CryptDerKey for import Error";
        return 1;
    } else {
        std::cout << "Derive session import key generated" << std::endl;
        std::cout << hPublicImportKey << std::endl;
    }

    DWORD dwDataLen = 0;
    //Вычисляем длину входного файла.
    passIfs.seekg(0, ios_base::end);
    int bufLen = passIfs.tellg();
    passIfs.seekg(0, ios_base::beg);
    //Готовим буфер для чтения.
    BYTE *bufAll = new BYTE[bufLen];
    passIfs.read((char*) bufAll, bufLen);
    cout << "bufLen " << bufLen << endl;
    HCRYPTKEY readKey = 0;
    if (!CryptImportKey(hImportProv, bufAll, bufLen, hPublicImportKey, 0, &readKey)) {
        cout << "Error CryptImportKey: ";
        errorReturn();
    } else {
        cout << "readKey " << readKey << endl; 
    }

Автор: feodorv 14.5.2012, 17:19
Цитата(frying @  14.5.2012,  18:11 Найти цитируемый пост)
даже CryptDeriveKey не совпадают

Попробуйте флаг CRYPT_NO_SALT при CryptGenKey smile 
Цитата

The Base Provider creates 40-bit symmetric keys created with eleven bytes of zero-value salt, eleven bytes of nonzero salt if CRYPT_CREATE_SALT is specified, or no salt value. A 40-bit symmetric key with zero-value salt, however, is not equivalent to a 40-bit symmetric key without salt. For interoperability, keys must be created without salt. This problem results from a default condition that occurs only with keys of exactly 40 bits. All other key lengths do not have salt allocated by default.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)