MQL5 中用于非对称加密的 RSA 库 - MetaTrader 5 库

原始 RSA 实现:
这个简单的示例演示了如何实现 RSA 加密。首先,创建 RSA 类的实例,然后将消息(要加密的数据)准备为 uchar[],其中每个元素都是一个字节。最后,调用EncryptPKCS1v15(plain,cipher)进行加密。结果作为 char 数组存储在 cipherData[] 中:
//+------------------------------------------------------------------+ //| RSA_Implementation.mq5 | //| Vahid Irak,SiavashNourmohammadi | //| https://www.mql5.com | //+------------------------------------------------------------------+ #财产版权 “瓦希德·伊拉克,西亚瓦什·努尔穆罕默迪” #财产关联 “https://www.mql5.com” #财产版本 “1.00” #包括//+------------------------------------------------------------------+ //|专家初始化函数 | //+------------------------------------------------------------------+ 整数 初始化时() { MQL5_RSA RSA; //公钥由模数和指数组成 细绳模数Hex =”f5746ac76303ef6b74ed9f6914c8f848d55ade9b16d0014d021c12fb1b0f8a63 b6409b15b887735b9f08d1e2b96c331b7793b4bcae04e94187e8a08e813251bc edaedd597a14bed263bbe7e0f6406e9d8dad526bc8aecf879afe2eb4fa1d88d707c48e9675b5d3fdb5fea2473b00dccb7b5066c8bed8515fd6f389b9f7f02c5f";// 你的十六进制模数 整数指数=65537; /* 公钥和私钥的原始格式相当于上面的十六进制格式密钥。 -----开始公钥----- MIGFMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1dGrHYwPva3Ttn2kUyPhI1Vre mxbQAU0CHBL7Gw+KY7ZAmxW4h3NbnwjR4rlsMxt3k7S8rgTpQYfooI6BMlG87a7d WXoUvtJju+fg9kBunY2tUmvIrs+Hmv4utPodiNcHxI6WdbXT/bX+okc7ANzLe1Bm yL7YUV/W84m59/AsXwIDAQAB -----结束公钥----- -----开始 RSA 私钥----- MIICXAIBAAKBgQD1dGrHYwPva3Ttn2kUyPhI1VremxbQAU0CHBL7Gw+KY7ZAmxW4 h3NbnwjR4rlsMxt3k7S8rgTpQYfooI6BMlG87a7dWXoUvtJju+fg9kBunY2tUmvI rs+Hmv4utPodiNcHxI6WdbXT/bX+okc7ANzLe1BmyL7YUV/W84m59/AsXwIDAQAB AoGAT5slMmtbkF/SeWq1Aue3FrATm5TDDk0Ns7x1L3l0TdbO+h8SKVnMwQ9QJfoZ Vw0wQFToTjVGJHx7XqgL77zpIvF9TJMsb5sASMJeeuGK1W6zGfkL70DWPEhNzOVf K8bBezdDt0DWaGpOH5f59vYgtmKbnL/fWb+wQoVAXYQDLZECQQD8IcOZs7OrsCIs grHBzuW8plJmHxd1fIiOcDSA4jAr2daeZ0tg8UhMY4nQVLOEBtYtBTGmbrt9ZLEE 1gsWA13HAkEA+ThtzNGVPrw4Zg58r2Hgo2xvjZKnUHSM0Ktr+ZynHDM17wQOxN7V zeJvKHp5ITs4Sr2iq6DA1XGpUayUCN6cqQJBANGVC2/fddGYhr+zICm3XzbSlpn2 7Fwn2ad1WUahvmMlIAbqXDlIN83vy+YWEmcD+9LOh3gOgeF6RKI6UFrLD48CQHE8 9JcF+7w/pZipqHnADWP0F1PKeP+TlZAS88K9LSkhE7aAr31AiwE7i6pmy7cPw2oi dFFrf3L8bCTSN7h5TdECQGoF6kvT209ImVT8PbBAXs9mE+/9P3nKaE/3kuo7AJBr +tDPu9bXxfjFl/bgxBJv37bavVviT4x06eO/kwxpOkk= -----结束 RSA 私钥-- */ rsa.Init(modulusHex, 指数); 细绳纯文本 =“你好,RSA!”; 乌查尔普通数据[]; 字符串转字符数组(纯文本、纯数据、0,字符串长度(纯文本)); 乌查尔密码数据[]; 如果(rsa.EncryptPKCS1v15(plainData, cipherData)) { 细绳base64Cipher = rsa.Base64Encode(cipherData); 打印(“加密:”,base64密码); } 别的 { 打印(“加密失败!”); } 返回(初始化成功); }
加密结果打印到控制台。由于填充行为,此结果每次都会改变
细绳密文=“Y9k1Qjxnh/IiQZeeGkf+8Og5iU6OQh8JUVUpc9E4bZTlGHRZPc/xqFUQxE8vTjQRMuB3hNoaT5GLmv7VabwZoR iplAbBR+KiD5bfLQ+CvqTe1W8g4C+7aLTurj0LY6pjiuyZKnM8wYolxRKBkXVMs8gy12TbD8gcH//1rZhrHdo=";
在实际项目中使用RSA + AES:

