CryptEncode() - ciphers not matching with others Libraries

To add comments, please log in or register
Romeu Bertho
4871
Romeu Bertho  

I'm wondering if anyone tried some comparisons with CryptEncode() MQL5 function and Crypto Nodejs library and get the same encrypted cipher.

So far I´ve tried Crypto Nodejs with these methods:

  • des
  • des-cbc
  • des-ecb
  • aes256
  • aes-256-cbc
  • aes-256-cbc-hmac-sha1
  • aes-256-cfb
  • aes-256-cfb1
  • aes-256-cfb8
  • aes-256-ctr
  • aes-256-ecb
  • aes-256-gcm
  • aes-256-ofb
  • aes-256-xts

For CryptEncode() MQL5 function:

  • CRYPT_DES
  • CRYPT_AES256

None of this tests resulted in the same encrypted cipher for both CryptEncode() and Crypto Nodejs.

On the other hand, if you try SHA512+HMAC library example and then try with Crypto Nodejs, you get the same cipher.

MQL5 code for DES:

//+------------------------------------------------------------------+ 
//| ArrayToHex                                                       | 
//+------------------------------------------------------------------+ 
string ArrayToHex(uchar &arr[],int count=-1) 
  { 
   string res=""; 
//--- check 
   if(count<0 || count>ArraySize(arr)) 
      count=ArraySize(arr); 
//--- transform to HEX string 
   for(int i=0; i<count; i++) 
      res+=StringFormat("%.2X",arr[i]); 
//--- 
   return(res); 
  } 
//+------------------------------------------------------------------+ 
//| Script program start function                                    | 
//+------------------------------------------------------------------+ 
void OnStart() 
  { 
   string text="test"; 
   string keystr="ABCDEFG"; 
   uchar src[],dst[],key[]; 
//--- prepare key 
   StringToCharArray(keystr,key); 
//--- copy text to source array src[] 
   StringToCharArray(text,src); 
//--- print initial data 
   PrintFormat("Initial data: size=%d, string='%s'",ArraySize(src),CharArrayToString(src)); 
//--- encrypt src[] with DES 56-bit key in key[] 
   int res=CryptEncode(CRYPT_DES,src,key,dst); 
//--- check error 
   if(res>0) 
     { 
      //--- print encrypted data 
      PrintFormat("Encoded data: size=%d %s",res,ArrayToHex(dst)); 
      //--- decode dst[] to src[] 
      res=CryptDecode(CRYPT_DES,dst,key,src); 
      //--- check error      
      if(res>0) 
        { 
         //--- print decoded data 
         PrintFormat("Decoded data: size=%d, string='%s'",ArraySize(src),CharArrayToString(src)); 
        } 
      else 
         Print("Error in CryptDecode. Error code=",GetLastError()); 
     } 
   else 
      Print("Error in CryptEncode. Error code=",GetLastError()); 
  }


MQL5 code for AES256 using Bcrypt library:

#include <Bcrypt.mqh>

string txt="test";
Bcrypt B;
//+------------------------------------------------------------------+ 
//| Script program start function                                    | 
//+------------------------------------------------------------------+ 
void OnStart()
{
B.Init("ABCDEFG",NULL,txt);
Print("Bcrypt key = ",B.Encrypt());
Print("Bcrypt decoded data = ",B.Decrypt(B.Encrypt()));
}


Nodejs code for AES/DES:

const crypto = require('crypto');
const cipher = crypto.createCipher('des', 'ABCDEFG');

let encrypted = cipher.update('test', 'utf8', 'hex');
encrypted += cipher.final('hex');
console.log(encrypted);

Methods could be changed by swapping 'des' for the desired method listed above.


Nodejs code for SHA512+HMAC:

// generate a hash from string
    var crypto = require('crypto'),
        text = 'test',
        key = 'ABCDEFG'

    // create hash
    var hash = crypto.createHmac('sha512', key)
    hash.update(text)
    var value = hash.digest('hex')

    // print result
    console.log(value);

If someone wants to test nodejs code, it's possible to do it online at repl.it


Now I´m wondering if there is nothing wrong with CryptEncode() MQL5 function as the ciphers should be matched.


Any idea would be appreciated!

Best regards,

Romeu.

Alain Verleyen
36551
Alain Verleyen  
Romeu Bertho:

What are the outputs ?

EDIT: After checking, the problem seems to be your nodejs code is using a 'password' while mql5 is using a key.
Romeu Bertho
4871
Romeu Bertho  
Alain Verleyen:

What are the outputs ?

EDIT: After checking, the problem seems to be your nodejs code is using a 'password' while mql5 is using a key.


Hello Alain,

I will do more tests with it and try some other libs. But checking some documentation from Crypto nodejs we have:

crypto.createCipher(algorithm, password)

It says: "The password is used to derive the cipher key and initialization vector (IV). The value must be either a 'latin1' encoded string, a Buffer, a TypedArray, or a DataView"

and

crypto.createCipheriv(algorithm, key, iv)

The second one accepts a key and IV

What about CryptEncode() not using IV? Maybe it generates an IV itself? I really don't have this answer right now.

