/*
 * Copyright(C) 2008 Проект ИОК
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто Про.
 */

/*!
 * \file $RCSfile$
 * \version $Revision: 87822 $
 * \date $Date: 2013-04-08 18:12:28 +0400 (РџРЅ, 08 Р°РїСЂ 2013) $
 * \author $Author: borodin $
 * \brief Криптографические операции ФКН.
 */

#include "rdr_prj.h"


DWORD rdr_crypt_simple_key_set_step1(
    TSupSysEContext *context, 
    TRdrFkcOrder masked_key, DWORD key_length, 
    TRdrFkcPoint* public_key, 
    TRdrFkcEllipticPointParam uiIDg, 
    char * oid,
    TKeyAlgType alg_type, 
    DWORD key_type, 
    BOOL is_able_dh,
    unsigned int alg_id, 
    DWORD permissions,
    int index
) 
{
    DWORD code;
    TReaderFkcKeySet ks;
    ks.alg_type = alg_type;
    ks.dfkc = masked_key;
    ks.public_key = public_key;
    ks.step = TSetKeyStep_first;
    ks.key_length = key_length;
    ks.group_id = uiIDg;
    ks.index = index;
    ks.key_type = key_type;
    ks.alg_id = alg_id;
    ks.is_able_dh = is_able_dh;
    ks.oid = oid;
    ks.permissions = permissions;

    code = supsys_call(context, READER_FUN_KEY_SET, &ks);

    LOGRETURN(code);
}

