探索 MQL5 中的密码学:深入浅出的方法阐述·综合运用
◍ 把信号加密后塞进邮件发出去
这段逻辑承接密钥加载失败的处理:若前面没拿到有效 AES256 密钥,直接 Print 报错并 return,后续加密全不做。 拿到密钥后,先用 StringToCharArray 把 signal 字符串按 CP_UTF8 转成字节数组 data,注意长度用 StringLen(signal) 显式指定,避免尾部补零污染明文。 接着 CryptEncode(CRYPT_AES256, data, key, encrypted) 做 256 位 AES 加密,返回值 result<=0 代表失败,此时用 GetLastError 打印具体错误码再 return。加密成功后再对 encrypted 跑一次 CRYPT_HASH_SHA256 得到 hash,用于接收端校验完整性。 为了走邮件传输,encrypted 和 hash 都要过 CRYPT_BASE64 编码,再用 CharArrayToString(..., WHOLE_ARRAY, CP_UTF8) 转回字符串。邮件正文把两段 Base64 拼起来,主题写 "Encrypted Trading Signal",最后 SendMail 发出;返回 false 时同样打印错误码。 在 MT5 里跑这段前,必须先在 工具→选项→邮件 里配好 SMTP 账号,否则 SendMail 永远返回 false,错误码通常是 4014 或 4015。外汇与贵金属信号传输涉及账户隐私,走加密邮件可降低泄露概率,但邮件通道本身不保证时效,高风险品种信号延迟可能直接影响成交。
else { Print("Failed to load the encryption key. Error: ", GetLastError()); class="kw">return; } class=class="str">"cmt">// Convert the signal to a byte array StringToCharArray(signal, data, class="num">0, StringLen(signal), CP_UTF8); class=class="str">"cmt">// Encrypt the signal class="type">int result = CryptEncode(CRYPT_AES256, data, key, encrypted); if(result <= class="num">0) { Print("Encryption failed. Error code: ", GetLastError()); class="kw">return; } class=class="str">"cmt">// Compute the hash of the encrypted signal result = CryptEncode(CRYPT_HASH_SHA256, encrypted, nullKey, hash); if(result <= class="num">0) { Print("Hashing failed. Error code: ", GetLastError()); class="kw">return; } class=class="str">"cmt">// Convert encrypted data and hash to Base64 for email transmission class="type">uchar base64Encrypted[], base64Hash[]; CryptEncode(CRYPT_BASE64, encrypted, nullKey, base64Encrypted); CryptEncode(CRYPT_BASE64, hash, nullKey, base64Hash); class="type">class="kw">string base64EncryptedStr = CharArrayToString(base64Encrypted, class="num">0, WHOLE_ARRAY, CP_UTF8); class="type">class="kw">string base64HashStr = CharArrayToString(base64Hash, class="num">0, WHOLE_ARRAY, CP_UTF8); class=class="str">"cmt">// Prepare the email content class="type">class="kw">string emailSubject = "Encrypted Trading Signal"; class="type">class="kw">string emailBody = "Encrypted Signal(Base64):\n" + base64EncryptedStr + "\n\nHash(SHA256, Base64):\n" + base64HashStr; class=class="str">"cmt">// Send the email(Assuming email settings are configured in MetaTrader) class="type">bool emailSent = SendMail(emailSubject, emailBody); if(emailSent) { Print("Email sent successfully."); } else { Print("Failed to send email. Error code: ", GetLastError()); } }
邮件信号的完整性校验与解密链路
从邮件拿到 Base64 编码的加密信号和哈希后,第一步不是急着解密,而是先验证数据没被篡改。代码里用 32 字节的本地密钥文件 encryption_key.bin 做 AES-256 解密准备,但在这之前必须先对加密字节流算一次 SHA-256,和邮件附带的哈希比对。
CryptEncode(CRYPT_HASH_SHA256, ...) 返回的字节数若 ≤0 说明哈希失败,此时直接退出;若 ArrayCompare 不相等则打印「Signal integrity compromised!」,这步能挡掉大部分传输中被中间人动过手脚的包。外汇与贵金属信号经公网邮件流转,这类校验不是可选项,而是降低误单概率的硬前置。
校验通过后才有资格 CryptDecode(CRYPT_AES256, encrypted, key, decrypted),解密结果用 CharArrayToString 转回 UTF-8 字符串打印。整段逻辑跑通后,你能在 MT5 专家日志里直接看到明文交易信号,后续接下单逻辑即可。建议把密钥文件权限设为仅 MT5 终端可读,避免明文落盘风险。
class=class="str">"cmt">// Received Base64-encoded encrypted signal and hash from email class="type">class="kw">string base64EncryptedStr = "Received encrypted signal in Base64"; class="type">class="kw">string base64HashStr = "Received hash in Base64"; class="type">uchar key[class="num">32]; class="type">uchar encrypted[]; class="type">uchar hash[]; class="type">uchar computedHash[]; class="type">uchar decrypted[]; 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); } else { Print("Failed to load the encryption key. Error: ", GetLastError()); class="kw">return; } class=class="str">"cmt">// Convert Base64 strings back to byte arrays class="type">uchar base64Encrypted[], base64Hash[]; StringToCharArray(base64EncryptedStr, base64Encrypted, class="num">0, WHOLE_ARRAY, CP_UTF8); StringToCharArray(base64HashStr, base64Hash, class="num">0, WHOLE_ARRAY, CP_UTF8); class=class="str">"cmt">// Decode Base64 to get encrypted data and hash CryptDecode(CRYPT_BASE64, base64Encrypted, nullKey, encrypted); CryptDecode(CRYPT_BASE64, base64Hash, nullKey, hash); class=class="str">"cmt">// Compute hash of the encrypted data class="type">int result = CryptEncode(CRYPT_HASH_SHA256, encrypted, nullKey, computedHash); if(result <= class="num">0) { Print("Hashing failed. Error code: ", GetLastError()); class="kw">return; } class=class="str">"cmt">// Compare the computed hash with the received hash if(ArrayCompare(hash, computedHash) != class="num">0) { Print("Signal integrity compromised!"); class="kw">return; } else { Print("Signal integrity verified."); } class=class="str">"cmt">// Decrypt the signal result = CryptDecode(CRYPT_AES256, encrypted, key, decrypted); if(result <= class="num">0) { Print("Decryption failed. Error code: ", GetLastError()); class="kw">return; } class=class="str">"cmt">// Convert decrypted data back to class="type">class="kw">string class="type">class="kw">string signal = CharArrayToString(decrypted, class="num">0, result, CP_UTF8); Print("Decrypted Trading Signal:\n", signal); class=class="str">"cmt">// Now you can act upon the trading signal }
「MQL5 密码学落地的几条硬规矩」
密钥别写死在代码里。硬编码字符串一进 exe 就能被逆向提取,正确做法是放加密文件或运行时从安全源拉取;用 CSecureZeroMemory 清残留也只是辅助,核心还是减少明文驻留时间。 动态密钥要在运行时由 CryptGenRandom 一类安全随机源生成,并设定更换周期。实测长期不换密钥的 EA,一旦分发版本泄露,历史通信全部可解密,更换频率建议按会话或按天。 组合拳比单加密更稳:先压缩再加密能缩小体积并增加混淆层;加密完再对密文算一次哈希,解密侧比对哈希可发现传输中被篡改。下面这段演示了密文哈希校验的基本顺序。
class="type">int enc_len = EncryptData(plain, key, cipher); class="type">uchar hash[class="num">32]; CryptSHA256(cipher, enc_len, hash); class=class="str">"cmt">// 对密文做摘要 class=class="str">"cmt">// 传输 cipher + hash class=class="str">"cmt">// 接收端重新 CryptSHA256 比对
class="type">int enc_len = EncryptData(plain, key, cipher); class="type">uchar hash[class="num">32]; CryptSHA256(cipher, enc_len, hash); class=class="str">"cmt">// 对密文做摘要 class=class="str">"cmt">// 传输 cipher + hash class=class="str">"cmt">// 接收端重新 CryptSHA256 比对
◍ 把这条线请下神坛
把密码学接进 MQL5 程序,本质只是给交易算法加了一道数据转换与访问控制的工序,不是点金术。用 CryptEncode/CryptDecode 做敏感参数加密、用独立 KeyGenerator 管密钥,能降低策略被扒和被篡改的概率,但外汇与贵金属本身高杠杆、高波动,加密层挡不住行情风险。 文中给的 Example1-Encrypt.mq5 到 SignalSender.mq5 共 8 个文件,体积都在 1.2–2.66 KB,说明这套实现很轻量,开 MT5 直接挂上就能跑通收发与解密链路。 真要把它用起来,别神话「安全即优势」——密钥泄露或编码误用,照样让保护形同虚设。开发者更该盯的是每次部署后密钥轮换和本地存储边界。