Welcome Forex EA downloads & MT4/MT5 auto-trading resources — EAs, Gold EAs, quant tools and real-world automation.
Sign In Sign Up

RSA Library for Asymmetric Encryption in MQL5 - MetaTrader 5 Library - MT4/MT5 Resources

author EAcpu | 3 reads | 0 comments |

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

Original RSA implementation:

This simple example demonstrates how to implement RSA encryption. First, create an instance of the RSA class, then prepare the message (the data to be encrypted) as a uchar[], where each element is a byte. Finally, EncryptPKCS1v15 (plain, cipher) is called for encryption. The results are stored in cipherData[] as a char array:

 //+------------------------------------------------------------------+
//| RSA_Implementation.mq5 |
//| Vahid Irak, SiavashNourmohammadi |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#Property Copyright "Wahid Iraq, Siavash Nur Mohammadi"
#Property association "https://www.mql5.com"
# Property version "1.00"
#include //+------------------------------------------------------------------+
//|Expert initialization function |
//+------------------------------------------------------------------+
Integer initialization ()
  {

  MQL5_RSA RSA;
//The public key consists of a modulus and an exponentStringModulusHex =  f5746ac76303ef6b74ed9f6914c8f848d55ade9b16d0014d021c12fb1b0f8a63 b6409b15b887735b9f08d1e2b96c331b7793b4bcae04e94187e8a08e813251bc edaedd597a14bed263bbe7e0f6406e9d8dad526bc8aecf879afe2eb4fa1d88d707c48e9675b5d3fdb5fea2473b00dccb7b5066c8bed8515fd6f389b9f7f02c5f" ; // your hexadecimal modulusintegerindex= 65537 ;

/* The original format of the public and private keys is equivalent to the hexadecimal format key above. 
  
   -----Start Public Key-----
MIGFMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1dGrHYwPva3Ttn2kUyPhI1Vre
mxbQAU0CHBL7Gw+KY7ZAmxW4h3NbnwjR4rlsMxt3k7S8rgTpQYfooI6BMlG87a7d
WXoUvtJju+fg9kBunY2tUmvIrs+Hmv4utPodiNcHxI6WdbXT/bX+okc7ANzLe1Bm
yL7YUV/W84m59/AsXwIDAQAB
-----End Public Key-----
  
  
    -----Start RSA private key-----
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=
-----End RSA private key--
  
   */  
   rsa.Init(modulusHex, index);

stringplaintext = "Hello, RSA!" ;
Uchar general data[];
String to character array (plain text, pure data, 0 , string length (plain text));

Uchar password data[];
if (rsa.EncryptPKCS1v15(plainData, cipherData))
  {
String base64Cipher = rsa.Base64Encode(cipherData);
print ( "Encrypted:" , base64 password);
  }
other {
print ( "Encryption failed!" );
  }

Return ( initialization successful );
  }

The encryption results are printed to the console. This result will change every time due to padding behavior

Thin string secret text = "Y9k1Qjxnh/IiQZeeGkf+8Og5iU6OQh8JUVUpc9E4bZTlGHRZPc/xqFUQxE8vTjQRMuB3hNoaT5GLmv7VabwZoR iplAbBR+KiD5bfLQ+CvqTe1W8g4C+7aLTurj0LY6pjiuyZKnM8wYolxRKBkXVMs8gy12TbD8gcH//1rZhrHdo=" ;



Using RSA+AES in a real project:

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

The hybrid encryption workflow generally follows these steps:

In the context of MQL5, this strategy allows developers to secure communications between Expert Advisors, indicators and external servers, even when using standard HTTP or socket connections. The RSA class implemented in this article can be used to encrypt AES keys, while the built-in MQL5 functions CryptEncode() and CryptDecode() handle AES encryption and decryption of actual messages.

This implements a completely separate security layer within MetaTrader 5, effectively creating a lightweight version of "HTTPS over HTTP". It can be used to protect sensitive data such as transaction commands, authentication credentials, or configuration messages without relying on external cryptographic libraries or DLLs.

Step 1 — Server generates RSA public key:

Generate the modulus (hex string), exponent (usually 65537), and private key (saved on the server side) using Python, Java, OpenSSL, or any backend environment.

The EA will only use public values. Do not expose private keys to clients .

 Modulus Hex = “A1B2C3……” ;
index = 65537 ;

Step 2 — EA creates RSA instance and loads key:

 #includes < RSA.mqh > 

 MQL5_RSA RSA; 
 rsa.Init(modulusHex, index);

Step 3 — EA prepares request message:

An example payload could be a login request containing: EA ID, account number, and timestamp. Create the correct JSON string for your request. You can use any third-party library to make JSON strings. The following code snippet demonstrates what the expected JSON string should look like:

 String json =