DWORD rdr_crypt_simple_key_set_step2(
    TSupSysEContext *context, 
    TRdrFkcOrder mask, DWORD key_length,
    TRdrFkcPoint* public_key, 
    TRdrFkcEllipticPointParam uiIDg, 
    char * oid,
    TKeyAlgType alg_type, 
    DWORD key_type, 
    BOOL is_able_dh,
    unsigned int alg_id,
    DWORD permissions,
    int* index
) 
{
    DWORD code;
    TReaderFkcKeySet ks;
    ks.dfkc = mask;
    ks.step = TSetKeyStep_second;
    ks.key_length = key_length;
    ks.index = *index;
    ks.alg_type = alg_type;
    ks.public_key = public_key;
    ks.group_id = uiIDg;
    ks.key_type = key_type;
    ks.alg_id = alg_id;
    ks.is_able_dh = is_able_dh;
    ks.oid = oid;
    ks.permissions = permissions;

    code = supsys_call(context, READER_FUN_KEY_SET, &ks);
    if (code)
	LOGRETURN(code);
    *index = ks.index;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_crypt_set_gost_2001(TSupSysEContext *context) {
    LOGRETURN(supsys_call(context, READER_FUN_SET_2001, NULL));
}

DWORD rdr_crypt_get_key_algid(TSupSysEContext *context, DWORD key_type, unsigned int *alg_id)
{
    TReaderFkcPublicKeyGet kg;
    DWORD code = 0;

    kg.key_type = key_type;
    kg.flags.alg_id = 1;
    kg.flags.id_g = kg.flags.value = kg.flags.oid = kg.flags.is_able_dh = kg.flags.permissions = 0;
    kg.value = NULL;
    kg.oid = NULL;
    code = supsys_call(context, READER_FUN_PUBLIC_KEY, &kg);
    if (code)
	LOGRETURN(code);
    *alg_id = kg.alg_id;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_crypt_get_rsa_public_key(TSupSysEContext *context, DWORD key_type, TRdrFkcRsaKey *public_key)
{
    TReaderFkcRsaPublicKeyGet kg;
    DWORD code = 0;

    kg.key_type = key_type;
    kg.value = public_key;
    code = supsys_call(context, READER_FUN_PUBLIC_KEY_RSA, &kg);
    if (code)
	LOGRETURN(code);
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_crypt_get_public_key(TSupSysEContext *context, DWORD key_type, TRdrFkcPoint* public_key) {
    TReaderFkcPublicKeyGet kg;
    kg.key_type = key_type;
    kg.flags.alg_id = kg.flags.id_g = kg.flags.oid = kg.flags.is_able_dh = kg.flags.permissions = 0 ;
    kg.flags.value = 1;
    kg.value = public_key;
    kg.oid = NULL;
    LOGRETURN(supsys_call(context, READER_FUN_PUBLIC_KEY, &kg));
}

DWORD rdr_crypt_get_able_dh(TSupSysEContext *context, DWORD key_type, BOOL * is_able_dh) 
{
    TReaderFkcPublicKeyGet kg;
    DWORD code;
    kg.key_type = key_type;
    kg.flags.alg_id = kg.flags.id_g = kg.flags.oid = kg.flags.value = kg.flags.permissions = 0;
    kg.flags.is_able_dh = 1;
    kg.value = NULL;
    kg.oid = NULL;
    kg.is_able_dh = FALSE;
    code = supsys_call(context, READER_FUN_PUBLIC_KEY, &kg);
    if (code)
	LOGRETURN(code);
    *is_able_dh = kg.is_able_dh;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_crypt_get_public_key_param(TSupSysEContext *context, DWORD key_type, unsigned int * alg_id, TRdrFkcEllipticPointParam * idG) {
    TReaderFkcPublicKeyGet kg;
    DWORD code;
    kg.key_type = key_type;
    kg.flags.alg_id = kg.flags.id_g = 1;
    kg.flags.value = kg.flags.oid = kg.flags.is_able_dh = kg.flags.permissions = 0;
    kg.value = NULL;
    kg.oid = NULL;
    code = supsys_call(context, READER_FUN_PUBLIC_KEY, &kg);
    if (code) LOGRETURN(code);
    *alg_id = kg.alg_id;
    *idG = kg.id_g;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_crypt_get_public_key_oid(TSupSysEContext *context, DWORD key_type, char * oid)
{
    TReaderFkcPublicKeyGet kg;
    kg.key_type = key_type;
    kg.oid = oid;
    kg.flags.oid = 1;
    kg.flags.alg_id = kg.flags.id_g = kg.flags.value = kg.flags.is_able_dh = kg.flags.permissions = 0;
    kg.value = NULL;
    LOGRETURN(supsys_call(context, READER_FUN_PUBLIC_KEY, &kg));
}

DWORD rdr_crypt_get_key_permissions(TSupSysEContext *context, DWORD key_type, DWORD * permissions)
{
    TReaderFkcPublicKeyGet kg;
    DWORD code;
    kg.key_type = key_type;
    kg.oid = NULL;
    kg.flags.permissions = 1;
    kg.flags.alg_id = kg.flags.id_g = kg.flags.value = kg.flags.is_able_dh = kg.flags.oid = 0;
    kg.value = NULL;
    kg.permissions = 0;
    code = supsys_call(context, READER_FUN_PUBLIC_KEY, &kg);
    if (code)
	LOGRETURN(code);
    *permissions = kg.permissions;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_crypt_agreement(
TSupSysEContext *context,
 int index,
 DWORD key_type,
 const TRdrFkcPoint *point_Qalpha,
 size_t coord_length,
 const TRdrFkcUKM ukm,
 size_t ukm_length, 
TRdrFkcOrder mask, 
size_t mask_length,
 TRdrFkcOrder key, 
size_t * key_length)
{
    TReaderAgreeInfo aI;
    DWORD err;
    aI.to_FKC.index = index;
    aI.to_FKC.Qb = (TRdrFkcPoint *)point_Qalpha;
    aI.to_FKC.Qb_coord_size = coord_length;
    aI.to_FKC.ukm = (TReaderFkcUKMPtr)ukm;
    aI.to_FKC.ukm_length = ukm_length;
    aI.to_FKC.mask = (TReaderFkcOrderPtr)mask;
    aI.to_FKC.mask_length = mask_length;
    aI.to_CSP.key = (TReaderFkcOrderPtr)key;
    aI.to_CSP.key_length = *key_length;    
    aI.key_type = key_type;

    err = supsys_call(context, READER_FUN_AGREEMENT_FULL, &aI);
    if (err)
	LOGRETURN(err);
    *key_length = aI.to_CSP.key_length;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_crypt_simple_key_gen(
    TSupSysEContext *context, 
    TRdrFkcEllipticPointParam uiIDg, 
    char * oid,
    TKeyAlgType alg_type, 
    DWORD key_type, 
    BOOL is_able_dh,
    unsigned int alg_id, 
    const BYTE * add_random_data, DWORD random_length, DWORD permissions,
    int* index, 
    TRdrFkcPoint * pubKey
)
{
    DWORD err;
    TReaderFkcKeyGen kg;
    kg.public_key = pubKey;
    kg.group_id = uiIDg;
    kg.alg_type = alg_type;
    kg.index = *index;
    kg.key_type = key_type;
    kg.alg_id = alg_id;
    kg.is_able_dh = is_able_dh;
    kg.oid = oid;
    kg.add_random_data = add_random_data;
    kg.random_data_length = random_length;
    kg.permissions = permissions;

    err = supsys_call(context, READER_FUN_KEY_GEN, &kg);
    if (err)
	LOGRETURN(err);
    *index = kg.index;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_crypt_simple_rsa_key_gen(TSupSysEContext *context, DWORD rsa_len, long public_exp, DWORD key_type,
    BOOL is_able_dh, unsigned int alg_id, const BYTE *add_random_data, DWORD random_length,
    DWORD permissions, int *index, TRdrFkcRsaKey *pubKey)
{
    DWORD err = 0;
    TReaderFkcRsaKeyGen kg;

    kg.rsa_len = rsa_len;
    kg.public_exp = public_exp;
    kg.public_key = pubKey;
    kg.index = *index;
    kg.key_type = key_type;
    kg.alg_id = alg_id;
    kg.is_able_dh = is_able_dh;
    kg.add_random_data = add_random_data;
    kg.random_data_length = random_length;
    kg.permissions = permissions;
    err = supsys_call(context, READER_FUN_KEY_GEN_RSA, &kg);
    if (err)
	LOGRETURN(err);
    *index = kg.index;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_set_provider_callbacks(const TSupSysEContext *context, TProvCallCtx car_ctx, const TCarrierCallbacks * callbacks)
{
    TReaderProviderInfo info;
    DWORD code = 0;
    if (!callbacks)
	LOGRETURN((DWORD)ERROR_INVALID_PARAMETER);
    info.callbacks = *callbacks;
    info.context = car_ctx;
    code = supsys_call(context, READER_FUN_PROVIDER_INFO, &info);
    LOGRETURN(code);
}

DWORD rdr_get_oids(TSupSysEContext* context, TSupSysMultiStringAsciiText* oids) {
    LOGRETURN(supsys_call(context, READER_FUN_OID_INFO, oids));
}

/* функция получения возможны идентификаторов алгоритмов */
static DWORD rdr_get_algids(TSupSysEContext *context, BOOL forUserKey, TRdrLoginInfoType auth_type, TRdrFkcEllipticPointParam * algid_array, size_t * size_algid_array)
{
    DWORD code = 0;
    TReaderInfoAlgIds algid = { 0 };

    algid.size = RDR_MAX_OIDS_COUNT;
    algid.algs = algid_array;
    algid.auth_type = auth_type;
    algid.forUserKey = forUserKey;

    if (!*size_algid_array) {
	*size_algid_array = RDR_MAX_OIDS_COUNT;
	LOGRETURN(ERROR_SUCCESS);
    }
    if (*size_algid_array && *size_algid_array < RDR_MAX_OIDS_COUNT) {
	*size_algid_array = RDR_MAX_OIDS_COUNT;
	LOGRETURN(ERROR_MORE_DATA);
    }

    code = supsys_call(context, READER_FUN_ALGID_INFO, &algid);
    if (code == ERROR_MORE_DATA) {
	code = (DWORD)NTE_FAIL;
    }
    if (code) {
	goto done;
    }
    *size_algid_array = algid.size;

done:
    LOGRETURN(code);
}

DWORD rdr_get_userkey_algids(TSupSysEContext *context, TRdrFkcEllipticPointParam * algid_array, size_t * size_algid_array)
{
    LOGRETURN(rdr_get_algids(context, TRUE, 0, algid_array, size_algid_array));
}

DWORD rdr_get_sespake_algids(TSupSysEContext *context, TRdrLoginInfoType auth_type, TRdrFkcEllipticPointParam * algid_array, size_t * size_algid_array)
{
    LOGRETURN(rdr_get_algids(context, FALSE, auth_type, algid_array, size_algid_array));
}

DWORD rdr_get_available_rsa_length(TSupSysEContext *context, DWORD * min_key_bits, DWORD* max_key_bits, DWORD* increment_bits)
{
    DWORD code = 0;
    TReaderAvailableRsaLength rsa_params_info = { 0 };

    code = supsys_call(context, READER_FUN_AVAILABLE_LENGTH_RSA, &rsa_params_info);
    if (code) {
	LOGRETURN(code);
    }
    *min_key_bits = rsa_params_info.min_key_bits;
    *max_key_bits = rsa_params_info.max_key_bits;
    *increment_bits = rsa_params_info.increment_bits;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_set_sm_state(TSupSysEContext *context, BOOL isSM, TRdrLoginInfoType auth_type)
{
    TReaderInfoSmState inf; 
    inf.isSM = isSM;
    inf.auth_type = auth_type;
    LOGRETURN(supsys_call(context, READER_FUN_SET_SM_STATE, &inf));
}

/* end of file: $Id: rfkc.c 87822 2013-04-08 14:12:28Z borodin $ */
