/************************************************************
* Details: 通信加密
* Encode: UTF-8
* Platform: Android & Linux
* Author: R&D 2
* Date: 2018-4-2
************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "gt.h"
#include "gtencrypt.h"
#include "gterror.h"
#include "gttoolkitext.h"
#include "gtcommencrypt.h"

GtCommEncrypt *GtCommEncrypt::_instance = NULL;

GtCommEncrypt::GtCommEncrypt():_encryptOffset(9)
{
    memset(_localPubCrypto, 0, sizeof(_localPubCrypto));
    memset(_localPriCrypto, 0, sizeof(_localPriCrypto));
    memset(_serverCrypto, 0, sizeof(_serverCrypto));
    _localPubCryptoSize = 0;
    _localPriCryptoSize = 0;
    _serverCryptoSize = 0;
    _encryptType = 0;
}

GtCommEncrypt::~GtCommEncrypt()
{

}

GtCommEncrypt *GtCommEncrypt::instance()
{
    if(_instance == NULL)
    {
        _instance = new GtCommEncrypt();
    }
    return _instance;
}

/************************************************************
*功能：获取通信报文加密类型
*输入：无
*输出：无
*返回：加密类型
*/
int GtCommEncrypt::getCommEncryptType()
{
    return _encryptType;
}


/************************************************************
*功能：生成密钥对
*输入：无
*输出：pubKey公钥
*返回：!=0错误
*/
int GtCommEncrypt::generateCommEncryptKey(char *pubKey)
{
    char rsaPubKey[256];
    char rsaPriKey[256];
    int rsaPubSize = 0;
    int rsaPriSize = 0;
    int result = 0;

    memset(rsaPubKey, 0, sizeof(rsaPubKey));
    memset(rsaPriKey, 0, sizeof(rsaPriKey));
    rsaPubSize = sizeof(rsaPubKey);
    rsaPriSize = sizeof(rsaPriKey);
    result = GtEncrypt::getRSAKeys(rsaPubKey, &rsaPubSize, rsaPriKey, &rsaPriSize);
    if(result != 0)
    {
        GtToolkitExt::logError(__FILE__, __LINE__, "生成通信密匙错误");
        return result;
    }
    memset(_localPubCrypto, 0, sizeof(_localPubCrypto));
    memcpy(_localPubCrypto, rsaPubKey, rsaPubSize);
    _localPubCryptoSize = rsaPubSize;
    memset(_localPriCrypto, 0, sizeof(_localPriCrypto));
    memcpy(_localPriCrypto, rsaPriKey, rsaPriSize);
    _localPriCryptoSize = rsaPriSize;
    memcpy(pubKey, rsaPubKey, rsaPubSize);
    _encryptType = 0;
    return 0;
}

/************************************************************
*功能：服务器通信密匙解密
*输入：type加密类型，key加密密匙，keySize密匙长度
*输出：无
*返回：!=0错误
*/
int GtCommEncrypt::commKeyDecrypt(int type, char *key, int keySize)
{
    int keyLen = 0;
    int result = 0;

    _encryptType = type;
    if(_encryptType == 4)
    {
        memset(_serverCrypto, 0, sizeof(_serverCrypto));
        memcpy(_serverCrypto, key, keySize);
        keyLen = keySize;
        result = GtEncrypt::rsaDecryptData(_localPriCrypto, _localPriCryptoSize, _serverCrypto, &keyLen);
        if(result != 0)
        {
            GtToolkitExt::logError(__FILE__, __LINE__, "通信密钥解密错误");
            return result;
        }
        _serverCrypto[keyLen] = '\0';
        _serverCryptoSize = keyLen;
    }
    return 0;
}

/************************************************************
*功能：通信报文数据加密
*输入：data加密前数据，inBufLen缓存长度，inLen数据长度
*输出：data加密后的通信报文，outLen加密后的数据长度
*返回：!=0错误
*/
int GtCommEncrypt::commDataEncrypt(unsigned char *data, int inBufLen, int inLen, int *outLen)
{
    int bufLen = 0;
    int result = 0;

    if(_encryptType == 4)
    {
        bufLen = inLen - 2 - _encryptOffset;
        result = GtEncrypt::encryptData(_encryptType, _serverCrypto, _serverCryptoSize,
                                &data[2 + _encryptOffset],
                                inBufLen - (2 + _encryptOffset),
                                 &bufLen);
        if(result != 0)
        {
            GtToolkitExt::logError(__FILE__, __LINE__, "通信数据加密错误");
            return result;
        }
        data[0] = (_encryptOffset + bufLen)/256;
        data[1] = (_encryptOffset + bufLen)%256;
        *outLen = 2 + _encryptOffset + bufLen;
        data[*outLen] = '\0';
    }
    return 0;
}

/************************************************************
*功能：通信报文数据解密
*输入：bufLen=缓存长度
*输出：dataBuf=解密后的通信报文
*输出：dataLen=解密后的数据长度
*返回：!=0错误
*/
int GtCommEncrypt::commDataDecrypt(unsigned char *dataBuf, int bufLen, int *dataLen)
{
    int result = 0;
    int dataSize = 0;

    if(_encryptType == 4)
    {
        dataSize = *dataLen;
        dataSize = dataSize - _encryptOffset - 2;
        result = GtEncrypt::decryptData(_encryptType, _serverCrypto, _serverCryptoSize,
        &dataBuf[_encryptOffset + 2], bufLen - _encryptOffset - 2, &dataSize);
        if(result != 0)
        {
            GtToolkitExt::logError(__FILE__, __LINE__, "通信数据解密错误");
            return result;
        }
        *dataLen = dataSize + _encryptOffset + 2;
        dataBuf[*dataLen] = '\0';
    }
    return 0;
}