混合加密工作流程一般遵循以下步骤:
在 MQL5 的背景下,该策略允许开发人员确保 EA 交易、指标和外部服务器之间的通信安全,即使在使用标准 HTTP 或套接字连接时也是如此。本文中实现的 RSA 类可用于加密 AES 密钥,而内置 MQL5 函数 CryptEncode() 和 CryptDecode() 则处理实际消息的 AES 加密和解密。
这在 MetaTrader 5 内部实现了完全独立的安全层,有效地创建了“HTTPS over HTTP”的轻量级版本。它可用于保护敏感数据,例如交易命令、身份验证凭据或配置消息,而无需依赖外部加密库或 DLL。
步骤1—服务器生成RSA公钥:
使用 Python、Java、OpenSSL 或任何后端环境生成模数(十六进制字符串)、指数(通常为 65537)和私钥(保存在服务器端)。
EA 将仅使用公共值。不要将私钥暴露给客户端。
模数Hex =“A1B2C3……”; 指数 =65537;
步骤2— EA 创建 RSA 实例并加载密钥:
#包括<RSA.mqh>
MQL5_RSA RSA;
rsa.Init(modulusHex, 指数); 步骤3— EA 准备请求消息:
示例有效负载可以是包含以下内容的登录请求:EA ID、帐号和时间戳。 为您的请求创建正确的 JSON 字符串。您可以使用任何第三方库来制作 JSON 字符串。下面的代码片段演示了预期的 JSON 字符串应是什么样子:
细绳json = "{\"cmd\":\"登录\"," “\“帐户\”:”+整数转字符串(账户信息整数(帐户登录)) +“,” “\”ts\“:”+整数转字符串((整数)时间当前()) + “,” “}”;乌查尔清楚的[];字符串转字符数组(json,普通,0,字符串长度(json));
步骤4— EA 使用 RSA 加密 AES 会话密钥:
用于会话其余部分的 AES 密钥:
乌查尔aesKey[]; 生成 AESKey(aesKey); // 16 个随机字节 (AES-128) 乌查尔加密的Aes[]; rsa.EncryptPKCS1v15(aesKey,加密的Aes);细绳加密的AesBase64 = rsa.Base64Encode(加密的Aes);步骤5— EA 使用 AES 加密实际数据:
乌查尔加密的有效负载[];加密编码(CRYPT_AES128、普通、aesKey、加密Payload);细绳PayloadBase64 = CryptBase64Encode(加密的Payload);
步骤6—EA 将所有内容发送到服务器:
细绳身体= “{\“钥匙\”:\””+ 加密AesBase64 +“\”、“ +“\“数据\”:\””+ 有效负载Base64 +“\”}”;细绳结果;字符标题[];整数状态=网络请求(“邮政”、网址、标题、5000、主体、结果);
步骤7— 服务器端解密(概念):
在服务器上,首先对 RSA 加密的 AES 密钥执行 Base64 解码,然后使用 RSA 私钥解密 AES 密钥。 一旦 AES 密钥被恢复,它就可以用来解密数据负载。由于 AES 密钥是为每个会话随机生成的,因此即使攻击者拦截了流量,每条消息仍然是唯一且安全的。该机制有效地建立了安全会话,类似于简化的 HTTPS 隧道。
步骤8— 客户端解密服务器响应:
乌查尔响应密码[]; CryptBase64Decode(结果,responseCipher);乌查尔响应平原[];密码解码(CRYPT_AES128、responseCipher、aesKey、responsePlain);细绳服务器回复 =字符数组转字符串(响应简单);打印(“服务器回复:”,服务器回复);
通过遵循这些步骤,可以在 MetaTrader 5 环境中直接实施现实世界的加密技术,从而为最终用户提供可靠且完全可移植的解决方案。你可以阅读本文获取有关 RSA 加密系统的更多信息。
这是 RSA 类源代码。您还可以使用该库进行大整数算术。
//+------------------------------------------------------------------+ //| RSA.mqh | //| 版权所有 2025,MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #财产版权 “版权所有 2025,MetaQuotes Ltd.” #财产关联 “https://www.mql5.com” // MQL5_RSA_fixed.mq5 // 修复并记录了纯 MQL5 RSA 实现(加密 PKCS#1 v1.5) // TL;DR:最初的逻辑错误是在 HexToBytes 中(它附加了字符代码,而不是十六进制字符) // 并且模例程非常慢(重复单次减法)。我修复了 HexToBytes, // 添加了字节移位长除法样式 Mod 实现,为 RNG 填充种子, // 并进行了小的稳健性改进。 /* 计划/伪代码: 1. 初始化 - 将十六进制模数字符串正确转换为字节数组 - 标准化(删除前导零) - 存储指数 2. PKCS#1 v1.5 填充 - 检查最大长度 - 构建 EM:0x00 || 0x02 || PS(非零随机字节)|| 0x00 ||中号 - 在构造函数中种子 RNG 一次 3. 大整数助手(大端字节数组) - 标准化:去除前导零 - 比较:比较长度,然后按字典顺序比较 - SubtractInPlace:a = a - b(假设 a >= b),大端序 - LeftShiftBytes:按整个字节移位(在末尾附加零) - 乘法:教科书、大端 - MulMod:模乘然后减少 - Mod:通过移动除数以与余数对齐并减去倍数来实现长除法(对于适度的密钥大小来说足够快) 4. ModExp:使用 MulMod 进行快速求幂 5. Base64编码助手(逻辑不变) 正确性注意事项: - 数组是大尾数法:索引 0 = 最高有效字节 - 函数通过在需要时进行复制来避免对外部数组的破坏性更改 - RNG 使用 MathSrand 进行播种,以实现不可预测的填充 */ #财产严格的 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 班级MQL5_RSA {私人的: 乌查尔 模数[];// 模数 (n),大端字节序 整数 指数; // 公共指数 (e) 布尔值 调试模式;民众: MQL5_RSA(布尔值调试=错误的) { 调试模式=调试; // 为 RNG 播种一次 数学兰德((整数)时间本地()); } 空白 初始化(细绳模数十六进制,整数e) { 数组调整大小(模数,0); 如果(调试模式) 打印格式(“初始化:模数十六进制长度=%d,e=%d”,字符串长度(模量十六进制), e); HexToBytes(modulusHex, 模数);// 固定转换 归一化(模数); 指数 = e; 如果(调试模式) 打印格式(“初始化完成:模数字节=%d”,数组大小(模数)); } 布尔值 加密PKCS1v15(乌查尔&清楚的[],乌查尔&密码[]) { 整数k =数组大小(模数); 整数姆伦=数组大小(清楚的); 如果(调试模式) 打印格式(“加密:密钥字节=%d,明文=%d,最大值=%d”, k, 姆伦, k-11); 如果(姆伦 > k -11) { 如果(调试模式) 打印(“错误:数据对于密钥来说太大”); 返回 错误的; } // 构建EM 乌查尔em[]; 数组调整大小(em,k); 数组初始化(他们,0); 嗯[0] =0x00; 嗯[1] =0x02; 整数psLen = k - mlen -3; 为了(整数我=0;i乌查尔b=0; // 确保填充字节非零 做 { 乙 = (乌查尔)(数学兰德()%256); } 尽管(b==0); 嗯[2+i] = b; } 嗯[2+psLen] =0x00; // 将消息复制到 em 的位置 3+psLen 处 数组复制(em,简单,3+psLen,0,姆伦); 如果(调试模式) 打印(“EM 构建”); // 模幂 乌查尔c大[]; 如果(!ModExp(em, 指数, 模数, cBig)) { 如果(调试模式) 打印(“ModExp 失败”); 返回 错误的; } // 确保密文长度与模数长度匹配(前导零) 整数克伦=数组大小(c大); 数组调整大小(密码,k); 如果(克伦 < k) { // 零填充 数组初始化(密码,0); 数组复制(密码、cBig、k-clen、0,克伦); } 别的 { 数组复制(密码,cBig); } 如果(调试模式) 打印(“加密完成”); 返回 真的; } 细绳 Base64编码(乌查尔&数据[]) { 细绳字符=“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/”; 整数长度=数组大小(数据); 细绳输出 =””; 为了(整数我=0;i<长度;i+=3) { 整数b0 = 数据[i]; 整数b1 = (i+1< 长度)?数据[i+1]:0; 整数b2 = (i+2< 长度)?数据[i+2]:0; 整数值 = (b0 <<16) | (b1 <<8) | b2; 输出 +=字符串子串(字符,(值>>18) &0x3F,1); 输出 +=字符串子串(字符,(值>>12) &0x3F,1); 输出 += (i+1< 长度)?字符串子串(字符,(值>>6) &0x3F,1):”=; 输出 += (i+2< 长度)?字符串子串(字符、值和0x3F,1):”=; } 返回出去; }私人的: // --- 助手 --- // 正确的 HexToBytes:仅保留十六进制字符并转换对 -> 字节 // 转换单个十六进制字符 → 半字节 (0-15) 整数十六进制半字节(超短c) { 如果(c >=‘0’&& c <=‘9’)返回(整数)(c-‘0’); 如果(c >='一个'&& c <='F')返回(整数)(c-'一个'+10); 如果(c >='一个'&& c <='f')返回(整数)(c-'一个'+10); 返回 0; }// MQL5 的正确 HexToBytes 空白十六进制转字节(细绳十六进制,乌查尔&出去[]) { 细绳干净=””; 整数L =字符串长度(十六进制); // 只保留十六进制字符 为了(整数我=0;我 < L;我++) { 超短c =字符串获取字符(十六进制,i); 如果((c >=‘0’&& c <=‘9’) || (c >='一个'&& c <='F') || (c >='一个'&& c <='f')) 干净+=字符串子串(十六进制,我,1); } // 确保长度均匀 如果(字符串长度(干净的) %2==1) 干净=“0”+ 干净; 整数n =字符串长度(干净的) /2; 数组调整大小(出,n); 为了(整数我=0;我 超短c1 =字符串获取字符(干净,我*2); 超短c2 =字符串获取字符(干净,我*2+1); 整数高 = HexNibble(c1); 整数低 = HexNibble(c2); 输出[i] = (乌查尔)((高<<4) |低的); } } 空白 标准化(乌查尔&a[]) { 整数尺寸=数组大小(一个); 整数领先 =0; 尽管(前导 < 大小 && a[前导] ==0) 领先++; 如果(领先==0) 返回; 整数newSize = 大小 - 行距; 如果(新大小 <=0) { 数组调整大小(一个,0); 返回; } 乌查尔温度[]; 数组调整大小(临时,新大小); 数组复制(温度,a,0、前导、新大小); 数组调整大小(a,新大小); 数组复制(a,温度); } 整数 比较(常量 乌查尔&a_in[],常量 乌查尔&垃圾桶[]) { // 非破坏性比较 乌查尔一个[]; 数组复制(a,a_in); 乌查尔b[]; 数组复制(b,b_in); 标准化(a); 标准化(b); 整数纳=数组大小(a), nb =数组大小(二); 如果(na>nb) 返回 1; 如果(na < nb) 返回-1; 为了(整数我=0;i 如果(a[i] > b[i]) 返回 1; 如果(a[i] < b[i]) 返回-1; } 返回 0; } 空白 原地减去(乌查尔&一个[],常量 乌查尔&b[]) { // 假设 a >= b;大端数组 整数纳=数组大小(一个); 整数NB =数组大小(二); 整数借=0; 为了(整数我=0;i 整数艾 = (整数)a[na-1-我]; 整数bi = (i < nb) ? (整数)b[nb-1-我] :0; 整数diff = ai - bi - 借用; 如果(差异 <0) { 差异 +=256; 借=1; } 别的 借=0; 一个[na-1-i] = (乌查尔)差异; } 标准化(a); } 空白 左移字节(常量 乌查尔&在[],整数移位字节,乌查尔&出去[]) { 整数n =数组大小(在); 如果(n==0||移位字节==0) { 数组复制(出、入); 返回; } 数组调整大小(输出,n + 移位字节); 为了(整数我=0;i 为了(整数i=n;i 0;// 在 LSB 端追加零 } 空白 乘(常量 乌查尔&一个[],常量 乌查尔&b[],乌查尔&结果[]) { 整数纳=数组大小(一个); 整数NB =数组大小(二); 如果(呐==0||注意==0) { 数组调整大小(结果,0); 返回; } 整数nRes = na + nb; 整数温度[]; 数组调整大小(温度,nRes); 数组初始化(温度,0); 为了(整数我=na-1;我>=0;我 - ) { 整数携带=0; 为了(整数j=nb-1;j>=0;j--) { 整数产品 = (整数)人工智能] * (整数)b[j] + 温度[i+j+1] + 进位; 温度[i+j+1] = 产品%256; 进位=产品/256; } temp[i] += 进位; } 数组调整大小(结果,nRes); 为了(整数我=0;i 乌查尔)温度[i]; 标准化(结果); } // 使用长除法对大整数取模(快速) 布尔值模(常量 乌查尔&a_in[],常量 乌查尔&m_in[],乌查尔&结果[]) { 如果(数组大小(m_in) ==0)返回 错误的; // 标准化输入 乌查尔股利[];数组复制(股息,a_in);标准化(股息); 乌查尔模数[]; 数组复制(modv,m_in); 标准化(modv); 如果(比较(股息,modv)<0) { 数组复制(业绩、股息); 返回 真的; } 整数米=数组大小(股利); // 工作余数 乌查尔雷姆[]; 数组调整大小(雷姆,0); 为了(整数我=0;我<米;我++) { // rem 左移 1 个字节并添加下一个被除数字节 整数长度 =数组大小(雷姆); 数组调整大小(rem, rlen +1); rem[rlen] = 股息[i]; 归一化(rem); // 减去模数,而余数 >= 模数 尽管(比较(rem,modv)> =0) { 就地减去(rem,modv); } } 归一化(rem); 数组复制(结果,雷姆); 返回 真的; }布尔值多模(常量 乌查尔&一个[],常量 乌查尔&b[],常量 乌查尔&m[],乌查尔&出去[]) { 乌查尔产品[]; 乘(a,b,乘积); // 标准教科书乘法 返回Mod(产品,m,输出); } 布尔值 模数表达式(常量 乌查尔&根据[],整数 经验值,常量 乌查尔&modn[],乌查尔&结果[]) { 如果(调试模式) 打印格式(“ModExp:exp=%d”,经验值); 乌查尔基复制[]; 数组复制(基础复制,基础); 规范化(baseCopy); // 减少基模 modn 如果(比较(baseCopy, modn) >=0) { 如果(!Mod(baseCopy, modn, baseCopy)) 返回 错误的; } 乌查尔资源[]; 数组调整大小(资源,1); 资源[0] =1; 标准化(res); 乌查尔基数Pow[]; 数组复制(basePow,baseCopy); 整数e =经验值; 尽管(e>0) { 如果((e &1) ==1) { 乌查尔tmp[]; 如果(!MulMod(res, basePow, modn, tmp)) 返回 错误的; 数组复制(资源,tmp); } e>>=1; 如果(e>0) { 乌查尔tmp2[]; 如果(!MulMod(basePow, basePow, modn, tmp2)) 返回 错误的; 数组复制(basePow, tmp2); } } 标准化(res); 数组复制(结果,资源); 返回 真的; } };/* 使用注意事项: - 创建实例:MQL5_RSA rsa(true); rsa.Init("<十六进制模数>", 65537); - 将明文准备为 uchar[],其中每个元素都是一个字节。 - 调用 EncryptPKCS1v15(明文、密码)。 */ // 用法示例: /* 无效 OnStart() { MQL5_RSA RSA; 字符串 modulusHex = "A1B2C3D4E5F6..."; // 你的十六进制模数 int 指数 = 65537; rsa.Init(modulusHex, 指数); string plainText = "你好 RSA!"; uchar plainData[]; StringToCharArray(plainText, plainData, 0, StringLen(plainText)); uchar 密码数据[]; if(rsa.EncryptPKCS1v15(plainData, cipherData)) { 字符串base64Cipher = rsa.Base64Encode(cipherData); Print("加密:", base64Cipher); } 否则 { Print("加密失败!"); } } */ //+------------------------------------------------------------------+
附件下载
📎 RSA.mqh (24.79 KB)
📎 RSA_Implementation.mq5 (5.04 KB)
Source: MQL5 #66671
💡 精彩内容推荐
✍️ 楼主最新发布
- •
- •
- •
- •
- •
- •
🔗 您可能感兴趣
- •
- •
- •
- •
- •
- •
