Статус: Сотрудник
Группы: Участники
Зарегистрирован: 17.10.2010(UTC) Сообщений: 147  Откуда: КРИПТО-ПРО Сказал «Спасибо»: 2 раз Поблагодарили: 10 раз в 9 постах
|
Да, пока не завалило рутиной: докурился до успеха. Правда совсем в соответствии с RFC 4357 не получилось - если UKM рандомным сделать - то ничtго не работает. Но для сельской месности сойдет. Код:
#define DBG_OUT(msg) fprintf(stderr, "MSG %s:%d:%s: %s\n", __FILE__, __LINE__, __FUNCTION__, msg);
#define DBG_OUT_E(msg) fprintf(stderr, "MSG %s:%d:%s: %s : 0x%X\n", __FILE__, __LINE__, __FUNCTION__, msg, GetLastError());
static int fill_default_simpleblob(CRYPT_SIMPLEBLOB *blob)
{
if (blob == NULL) {
return 0;
}
/*BLOBHEADER*/
blob->tSimpleBlobHeader.BlobHeader.bType = SIMPLEBLOB;
blob->tSimpleBlobHeader.BlobHeader.bVersion = BLOB_VERSION; // 0x20 current.
blob->tSimpleBlobHeader.BlobHeader.reserved = 0x0;
blob->tSimpleBlobHeader.BlobHeader.aiKeyAlg = CALG_G28147; // CALG_G28147_IMIT;
blob->tSimpleBlobHeader.Magic = G28147_MAGIC;
blob->tSimpleBlobHeader.EncryptKeyAlgId = CALG_G28147;
return 1;
}
/** Magic value for EncryptionParamSet.
* Designated to represent DER-encoded ASN1-structure for GOST 28147 paramset.
* Probably it's corresponds to id-GostR3410-2001-CryptoPro-XchA-ParamSet.
*/
static const BYTE default_params[] = { 0x30, 0x09, 0x06, 0x07,
0x2A, 0x85, 0x03, 0x02,
0x02, 0x1F, 0x01 };
/**
* Converts raw key data to HCRYPTKEY suitable for later usage.
* @param hProvider must be exportable
* @param key raw key (rfc4357 6.1 CEK)
* @return - HCRYPTKEY if success
* - 0 if fails
*/
HCRYPTKEY get_CAPI_key_from_raw(HCRYPTPROV hProvider, const unsigned char *key){
/// The idea is from here: http://etutorials.org/Programming/secure+programming/Chapter+5.+Symmetric+Encryption/5.26+Creating+a+CryptoAPI+Key+Object+from+Raw+Key+Data/
/// But GOST has a specific...
HCRYPTKEY resKey = 0;
DWORD dataLen = 0;
// We decrement it by 4 due to 4 bytes alignment of BYTE bEncryptionParamSet[1] array.
// @bug incompatible with x64?
const size_t REAL_CRYPT_SIMPLEBLOB_LEN = sizeof(CRYPT_SIMPLEBLOB)
+ sizeof(default_params) - 4;
CRYPT_SIMPLEBLOB *keyBlob = NULL;
keyBlob = malloc(REAL_CRYPT_SIMPLEBLOB_LEN);
if(!keyBlob){
DBG_OUT_E("Can't allocate CRYPT_SIMPLEBLOB");
goto done;
}
memset(keyBlob, 0 , REAL_CRYPT_SIMPLEBLOB_LEN);
fill_default_simpleblob(keyBlob);
// key is a CEK rfc4357 6.1
memcpy(keyBlob->bEncryptedKey, key, G28147_KEYLEN);
memcpy(keyBlob->bEncryptionParamSet, default_params, sizeof(default_params));
// Generate random KEK rfc4357 6.1.1.
HCRYPTKEY kek;
if (!CryptGenKey(hProvider, CALG_G28147, CRYPT_EXPORTABLE, &kek))
{
DBG_OUT_E("Can't generate KEK");
goto done;
}
DWORD dparam = 0;
dparam = ZERO_PADDING;
if (!CryptSetKeyParam(kek, KP_PADDING, (BYTE*)&dparam, 0))
{
DBG_OUT_E("Can't set ZERO_PADDING for generated KEK.");
goto done;
}
/* Well, let's assume UMK is always zeros...
// Generate UKM rfc4357 6.1.1.
if(!CryptGenRandom(hProvider, sizeof(keyBlob->bSV), keyBlob->bSV)){
DBG_OUT_E("Can't generate UKM");
goto done;
}
*/
// Compute CEK_MAC rfc4357 6.1.2.
HCRYPTKEY im_key;
if(!CryptDuplicateKey(kek, // from
NULL, 0, // two reserved
&im_key)) // to
{
DBG_OUT_E("Can't duplicate key for IMITO");
goto done;
}
// Useless as UKV is always zeros, but still...
// Set IV for IMITO
if (!CryptSetKeyParam(
im_key,
KP_IV,
keyBlob->bSV,
0)) {
DBG_OUT_E("Can't set IV for IMITO");
goto done;
}
HCRYPTHASH im = 0;
if(!CryptCreateHash(hProv, CALG_G28147_IMIT, im_key, 0, &im))
{
DBG_OUT_E("Can't create IMITO hash");
goto done;
}
if(!CryptHashData(im, keyBlob->bEncryptedKey, G28147_KEYLEN, 0))
{
DBG_OUT_E("Can't hash CEK");
goto done;
}
DWORD imitLen = EXPORT_IMIT_SIZE;
if(!CryptGetHashParam(im,
HP_HASHVAL,
keyBlob->bMacKey, // This is a CEK_MAC in RFC4357 6.1.2
&imitLen, 0))
{
DBG_OUT_E("Can't get CEK hash");
goto done;
}
// END compute CEK_MAC
// Encrypt key to CEK_ENC rfc4357 6.1.3.
HCRYPTKEY enc_key;
if (!CryptDuplicateKey(kek, 0, 0, &enc_key)) {
DBG_OUT_E("Can't dup KEK for encryption.");
goto done;
}
dparam = CRYPT_MODE_ECB;
if (!CryptSetKeyParam(enc_key, KP_MODE, (BYTE*)&dparam, 0)){
DBG_OUT_E("Can't set ECB mode");
goto done;
}
dataLen = G28147_KEYLEN;
if (!CryptEncrypt(enc_key, 0, TRUE, 0, NULL, &dataLen, 0)) {
DBG_OUT_E("Can't detemine required buffer size.");
goto done;
}
printf("Buffer size required: %d\n", dataLen);
if(G28147_KEYLEN != dataLen){
DBG_OUT("Required buffer size and G28147_KEYLEN mismatch");
goto done;
}
if (!CryptEncrypt(enc_key, 0, TRUE, 0, keyBlob->bEncryptedKey, &dataLen, dataLen)) {
DBG_OUT_E("Can't encrypt raw key");
goto done;
}
// END Encrypt key to CEK_ENC rfc4357 6.1.3.
dparam = CALG_SIMPLE_EXPORT;
if (!CryptSetKeyParam(kek, KP_ALGID, (BYTE *) & dparam, 0))
{
DBG_OUT_E("Can't set SIMPLE_EXPORT param for KEK");
goto done;
}
dataLen = REAL_CRYPT_SIMPLEBLOB_LEN;
if (!CryptImportKey(hProvider,
(BYTE*)keyBlob,
dataLen,
kek,
0,
&resKey))
{
DBG_OUT_E("Can't import key");
resKey = 0;
goto done;
}else{
DBG_OUT("Our key imported!");
}
done:
if(!CryptDestroyKey(enc_key)){
DBG_OUT_E("Fail to destroy enc_key:");
}
if(!CryptDestroyKey(enc_key)){
DBG_OUT_E("Fail to destroy im_key:");
}
if(!CryptDestroyKey(enc_key)){
DBG_OUT_E("Fail to destroy kek:");
}
free(keyBlob);
return resKey;
}
Отредактировано пользователем 30 ноября 2010 г. 16:55:15(UTC)
| Причина: Не указана
|
 1 пользователь поблагодарил Андрей Куликов за этот пост.
|
rik оставлено 30.07.2014(UTC)
|