//+------------------------------------------------------------------+ //| Encrypt.mqh | //| Copyright 2026, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd." #property link "https://www.mql5.com" #property strict #ifndef MQLARTICLES_UTILS_ENCRYPT_ENCRYPT_MQH #define MQLARTICLES_UTILS_ENCRYPT_ENCRYPT_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "..\\Basic.mqh" #include "..\\RandomSimple.mqh" #include "..\\File\\File.mqh" /* 2026.03.26 17:37:44.570 Test (EURUSD,H1) CRYPT_BASE64 = 0 2026.03.26 17:37:44.570 Test (EURUSD,H1) CRYPT_AES128 = 1 2026.03.26 17:37:44.570 Test (EURUSD,H1) CRYPT_AES256 = 2 2026.03.26 17:37:44.570 Test (EURUSD,H1) CRYPT_DES = 3 2026.03.26 17:37:44.570 Test (EURUSD,H1) CRYPT_HASH_SHA1 = 4 2026.03.26 17:37:44.570 Test (EURUSD,H1) CRYPT_HASH_SHA256 = 5 2026.03.26 17:37:44.570 Test (EURUSD,H1) CRYPT_HASH_MD5 = 6 2026.03.26 17:37:44.570 Test (EURUSD,H1) CRYPT_ARCH_ZIP = 7 */ //--- const uint8_t g_mqlarticles_entryptor_key_len[3] = { 16, // CRYPT_AES128 32, // CRYPT_AES256 7 // CRYPT_DES }; //--- const bool g_mqlarticles_entryptor_is_encrypther[8] = { false, true, true, true, false, false, false, false }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ typedef uchar(*FuncGenerateRandomUchar)(void* ptr, uchar start, uchar stop); uchar RandomSimpleGenerateRandomUchar(void* ptr, uchar start, uchar stop) { return (uchar)((CRandomSimple*)ptr).RandomShort(start, stop); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CEncryptor : public CLoggerBase { private: string m_key; public: CEncryptor(void) {} ~CEncryptor(void) {} //--- void Key(const string& key) { m_key = key; } __forceinline string Key() const { return m_key; } //--- bool SetAleatoryKey(ENUM_CRYPT_METHOD method, FuncGenerateRandomUchar f_generate_char, void* ptr = NULL, uchar chart_start = 32, uchar chart_stop = 255); //--- bool EncryptFile(const string& file_name, bool common_flag, ENUM_CRYPT_METHOD method, bool delete_prev_file, string ext_encrypt = ""); bool DecryptFile(const string& file_name, bool common_flag, ENUM_CRYPT_METHOD method, bool delete_prev_file, string ext_decrypt = ""); bool DecryptFile(const string& file_name, bool common_flag, ENUM_CRYPT_METHOD method, bool delete_prev_file, uchar& res_data[]); __forceinline bool DecryptFile(const string& file_name, bool common_flag, ENUM_CRYPT_METHOD method, bool delete_prev_file, string& res_data, int start, int count = WHOLE_ARRAY, uint codepage = CP_ACP); //--- bool EncryptText(const string& initial_text, ENUM_CRYPT_METHOD method, string& encrypted_text); bool DecryptText(const string& encrypted_text, ENUM_CRYPT_METHOD method, string& decrypted_text); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CEncryptor::SetAleatoryKey(ENUM_CRYPT_METHOD method, FuncGenerateRandomUchar f_generate_char, void* ptr = NULL, uchar chart_start = 32, uchar chart_stop = 255) { //--- if(!g_mqlarticles_entryptor_is_encrypther[method]) { LogError(StringFormat("El metodo de encrypt = %s, no es de encryptacion de archivos", EnumToString(method)), FUNCION_ACTUAL); return false; } //--- const uint8_t clen = g_mqlarticles_entryptor_key_len[method - 1]; m_key.Truncate(clen); for(int i = 0; i < clen; i++) { m_key.SetChar(i, f_generate_char(ptr, chart_start, chart_stop)); } //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CEncryptor::EncryptFile(const string& file_name, bool common_flag, ENUM_CRYPT_METHOD method, bool delete_prev_file, string ext_encrypt = "") { //--- if(!g_mqlarticles_entryptor_is_encrypther[method]) { LogError(StringFormat("El metodo de encrypt = %s, no es de encryptacion de archivos", EnumToString(method)), FUNCION_ACTUAL); return false; } //--- const uint8_t clen = g_mqlarticles_entryptor_key_len[method - 1]; if(m_key.Length() != clen) { LogError(StringFormat("La clave debe de tener un len de %u chars, con el metodo = %s", clen, EnumToString(method)), FUNCION_ACTUAL); return false; } //--- ::ResetLastError(); const int common_file_flag = (common_flag ? FILE_COMMON : 0); int fh = FileOpen(file_name, FILE_BIN | FILE_READ | common_file_flag); if(fh == INVALID_HANDLE) { LogError(StringFormat("Fallo al abrir el archivo = %s, ultimo error =%d", file_name, ::GetLastError()), FUNCION_ACTUAL); return false; } //--- uchar data[]; FileReadArray(fh, data); FileClose(fh); //--- uchar key_chars[]; StringToCharArray(m_key, key_chars, 0, clen); //--- Encryptamos uchar res[]; ::ResetLastError(); if(CryptEncode(method, data, key_chars, res) == 0) { LogError(StringFormat("Fallo al encriptar el archivo %s a AES256, ultimo error = %d", file_name, ::GetLastError()), FUNCION_ACTUAL); return false; } //--- Creamos el archivo 2 (o sobreescribimos si ext = "") // Para la extension como minimo se requiere dos caracteres el punto y algo eg: .h minimo de lo contraio se considera que no se desea extension ::ResetLastError(); fh = FileOpen((file_name + (ext_encrypt.Length() > 2 ? ext_encrypt : "")), FILE_BIN | FILE_WRITE | common_file_flag); if(fh == INVALID_HANDLE) { LogError(StringFormat("Fallo al abrir el archivo = %s, ultimo error =%d", (file_name + ext_encrypt), ::GetLastError()), FUNCION_ACTUAL); return false; } FileWriteArray(fh, res); FileClose(fh); //--- Ahora si eliminamso el archivo previo si es que se pide ::ResetLastError(); if(delete_prev_file && !FileDelete(file_name, common_file_flag)) { LogWarning(StringFormat("Fallo al eliminar el archivo = %s, ultimo error = %d", file_name, ::GetLastError()), FUNCION_ACTUAL); } //--- return true; } //+------------------------------------------------------------------+ //| Desencripta un archivo | //| file_name : ruta del archivo encriptado | //| common_flag : true = carpeta Common, false = carpeta Files\ | //| method : metodo de encriptacion usado al encriptar | //| delete_prev_file: true = elimina el archivo encriptado original | //| ext_decrypt : controla el nombre del archivo de salida: | //| - "" = sobreescribe el mismo archivo | //| - ".ext" = agrega extension file.enc → file.enc.ext | //| - "-" = quita la ultima extension file.enc → file | //| - ".ext-" = reemplaza ultima ext file.enc → file.ext | //+------------------------------------------------------------------+ bool CEncryptor::DecryptFile(const string& file_name, bool common_flag, ENUM_CRYPT_METHOD method, bool delete_prev_file, string ext_decrypt = "") { //--- if(!g_mqlarticles_entryptor_is_encrypther[method]) { LogError(StringFormat("El metodo = %s, no es de encryptacion de archivos", EnumToString(method)), FUNCION_ACTUAL); return false; } //--- const uint8_t clen = g_mqlarticles_entryptor_key_len[method - 1]; if(m_key.Length() != clen) { LogError(StringFormat("La clave debe de tener un len de %u chars, con el metodo = %s", clen, EnumToString(method)), FUNCION_ACTUAL); return false; } //--- ::ResetLastError(); const int common_file_flag = (common_flag ? FILE_COMMON : 0); int fh = FileOpen(file_name, FILE_BIN | FILE_READ | common_file_flag); if(fh == INVALID_HANDLE) { LogError(StringFormat("Fallo al abrir el archivo = %s, ultimo error = %d", file_name, ::GetLastError()), FUNCION_ACTUAL); return false; } //--- uchar data[]; FileReadArray(fh, data); FileClose(fh); //--- uchar key_chars[]; StringToCharArray(m_key, key_chars, 0, clen); //--- Desencryptamos uchar res[]; ::ResetLastError(); if(CryptDecode(method, data, key_chars, res) == 0) { LogError(StringFormat("Fallo al desencriptar el archivo %s, ultimo error = %d", file_name, ::GetLastError()), FUNCION_ACTUAL); return false; } //--- Creamos el archivo destino (o sobreescribimos si ext = "") // si ext_decrypt contiene el . entonces es exntesion si no el nombre del archivo out string out_file_name = ""; if(StringFindCharWRef(ext_decrypt, '.')) { const uint len = (ext_decrypt.Length()); if(ext_decrypt[len - 1] == '-') // -. quiere decir elimina la extension previa y añade esta nueva { ext_decrypt.Truncate(len - 1); // quitamos el - final eg si tiewnmaos extdecurp como .txt- queda .txt out_file_name = FileRemoveExtension(file_name) + ext_decrypt; } else { out_file_name = file_name + ext_decrypt; } } else if(StringFindCharWRef(ext_decrypt, '-')) // quiere decir solo quita la extension que ya tenia { out_file_name = FileRemoveExtension(file_name); // Removes la primera extension (volvemos al extado original) } else { out_file_name = file_name; // lo mismo sobrescribe } // Abrimos el archivo res ::ResetLastError(); fh = FileOpen(out_file_name, FILE_BIN | FILE_WRITE | common_file_flag); if(fh == INVALID_HANDLE) { LogError(StringFormat("Fallo al abrir el archivo = %s, ultimo error = %d", out_file_name, ::GetLastError()), FUNCION_ACTUAL); return false; } FileWriteArray(fh, res); FileClose(fh); //--- Ahora si eliminamos el archivo previo si es que se pide ::ResetLastError(); if(delete_prev_file && !FileDelete(file_name, common_file_flag)) { LogWarning(StringFormat("Fallo al eliminar el archivo = %s, ultimo error = %d", file_name, ::GetLastError()), FUNCION_ACTUAL); } //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CEncryptor::DecryptFile(const string &file_name, bool common_flag, ENUM_CRYPT_METHOD method, bool delete_prev_file, uchar &res_data[]) { //--- if(!g_mqlarticles_entryptor_is_encrypther[method]) { LogError(StringFormat("El metodo = %s, no es de encryptacion de archivos", EnumToString(method)), FUNCION_ACTUAL); return false; } //--- const uint8_t clen = g_mqlarticles_entryptor_key_len[method - 1]; if(m_key.Length() != clen) { LogError(StringFormat("La clave debe de tener un len de %u chars, con el metodo = %s", clen, EnumToString(method)), FUNCION_ACTUAL); return false; } //--- ::ResetLastError(); const int common_file_flag = (common_flag ? FILE_COMMON : 0); int fh = FileOpen(file_name, FILE_BIN | FILE_READ | common_file_flag); if(fh == INVALID_HANDLE) { LogError(StringFormat("Fallo al abrir el archivo = %s, ultimo error = %d", file_name, ::GetLastError()), FUNCION_ACTUAL); return false; } //--- uchar data[]; FileReadArray(fh, data); FileClose(fh); //--- uchar key_chars[]; StringToCharArray(m_key, key_chars, 0, clen); //--- Desencryptamos ::ResetLastError(); if(CryptDecode(method, data, key_chars, res_data) == 0) // Los datos lo ponemos en el array uchar proporcionado { LogError(StringFormat("Fallo al desencriptar el archivo %s, ultimo error = %d", file_name, ::GetLastError()), FUNCION_ACTUAL); return false; } //--- Ahora si eliminamos el archivo previo si es que se pide ::ResetLastError(); if(delete_prev_file && !FileDelete(file_name, common_file_flag)) { LogWarning(StringFormat("Fallo al eliminar el archivo = %s, ultimo error = %d", file_name, ::GetLastError()), FUNCION_ACTUAL); } //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ __forceinline bool CEncryptor::DecryptFile(const string &file_name, bool common_flag, ENUM_CRYPT_METHOD method, bool delete_prev_file, string &res_data, int start, int count = WHOLE_ARRAY, uint codepage = CP_ACP) { uchar temp_data[]; if(!DecryptFile(file_name, common_flag, method, delete_prev_file, temp_data)) return false; //--- res_data = CharArrayToString(temp_data, start, count, codepage); //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CEncryptor::EncryptText(const string& initial_text, ENUM_CRYPT_METHOD method, string& encrypted_text) { //--- if(!g_mqlarticles_entryptor_is_encrypther[method]) { LogError(StringFormat("El metodo = %s no es de encryptacion", EnumToString(method)), FUNCION_ACTUAL); return false; } //--- const uint8_t clen = g_mqlarticles_entryptor_key_len[method - 1]; if(m_key.Length() != clen) { LogError(StringFormat("La clave debe de tener un len de %u chars, con el metodo = %s", clen, EnumToString(method)), FUNCION_ACTUAL); return false; } //--- Convertimos el texto a uchar uchar data[]; StringToCharArray(initial_text, data, 0, StringLen(initial_text)); //--- uchar key_chars[]; StringToCharArray(m_key, key_chars, 0, clen); //--- Encryptamos uchar res[]; ::ResetLastError(); if(CryptEncode(method, data, key_chars, res) == 0) { LogError(StringFormat("Fallo al encriptar el texto, ultimo error = %d", ::GetLastError()), FUNCION_ACTUAL); return false; } //--- Convertimos el resultado a BASE64 para poder guardarlo como string uchar base64[]; ::ResetLastError(); if(CryptEncode(CRYPT_BASE64, res, key_chars, base64) == 0) { LogError(StringFormat("Fallo al convertir a BASE64, ultimo error = %d", ::GetLastError()), FUNCION_ACTUAL); return false; } //--- encrypted_text = CharArrayToString(base64); return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CEncryptor::DecryptText(const string& encrypted_text, ENUM_CRYPT_METHOD method, string& decrypted_text) { //--- if(!g_mqlarticles_entryptor_is_encrypther[method]) { LogError(StringFormat("El metodo = %s no es de encryptacion", EnumToString(method)), FUNCION_ACTUAL); return false; } //--- const uint8_t clen = g_mqlarticles_entryptor_key_len[method - 1]; if(m_key.Length() != clen) { LogError(StringFormat("La clave debe de tener un len de %u chars, con el metodo = %s", clen, EnumToString(method)), FUNCION_ACTUAL); return false; } //--- Convertimos el string BASE64 a uchar uchar base64[]; StringToCharArray(encrypted_text, base64, 0, StringLen(encrypted_text)); //--- uchar key_chars[]; StringToCharArray(m_key, key_chars, 0, clen); //--- Decodificamos BASE64 primero uchar data[]; ::ResetLastError(); if(CryptDecode(CRYPT_BASE64, base64, key_chars, data) == 0) { LogError(StringFormat("Fallo al decodificar BASE64, ultimo error = %d", ::GetLastError()), FUNCION_ACTUAL); return false; } //--- Desencryptamos uchar res[]; ::ResetLastError(); if(CryptDecode(method, data, key_chars, res) == 0) { LogError(StringFormat("Fallo al desencriptar el texto, ultimo error = %d", ::GetLastError()), FUNCION_ACTUAL); return false; } //--- decrypted_text = CharArrayToString(res); return true; } //+------------------------------------------------------------------+ CEncryptor g_mqlarticles_encryptor; //+------------------------------------------------------------------+ #endif // MQLARTICLES_UTILS_ENCRYPT_ENCRYPT_MQH