├── ChangeLog.md ├── conanfile.txt ├── debug_version_dependencies ├── Qt5Cored.dll ├── msvcp140d.dll ├── ucrtbased.dll └── vcruntime140d.dll ├── tts_encrypt.h ├── tts_server.h ├── tts_common.h ├── tts_setting.h ├── .gitignore ├── TdxTradeServer.pro ├── main.cpp ├── aes.h ├── tts_encrypt.cpp ├── tts_tradeapi.h ├── tts_setting.cpp ├── README.md ├── tts_tradeapi.cpp ├── tts_server.cpp └── aes.cpp /ChangeLog.md: -------------------------------------------------------------------------------- 1 | 0.1 基础版本完成 2 | ---- 3 | * 基于http的rest api 4 | * 给予aes128的加密传输模式 5 | -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | restbed/next@nunojpg/ci 3 | jsonformoderncpp/2.1.1@vthiery/stable 4 | 5 | [generators] 6 | qmake 7 | -------------------------------------------------------------------------------- /debug_version_dependencies/Qt5Cored.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corefan/TdxTradeServer/HEAD/debug_version_dependencies/Qt5Cored.dll -------------------------------------------------------------------------------- /debug_version_dependencies/msvcp140d.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corefan/TdxTradeServer/HEAD/debug_version_dependencies/msvcp140d.dll -------------------------------------------------------------------------------- /debug_version_dependencies/ucrtbased.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corefan/TdxTradeServer/HEAD/debug_version_dependencies/ucrtbased.dll -------------------------------------------------------------------------------- /debug_version_dependencies/vcruntime140d.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corefan/TdxTradeServer/HEAD/debug_version_dependencies/vcruntime140d.dll -------------------------------------------------------------------------------- /tts_encrypt.h: -------------------------------------------------------------------------------- 1 | #ifndef TTS_ENCRYPT_H 2 | #define TTS_ENCRYPT_H 3 | #include "tts_setting.h" 4 | #include "aes.h" 5 | 6 | using namespace std; 7 | 8 | /** 9 | * @brief The TTS_Encrypt class 使用AES_128_CBC进行加密 zeropadding... 10 | * 11 | */ 12 | class TTS_Encrypt 13 | { 14 | private: 15 | unsigned char key[16]; 16 | unsigned char iv[16]; 17 | AESModeOfOperation moo; 18 | 19 | public: 20 | TTS_Encrypt(TTS_SettingObject so); 21 | ~TTS_Encrypt(); 22 | 23 | // 进行加密 24 | string encryptString(const string plaintext); 25 | // 进行解密 26 | string decryptString(const string enctext); 27 | 28 | string toBase64(const string input); 29 | string fromBase64(const string input); 30 | }; 31 | 32 | #endif // TTS_ENCRYPT_H 33 | -------------------------------------------------------------------------------- /tts_server.h: -------------------------------------------------------------------------------- 1 | #ifndef TTS_SERVER_H 2 | #define TTS_SERVER_H 3 | #include "tts_setting.h" 4 | #include "tts_tradeapi.h" 5 | #include "tts_encrypt.h" 6 | #include 7 | #include 8 | 9 | using namespace restbed; 10 | using namespace std; 11 | 12 | class TTS_Server 13 | { 14 | 15 | private: 16 | TTS_SettingObject _setting; 17 | Service service; 18 | shared_ptr resource; 19 | shared_ptr statusResource; 20 | shared_ptr restbed_settings; 21 | shared_ptr ssl_settings; 22 | shared_ptr tradeApi; 23 | shared_ptr encryter; 24 | 25 | 26 | 27 | unsigned long reqnum; 28 | void performResponse(const shared_ptr< Session > session, string _noFunc); 29 | 30 | public: 31 | TTS_Server(TTS_SettingObject setting); 32 | 33 | void start(); 34 | void stop(); 35 | 36 | void postMethodHandler(const shared_ptr< Session > session); 37 | }; 38 | 39 | #endif // TTS_SERVER_H 40 | -------------------------------------------------------------------------------- /tts_common.h: -------------------------------------------------------------------------------- 1 | #ifndef TTS_COMMON_H 2 | #define TTS_COMMON_H 3 | 4 | #define TTS_SUCCESS "success" 5 | #define TTS_ERROR "error" 6 | #define TTS_DATA "data" 7 | 8 | 9 | #define TTS_ASCII_WELCOME "+--------------------------------------------------------+\n" \ 10 | "| |\n" \ 11 | "| TongDaXin Trade Server |\n" \ 12 | "| |\n" \ 13 | "+--------------------------------------------------------+\n" \ 14 | "| |\n" \ 15 | "| A Rest Proxy for trade.dll -------------> RainX! |\n" \ 16 | "| |\n" \ 17 | "+--------------------------------------------------------+\n" 18 | #endif // TTS_COMMON_H 19 | -------------------------------------------------------------------------------- /tts_setting.h: -------------------------------------------------------------------------------- 1 | #ifndef TTS_SETTING_H 2 | #define TTS_SETTING_H 3 | 4 | #include 5 | #include 6 | 7 | #define DEFAULT_TRADE_DLL_NAME "trade.dll" 8 | #define DEFAULT_PORT 19820 9 | #define DEFAULT_BIND "127.0.0.1" 10 | 11 | typedef struct _TTS_SettingObject { 12 | int32_t port; // 监听端口 13 | QString trade_dll_path; // dll路径 14 | QString bind; // 邦定ip 15 | bool ssl_enabled; // 是否启用ssl 16 | QString ssl_private_key; // 私钥 17 | QString ssl_certificate; // CA 证书 18 | QString transport_enc_key; // 对传输进行签名的密钥 19 | QString transport_enc_iv; // 20 | bool transport_enc_enabled; // 是否开启了签名加密 21 | } TTS_SettingObject; 22 | 23 | class TTS_Setting : public QObject 24 | { 25 | Q_OBJECT 26 | public: 27 | explicit TTS_Setting(QObject *parent = nullptr); 28 | 29 | 30 | public: 31 | static QSettings* loadSettingsFile(); 32 | static TTS_SettingObject loadSettings(); 33 | 34 | signals: 35 | 36 | public slots: 37 | }; 38 | 39 | #endif // TTS_SETTING_H 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | package_build_path/ 75 | conanbuildinfo.pri 76 | conaninfo.txt 77 | 78 | !debug_version_dependencies/*.dll 79 | -------------------------------------------------------------------------------- /TdxTradeServer.pro: -------------------------------------------------------------------------------- 1 | QT += core 2 | QT -= gui 3 | 4 | CONFIG += c++11 5 | 6 | TARGET = TdxTradeServer 7 | CONFIG += console 8 | CONFIG -= app_bundle 9 | 10 | TEMPLATE = app 11 | 12 | SOURCES += main.cpp \ 13 | tts_setting.cpp \ 14 | tts_tradeapi.cpp \ 15 | tts_server.cpp \ 16 | tts_encrypt.cpp \ 17 | aes.cpp 18 | 19 | # The following define makes your compiler emit warnings if you use 20 | # any feature of Qt which as been marked deprecated (the exact warnings 21 | # depend on your compiler). Please consult the documentation of the 22 | # deprecated API in order to know how to port your code away from it. 23 | DEFINES += QT_DEPRECATED_WARNINGS 24 | 25 | # You can also make your code fail to compile if you use deprecated APIs. 26 | # In order to do so, uncomment the following line. 27 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 28 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 29 | 30 | CONFIG += conan_basic_setup 31 | include("./conanbuildinfo.pri") 32 | 33 | QMAKE_CXXFLAGS_DEBUG+=-MTd 34 | QMAKE_CXXFLAGS_RELEASE+=-MT 35 | 36 | HEADERS += \ 37 | tts_setting.h \ 38 | tts_tradeapi.h \ 39 | tts_common.h \ 40 | tts_server.h \ 41 | tts_encrypt.h \ 42 | aes.h 43 | 44 | DISTFILES += \ 45 | conanfile.txt \ 46 | README.md \ 47 | build_debug_version.py \ 48 | .gitignore \ 49 | ChangeLog.md 50 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tts_setting.h" 6 | #include "tts_tradeapi.h" 7 | #include "tts_common.h" 8 | #include "tts_server.h" 9 | #include "tts_encrypt.h" 10 | 11 | using namespace std; 12 | using namespace restbed; 13 | 14 | void test(TTS_SettingObject so); 15 | 16 | 17 | void xMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { 18 | QByteArray localMsg = msg.toLocal8Bit(); 19 | QString now = QDateTime::currentDateTime().toString("MM/dd HH:mm:ss"); 20 | fprintf(stderr, "%s TdxTradeServer> %s\n", now.toLocal8Bit().constData(), localMsg.constData()); 21 | } 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | qInstallMessageHandler(xMessageHandler); 26 | 27 | 28 | cout << TTS_ASCII_WELCOME; 29 | // load settings 30 | TTS_SettingObject so = TTS_Setting::loadSettings(); 31 | //test(so); 32 | //exit(-1); 33 | // TTS_TradeApi api(so.trade_dll_path); 34 | TTS_Server server(so); 35 | // start msg loop 36 | server.start(); 37 | 38 | return EXIT_SUCCESS; 39 | } 40 | 41 | 42 | void test(TTS_SettingObject so) { 43 | string s = "x5gnMcO8%2FWV8CbsyKAWJJL3JYUMkK4jL7kod3a3UhyFRgHKIWHX6M%2Fdxl25GRam5fDKwis3dQVUuQ1cw3XDltBniXFBDTjzea0ibVAIQcxZQgDqKBK2J%2FHi3fi5tAnTQHPizhsuRY51fqEsAleDv3ZVVJFVaLNb0Wubg02h8RiXJnvPYcAO%2BBWUw4ZsLKi%2BaYRBsvw%2BUxyeAypPljKTASqNTvfh9vBTkTi4KiNrlEzkSPVfdvhFCJ3xJ3yOvrc58TXHVneJxN6iR%2FxlnBn5853k0h4CxdV7ru3VhsXaO7b%2B9aoCUddsidJH47fo%2F9%2BU1wtW7zKbaJjaBBuCwOlw%2BoGV9AAAAAAAAAAAAAAAAAADHRlOooBvMWqXmgHXwnBBN"; 44 | TTS_Encrypt* e = new TTS_Encrypt(so); 45 | string decoded = restbed::Uri::decode(s); 46 | string un64 = e->fromBase64(s); 47 | string sx = e->decryptString(un64); 48 | 49 | cout << sx << endl;; 50 | } 51 | -------------------------------------------------------------------------------- /aes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FileName : AES.h 3 | * 4 | */ 5 | #ifndef __AES_H__ 6 | #define __AES_H__ 7 | 8 | #include 9 | 10 | void print(unsigned char* state, int len); 11 | 12 | class AES 13 | { 14 | public: 15 | AES(unsigned char* key = NULL); 16 | virtual ~AES(); 17 | void SetKey(unsigned char *key); 18 | unsigned char* Cipher(unsigned char* input, unsigned char* output); 19 | unsigned char* InvCipher(unsigned char* input, unsigned char* output); 20 | void* Cipher(void* input, void *output, int length=0); 21 | void* InvCipher(void* input,void *output, int length); 22 | 23 | private: 24 | unsigned char Sbox[256]; 25 | unsigned char InvSbox[256]; 26 | unsigned char w[11][4][4]; 27 | 28 | void KeyExpansion(unsigned char* key, unsigned char w[][4][4]); 29 | unsigned char FFmul(unsigned char a, unsigned char b); 30 | 31 | void SubBytes(unsigned char state[][4]); 32 | void ShiftRows(unsigned char state[][4]); 33 | void MixColumns(unsigned char state[][4]); 34 | void AddRoundKey(unsigned char state[][4], unsigned char k[][4]); 35 | 36 | void InvSubBytes(unsigned char state[][4]); 37 | void InvShiftRows(unsigned char state[][4]); 38 | void InvMixColumns(unsigned char state[][4]); 39 | }; 40 | 41 | enum AESMode_t { MODE_OFB = 1, MODE_CFB, MODE_CBC, MODE_ECB }; 42 | class AESModeOfOperation { 43 | private: 44 | AES *m_aes; 45 | AESMode_t m_mode; 46 | unsigned char m_key[16]; 47 | unsigned char m_iv[16]; 48 | // bool m_firstround; 49 | public: 50 | AESModeOfOperation(); 51 | ~AESModeOfOperation(); 52 | void set_mode(AESMode_t _mode); 53 | //AESMode_t get_mode(); 54 | void set_key (unsigned char *key); 55 | void set_iv(unsigned char *iv); 56 | int Encrypt(unsigned char *input, int length, unsigned char *output); 57 | int Decrypt(unsigned char *input, int length, unsigned char *output); 58 | }; 59 | 60 | 61 | 62 | #endif 63 | 64 | -------------------------------------------------------------------------------- /tts_encrypt.cpp: -------------------------------------------------------------------------------- 1 | #include "tts_encrypt.h" 2 | #include "aes.h" 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | TTS_Encrypt::TTS_Encrypt(TTS_SettingObject so) 9 | { 10 | // init key and iv 11 | memcpy(key, so.transport_enc_key.toLocal8Bit().constData(), 16); 12 | memcpy(iv, so.transport_enc_iv.toLocal8Bit().constData(), 16); 13 | moo.set_key(key); 14 | moo.set_mode(MODE_CBC); 15 | moo.set_iv(iv); 16 | } 17 | 18 | TTS_Encrypt::~TTS_Encrypt() 19 | { 20 | 21 | } 22 | 23 | string TTS_Encrypt::encryptString(const string plaintext) 24 | { 25 | 26 | int plaintextSize = plaintext.size(); 27 | int encryptedDataSize = plaintextSize + 32; // alloc more space 28 | 29 | string paddedtext; 30 | 31 | int needToPadding = 16 - plaintextSize % 16; 32 | 33 | int paddedSize = plaintextSize + needToPadding; 34 | 35 | // 添加zeropadding 36 | if (needToPadding != 0) { 37 | string padding(needToPadding, '\x00'); 38 | paddedtext = plaintext + padding; 39 | } else { 40 | paddedtext = plaintext; 41 | } 42 | 43 | unsigned char* encryptedData = new unsigned char[encryptedDataSize]; 44 | memset(encryptedData, 0, encryptedDataSize); 45 | int len = moo.Encrypt((unsigned char*) paddedtext.data(), paddedSize, encryptedData); 46 | string estr; 47 | estr.assign((char*)encryptedData, len); 48 | delete[] encryptedData; 49 | return estr; 50 | } 51 | 52 | string TTS_Encrypt::decryptString(const string enctext) 53 | { 54 | int encsize = enctext.size(); 55 | unsigned char* decdata = new unsigned char[encsize]; 56 | int len = moo.Decrypt( (unsigned char*) enctext.data(), encsize, decdata ); 57 | string dstr; 58 | dstr.assign((char*)decdata, len); 59 | delete[] decdata; 60 | return dstr; 61 | } 62 | 63 | string TTS_Encrypt::toBase64(const string input) 64 | { 65 | QByteArray qb = QByteArray::fromStdString(input); 66 | QByteArray qb64 = qb.toBase64(); 67 | string out(qb64.data(), qb64.size()); 68 | return out; 69 | } 70 | 71 | string TTS_Encrypt::fromBase64(const string input) 72 | { 73 | QByteArray qb64 = QByteArray::fromStdString(input); 74 | QByteArray qb = qb64.fromBase64(qb64); 75 | string out(qb.data(), qb.size()); 76 | return out; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /tts_tradeapi.h: -------------------------------------------------------------------------------- 1 | #ifndef TTS_TRADEAPI_H 2 | #define TTS_TRADEAPI_H 3 | #include 4 | #include 5 | #include "json.hpp" 6 | #include "tts_common.h" 7 | 8 | using json = nlohmann::json; 9 | 10 | 11 | typedef void (__stdcall *LPFN_OPENTDX)(); 12 | typedef void (__stdcall *LPFN_CLOSETDX)(); 13 | 14 | // int Logon(char* IP, short Port, char* Version, short YybID, char* AccountNo,char* TradeAccount, char* JyPassword, char* TxPassword, char* ErrInfo);//登录帐号 15 | // void Logoff(int ClientID);//注销 16 | // void QueryData(int ClientID, int Category, char* Result, char* ErrInfo);//查询各类交易数据 17 | // void SendOrder(int ClientID, int Category ,int PriceType, char* Gddm, char* Zqdm , float Price, int Quantity, char* Result, char* ErrInfo);//下单 18 | // void CancelOrder(int ClientID, char* ExchangeID, char* hth, char* Result, char* ErrInfo);//撤单 19 | // void GetQuote(int ClientID, char* Zqdm, char* Result, char* ErrInfo);//获取五档报价 20 | // void Repay(int ClientID, char* Amount, char* Result, char* ErrInfo);//融资融券账户直接还款 21 | 22 | typedef int (__stdcall *LPFN_LOGON)(const char* IP, const short Port, const char* Version, short YybID, const char* AccountNo, const char* TradeAccount, const char* JyPassword, const char* TxPassword, char* ErrInfo); 23 | typedef void(__stdcall *LPFN_LOGOFF)(int ClientID); 24 | typedef void(__stdcall *LPFN_QUERYDATA)(int ClientID, int Category, char* result, char* errInfo); 25 | typedef void(__stdcall *LPFN_SENDORDER)(int ClientID, int Category ,int PriceType, const char* Gddm, const char* Zqdm , float Price, int Quantity, char* Result, char* ErrInfo); 26 | typedef void(__stdcall *LPFN_CANCELORDER)(int ClientID, const char* ExchangeID, const char* hth, char* Result, char* ErrInfo); 27 | typedef void(__stdcall *LPFN_GETQUOTE)(int ClientID, const char* Zqdm, char* Result, char* ErrInfo); 28 | typedef void(__stdcall *LPFN_REPAY)(int ClientID, const char* Amount, char* Result, char* ErrInfo); 29 | 30 | #define P_LOGON "logon" 31 | #define P_LOGOFF "logoff" 32 | #define P_QUERYDATA "query_data" 33 | #define P_SENDORDER "send_order" 34 | #define P_CANCELORDER "cancel_order" 35 | #define P_GETQUOTE "get_quote" 36 | #define P_REPAY "repay" 37 | 38 | class TTS_TradeApi 39 | { 40 | 41 | private: 42 | HINSTANCE hDLL; 43 | int32_t lastClientId; 44 | /// api far call 45 | LPFN_OPENTDX lpOpenTdx; 46 | LPFN_CLOSETDX lpCloseTdx; 47 | LPFN_LOGON lpLogon; 48 | LPFN_LOGOFF lpLogoff; 49 | LPFN_QUERYDATA lpQueryData; 50 | LPFN_SENDORDER lpSendOrder; 51 | LPFN_CANCELORDER lpCancelOrder; 52 | LPFN_GETQUOTE lpGetQuote; 53 | LPFN_REPAY lpRepay; 54 | 55 | QMutex apiCallMutex; // add lock to all network call 56 | 57 | // store error and result; 58 | char* errout; 59 | char* result; 60 | 61 | bool outputUtf8; 62 | 63 | /// end api far call 64 | 65 | void setupErrForJson(const char* errout, json& resultJSON); 66 | 67 | protected: 68 | json convertTableToJSON(const char* result, const char* errout); 69 | 70 | public: 71 | TTS_TradeApi(const QString& dllFilePath); 72 | ~TTS_TradeApi(); 73 | 74 | void setOutputUtf8(bool utf8); 75 | 76 | json logon(const char* IP, const short Port, 77 | const char* Version, short YybID, 78 | const char* AccountNo, const char* TradeAccount, 79 | const char* JyPassword, const char* TxPassword); 80 | 81 | json logoff(int ClientID); 82 | json queryData(int ClientID, int Category); 83 | json sendOrder(int ClientID, int Category ,int PriceType, const char* Gddm, const char* Zqdm , float Price, int Quantity); 84 | json cancelOrder(int ClientID, const char* ExchangeID, const char* hth); 85 | json getQuote(int ClientID, const char* Zqdm); 86 | json repay(int ClientID, const char* Amount); 87 | json jsonError(QString str); 88 | }; 89 | 90 | #endif // TTS_TRADEAPI_H 91 | -------------------------------------------------------------------------------- /tts_setting.cpp: -------------------------------------------------------------------------------- 1 | #include "tts_setting.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define TTS_SETTING_FILE_NAME QString::fromUtf8("TdxTradeServer.ini") 7 | #define TTS_SETTING_DIR_NAME QString::fromUtf8("TdxTradeServer") 8 | 9 | TTS_Setting::TTS_Setting(QObject *parent) : QObject(parent) 10 | { 11 | 12 | } 13 | 14 | 15 | // 1. [current_path]/TdxTradeServer.ini 16 | // 2. ~/TdxTradeServer/TdxTradeServer.ini 17 | // 3. default config 18 | QSettings* TTS_Setting::loadSettingsFile() 19 | { 20 | QString ini_file = TTS_SETTING_FILE_NAME; 21 | QSettings* setting; 22 | if (QDir::current().exists(ini_file)) { 23 | setting = new QSettings(QDir::current().filePath(ini_file), QSettings::IniFormat); 24 | qInfo() << "Load setting file from " << setting->fileName(); 25 | return setting; 26 | } else if (QDir::home().exists(TTS_SETTING_DIR_NAME)) { 27 | QDir dir = QDir::home(); 28 | dir.cd(TTS_SETTING_DIR_NAME); 29 | if (dir.exists(ini_file)) { 30 | setting = new QSettings(dir.filePath(ini_file), QSettings::IniFormat); 31 | qInfo() << "Load setting file from " << setting->fileName(); 32 | return setting; 33 | } else { 34 | qInfo() << "No setting file loaded, use default values"; 35 | return NULL; 36 | } 37 | } else { 38 | qInfo() << "No setting file loaded, use default values"; 39 | return NULL; 40 | } 41 | } 42 | 43 | TTS_SettingObject TTS_Setting::loadSettings() 44 | { 45 | TTS_SettingObject so; 46 | 47 | QSettings* setting = TTS_Setting::loadSettingsFile(); 48 | 49 | QDir currentDir = QDir::current(); 50 | QString defaultPath = currentDir.cleanPath(DEFAULT_TRADE_DLL_NAME); 51 | // use default 52 | if (setting == NULL) { 53 | so.port = DEFAULT_PORT; 54 | so.trade_dll_path = defaultPath; 55 | so.bind = DEFAULT_BIND; 56 | so.ssl_enabled = false; 57 | } else { 58 | so.port = setting->value("port", DEFAULT_PORT).toInt(); 59 | so.trade_dll_path = setting->value("trade_dll_path", defaultPath).toString(); 60 | so.bind = setting->value("bind", QString(DEFAULT_BIND)).toString(); 61 | so.ssl_enabled = setting->value("ssl_enabled").toBool(); 62 | if (so.ssl_enabled) { 63 | so.ssl_certificate = setting->value("ssl_certificate", QString("")).toString(); 64 | so.ssl_private_key = setting->value("ssl_private_key", QString("")).toString(); 65 | } 66 | so.transport_enc_key = setting->value("transport_enc_key", QString("")).toString(); 67 | so.transport_enc_iv = setting->value("transport_enc_iv", QString("")).toString(); 68 | } 69 | 70 | qInfo() << "Using port : " << so.port; 71 | qInfo() << "Using dll file : " << so.trade_dll_path; 72 | qInfo() << "Bind Address is : " << so.bind; 73 | if (so.ssl_enabled) { 74 | qInfo() << "SSL connection is endabled"; 75 | qInfo() << "SSL certificate : " << so.ssl_certificate; 76 | qInfo() << "SSL private key : " << so.ssl_private_key; 77 | } 78 | 79 | if (!so.transport_enc_key.isEmpty()) { 80 | // 检测有效性 81 | if (so.transport_enc_key.size() != 16) { 82 | qInfo() << "Error: transport_enc_key must be a string with size 16Byte (128bit)"; 83 | exit(-1); 84 | } 85 | 86 | if (so.transport_enc_iv.size() != 16) { 87 | qInfo() << "Error: transport_enc_iv must be a string with size 16Bytes (128bit)"; 88 | exit(-1); 89 | } 90 | 91 | so.transport_enc_enabled = true; 92 | qInfo() << "Transport Sign Key enabled! "; 93 | } else { 94 | so.transport_enc_enabled = false; 95 | qInfo() << "Transport Sign Key **NOT** enabled! "; 96 | } 97 | 98 | delete setting; 99 | 100 | // check if dll exists 101 | if (!QFileInfo(so.trade_dll_path).exists()) { 102 | qInfo() << "Dll file not exits, Please Check!!!!"; 103 | exit(-1); 104 | } 105 | return so; 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TongDaXin Trade Server 2 | 3 | ## 概述 4 | 5 | 本程序实现了一个服务器,用来接收交易请求,并将请求转发给trade.dll,使其可以通过rest api 被其它程序调用。 6 | 7 | ``` 8 | 注意,注意,注意: 本程序不提供trade.dll文件,仅仅调用该dll库进行交易,并将其封装成rest api使用, 9 | 我们也不会提供任何trade.dll文件给使用者(关于trade.dll,请自行百度\谷歌) 10 | 如需技术支持,可以想办法联系我。 11 | ``` 12 | 13 | 结构图 14 | 15 | ``` 16 | +--------------------------------------------------------------+ 17 | | Your Quant or Other System | 18 | | | 19 | | | 20 | | +----------------------+ +----------------------------------+ 21 | | | | | || 22 | | | Python client Api | | Other Language Apis || 23 | | | pytdx | | || 24 | | | | | || 25 | | | | | || 26 | | +----------------------+ +----------------------------------+ 27 | | | 28 | | | 29 | +----------------------------+---^-----------------------------+ 30 | | | 31 | +----------------------------v---+-----------------------------+ 32 | | | 33 | | TongDaXin Trade SerVer Listening : 10092 port | 34 | | + | 35 | | | +---------------------+ | 36 | | | | | | 37 | | +----->+ Trade.dll | | 38 | | | | | 39 | | | | | 40 | | + +---------------------+ | 41 | +--------------------------------^-----------------------------+ 42 | | | 43 | +----------------------------v---+-----------------------------+ 44 | | | 45 | | Tong Da Xin Trade Servers | 46 | | | 47 | | | 48 | | | 49 | +--------------------------------------------------------------+ 50 | ``` 51 | 52 | ## 构建 53 | 54 | 本程序使用QT5.9.1开发,使用`restbed`作为web server实现,使用`jsonformoderncpp`作为json序列化和反序列化工具,使用`conan`作为c++依赖库的管理。 请使用兼容`c++11`的编译器编译(这里我使用的vs2015的编译器,理论上mingw应该也可以) 55 | 56 | ### 构建过程 57 | 58 | 1. 安装python 59 | 2. 安装Conan 60 | 3. 安装Qt 并配置VS2015 C++ Compiler 61 | 4. 配置git 62 | 5. 安装cmake 63 | 6. 配置git,mingz,cmake命令在系统path中可以调用 64 | 7. 安装msys2 (openssl编译需要) 65 | 8. 在msys2中安装perl, cmake 66 | 67 | ```bash 68 | pacman -S perl 69 | pacman -S make 70 | ``` 71 | 72 | 9. 配置conan.conf 73 | 74 | ``` 75 | [general] 76 | bash_path="c:\msys32\bin\bash" 77 | .. 78 | [settings_defaults] 79 | arch=x86 80 | compiler=Visual Studio 81 | compiler.version=14 82 | compiler.runtime=MTd 83 | build_type=Debug 84 | os=Windows 85 | ``` 86 | 87 | 10. 在项目目录下执行 88 | 89 | ``` 90 | conan install --build zlib --buildOpenSSL --build asio --build restbed 91 | ``` 92 | 93 | 然后打开QT Creator编译即可。 94 | 95 | ## 配置 96 | 97 | 我们可以通过配置文件来配置系统,配置文件可以在如下两个地方被放置 98 | 99 | 1. [程序运行目录]/TdxTradeServer.ini 100 | 2. ~/TdxTradeServer/TdxTradeServer.ini , ~ 代表当前用户的主目录 101 | 102 | 配置文件Demo 103 | 104 | ``` 105 | bind=10.11.5.175 ; 绑定的ip地址,默认是127.0.0.1 106 | port=10092 ; 绑定的端口 107 | trade_dll_path=D:\\trade_rainx.dll ;一份可以使用的trade.dll文件 108 | transport_enc_key=4f1cf3fec4c84c84 ; 可选, aes加密秘钥 109 | transport_enc_iv=0c78abc083b011e7 ; 可选, aes加密iv 110 | ``` 111 | 112 | 注意,后面的加密选项为可选,如果`transport_enc_key` 或者 `transport_enc_iv` 不提供的话,将使用明文和`client api`通讯,请注意和`client api`保持一致。 如果您跨机器调用接口,建议使用加密功能,并且,请生成随即密钥和iv, 注意,我们这里`key`和`iv`必须是`16`个字节 113 | 114 | ## 通讯协议 115 | 116 | 服务器端通过`restbed`实现了一个webserver, 程序会提供 `http://[your_bind]:[your_port]/api` endpoint, 所有的交互都由客户端通过HTTP `POST`到本endpoint 实现。 117 | 118 | - 请求的内容(payload)放在Request的Body中 119 | - 应答的内容(payload)放在Response的Body中 120 | - 在非加密的情况下,payload 使用json序列化方式传输 121 | - 在加密情况下,payload 使用 `URLENCODE(BASE64(AES128_CBC(JSON(PAYLOAD))))` 结构加密传输,双方都采用相同方式加密解密 122 | 123 | 请求的内容结构如下 124 | 125 | ```json 126 | { 127 | "func": "one_function", 128 | "params": { 129 | "param1": "p1", 130 | "param2": "p2" 131 | } 132 | } 133 | ``` 134 | 135 | 应答的结构如下 136 | 137 | ```json 138 | { 139 | "success": true, 140 | "data": { 141 | .... 142 | }, 143 | "error": "some errors only appear when success is False" 144 | } 145 | ``` 146 | 147 | ## 测试连通性 148 | 149 | 假设端口为 19820 150 | 151 | ```python 152 | In [5]: requests.post("http://127.0.0.1:19820/api", json={"func":"ping"}).text 153 | Out[5]: '{"success":true, "data": "pong"}' 154 | 155 | In [6]: requests.get("http://127.0.0.1:19820/status").text 156 | Out[6]: '{"reqnum":1,"success":true}' 157 | ``` 158 | -------------------------------------------------------------------------------- /tts_tradeapi.cpp: -------------------------------------------------------------------------------- 1 | #include "tts_tradeapi.h" 2 | #include "Windows.h" 3 | #include 4 | #include "json.hpp" 5 | #include "tts_common.h" 6 | #include 7 | 8 | using namespace std; 9 | using json = nlohmann::json; 10 | 11 | 12 | TTS_TradeApi::TTS_TradeApi(const QString& dllFilePath) 13 | { 14 | outputUtf8 = true; 15 | string strDllFilePath = dllFilePath.toStdString(); 16 | hDLL = LoadLibraryA(strDllFilePath.c_str()); 17 | if (0 == hDLL) { 18 | qInfo() << "Load dll failed"; 19 | exit(-1); 20 | } 21 | 22 | // load functions 23 | lpOpenTdx = (LPFN_OPENTDX) GetProcAddress(hDLL, "OpenTdx"); 24 | lpCloseTdx = (LPFN_CLOSETDX) GetProcAddress(hDLL, "CloseTdx"); 25 | lpLogon = (LPFN_LOGON) GetProcAddress(hDLL, "Logon"); 26 | lpLogoff = (LPFN_LOGOFF) GetProcAddress(hDLL, "Logoff"); 27 | lpQueryData = (LPFN_QUERYDATA) GetProcAddress(hDLL, "QueryData"); 28 | lpSendOrder = (LPFN_SENDORDER) GetProcAddress(hDLL, "SendOrder"); 29 | lpCancelOrder = (LPFN_CANCELORDER) GetProcAddress(hDLL, "CancelOrder"); 30 | lpGetQuote = (LPFN_GETQUOTE) GetProcAddress(hDLL, "GetQuote"); 31 | lpRepay = (LPFN_REPAY) GetProcAddress(hDLL, "Repay"); 32 | // end load functioins 33 | 34 | // initialize tdx 35 | lpOpenTdx(); 36 | 37 | errout = new char[1024]; 38 | result = new char[1024 * 1024]; 39 | // 这里强制设定本地编码为gbk 40 | QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030")); 41 | } 42 | 43 | TTS_TradeApi::~TTS_TradeApi() 44 | { 45 | // close tdx 46 | lpCloseTdx(); 47 | if (hDLL) { 48 | FreeLibrary(hDLL); 49 | } 50 | delete[] errout; 51 | delete[] result; 52 | } 53 | 54 | void TTS_TradeApi::setOutputUtf8(bool utf8) { 55 | outputUtf8 = utf8; 56 | } 57 | 58 | /** 59 | * @brief TTS_TradeApi::logon 登陆到服务器 60 | * @param IP 服务器ip地址 61 | * @param Port 端口号 62 | * @param Version 客户端版本 63 | * @param YybID 营业部id 64 | * @param AccountNo 帐号 65 | * @param TradeAccount 交易帐号 66 | * @param JyPassword 交易密码 67 | * @param TxPassword 通讯密码 68 | * @return data -> { "client_id" : xxx } 69 | * 70 | */ 71 | json TTS_TradeApi::logon(const char* IP, const short Port, 72 | const char* Version, short YybID, 73 | const char* AccountNo, const char* TradeAccount, 74 | const char* JyPassword, const char* TxPassword) { 75 | json j; 76 | int ret = lpLogon(IP, Port, Version, YybID, AccountNo, TradeAccount, JyPassword, TxPassword, errout); 77 | if (ret == -1) { 78 | j[TTS_SUCCESS] = false; 79 | setupErrForJson(errout, j); 80 | return j; 81 | } else { 82 | j[TTS_SUCCESS] = true; 83 | j[TTS_DATA]["client_id"] = ret; 84 | } 85 | return j; 86 | } 87 | 88 | /** 89 | * @brief TTS_TradeApi::logoff 登出 90 | * @param ClientID cilent_id 91 | * @return success => true/false 92 | */ 93 | json TTS_TradeApi::logoff(int ClientID) { 94 | lpLogoff(ClientID); 95 | json j; 96 | j[TTS_SUCCESS] = true; 97 | return j; 98 | } 99 | 100 | /** 101 | * @brief TTS_TradeApi::queryData 查询信息 102 | * @param ClientID client_id 103 | * @param Category 信息类别 104 | * @return [{}, {}, {} ] 105 | */ 106 | json TTS_TradeApi::queryData(int ClientID, int Category) { 107 | lpQueryData(ClientID, Category, result, errout); 108 | return convertTableToJSON(result, errout); 109 | } 110 | 111 | 112 | json TTS_TradeApi::sendOrder(int ClientID, int Category ,int PriceType, const char* Gddm, const char* Zqdm , float Price, int Quantity) { 113 | lpSendOrder(ClientID, Category, PriceType, Gddm, Zqdm, Price, Quantity, result, errout); 114 | return convertTableToJSON(result, errout); 115 | } 116 | 117 | json TTS_TradeApi::cancelOrder(int ClientID, const char *ExchangeID, const char *hth) { 118 | lpCancelOrder(ClientID, ExchangeID, hth, result, errout); 119 | return convertTableToJSON(result, errout); 120 | } 121 | 122 | json TTS_TradeApi::getQuote(int ClientID, const char *Zqdm) { 123 | lpGetQuote(ClientID, Zqdm, result, errout); 124 | return convertTableToJSON(result, errout); 125 | } 126 | 127 | json TTS_TradeApi::repay(int ClientID, const char *Amount) { 128 | lpRepay(ClientID, Amount, result, errout); 129 | return convertTableToJSON(result, errout); 130 | } 131 | 132 | 133 | void TTS_TradeApi::setupErrForJson(const char* errout, json& resultJSON) 134 | { 135 | if (outputUtf8) { 136 | QString qErrout = QString::fromLocal8Bit(errout); 137 | string utf8Errout = qErrout.toUtf8().constData(); 138 | resultJSON[TTS_ERROR] = utf8Errout; 139 | } else { 140 | resultJSON[TTS_ERROR] = errout; 141 | } 142 | } 143 | 144 | 145 | /** 146 | * @brief TTS_TradeApi::convertTableToJSON 将\n分割行\t分割字符的类似 csv格式的信息转换为json格式 147 | * @param result 148 | * @return json结构的 [{line1}, {line2} ... ] 信息 149 | */ 150 | 151 | json TTS_TradeApi::convertTableToJSON(const char *result, const char* errout) { 152 | 153 | json resultJSON; 154 | if (result[0] == 0) { 155 | resultJSON[TTS_SUCCESS] = false; 156 | setupErrForJson(errout, resultJSON); 157 | return resultJSON; 158 | } 159 | 160 | json j; 161 | j = json::array(); 162 | QString strResult = QString::fromLocal8Bit(result); 163 | // qInfo() << strResult; 164 | QStringList sl = strResult.split("\n"); 165 | if (sl.length() > 1) { 166 | QString head = sl[0]; 167 | QStringList hlist = head.split("\t"); 168 | 169 | int line = 0; 170 | for (QString row : sl) { 171 | line++; 172 | if (line==1) continue; 173 | 174 | QStringList rowlist = row.split("\t"); 175 | 176 | json oneRecord = json({}); 177 | for(int i = 0; i < hlist.length(); i++) { 178 | string key, value; 179 | if (outputUtf8) { 180 | key = hlist[i].toUtf8(); 181 | value = rowlist[i].toUtf8(); 182 | } else { 183 | key = hlist[i].toLocal8Bit(); 184 | value = rowlist[i].toLocal8Bit(); 185 | } 186 | 187 | oneRecord[key]= value; 188 | } 189 | j.push_back(oneRecord); 190 | } 191 | } 192 | resultJSON[TTS_SUCCESS] = true; 193 | resultJSON[TTS_DATA] = j; 194 | return resultJSON; 195 | } 196 | 197 | 198 | json TTS_TradeApi::jsonError(QString str) { 199 | string value; 200 | if (outputUtf8) { 201 | value = str.toUtf8(); 202 | } else { 203 | value = str.toLocal8Bit(); 204 | } 205 | json j; 206 | j[TTS_SUCCESS] = false; 207 | j[TTS_ERROR] = value; 208 | return j; 209 | } 210 | 211 | 212 | -------------------------------------------------------------------------------- /tts_server.cpp: -------------------------------------------------------------------------------- 1 | #include "tts_server.h" 2 | #include "tts_tradeapi.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace restbed; 9 | using json = nlohmann::json; 10 | 11 | TTS_Server::TTS_Server(TTS_SettingObject setting) 12 | { 13 | _setting = setting; 14 | resource = make_shared< Resource >(); 15 | statusResource = make_shared< Resource >(); 16 | restbed_settings = make_shared< Settings >(); 17 | ssl_settings = make_shared(); 18 | encryter = make_shared(setting); 19 | } 20 | 21 | void TTS_Server::start() { 22 | reqnum = 0; 23 | auto callback = bind(&TTS_Server::postMethodHandler, this, placeholders::_1); 24 | tradeApi = make_shared(_setting.trade_dll_path); 25 | resource->set_path("/api"); 26 | resource->set_method_handler("POST", callback); 27 | 28 | statusResource->set_path("/status"); 29 | statusResource->set_method_handler("GET", [&](const shared_ptr< Session > session){ 30 | const auto request = session->get_request(); 31 | json j; 32 | j["success"] = true; 33 | j["reqnum"] = reqnum; 34 | session->close(OK, j.dump()); 35 | }); 36 | 37 | //restbed_settings->set_bind_address(_setting.bind.toStdString()); 38 | restbed_settings->set_default_header("Connection", "close"); 39 | 40 | if (_setting.ssl_enabled) { 41 | ssl_settings->set_http_disabled(true); 42 | ssl_settings->set_port(_setting.port); 43 | ssl_settings->set_certificate(Uri(_setting.ssl_certificate.toStdString())); 44 | ssl_settings->set_private_key(Uri(_setting.ssl_private_key.toStdString())); 45 | restbed_settings->set_ssl_settings(ssl_settings); 46 | } else { 47 | restbed_settings->set_port(_setting.port); 48 | } 49 | 50 | 51 | service.publish(resource); 52 | service.publish(statusResource); 53 | qInfo() << "Starting to listening.." ; 54 | service.start(restbed_settings); 55 | 56 | } 57 | 58 | 59 | void TTS_Server::stop() { 60 | qInfo() << "GoodByte!"; 61 | service.stop(); 62 | } 63 | 64 | /** 65 | * @brief TTS_Server::postMethodHandler 66 | * 67 | * 这里,请求体的结构应为 68 | * { 69 | * "func": "Logon", 70 | * "params": { 71 | * .. 72 | * .. 73 | * } 74 | * } 75 | * 76 | * @param session 77 | */ 78 | void TTS_Server::performResponse(const shared_ptr< Session > session, string output) 79 | { 80 | if (_setting.transport_enc_enabled) { 81 | string encoutput = encryter->encryptString(output); 82 | string encoutput64 = encryter->toBase64(encoutput); 83 | string urlencodedencoutput64 = restbed::Uri::encode(encoutput64); 84 | session->close(OK, urlencodedencoutput64); 85 | } else { 86 | session->close(OK, output); 87 | } 88 | } 89 | 90 | void TTS_Server::postMethodHandler(const shared_ptr< Session > session) { 91 | const auto request = session->get_request(); 92 | int contentLength = request->get_header("Content-Length", 0); 93 | 94 | session->fetch(contentLength, [&] (const shared_ptr session, const Bytes& body) { 95 | string requestBody(body.begin(), body.end()); 96 | reqnum++; 97 | 98 | if (_setting.transport_enc_enabled) { 99 | string requestBodyUnquote = restbed::Uri::decode(requestBody); 100 | string requestBodyPlain = encryter->fromBase64(requestBodyUnquote); 101 | requestBody = encryter->decryptString(requestBodyPlain); 102 | } 103 | 104 | json requestJson = json::parse(requestBody); 105 | 106 | if (requestJson["func"].is_null()) { 107 | QString _err= "parameter func does not exists"; 108 | string _noFunc = tradeApi->jsonError(_err).dump(); 109 | performResponse(session, _noFunc); 110 | return; 111 | } 112 | 113 | string func = requestJson["func"].get(); 114 | qInfo("Receiving request func=%s", func.c_str()); 115 | string responseBody; 116 | auto params = requestJson["params"]; 117 | // 参数的解析,后续应该用Command等模式将实现放到具体的类中 118 | if (func == P_LOGON) { 119 | if (params["ip"].is_string() && params["port"].is_number() && params["version"].is_string() 120 | && params["yyb_id"].is_number() && params["account_no"].is_string() 121 | && params["trade_account"].is_string() 122 | && params["jy_password"].is_string() && params["tx_password"].is_string()) { 123 | string ip = params["ip"].get(); 124 | int port = params["port"].get(); 125 | string version = params["version"].get(); 126 | int yybId = params["yyb_id"].get(); 127 | string accountNo = params["account_no"].get(); 128 | string tradeAccount = params["trade_account"].get(); 129 | string jyPassword = params["jy_password"].get(); 130 | string txPassword = params["tx_password"].get(); 131 | 132 | responseBody = tradeApi->logon(ip.c_str(), port, version.c_str(), yybId, accountNo.c_str(), tradeAccount.c_str(), jyPassword.c_str(), txPassword.c_str()).dump(); 133 | } else { 134 | responseBody = tradeApi->jsonError("error params").dump(); 135 | } 136 | 137 | } else if (func == P_LOGOFF) { 138 | if (params["client_id"].is_number()) { 139 | responseBody = tradeApi->logoff(params["client_id"].get()).dump(); 140 | } else { 141 | responseBody = tradeApi->jsonError("error params").dump(); 142 | } 143 | } else if (func == P_QUERYDATA) { 144 | if (params["client_id"].is_number() 145 | && params["category"].is_number() 146 | ) { 147 | int clientId = params["client_id"].get(); 148 | int category = params["category"].get(); 149 | responseBody = tradeApi->queryData(clientId, category).dump(); 150 | } else { 151 | responseBody = tradeApi->jsonError("error params").dump(); 152 | } 153 | } else if (func == P_SENDORDER) { 154 | if (params["client_id"].is_number() 155 | && params["category"].is_number() 156 | && params["price_type"].is_number() 157 | && params["gddm"].is_string() 158 | && params["zqdm"].is_string() 159 | && params["price"].is_number() 160 | && params["quantity"].is_number()) { 161 | responseBody = tradeApi->sendOrder( 162 | params["client_id"].get(), 163 | params["category"].get(), 164 | params["price_type"].get(), 165 | params["gddm"].get().c_str(), 166 | params["zqdm"].get().c_str(), 167 | params["price"].get(), 168 | params["quantity"].get() 169 | ).dump(); 170 | } else { 171 | responseBody = tradeApi->jsonError("error params").dump(); 172 | } 173 | } else if (func == P_CANCELORDER) 174 | { 175 | if (params["client_id"].is_number() 176 | && params["exchange_id"].is_string() 177 | && params["hth"].is_string()) { 178 | responseBody = tradeApi->cancelOrder( 179 | params["client_id"].get(), 180 | params["exchange_id"].get().c_str(), 181 | params["hth"].get().c_str() 182 | ).dump(); 183 | } else { 184 | responseBody = tradeApi->jsonError("error params").dump(); 185 | } 186 | } else if (func == P_GETQUOTE) { 187 | if (params["client_id"].is_number() 188 | && params["code"].is_string()){ 189 | responseBody = tradeApi->getQuote(params["client_id"].get(), 190 | params["code"].get().c_str()).dump(); 191 | } else { 192 | responseBody = tradeApi->jsonError("error params").dump(); 193 | } 194 | } else if (func == P_REPAY) { 195 | if (params["client_id"].is_number() 196 | && params["amount"].is_string()) { 197 | responseBody = tradeApi->repay(params["client_id"].get(), params["amount"].get().c_str()).dump(); 198 | } else { 199 | responseBody = tradeApi->jsonError("error params").dump(); 200 | } 201 | } else if (func == "stop_server") { 202 | qInfo() << "Server Stop Command Called!"; 203 | stop(); 204 | } else if (func == "ping") { 205 | responseBody = "{\"success\":true, \"data\": \"pong\"}"; 206 | } else { 207 | responseBody = "{\"success\":false, \"error\": \"unknown command\"}"; 208 | } 209 | 210 | performResponse(session, responseBody); 211 | }); 212 | } 213 | -------------------------------------------------------------------------------- /aes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | */ 3 | 4 | 5 | #include "AES.h" 6 | #include 7 | #include 8 | #include 9 | 10 | AES::AES(unsigned char* key) 11 | { 12 | unsigned char sBox[] = 13 | { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 14 | 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, /*0*/ 15 | 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, /*1*/ 16 | 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, /*2*/ 17 | 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, /*3*/ 18 | 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, /*4*/ 19 | 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, /*5*/ 20 | 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, /*6*/ 21 | 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, /*7*/ 22 | 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, /*8*/ 23 | 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, /*9*/ 24 | 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, /*a*/ 25 | 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, /*b*/ 26 | 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, /*c*/ 27 | 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, /*d*/ 28 | 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, /*e*/ 29 | 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16 /*f*/ 30 | }; 31 | unsigned char invsBox[256] = 32 | { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 33 | 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, /*0*/ 34 | 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, /*1*/ 35 | 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, /*2*/ 36 | 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, /*3*/ 37 | 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, /*4*/ 38 | 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, /*5*/ 39 | 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, /*6*/ 40 | 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, /*7*/ 41 | 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, /*8*/ 42 | 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, /*9*/ 43 | 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, /*a*/ 44 | 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, /*b*/ 45 | 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, /*c*/ 46 | 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, /*d*/ 47 | 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, /*e*/ 48 | 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d /*f*/ 49 | }; 50 | memcpy(Sbox, sBox, 256); 51 | memcpy(InvSbox, invsBox, 256); 52 | if (key != NULL) { 53 | KeyExpansion(key, w); 54 | } 55 | } 56 | 57 | AES::~AES() 58 | { 59 | 60 | } 61 | 62 | void AES::SetKey (unsigned char *key) { 63 | KeyExpansion(key, w); 64 | } 65 | 66 | unsigned char* AES::Cipher(unsigned char* input, unsigned char *output) 67 | { 68 | unsigned char state[4][4]; 69 | int i,r,c; 70 | 71 | for(r=0; r<4; r++) 72 | { 73 | for(c=0; c<4 ;c++) 74 | { 75 | state[r][c] = input[c*4+r]; 76 | } 77 | } 78 | 79 | AddRoundKey(state,w[0]); 80 | 81 | for(i=1; i<=10; i++) 82 | { 83 | SubBytes(state); 84 | ShiftRows(state); 85 | if(i!=10)MixColumns(state); 86 | AddRoundKey(state,w[i]); 87 | } 88 | 89 | for(r=0; r<4; r++) 90 | { 91 | for(c=0; c<4 ;c++) 92 | { 93 | output[c*4+r] = state[r][c]; 94 | } 95 | } 96 | 97 | return output; 98 | } 99 | 100 | unsigned char* AES::InvCipher(unsigned char* input, unsigned char *output) 101 | { 102 | unsigned char state[4][4]; 103 | int i,r,c; 104 | 105 | for(r=0; r<4; r++) 106 | { 107 | for(c=0; c<4 ;c++) 108 | { 109 | state[r][c] = input[c*4+r]; 110 | } 111 | } 112 | 113 | AddRoundKey(state, w[10]); 114 | for(i=9; i>=0; i--) 115 | { 116 | InvShiftRows(state); 117 | InvSubBytes(state); 118 | AddRoundKey(state, w[i]); 119 | if(i) 120 | { 121 | InvMixColumns(state); 122 | } 123 | } 124 | 125 | for(r=0; r<4; r++) 126 | { 127 | for(c=0; c<4 ;c++) 128 | { 129 | output[c*4+r] = state[r][c]; 130 | } 131 | } 132 | return output; 133 | } 134 | 135 | void* AES::Cipher(void* input, void *output, int length) 136 | { 137 | unsigned char* in = (unsigned char*) input; 138 | unsigned char* out = (unsigned char*) output; 139 | int i; 140 | if(!length) 141 | { 142 | while(*(in+length++)); 143 | in = (unsigned char*) input; 144 | } 145 | for(i=0; i>i)&0x01) 219 | { 220 | res ^= bw[i]; 221 | } 222 | } 223 | return res; 224 | } 225 | 226 | void AES::SubBytes(unsigned char state[][4]) 227 | { 228 | int r,c; 229 | for(r=0; r<4; r++) 230 | { 231 | for(c=0; c<4; c++) 232 | { 233 | state[r][c] = Sbox[state[r][c]]; 234 | } 235 | } 236 | } 237 | 238 | void AES::ShiftRows(unsigned char state[][4]) 239 | { 240 | unsigned char t[4]; 241 | int r,c; 242 | for(r=1; r<4; r++) 243 | { 244 | for(c=0; c<4; c++) 245 | { 246 | t[c] = state[r][(c+r)%4]; 247 | } 248 | for(c=0; c<4; c++) 249 | { 250 | state[r][c] = t[c]; 251 | } 252 | } 253 | } 254 | 255 | void AES::MixColumns(unsigned char state[][4]) 256 | { 257 | unsigned char t[4]; 258 | int r,c; 259 | for(c=0; c< 4; c++) 260 | { 261 | for(r=0; r<4; r++) 262 | { 263 | t[r] = state[r][c]; 264 | } 265 | for(r=0; r<4; r++) 266 | { 267 | state[r][c] = FFmul(0x02, t[r]) 268 | ^ FFmul(0x03, t[(r+1)%4]) 269 | ^ FFmul(0x01, t[(r+2)%4]) 270 | ^ FFmul(0x01, t[(r+3)%4]); 271 | } 272 | } 273 | } 274 | 275 | void AES::AddRoundKey(unsigned char state[][4], unsigned char k[][4]) 276 | { 277 | int r,c; 278 | for(c=0; c<4; c++) 279 | { 280 | for(r=0; r<4; r++) 281 | { 282 | state[r][c] ^= k[r][c]; 283 | } 284 | } 285 | } 286 | 287 | void AES::InvSubBytes(unsigned char state[][4]) 288 | { 289 | int r,c; 290 | for(r=0; r<4; r++) 291 | { 292 | for(c=0; c<4; c++) 293 | { 294 | state[r][c] = InvSbox[state[r][c]]; 295 | } 296 | } 297 | } 298 | 299 | void AES::InvShiftRows(unsigned char state[][4]) 300 | { 301 | unsigned char t[4]; 302 | int r,c; 303 | for(r=1; r<4; r++) 304 | { 305 | for(c=0; c<4; c++) 306 | { 307 | t[c] = state[r][(c-r+4)%4]; 308 | } 309 | for(c=0; c<4; c++) 310 | { 311 | state[r][c] = t[c]; 312 | } 313 | } 314 | } 315 | 316 | void AES::InvMixColumns(unsigned char state[][4]) 317 | { 318 | unsigned char t[4]; 319 | int r,c; 320 | for(c=0; c< 4; c++) 321 | { 322 | for(r=0; r<4; r++) 323 | { 324 | t[r] = state[r][c]; 325 | } 326 | for(r=0; r<4; r++) 327 | { 328 | state[r][c] = FFmul(0x0e, t[r]) 329 | ^ FFmul(0x0b, t[(r+1)%4]) 330 | ^ FFmul(0x0d, t[(r+2)%4]) 331 | ^ FFmul(0x09, t[(r+3)%4]); 332 | } 333 | } 334 | } 335 | 336 | /**************************************************************/ 337 | //AESModeOfOperation 338 | 339 | AESModeOfOperation::AESModeOfOperation() { 340 | m_mode = MODE_ECB; 341 | m_aes = NULL; 342 | memset(m_key, 0, 16); 343 | memset(m_iv, 0, 16); 344 | m_aes = new AES(m_key); 345 | assert(m_aes != NULL); 346 | } 347 | 348 | AESModeOfOperation::~AESModeOfOperation() { 349 | delete m_aes; 350 | } 351 | 352 | void AESModeOfOperation::set_mode(AESMode_t _mode) { 353 | m_mode = _mode; 354 | } 355 | 356 | void AESModeOfOperation::set_key(unsigned char *_key) { 357 | assert(_key != NULL); 358 | memcpy(m_key, _key, 16); 359 | m_aes->SetKey(m_key); 360 | } 361 | void AESModeOfOperation::set_iv(unsigned char *_iv) { 362 | assert(_iv != NULL); 363 | memcpy(m_iv, _iv, 16); 364 | } 365 | 366 | int AESModeOfOperation::Encrypt(unsigned char *_in, int _length, unsigned char *_out) { 367 | bool first_round = true; 368 | int rounds = 0; 369 | int start = 0; 370 | int end = 0; 371 | unsigned char input[16] = {0}; 372 | unsigned char output[16] = {0}; 373 | unsigned char ciphertext[16] = {0}; 374 | unsigned char* cipherout = new unsigned char[_length+16]; 375 | unsigned char plaintext[16] = {0}; 376 | int co_index = 0; 377 | // 1. get rounds 378 | if ( _length % 16 == 0) { 379 | rounds = _length / 16; 380 | } else { 381 | rounds = _length / 16 + 1; 382 | } 383 | // 2. for all rounds 384 | for (int j = 0; j < rounds; ++j) { 385 | start = j*16; 386 | end = j*16 + 16; 387 | if (end > _length) end = _length; // end of input 388 | // 3. copyt input to m_plaintext 389 | memset(plaintext, 0, 16); 390 | memcpy(plaintext, _in + start, end - start); 391 | // 4. handle all modes 392 | if (m_mode == MODE_CFB) { 393 | if (first_round == true) { 394 | m_aes->Cipher(m_iv, output); 395 | first_round = false; 396 | } else { 397 | m_aes->Cipher(input,output); 398 | } 399 | for (int i = 0; i < 16; ++i) { 400 | if ( (end - start) - 1 < i) { 401 | ciphertext[i] = 0 ^ output[i]; 402 | } else { 403 | ciphertext[i] = plaintext[i] ^ output[i]; 404 | } 405 | } 406 | for (int k = 0 ; k < end - start; ++k) { 407 | cipherout[co_index++] = ciphertext[k]; 408 | } 409 | //memset(input,0, 16); 410 | memcpy(input,ciphertext, 16); 411 | } else if (m_mode == MODE_OFB) { // MODE_OFB 412 | if (first_round == true) { 413 | m_aes->Cipher(m_iv,output); // 414 | first_round = false; 415 | } else { 416 | m_aes->Cipher(input, output); 417 | } 418 | // ciphertext = plaintext ^ output 419 | for (int i = 0; i < 16; ++i) { 420 | if ( (end - start) - 1 < i) { 421 | ciphertext[i] = 0 ^ output[i]; 422 | } else { 423 | ciphertext[i] = plaintext[i] ^ output[i]; 424 | } 425 | } 426 | // 427 | for (int k = 0; k < end - start; ++k) { 428 | cipherout[co_index++] = ciphertext[k]; 429 | } 430 | //memset(input,0,16); 431 | memcpy(input, output, 16); 432 | } else if (m_mode == MODE_CBC) { // MODE_CBC 433 | for (int i = 0; i < 16; ++i) { 434 | if (first_round == true) { 435 | input[i] = plaintext[i] ^ m_iv[i]; 436 | } else { 437 | input[i] = plaintext[i] ^ ciphertext[i]; 438 | } 439 | } 440 | first_round = false; 441 | m_aes->Cipher(input, ciphertext); 442 | for (int k = 0; k < end - start; ++k){ 443 | cipherout[co_index++] = ciphertext[k]; 444 | } 445 | 446 | } else if (m_mode == MODE_ECB) { 447 | // TODO: 448 | } 449 | } 450 | memcpy(_out, cipherout, co_index); 451 | delete[] cipherout; 452 | return co_index; 453 | } 454 | 455 | int AESModeOfOperation::Decrypt(unsigned char *_in, int _length, unsigned char *_out) { 456 | // TODO : 457 | bool first_round = true; 458 | int rounds = 0; 459 | unsigned char ciphertext[16] = {0}; 460 | unsigned char input[16] = {0}; 461 | unsigned char output[16] = {0}; 462 | unsigned char plaintext[16] = {0}; 463 | unsigned char* plainout = new unsigned char[_length + 16]; 464 | int po_index = 0 ; 465 | if (_length % 16 == 0) { 466 | rounds = _length / 16; 467 | } else { 468 | rounds = _length / 16 + 1; 469 | } 470 | 471 | int start = 0; 472 | int end = 0; 473 | 474 | for (int j = 0; j < rounds; j++) { 475 | start = j * 16; 476 | end = start + 16; 477 | if ( end > _length) { 478 | end = _length; 479 | } 480 | memset(ciphertext, 0, 16); 481 | memcpy(ciphertext, _in + start, end - start); 482 | if ( m_mode == MODE_CFB ) { 483 | if (first_round = true) { 484 | m_aes->Cipher(m_iv, output); 485 | first_round = false; 486 | } else { 487 | m_aes->Cipher(input, output); 488 | } 489 | for (int i = 0; i < 16; i++) { 490 | if ( end - start - 1 < i) { 491 | plaintext[i] = output[i] ^ 0; 492 | } else { 493 | plaintext[i] = output[i] ^ ciphertext[i]; 494 | } 495 | } 496 | for (int k = 0; k < end - start; ++k) { 497 | plainout[po_index++] = plaintext[k]; 498 | } 499 | //memset(input, 0, 16); 500 | memcpy(input, ciphertext, 16); 501 | } else if (m_mode == MODE_OFB) { 502 | if (first_round == true) { 503 | m_aes->Cipher(m_iv, output); 504 | first_round = false; 505 | } else { 506 | m_aes->Cipher(input, output); 507 | } 508 | for (int i = 0; i < 16; i++) { 509 | if ( end - start -1 < i) { 510 | plaintext[i] = 0 ^ ciphertext[i]; 511 | first_round = false; 512 | } else { 513 | plaintext[i] = output[i] ^ ciphertext[i]; 514 | } 515 | } 516 | for (int k = 0; k < end - start; ++k) { 517 | plainout[po_index++] = plaintext[k]; 518 | } 519 | memcpy(input, output, 16); 520 | } else if (m_mode == MODE_CBC) { 521 | m_aes->InvCipher(ciphertext, output); 522 | for (int i = 0; i < 16; ++i) { 523 | if ( first_round == true) { 524 | plaintext[i] = m_iv[i] ^ output[i]; 525 | } else { 526 | plaintext[i] = input[i] ^ output[i]; 527 | } 528 | } 529 | first_round = false; 530 | for ( int k = 0; k < end - start; ++k) { 531 | plainout[po_index++] = plaintext[k]; 532 | } 533 | memcpy(input, ciphertext, 16); 534 | } else { 535 | // TODO 536 | } 537 | } 538 | memcpy(_out, plainout, po_index); 539 | delete[] plainout; 540 | return po_index; 541 | } 542 | 543 | 544 | --------------------------------------------------------------------------------