"{\"cmd\":\"Login\"," " \"Account\":" + Integer to string ( account information integer ( account login )) + "," "\"ts\":" + Integer to string (( integer ) time current ()) + ","
"}" ; Uchar clear []; string to character array (json, normal, 0 , string length (json));

Step 4 — The EA encrypts the AES session key using RSA:

AES key used for the rest of the session:

 UcharaesKey [];
Generate AESKey(aesKey); // 16 random bytes (AES-128)
Uchar encrypted Aes[];
rsa.EncryptPKCS1v15(aesKey, encrypted Aes); string encrypted AesBase64 = rsa.Base64Encode(encrypted Aes);
Step 5 — The EA encrypts the actual data using AES:
 Uchar encrypted payload[]; encryption encoding ( CRYPT_AES128 , normal, aesKey, encrypted Payload); string PayloadBase64 = CryptBase64Encode (encrypted Payload);

Step 6 —The EA sends everything to the server:

 string body =
"{\"key\":\"" + encrypted AesBase64 + "\"," + "\"data\":\"" + payload Base64 + "\"}" ; string result; character headers[]; integer status = networkRequest ( "post" , url, header, 5000 , body, result);

Step 7 — Server Side Decryption (Concept):

On the server, the RSA-encrypted AES key is first Base64 decoded, and then the AES key is decrypted using the RSA private key. Once the AES key is recovered, it can be used to decrypt the data payload. Because AES keys are randomly generated for each session, even if an attacker intercepts the traffic, each message remains unique and secure. This mechanism effectively establishes a secure session, similar to a simplified HTTPS tunnel.

Step 8 — Client decrypts server response:

 Uchar response password[];
CryptBase64Decode(result, responseCipher); urchar response plain[]; cipher decode ( CRYPT_AES128 , responseCipher, aesKey, responsePlain); string server reply = character array to string (response simple); print ( "server reply:" , server reply);

By following these steps, real-world cryptography can be implemented directly within the MetaTrader 5 environment, providing end users with a reliable and fully portable solution. You can read this article to get more information about the RSA encryption system.

This is the RSA class source code. You can also use this library for large integer arithmetic.

//+------------------------------------------------------------------+
//| RSA.mqh |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#Property Copyright "Copyright 2025, MetaQuotes Ltd."
#Property association "https://www.mql5.com"

// MQL5_RSA_fixed.mq5
// Fixed and documented pure MQL5 RSA implementation (encrypted PKCS#1 v1.5)
// TL;DR: The original logic error was in HexToBytes (it appended character codes instead of hex characters)
// And the modular routine is very slow (repeating a single subtraction). I fixed HexToBytes,
//Added byte shift long division style Mod implementation to fill the seed for RNG,
// and made small robustness improvements.

/*
Plan/pseudocode:
1. Initialization - Correct conversion of hex modulus string to byte array - Normalization (remove leading zeros)
  - Storage index 2. PKCS#1 v1.5 padding - Check max length - Build EM: 0x00 || 0x02 || PS (non-zero random bytes) || 0x00 || M - Seed RNG once in constructor 3. Big integer helper (big-endian byte array)
  - Normalize: remove leading zeros - Compare: compare lengths, then compare lexicographically - SubtractInPlace: a = a - b (assuming a >= b), big-endian - LeftShiftBytes: shift by whole byte (append zeroes at the end)
  - Multiplication: textbook, big endian - MulMod: modular multiplication then reduction - Mod: long division by moving the divisor to align with the remainder and subtracting the multiple (fast enough for modest key sizes)
4. ModExp: Use MulMod for fast exponentiation 5. Base64 encoding assistant (logic unchanged)

Correctness Notes:
- Arrays are big-endian: index 0 = most significant byte - Functions avoid destructive changes to outer arrays by making copies when needed - RNGs are seeded using MathSrand for unpredictable filling */

#propertystrict

