探索 MQL5 中的密码学:深入浅出的方法阐述·进阶篇
「在 MT5 里跑通三种编码函数」
把交易参数或信号文本写进文件、发往接口之前,先用 MQL5 自带的 CryptEncode / CryptDecode 做一层转换,是低成本防泄露的做法。下面三段脚本分别覆盖 AES128 加密解密、SHA256 哈希、Base64 编码,直接丢进 MT5 脚本文件就能编译运行。 AES 那段先用 for 循环填了一个 16 字节的演示密钥(i+1 递增),真实环境务必换成随机安全密钥,否则等于没锁门。StringToCharArray 按 CP_UTF8 把字符串转字节数组,CryptEncode(CRYPT_AES128,...) 返回大于 0 才代表加密成功,失败就打印 GetLastError 代码,方便定位。 哈希示例不需要密钥,CRYPT_HASH_SHA256 直接对字节数组出 32 字节结果;Base64 则把二进制转成 ASCII,适合塞进 JSON 或 XML 这类纯文本协议。三者都是同步调用,在脚本里跑完即退出,不占用图表事件循环。 验证方式很简单:开 MT5 新建 Script,把代码贴入,跑加密脚本看日志是否打印 'Encryption successful.',再手动把 encrypted 数组喂给解密脚本,能还原 'Confidential Trade Parameters' 就说明链路通了。外汇与贵金属交易本身高风险,这类工具只解决数据传输与存储的保密和完整性,不改善任何进场胜率。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class="type">class="kw">string message = "Confidential Trade Parameters"; class="type">uchar key[class="num">16]; class="type">uchar data[]; class="type">uchar encrypted[]; class=class="str">"cmt">// Generate a class="num">16-byte key(In practice, use a secure key) for(class="type">int i = class="num">0; i < class="num">16; i++) key[i] = (class="type">uchar)(i + class="num">1); class=class="str">"cmt">// Convert message to byte array StringToCharArray(message, data, class="num">0, StringLen(message), CP_UTF8); class=class="str">"cmt">// Encrypt the data if(CryptEncode(CRYPT_AES128, data, key, encrypted) > class="num">0) { Print("Encryption successful."); class=class="str">"cmt">// Save or transmit &class="macro">#x27;encrypted&class="macro">#x27; array } else { Print("Encryption failed. Error code: ", GetLastError()); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class="type">uchar key[class="num">16]; class="type">uchar encrypted[]; class=class="str">"cmt">// Load encrypted data class="type">uchar decrypted[]; class=class="str">"cmt">// Generate the same class="num">16-byte key for(class="type">int i = class="num">0; i < class="num">16; i++) key[i] = (class="type">uchar)(i + class="num">1); class=class="str">"cmt">// Decrypt the data if(CryptDecode(CRYPT_AES128, encrypted, key, decrypted) > class="num">0) { class="type">class="kw">string message = CharArrayToString(decrypted, class="num">0, -class="num">1, CP_UTF8); Print("Decryption successful: ", message); } else { Print("Decryption failed. Error code: ", GetLastError()); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class="type">class="kw">string dataToHash = "VerifyThisData"; class="type">uchar data[]; class="type">uchar hash[]; class=class="str">"cmt">// Convert class="type">class="kw">string to byte array StringToCharArray(dataToHash, data, class="num">0, StringLen(dataToHash), CP_UTF8); class=class="str">"cmt">// Compute SHA256 hash if(CryptEncode(CRYPT_HASH_SHA256, data, NULL, hash) > class="num">0) { class=class="str">"cmt">// Convert hash to hexadecimal class="type">class="kw">string for display class="type">class="kw">string hashString = ""; for(class="type">int i = class="num">0; i < ArraySize(hash); i++)
在 MT5 里把字符串做成 SHA256 与 Base64
上面这段脚本展示了两套编码在 MQL5 里的落地方式:SHA256 走 CryptHash 系列函数,Base64 走 CryptEncode(CRYPT_BASE64)。两者都依赖 uchar 数组作为中间载体,不能直接拿 string 硬算。 以 "BinaryDataExample" 为例,StringToCharArray 配合 CP_UTF8 把明文字符串转成 data[] 字节流;CryptEncode 返回大于 0 时才代表编码成功,否则用 GetLastError 看底层错误码。 Base64 编码后通过 CharArrayToString(base64,0,-1,CP_UTF8) 还原成可打印字符串,控制台会输出类似 'QmluYXJ5RGF0YUV4YW1wbGU=' 的结果(实际值取决于输入字节)。外汇与贵金属 EA 里做信号校验或参数混淆时,这类编码可用于本地指纹比对,但涉及实盘须清醒:任何本地编码校验都不构成交易胜率保证,杠杆市场仍属高风险。 SHA256 分支里用 StringFormat("%02X", hash[i]) 把每个字节格式化成两位十六进制并拼接,Print 出完整哈希串;失败时同样打印错误码而非静默跳过,这是排查 Crypt 函数失败的基本动作。
hashString += StringFormat("%02X", hash[i]); Print("SHA256 Hash: ", hashString); } else { Print("Hashing failed. Error code: ", GetLastError()); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class="type">class="kw">string binaryData = "BinaryDataExample"; class="type">uchar data[]; class="type">uchar base64[]; class=class="str">"cmt">// Convert class="type">class="kw">string to byte array StringToCharArray(binaryData, data, class="num">0, StringLen(binaryData), CP_UTF8); class=class="str">"cmt">// Encode with Base64 if(CryptEncode(CRYPT_BASE64, data, NULL, base64) > class="num">0) { class="type">class="kw">string base64String = CharArrayToString(base64, class="num">0, -class="num">1, CP_UTF8); Print("Base64 Encoded Data: ", base64String); } else { Print("Base64 Encoding failed. Error code: ", GetLastError()); } }
◍ 用邮件发信号前先过一遍加密
邮件通道天生不安全,交易信号若在明文里跑一遍 SMTP,中途被截获或篡改的概率并不低。尤其是喊单类内容带仓位和止损位,落到第三方手里就是现成的反向样本。 MQL5 自带密码学函数,能在发送前把信号做对称加密,再附一段哈希值。接收端用同一密钥解开,比对哈希一致才认定没被动过。这样即便邮件被嗅探,看到的也只是密文。 实操上,交易者可以在 EA 的 OnTimer 里触发加密发送,把信号结构体序列化后喂给 CryptEncode,哈希用 HashToString 生成摘要。开 MT5 新建脚本把这两步跑通,比直接调 SendMail 更稳。
「给信号邮件上锁与签名」
做信号分发的老手都懂,把入场价、止损位、获利目标直接明文发邮件等于把仓位摊在阳光下。客户群之外的人一旦截获,就能白嫖策略甚至反向狙击你的流动性。 给邮件内容做对称加密,只把密钥通过独立渠道发给付费客户,能挡住绝大多数非授权读取。光加密还不够,传输链路里内容可能被改——比如把止损从 1.0950 改成 1.0850,客户照做就爆仓。 这时候再对原文算一个哈希值,用你自己的私钥签上名,客户用公钥验签就能确认:这封信号既没被改过,也确实出自你手。外汇与贵金属杠杆高,信号泄露或篡改都可能引发连锁亏损,这套加密+签名流程建议直接在 MT5 信号推送前固化进发送脚本。
用 AES256 和 SHA256 给信号上锁
想在 MT5 里把交易信号只给授权客户看,核心就三件事:AES256 加密内容、SHA256 算哈希验篡改、提前离线共享密钥。原文方案里密钥用 MathRand() 生成 32 字节,等于 256 位,刚好塞进 AES256。 密钥绝不可以走邮件。脚本把密钥写进 encryption_key.bin 二进制文件,这个文件得当面或安全 IM 交给客户,否则加密等于没锁门。MT5 本身不提供非对称签名,要验发件人真伪得挂外部库。 加密侧流程是:加载密钥 → 信号转字节数组 → CryptEncode(CRYPT_AES256) → 对密文算 SHA256 → Base64 编码塞进 SendMail 正文。客户端反向 Base64 解码、复算哈希比对、匹配才解密。外汇和贵金属信号分发属高风险操作,密钥泄露可能导致跟单被劫持,务必定期换钥。 下面这段是密钥生成与读取的 MQL5 骨架,逐行看: void OnStart() 脚本入口 uchar key[32]; 声明 32 字节密钥数组 for(int i=0;i<32;i++) key[i]=(uchar)MathRand(); 用伪随机填充每个字节,随机性偏弱 StringFormat("%02X",key[i]) 转十六进制便于记录打印 FileOpen("encryption_key.bin",FILE_BIN|FILE_WRITE) 开二进制写文件 FileWriteArray 把密钥原样落盘 第二个 OnStart 里 FileReadArray 从同一文件读回 32 字节密钥供加密用 把密钥当大门钥匙,别塞门垫下;多年不换钥就像从不换锁,被扒的概率会随时长累积。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class="type">uchar key[class="num">32]; class=class="str">"cmt">// Generate a secure random key for(class="type">int i = class="num">0; i < class="num">32; i++) key[i] = (class="type">uchar)MathRand(); class=class="str">"cmt">// Display the key in hexadecimal format class="type">class="kw">string keyHex = ""; for(class="type">int i = class="num">0; i < class="num">32; i++) keyHex += StringFormat("%02X", key[i]); Print("Generated Key(Hex): ", keyHex); class=class="str">"cmt">// Save the key to a file(securely store this file) class="type">int fileHandle = FileOpen("encryption_key.bin", FILE_BIN|FILE_WRITE); if(fileHandle != INVALID_HANDLE) { FileWriteArray(fileHandle, key, class="num">0, ArraySize(key)); FileClose(fileHandle); Print("Key saved to encryption_key.bin"); } else { Print("Failed to save the key. Error: ", GetLastError()); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class="type">class="kw">string signal = "BUY EURUSD at class="num">1.12345\nSL: class="num">1.12000\nTP: class="num">1.13000"; class="type">uchar data[]; class="type">uchar key[class="num">32]; class="type">uchar encrypted[]; class="type">uchar hash[]; class="type">uchar nullKey[]; class=class="str">"cmt">// Load the encryption key class="type">int fileHandle = FileOpen("encryption_key.bin", FILE_BIN|FILE_READ); if(fileHandle != INVALID_HANDLE) { FileReadArray(fileHandle, key, class="num">0, class="num">32); FileClose(fileHandle); }