Key and IV are a common argument among other language libs for AES256.

I will do some tests with cryptojs and a C code for AES256.

Let's see what happens.


Thank you! 

Crypto | Node.js v8.4.0 Documentation
  • nodejs.org
The module provides cryptographic functionality that includes a set of wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign and verify functions. Use to access this module. Determining if crypto support is unavailable It is possible for Node.js to be built without including support for the module. In such cases, calling will result in an...
Alain Verleyen
36551
Alain Verleyen  
Romeu Bertho:


Hello Alain,

I will do more tests with it and try some other libs. But checking some documentation from Crypto nodejs we have:

crypto.createCipher(algorithm, password)

It says: "The password is used to derive the cipher key and initialization vector (IV). The value must be either a 'latin1' encoded string, a Buffer, a TypedArray, or a DataView"

and

crypto.createCipheriv(algorithm, key, iv)

The second one accepts a key and IV

What about CryptEncode() not using IV? Maybe it generates an IV itself? I really don't have this answer right now.

Key and IV are a common argument among other language libs for AES256.

I will do some tests with cryptojs and a C code for AES256.

Let's see what happens.


Thank you! 

CryptEncode() is using DES-ECB (from my tests as it's not documented) which doesn't require an IV. It requires a 7 bytes char array for the key (if it's less it returns an error, if it's more it will be truncated).
Gustavo Hennemann
266
Gustavo Hennemann  

Hi folks,

A litle late to answer, but...

I faced exactly the same problem, my application and my EA was not creating the same encrypted code, due to the lack of information, I made a big research (also try and error) and after a lot of effort I discovered the configuration used by MetaQuotes in the CryptEncode() and CryptDecode() functions.

My code is made in C#, but it is easy to read and understand.

Note 1: in AES-128 the key maximum size is 16 bytes, if the size is minor then 16, fill the remaining bytes with zeros;

Note 2: in DES the key maximum size is 8, if the size is minor then 8, fill the remaining bytes with zeros and the last byte must be zero too.

Note 3: in DES the size of the text must be multiple of 8 with the extra bytes filled by zero;


Configuration for AES-128 (C# code):

byte[] arrKey = Encoding.UTF8.GetBytes(key);
if (arrKey.Length != 16) Array.Resize(ref arrKey, 16);

using (Aes aesAlg = Aes.Create())
{
    aesAlg.Mode = CipherMode.ECB;
    aesAlg.Padding = PaddingMode.Zeros;
    aesAlg.BlockSize = 128;
    aesAlg.KeySize = 128;
    aesAlg.Key = arrKey;
    aesAlg.IV = new byte[16];


Configuration for DES (C# code):

// Encode and check message and password
byte[] arrText = Encoding.UTF8.GetBytes(originalString);
byte[] arrKey = Encoding.UTF8.GetBytes(keyString);

if (arrKey.Length != 8) Array.Resize(ref arrKey, 8);
arrKey[7] = 0;

if (arrText.Length % 8 == 0) Array.Resize(ref arrText, arrText.Length + 8);

// Set encryption settings
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
provider.Mode = CipherMode.ECB;
provider.Padding = PaddingMode.Zeros;
provider.BlockSize = 64;
provider.KeySize = 64;
provider.Key = arrKey;
provider.IV = new byte[8];


I expect this can help others.

Alain Verleyen
36551
Alain Verleyen  
Gustavo Hennemann:

Hi folks,

A litle late to answer, but...

I faced exactly the same problem, my application and my EA was not creating the same encrypted code, due to the lack of information, I made a big research (also try and error) and after a lot of effort I discovered the configuration used by MetaQuotes in the CryptEncode() and CryptDecode() functions.

My code is made in C#, but it is easy to read and understand.

Note 1: in AES-128 the key maximum size is 16 bytes, if the size is minor then 16, fill the remaining bytes with zeros;

Note 2: in DES the key maximum size is 8, if the size is minor then 8, fill the remaining bytes with zeros and the last byte must be zero too.

Note 3: in DES the size of the text must be multiple of 8 with the extra bytes filled by zero;


Configuration for AES-128 (C# code):


Configuration for DES (C# code):


I expect this can help others.

Thanks for sharing, can always be useful.
Romeu Bertho
4871
Romeu Bertho  
Gustavo Hennemann:

Hi folks,

A litle late to answer, but...

I faced exactly the same problem, my application and my EA was not creating the same encrypted code, due to the lack of information, I made a big research (also try and error) and after a lot of effort I discovered the configuration used by MetaQuotes in the CryptEncode() and CryptDecode() functions.

My code is made in C#, but it is easy to read and understand.

Note 1: in AES-128 the key maximum size is 16 bytes, if the size is minor then 16, fill the remaining bytes with zeros;

Note 2: in DES the key maximum size is 8, if the size is minor then 8, fill the remaining bytes with zeros and the last byte must be zero too.

Note 3: in DES the size of the text must be multiple of 8 with the extra bytes filled by zero;


Configuration for AES-128 (C# code):


Configuration for DES (C# code):


I expect this can help others.

Thanks for sharing it! :)

To add comments, please log in or register