//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Class MQL5_RSA
  { Private :
uchal modulus[]; // modulus(n), big-endian integer exponent ; // public exponent(e) boolean debug mode; public :
                    MQL5_RSA( boolean debug= false )
    {
      debugmode = debug;
// Seed the RNG once math rand (( integer ) timelocal ());
    }

blank initialize( string modulo hexadecimal, integer e)
    {
arrayResize (modulo, 0 );
if (debug mode)
Print format ( "Initialization: modulus hexadecimal length = %d, e = %d" , string length (modulus hexadecimal), e);
      HexToBytes(modulusHex, modulus); // Fixed conversion normalization (modulus);
      index = e;
if (debug mode)
Print format ( "Initialization completed: modulo byte = %d" , array size (modulo));
    }

Boolean Encryption PKCS1v15( uchal &clear[], uchal &cipher[])
    {
Integer k = array size (modulo);
integer mulen = array_size (clear);

if (debug mode)
Print format ( "Encryption: Key bytes=%d, plaintext=%d, maximum value=%d" , k, mlen, k- 11 );

if (mulun>k- 11 )
        {
if (debug mode)
print ( "Error: data too large for key" );
return false ;
        }

//Construct EM Uchar em[];
arrayresize (em,k);
arrayInit (them, 0 );
um[ 0 ] = 0x00 ; um[ 1 ] = 0x02 ; integer psLen = k - mlen - 3 ; for ( integer i = 0 ; i uchal b = 0 ; // Make sure the padding bytes are non-zero do { b = ( wchar )( math rand ()% 256 ); } although (b== 0 ); um[ 2 +i] = b; } um[ 2 +psLen] = 0x00 ; // Copy the message to em at position 3+psLen array copy (em, simple, 3 +psLen, 0 , mlen); if (debug mode) print ( "em build" ); // modulo exponent cbig[]; if (!ModExp(em, exponent, modulus, cBig)) { if (debug mode) print ( "ModExp failed" ); return false ; } // Make sure the ciphertext length matches the modulus length (leading zeros) integer clen = array size (cbig); array resize (password, k); if (clen < k) { // zero-padded array initialization (password, 0 ); array copy (password, cbig, k-clen, 0 , clen); } else { array copy (password, cbig); } if (debug mode) print ( "Encryption Completed" ); return true ; } string Base64 encoding( urchar &data[]) { string char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; integer length = array size (data); string output = "" ; for ( integer i = 0 ; i<length; i+= 3 ) { integer b0 = data[i]; integer b1 = (i+ 1 < length)? Data[i+ 1 ]: 0 ; integer b2 = (i+ 2 < length)? data[i+ 2 ]: 0 ; integer value = (b0 << 16 ) | (b1 << 8 ) | b2; output += string substring (character, (value >> 18 ) & 0x3F , 1 ); output += string substring (character, (value >> 12 ) & 0x3F , 1 ); output += (i+ 1 < length)? String substring (char, (value >> 6 ) & 0x3F , 1 ): ”= ; output += (i+ 2 < length)? String substring (char, value >> 0x3F , 1 ): ”= ; } return out; } private : // --- Helper --- // Proper HexToBytes: keep only hex characters and convert pairs -> bytes // Convert single hex character → nibble (0-15) to integer hex nibble ( ultra short c) {class="keyword">If (c >= '0' && c <= '9' ) return ( integer )(c- '0' ); if (c >= 'a' && c <= 'F' ) return ( integer )(c- 'a' + 10 ); if (c >= 'a' && c <= 'f' ) return ( integer )(c- 'a' + 10 ); return 0 ; } // Correct HexToBytes for MQL5 whitespace hex to bytes( string hex, urchar & out[]) { string clean = ''" ; integer L = string length (hex); // keep only hex characters for ( integer i = 0 ; i < L; i++) { super short c = string get character (hex, i); if ((c >= '0' && c <= '9' ) || (c >= 'a' && c <= 'F' ) || (c >= 'a' && c <= 'f' )) clean += string substring (hex, i, 1 ); } // Ensure uniform length if ( string length (clean) % 2 == 1 ) clean = "0" + clean; integer n = string length (clean) / 2 ; array resize (out, n); for ( integer i = 0 ;I supershort c1 = string getchars (clean,i* 2 ); supershort c2 = string getchars (clean,i* 2 + 1 ); integer high = HexNibble(c1); integer low = HexNibble(c2); output[i] = ( Uchar )((High<< 4 ) | Low); } } whitespace normalize( Uchar &a[]) { int size = array_size (a); int leading = 0 ; although (leading < size && a[leading] == 0 ) leading++; if (leading == 0 ) return ; integer newSize = size - leading; if (newSize <= 0 ) { array resize (a, 0 ); return ; } urchar temp[]; array resize (temporary, new size); array copy (temperature, a, 0 , leading, new size); array resize (a, new size); array copy (a, temp); } integer compare( const urchar &a_in[], const urchar &trash[]) { // non-destructive comparison uchal a[]; array copy (a, a_in); uchal b[]; array copy (b, b_in); normalize(a); normalize(b); integer na = array size (a), nb = array size (b); if (na > nb) return 1 ; if (na < nb) return - 1 ; for ( integer i = 0 ;i if (a[i] > b[i]) return - 1 ; if (a[i] < b[i]) return - 1 ; } return 0 ; } blank in-place subtraction ( wchar &a[], const wchar &b[]) { // Assume a >= b; big-endian array integer na = array size (one); integer nb = array size (two); integer borrow = 0 ; for ( integer i = 0 ; i integer ai = ( integer )a[na- 1 -i]; integer bi = (i < nb) ? ( integer )b[nb- 1 -i] : 0 ; integer diff = ai - bi - borrow; if (diff < 0 ) { diff + = 256 ; borrow = 1 ; } else borrow = 0 ; a[na- 1 -i] = ( Uchar ) difference; } normalize(a); } blank left shift bytes( const uchar &in[], int shiftbytes, uchar &out[]) { integer n = array size (in); if (n == 0 || shiftbytes == 0 ) { array copy (out, in); return ; } array resize (out, n + shiftbytes); for ( integer i = 0 ; i for ( integer i=n;i  0; //append zeros at LSB end } blank multiplier( const uchal &a[], const uchal &b[], uchal &result[]) { integer na = array size (one); integer nb = array size (two); if (na == 0 || note == 0 ) { array resize (result, 0 ); return ; } integer nRes = na + nb; integer temperature[]; array resize (temperature, nRes); array init (temperature, 0 ); for ( integer i = na- 1 ; i >= 0 ; i-) { integer carry = 0 ; for ( integer j = nb- 1 ; j>= 0 ; j--) { integer product = ( integer ) ai] * ( integer )b[j] + temperature[i+j+ 1 ] + carry; temp[i+j+ 1 ] = product % 256 ; carry = product/ 256 ; } temp[i] += carry; } array resize (result, nRes); for/span> ( integer i = 0 ;i  uchal) temperature[i]; normalize(result); } // Use long division to take modulo a large integer (fast) boolean modulo ( const uchal &a_in[], const uchal &m_in[], uchal &result[]) { if ( array size (m_in) == 0 ) return false ; // normalize input uchal div []; array copy (dividend, a_in); normalize(dividend); uchal modulo[]; array copy (modv, m_in); normalize(modv); if (compare(dividend, modv) < 0 ) { array copy (dividend, modv); return true ; } integer m = array size (dividend); // working remainder uchal rem []; array resize (rem, 0 ) ); for ( integer i = 0 ; i < m; i++) { // rem left shift 1 byte and add next dividend byte integer length = array size (rem); array resize (rem, rlen + 1 ); rem[rlen] = dividend[i]; normalize(rem); // subtract modulus while remainder >= modulo although (compare (rem, modv) >= 0 ) { subtract in place(rem, modv); } } normalize(rem); array copy (result, rem); return true ; } boolean multimod( const uchal &a[], const uchal &b[], const uchal &m[], uchal &out[]) { uchal product[]; multiply(a, b, product); // Standard textbook multiplication returns Mod(product, m, output); } Boolean modulo expression( const uchal &base[], integer exp , const uchal &modn[], uchal &result[]) { if (debug mode) print format ( "ModExp: exp=%d" , emp ); uchal base copy[]; array copy (basecopy, base); normalize(baseCopy); // reduce base modn if (compare(baseCopy, modn) >= 0 ) { if (!Mod(baseCopy, modn, baseCopy)) returns false ; } uchal resources[]; array resize (resource, 1 ); resources[ 0 ] = 1 ; normalize(res); uchal base Pow[]; array copy (basePow, baseCopy); integer e = em ; although (e > 0 ) { if ((e & 1 ) == 1 ) { Uchar tmp[]; if (!MulMod(res, basePow, modn, tmp)) returns error ; array copy (resource, tmp); } e>>= 1 ; if (e> 0 ) { Uchar tmp2[]; if (!MulMod(basePow, basePow, modn, tmp2)) returns wrong ; array copy (basePow, tmp2); } } normalize(res); array copy (result, resource); return true ; } }; /* Usage notes: - Create an instance: MQL5_RSA rsa(true); rsa.Init("<hexadecimal modulus>", 65537); - Prepare the plaintext as uchar[], where each element is a byte. - Call EncryptPKCS1v15 (plain text, password). */ // Usage example: /* Invalid OnStart() { MQL5_RSA RSA; string modulusHex = "A1B2C3D4E5F6..."; // Your hexadecimal modulus int exponent = 65537; rsa.Init(modulusHex, exponent); string plainText = "Hello RSA!"; uchar plainData[]; StringToCharArray(plainText, plainData, 0, StringLen(plainText)); uchar password data[]; if(rsa.EncryptPKCS1v15(plainData, cipherData)) { String base64Cipher = rsa.Base64Encode(cipherData); Print("Encryption:", base64Cipher); } otherwise { Print("Encryption failed!"); } } */ //+--------------------------------------------------------------------------------+



Attachment download

📎RSA.mqh (24.79 KB)

📎RSA_Implementation.mq5 (5.04 KB)

Source: MQL5 #66671

Verification code Refresh