// CommPackageImp.cpp: implementation of the CCommPackage class. // ////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "Package.h" #include #include #include #include "dbgutil.h" #include #include #define TAG RVCCOMM_TAG("package") #include "XZip.h" #include "XUnzip.h" #include "openssl/md5.h" #include "CMBSMDLL.h" #include "utils.h" //#include "openssl/des.h" using namespace std::placeholders; //#define USE_SM ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// DWORD CCommPackage::m_nLastReqTime(0); WORD CCommPackage::m_nLastReqSN(0); CCommPackage::CCommPackage(const BYTE sessionKey[16], const char *pServiceCode) { #ifdef USE_SM EncryptData = std::bind(&CCommPackage::EncryptDataBySM4, this, _1, _2, _3, _4); DecryptData = std::bind(&CCommPackage::DecryptDataBySM4, this, _1, _2, _3, _4); GenerateMac = std::bind(&CCommPackage::GenerateMacMd5, this, _1, _2, _3); #else EncryptData = std::bind(&CCommPackage::EncryptDataByDES, this, _1, _2, _3, _4); DecryptData = std::bind(&CCommPackage::DecryptDataByDES, this, _1, _2, _3, _4); GenerateMac = std::bind(&CCommPackage::GenerateMacSM3, this, _1, _2, _3); #endif // USE_SM if (sessionKey != NULL) { WLog_DBG(TAG, "session key is not nullptr"); memcpy(m_SessionKey, sessionKey, 16); // 前8个字节作为DesKey,后8个字节作为IVec DES_set_key_unchecked((BYTE(*)[8])&m_SessionKey, &m_DesKey); Aschex_2_bcdhex(m_SessionKey, 16, m_SM4Key); m_bHasSessionKey = true; } else { memset(m_SessionKey, 0, 16); m_bHasSessionKey = false; WLog_DBG(TAG, "memset session key."); } m_Header.m_nStructNum =0; m_Header.m_nPackageLen = sizeof(CPackageHeader); if (pServiceCode != NULL) { if (strlen(pServiceCode) >=8) memcpy(m_Header.m_arrServiceCode, pServiceCode, 8); else strcpy(m_Header.m_arrServiceCode, pServiceCode); } } CCommPackage::CCommPackage(CCommPackage *pkg) { #ifdef USE_SM EncryptData = std::bind(&CCommPackage::EncryptDataBySM4, this, _1, _2, _3, _4); DecryptData = std::bind(&CCommPackage::DecryptDataBySM4, this, _1, _2, _3, _4); GenerateMac = std::bind(&CCommPackage::GenerateMacMd5, this, _1, _2, _3); #else EncryptData = std::bind(&CCommPackage::EncryptDataByDES, this, _1, _2, _3, _4); DecryptData = std::bind(&CCommPackage::DecryptDataByDES, this, _1, _2, _3, _4); GenerateMac = std::bind(&CCommPackage::GenerateMacSM3, this, _1, _2, _3); #endif // USE_SM m_bHasSessionKey = pkg->m_bHasSessionKey; if (m_bHasSessionKey) { memcpy(m_SessionKey, pkg->m_SessionKey, 16); // 前8个字节作为DesKey,后8个字节作为IVec DES_set_key_unchecked((BYTE(*)[8])&m_SessionKey, &m_DesKey); Aschex_2_bcdhex(m_SessionKey, 16, m_SM4Key); WLog_DBG(TAG, "%s: session key is not nullptr", __FUNCTION__); } else { memset(m_SessionKey, 0, 16); WLog_DBG(TAG, "%s: memset session key.", __FUNCTION__); } m_Header.m_nStructNum =0; m_Header.m_nPackageLen = sizeof(CPackageHeader); // 拷贝ServiceCode memcpy(m_Header.m_arrServiceCode, pkg->m_Header.m_arrServiceCode, 8); // 拷贝ReqTime和DSN m_Header.m_nReqTime = pkg->m_Header.m_nReqTime; m_Header.m_nSN = pkg->m_Header.m_nSN; } CCommPackage::~CCommPackage() { Clear(); } void CCommPackage::Clear() { std::vector::iterator it; for(it = m_Structs.begin(); it != m_Structs.end(); it++) { if ((*it)->m_pData != NULL) delete[](*it)->m_pData; delete *it; } m_Structs.clear(); memset(&m_Header, 0, sizeof(CPackageHeader)); } void CCommPackage::AddStruct(const char *pStructName, bool bZip, bool bEncrypt, BYTE *pDataBuf, int nBufLen, int nArrayNum) { TOOLKIT_ASSERT(m_Header.m_nPackageLen + nBufLen + CStructDef::GetStructDefLen() < 0xFFFF); CStructDef *pDef = new CStructDef(); if (strlen(pStructName) <8) strcpy(pDef->m_arrName, pStructName); else memcpy(pDef->m_arrName, pStructName, 8); pDef->m_nArrayNum = nArrayNum; pDef->m_cEncCode = 'N'; pDef->m_cZipCode = 'N'; pDef->m_nSourceLen = nBufLen; pDef->m_nTargetLen = nBufLen; pDef->m_pData = new BYTE[nBufLen]; memcpy(pDef->m_pData, pDataBuf, nBufLen); // 先压缩,后加密,提高压缩效率 if (bZip) { // 压缩后最大长度不应大于源长度 int nTempBufLen = pDef->m_nTargetLen; BYTE *pTempBuf = new BYTE[nTempBufLen]; memset(pTempBuf, 0, nTempBufLen); ZRESULT result = ZipData(pDef->m_pData, pDef->m_nTargetLen, pTempBuf, &nTempBufLen); if (result == ZR_OK) { delete[] pDef->m_pData; pDef->m_pData = pTempBuf; pDef->m_nTargetLen = nTempBufLen; pDef->m_cZipCode = 'Y'; } else { WLog_WARN(TAG, "ZipData failed: %d", result); delete[] pTempBuf; } } // 加密,加密后长度可能变长,变成8的倍数。需要在输出数据前加上4字节长度,指明加密前长度 if (bEncrypt && m_bHasSessionKey) { // 加密后最大长度 int nTempBufLen = pDef->m_nTargetLen + 12; BYTE *pTempBuf = new BYTE[nTempBufLen]; memset(pTempBuf, 0, nTempBufLen); if (EncryptData(pDef->m_pData, pDef->m_nTargetLen, pTempBuf, &nTempBufLen)) { delete[] pDef->m_pData; pDef->m_pData = pTempBuf; pDef->m_nTargetLen = nTempBufLen; // 加密后实际长度 pDef->m_cEncCode = 'Y'; } else { delete[] pTempBuf; } } // 保存到结构定义 m_Structs.push_back(pDef); // 处理包头 m_Header.m_nStructNum++; m_Header.m_nPackageLen += pDef->m_nTargetLen + CStructDef::GetStructDefLen(); } void CCommPackage::SetErrMsg(DWORD dwSysCode, DWORD dwUserCode, const char *pErrMsg) { char buf[512]; memset(buf, 0, sizeof(buf)); CErrorReturn *pErrRet = (CErrorReturn*) buf; pErrRet->m_dwSysCode = dwSysCode; pErrRet->m_dwUserCode = dwUserCode; int nDataLen =8; if (strlen(pErrMsg) >= 256) { memcpy(pErrRet->m_arrErrMsg, pErrMsg, 256); nDataLen += 256; } else { strcpy(pErrRet->m_arrErrMsg, pErrMsg); nDataLen += strlen(pErrMsg); //nDataLen += 256; // 考虑与C#对接,故不使用变长字段 } AddStruct("ERRORRET", false, false, (BYTE*)buf, nDataLen, 1); } bool CCommPackage::GetErrMsg(DWORD& dwSysCode, DWORD& dwUserCode, std::string& rErrMsg) { std::vector::iterator it; for(it = m_Structs.begin(); it != m_Structs.end(); it++) { if (memcmp((*it)->m_arrName, "ERRORRET", 8) ==0) break; } if (it == m_Structs.end()) return false; TOOLKIT_ASSERT((*it)->m_cEncCode == 'N'); TOOLKIT_ASSERT((*it)->m_cZipCode == 'N'); CErrorReturn *pErrRet = (CErrorReturn*)(*it)->m_pData; dwSysCode = pErrRet->m_dwSysCode; dwUserCode = pErrRet->m_dwUserCode; int nErrMsgLen = (*it)->m_nSourceLen - 8; char buf[512]; memset(buf, 0, sizeof(buf)); memcpy(buf, pErrRet->m_arrErrMsg, nErrMsgLen); rErrMsg = buf; return true; } std::string CCommPackage::GetServiceCode() { if (m_Header.m_arrServiceCode[7] == 0) return m_Header.m_arrServiceCode; else { char buf[9]; memset(buf, 0, sizeof(buf)); memcpy(buf, m_Header.m_arrServiceCode, 8); return buf; } } int CCommPackage::GetStructLen(const char *pStructName) { int nCompLen = strlen(pStructName); if (nCompLen >8 ) nCompLen = 8; std::vector::iterator it; for(it = m_Structs.begin(); it != m_Structs.end(); it++) { if (memcmp((*it)->m_arrName, pStructName, nCompLen) ==0) break; } if (it == m_Structs.end()) return -1; return (*it)->m_nSourceLen; } bool CCommPackage::GetStructData(const char *pStructName, BYTE *pDataBuf, int *pBufLen, int *pArrayNum) { int nCompLen = strlen(pStructName); if (nCompLen >8 ) nCompLen = 8; std::vector::iterator it; for(it = m_Structs.begin(); it != m_Structs.end(); it++) { if (memcmp((*it)->m_arrName, pStructName, nCompLen) ==0) break; } if (it == m_Structs.end()) return false; *pArrayNum = (*it)->m_nArrayNum; int nCopyLen = (*it)->m_nSourceLen; if (nCopyLen > *pBufLen) nCopyLen = *pBufLen; *pBufLen = nCopyLen; memcpy(pDataBuf, (*it)->m_pData, nCopyLen); return true; } bool CCommPackage::ParseRecvData(BYTE *pData, int *pLen, std::string& strErrMsg) { if (*pLen < sizeof(CPackageHeader)) { strErrMsg = "pack len < sizeof(CPackageHeader)"; return false; } CPackageHeader *pHeader = (CPackageHeader *)pData; // 校验标志位 if (pHeader->m_nFlag != 0xA5C3) { strErrMsg = "Header->m_nFlag != 0xA5C3"; return false; } // 检查版本 if (pHeader->m_nVersion != 2) { strErrMsg = "Header->m_nVersion != 2"; return false; } // 检查Mac BYTE pkgMac[8]; memcpy(pkgMac, pHeader->m_arrMac, 8); // 清空Mac,方便检验 memset(pHeader->m_arrMac, 0, 8); WLog_DBG(TAG, "to generate mac data."); BYTE genMac[8]; if (GenerateMac(pData, *pLen, genMac)) { WLog_DBG(TAG, "to cmpare two mac data."); if (memcmp(pkgMac, genMac, 8) != 0) { strErrMsg = "mac check not pass"; WLog_WARN(TAG, "mac data is not the same."); return false; } } else { WLog_ERR(TAG, "generate mac data failed."); } // 保存包头信息 memcpy(&m_Header, pHeader, sizeof(CPackageHeader)); int nStructDefLen = CStructDef::GetStructDefLen(); // 处理接口定义 CStructDef *pIDef = (CStructDef *) (pData + sizeof(CPackageHeader)); BYTE *pIData = pData + sizeof(CPackageHeader) + m_Header.m_nStructNum * nStructDefLen; bool bParseSuc = true; for(int i=0; im_nTargetLen > pDef->m_nSourceLen ? pDef->m_nTargetLen : pDef->m_nSourceLen; pDef->m_pData = new BYTE[nBufLen]; memset(pDef->m_pData, 0, nBufLen); memcpy(pDef->m_pData, pIData, pDef->m_nTargetLen); // 改变指针位置 pIDef = (CStructDef *)(((BYTE *) pIDef) + nStructDefLen); pIData += pDef->m_nTargetLen; int nLastLength = pDef->m_nTargetLen; // 先解密 if (pDef->m_cEncCode == 'Y') { TOOLKIT_ASSERT(m_bHasSessionKey); WLog_DBG(TAG, "to decrypt data."); // 解密后长度最大长度为源长度+12 int nTempBufLen = pDef->m_nSourceLen + 12; BYTE *pTempBuf = new BYTE[nTempBufLen]; memset(pTempBuf, 0, nTempBufLen); if (DecryptData(pDef->m_pData, pDef->m_nTargetLen, pTempBuf, &nTempBufLen)) { TOOLKIT_ASSERT(nTempBufLen <= pDef->m_nSourceLen); delete[] pDef->m_pData; pDef->m_pData = pTempBuf; nLastLength = nTempBufLen; // 解密后实际长度 } else { WLog_ERR(TAG, "decrypt data failed."); strErrMsg = "decrypt data fail"; delete[] pTempBuf; bParseSuc = false; } } // 解压 if (bParseSuc && pDef->m_cZipCode == 'Y') { // 解压后最大长度不超过源长度 int nTempBufLen = pDef->m_nSourceLen; BYTE *pTempBuf = new BYTE[nTempBufLen]; memset(pTempBuf, 0, nTempBufLen); WLog_DBG(TAG, "to unzip data."); if (UnzipData(pDef->m_pData, nLastLength, pTempBuf, &nTempBufLen)) { WLog_DBG(TAG, "unzip data succeed."); delete[] pDef->m_pData; pDef->m_pData = pTempBuf; nLastLength = nTempBufLen; } else { WLog_ERR(TAG, "unzip data failed."); strErrMsg = "unzip data fail"; delete[] pTempBuf; bParseSuc = false; } } // 保存接口 m_Structs.push_back(pDef); if (nLastLength != pDef->m_nSourceLen) { memset(pDef->m_pData, 0, pDef->m_nSourceLen); strErrMsg = "parsed length != m_nSourceLen"; bParseSuc = false; } } *pLen = m_Header.m_nPackageLen; return bParseSuc; } int CCommPackage::GetPackageLen() { return m_Header.m_nPackageLen; } std::string CCommPackage::GetPackageReqID() { char szBuf[128]; memset(szBuf, 0, sizeof(szBuf)); sprintf(szBuf, "%d:%d", m_Header.m_nReqTime, m_Header.m_nSN); return szBuf; } bool CCommPackage::GenerateSendData(BYTE *pData, int *pLen) { if (*pLen < m_Header.m_nPackageLen) return false; *pLen = m_Header.m_nPackageLen; // 生成发送时间 if (m_Header.m_nReqTime ==0) { //WLog_DBG(TAG, "1 req time: %u", (DWORD)time(NULL)); m_Header.m_nReqTime = time(NULL); //m_Header.m_nReqTime = 10241024; // 生成序号 if (m_Header.m_nReqTime == m_nLastReqTime) m_Header.m_nSN = ++m_nLastReqSN; else m_Header.m_nSN = m_nLastReqSN = 0; m_nLastReqTime = m_Header.m_nReqTime; } else { //WLog_DBG(TAG, "2 req time: %u", (DWORD)time(NULL)); m_Header.m_nAnsTime = time(NULL); //m_Header.m_nAnsTime = 10241024; } // 拷贝包头 BYTE *pHead = pData; memcpy(pHead, &m_Header, sizeof(CPackageHeader)); // 拷贝接口 pData += sizeof(CPackageHeader); BYTE *pIntData = pData + m_Header.m_nStructNum * CStructDef::GetStructDefLen(); std::vector::iterator it; for(it = m_Structs.begin(); it != m_Structs.end(); it++) { CStructDef *pIntDef = (*it); memcpy(pData, pIntDef, CStructDef::GetStructDefLen()); memcpy(pIntData, pIntDef->m_pData, pIntDef->m_nTargetLen); pData += CStructDef::GetStructDefLen(); pIntData += pIntDef->m_nTargetLen; } // 生成Mac BYTE mac[8]; memset(mac, 0, sizeof(mac)); // 先将相应Mac位清0 memset(((CPackageHeader *)pHead)->m_arrMac, 0, 8); if (!GenerateMac(pHead, *pLen, mac)) { WLog_ERR(TAG, "generate mac failed!"); return false; } memcpy(((CPackageHeader *)pHead)->m_arrMac, mac, 8); return true; } bool CCommPackage::ZipData(BYTE *pSourceData, int nSourceLen, BYTE *pDestBuf, int *pDestLen) { HZIP hz = CreateZip(0, nSourceLen, ZIP_MEMORY); ZRESULT zs = ZR_OK; if (hz == 0) { WLog_ERR(TAG, "create zip returned empty"); return false; } if ((zs = ZipAdd(hz, "ZIPDATA", pSourceData, nSourceLen, ZIP_MEMORY)) != ZR_OK) { WLog_ERR(TAG, "ZipAdd failed: %d", zs); CloseZip(hz); return false; } void* pZipBuf = NULL; unsigned long nZipLen = 0; if ((zs = ZipGetMemory(hz, &pZipBuf, &nZipLen)) != ZR_OK) { WLog_ERR(TAG, "ZipGetMemory failed: %d", zs); CloseZip(hz); return false; } // 如果压缩长度变大,放弃压缩 if (nZipLen >= nSourceLen) { CloseZip(hz); WLog_WARN(TAG, "the compress len is large than before."); return false; } // 拷贝压缩后内容 int nCopyLen = nZipLen <= *pDestLen ? nZipLen : *pDestLen; *pDestLen = nCopyLen; memcpy(pDestBuf, pZipBuf, nCopyLen); CloseZip(hz); return true; } bool CCommPackage::UnzipData(BYTE *pSourceData, int nSourceLen, BYTE *pDestBuf, int *pDestLen) { WLog_DBG(TAG, "unzip data"); memset(pDestBuf, 0, *pDestLen); ZRESULT zs = ZR_OK; HZIP hz = OpenZip(pSourceData, nSourceLen, ZIP_MEMORY); if (hz == 0) { WLog_ERR(TAG, "create zip returned empty"); return false; } ZIPENTRY ze; memset(&ze, 0, sizeof(ze)); if ((zs = GetZipItem(hz, 0, &ze)) != ZR_OK) { WLog_ERR(TAG, "GetZipItem failed: %d", zs); CloseZip(hz); return false; } if (ze.unc_size < *pDestLen) *pDestLen = ze.unc_size; if ((zs = UnzipItem(hz, 0, pDestBuf, *pDestLen, ZIP_MEMORY)) != ZR_MORE || *pDestLen != ze.unc_size) { WLog_ERR(TAG, "UnzipItem failed: %d", zs); CloseZip(hz); return false; } CloseZip(hz); return true; } bool CCommPackage::EncryptDataByDES(BYTE* pSourceData, int nSourceLen, BYTE* pDestBuf, int* pDestLen) { TOOLKIT_ASSERT(m_bHasSessionKey); if (!m_bHasSessionKey) return false; int nMinBufLen = nSourceLen % 8 == 0 ? nSourceLen : (nSourceLen / 8 + 1) * 8; nMinBufLen += 4; // 4字节头指定加密前长度 if (nMinBufLen > * pDestLen) return false; *pDestLen = nMinBufLen; *(int*)pDestBuf = nSourceLen; // 保存加密前长度 BYTE iv[8]; memcpy(iv, m_SessionKey + 8, 8); DES_ncbc_encrypt(pSourceData, pDestBuf + 4, nSourceLen, &m_DesKey, &iv, DES_ENCRYPT); return true; } bool CCommPackage::EncryptDataBySM4(BYTE* pSourceData, int nSourceLen, BYTE* pDestBuf, int* pDestLen) { TOOLKIT_ASSERT(m_bHasSessionKey); if (!m_bHasSessionKey) return false; int nMinBufLen = nSourceLen % 8 == 0 ? nSourceLen : (nSourceLen / 8 + 1) * 8; nMinBufLen += 4; // 4字节头指定加密前长度 if (nMinBufLen > * pDestLen) return false; *pDestLen = nMinBufLen; *(int*)pDestBuf = nSourceLen; // 保存加密前长度 return 0 == CMBSM4EncryptWithECB(m_SM4Key, pSourceData, nSourceLen, pDestBuf + 4, pDestLen); } bool CCommPackage::DecryptDataByDES(BYTE* pSourceData, int nSourceLen, BYTE* pDestBuf, int* pDestLen) { TOOLKIT_ASSERT(m_bHasSessionKey); if (!m_bHasSessionKey) return false; // 取出解密后长度 int nActLen = *(int*)pSourceData; if (nActLen > * pDestLen) return false; nSourceLen -= 4; int nMinBufLen = nSourceLen % 8 == 0 ? nSourceLen : (nSourceLen / 8 + 1) * 8; if (nMinBufLen > * pDestLen) return false; *pDestLen = nActLen; BYTE iv[8]; memcpy(iv, m_SessionKey + 8, 8); DES_ncbc_encrypt(pSourceData + 4, pDestBuf, nSourceLen, &m_DesKey, &iv, DES_DECRYPT); return true; } bool CCommPackage::DecryptDataBySM4(BYTE* pSourceData, int nSourceLen, BYTE* pDestBuf, int* pDestLen) { TOOLKIT_ASSERT(m_bHasSessionKey); if (!m_bHasSessionKey) return false; // 取出解密后长度 int nActLen = *(int*)pSourceData; if (nActLen > * pDestLen) return false; nSourceLen -= 4; int nMinBufLen = nSourceLen % 8 == 0 ? nSourceLen : (nSourceLen / 8 + 1) * 8; if (nMinBufLen > * pDestLen) return false; *pDestLen = nActLen; return 0 == CMBSM4DecryptWithECB(m_SM4Key, pSourceData + 4, nSourceLen, pDestBuf, pDestLen); } // Mac算法约定。为了减低校验码运算复杂度,使用整包进行Hash运算然后取低8位再进行加密运算的方式。 // 如果当前没有协商传输密钥,直接使用Hash低8位表示 bool CCommPackage::GenerateMacMd5(BYTE *pData, int nLen, BYTE mac[8]) { BYTE md5[16]; memset(md5, 0, 16); MD5Hash(pData, nLen, md5); // 加密前8位 BYTE buf[16]; memset(buf, 0, sizeof(buf)); int nBufLen = 16; if (m_bHasSessionKey) { EncryptData(md5, 8, buf, &nBufLen); memcpy(mac, buf+4, 8); return true; } else { memcpy(mac, md5, 8); return true; } } bool CCommPackage::GenerateMacSM3(BYTE* pData, int nLen, BYTE mac[8]) { BYTE sm3[32]; memset(sm3, 0, 32); if (!SM3Hash(pData, nLen, sm3)) { return false; } BYTE buf[16]; memset(buf, 0, sizeof(buf)); memcpy(mac, sm3, 8); return true; }