欢迎访问 外汇EA下载与MT4/MT5自动交易资源 - 聚合外汇EA、黄金EA、量化交易工具与自动化交易实战内容。
登录 注册

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

author emer | 313 人阅读 | 0 人评论 |

RSA Library for asymmetric encryption in MQL5 - library for 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:

RSA Library for asymmetric encryption in MQL5 - library for MetaTrader 5

混合加密工作流程一般遵循以下步骤:

在 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;i0;// 在 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

🔐
请登录后参与评论
注册满12小时后评论,即可解锁附件下载
立即登录