208 lines
7.2 KiB
MQL5
208 lines
7.2 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| CryptDecode.mq5 |
|
|
//| Copyright 2022, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2022, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
#property description "Use CryptDecode to restore protected data from given cipher, using different methods."
|
|
#property script_show_inputs
|
|
|
|
#include "..\..\Include\PRTF.mqh"
|
|
#include "..\..\Include\EnumToArray.mqh"
|
|
#include "..\..\Include\ArrayUtils.mqh"
|
|
|
|
#define KEY_REQUIRED(C) ((C) == CRYPT_DES || (C) == CRYPT_AES128 || (C) == CRYPT_AES256)
|
|
#define IS_HASH(C) ((C) == CRYPT_HASH_MD5 || (C) == CRYPT_HASH_SHA1 || (C) == CRYPT_HASH_SHA256)
|
|
|
|
enum ENUM_CRYPT_METHOD_EXT
|
|
{
|
|
_CRYPT_DES = CRYPT_DES, // DES
|
|
_CRYPT_AES128 = CRYPT_AES128, // AES128
|
|
_CRYPT_AES256 = CRYPT_AES256, // AES256
|
|
_CRYPT_HASH_MD5 = CRYPT_HASH_MD5, // MD5 (irreversible)
|
|
_CRYPT_HASH_SHA1 = CRYPT_HASH_SHA1, // SHA1 (irreversible)
|
|
_CRYPT_HASH_SHA256 = CRYPT_HASH_SHA256, // SHA256 (irreversible)
|
|
_CRYPT_ARCH_ZIP = CRYPT_ARCH_ZIP, // ZIP
|
|
_CRYPT_BASE64 = CRYPT_BASE64, // BASE64
|
|
};
|
|
|
|
enum DUMMY_KEY_LENGTH
|
|
{
|
|
DUMMY_KEY_0 = 0, // 0 bytes (no key)
|
|
DUMMY_KEY_7 = 7, // 7 bytes (sufficient for DES)
|
|
DUMMY_KEY_16 = 16, // 16 bytes (sufficient for AES128)
|
|
DUMMY_KEY_32 = 32, // 32 bytes (sufficient for AES256)
|
|
DUMMY_KEY_CUSTOM, // use CustomKey
|
|
};
|
|
|
|
input string Text; // Text (base64, or empty to process File)
|
|
input string File = "MQL5Book/clock10.htm.BASE64";
|
|
input ENUM_CRYPT_METHOD_EXT Method = _CRYPT_BASE64;
|
|
input DUMMY_KEY_LENGTH GenerateKey = DUMMY_KEY_CUSTOM; // GenerateKey (length, or take from CustomKey)
|
|
input string CustomKey = "My top secret key is very strong"; // CustomKey
|
|
input bool DisableCRCinZIP = false;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Script program start function |
|
|
//+------------------------------------------------------------------+
|
|
void OnStart()
|
|
{
|
|
ENUM_CRYPT_METHOD method = 0;
|
|
int methods[];
|
|
uchar key[] = {}; // key is empty by default: ok for zip, base64
|
|
uchar data[], result[];
|
|
uchar zip[], opt[] = {1, 0, 0, 0};
|
|
|
|
if(!StringLen(Text) && !StringLen(File))
|
|
{
|
|
Alert("Please specify either Text or File to decode");
|
|
return;
|
|
}
|
|
|
|
if(GenerateKey == DUMMY_KEY_CUSTOM)
|
|
{
|
|
if(StringLen(CustomKey))
|
|
{
|
|
PRTF(CustomKey);
|
|
StringToCharArray(CustomKey, key, 0, -1, CP_UTF8);
|
|
ArrayResize(key, ArraySize(key) - 1);
|
|
}
|
|
}
|
|
else if(GenerateKey != DUMMY_KEY_0)
|
|
{
|
|
// normally the key should be a secret, hard to guess, random selected token,
|
|
// here we generate it in straightforward manner for your easy testing
|
|
ArrayResize(key, GenerateKey);
|
|
for(int i = 0; i < GenerateKey; ++i) key[i] = (uchar)i;
|
|
}
|
|
|
|
if(ArraySize(key))
|
|
{
|
|
Print("Key (bytes):");
|
|
ByteArrayPrint(key);
|
|
}
|
|
else
|
|
{
|
|
Print("Key is not provided");
|
|
}
|
|
|
|
method = (ENUM_CRYPT_METHOD)Method;
|
|
Print("- ", EnumToString(method), ", key required: ", KEY_REQUIRED(method));
|
|
|
|
if(StringLen(Text))
|
|
{
|
|
if(method != CRYPT_BASE64)
|
|
{
|
|
// Since all methods except for Base64 produce binary results,
|
|
// it was additionally converted to Base64 in CryptEncode.mq5,
|
|
// hence we need to restore binary data from text input
|
|
// before deciphering it
|
|
uchar base64[];
|
|
const uchar dummy[] = {};
|
|
PRTF(Text);
|
|
PRTF(StringToCharArray(Text, base64, 0, -1, CP_UTF8));
|
|
ArrayResize(base64, ArraySize(base64) - 1);
|
|
Print("Text (bytes):");
|
|
ByteArrayPrint(base64);
|
|
if(!PRTF(CryptDecode(CRYPT_BASE64, base64, dummy, data)))
|
|
{
|
|
return; // error
|
|
}
|
|
|
|
Print("Raw data to decipher (after de-base64):");
|
|
ByteArrayPrint(data);
|
|
}
|
|
else
|
|
{
|
|
PRTF(StringToCharArray(Text, data, 0, -1, CP_UTF8));
|
|
ArrayResize(data, ArraySize(data) - 1);
|
|
}
|
|
}
|
|
else if(StringLen(File))
|
|
{
|
|
PRTF(File);
|
|
if(PRTF(FileLoad(File, data)) <= 0)
|
|
{
|
|
return; // error
|
|
}
|
|
}
|
|
|
|
if(IS_HASH(method))
|
|
{
|
|
Print("WARNING: hashes can not be used to restore data! CryptDecode will fail.");
|
|
}
|
|
|
|
if(method == CRYPT_ARCH_ZIP)
|
|
{
|
|
// a special key is supported for CRYPT_ARCH_ZIP:
|
|
// at least 4 bytes with 1-st '1' is used to disable specific to MQL5
|
|
// Adler32 checksum embedding into the compressed data,
|
|
// needed for compatibility with some standards such as ZIP archives
|
|
if(DisableCRCinZIP)
|
|
{
|
|
ArrayCopy(zip, opt); // make dynamic copy of array (dynamic needed for ArraySwap)
|
|
}
|
|
ArraySwap(key, zip); // substitute the key with empty or optional
|
|
}
|
|
|
|
ResetLastError();
|
|
if(PRTF(CryptDecode(method, data, key, result)))
|
|
{
|
|
if(StringLen(Text))
|
|
{
|
|
Print("Text restored:");
|
|
Print(CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8));
|
|
}
|
|
else // File
|
|
{
|
|
const string filename = File + ".dec";
|
|
if(PRTF(FileSave(filename, result)))
|
|
{
|
|
Print("File saved: ", filename);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
/*
|
|
|
|
- CRYPT_BASE64, key required: false
|
|
File=MQL5Book/clock10.htm.BASE64 / ok
|
|
FileLoad(File,data)=1320 / ok
|
|
CryptDecode(method,data,key,result)=988 / ok
|
|
FileSave(filename,result)=true / ok
|
|
File saved: MQL5Book/clock10.htm.BASE64.dec
|
|
|
|
...
|
|
|
|
CustomKey=My top secret key is very strong / ok
|
|
Key (bytes):
|
|
[00] 4D | 79 | 20 | 74 | 6F | 70 | 20 | 73 | 65 | 63 | 72 | 65 | 74 | 20 | 6B | 65 |
|
|
[16] 79 | 20 | 69 | 73 | 20 | 76 | 65 | 72 | 79 | 20 | 73 | 74 | 72 | 6F | 6E | 67 |
|
|
- CRYPT_AES128, key required: true
|
|
Text=AQuvVCoSy1szaN8Owy8tQxl9rIrRj9hOqK7KgYYGh9E= / ok
|
|
StringToCharArray(Text,base64,0,-1,CP_UTF8)=44 / ok
|
|
Text (bytes):
|
|
[00] 41 | 51 | 75 | 76 | 56 | 43 | 6F | 53 | 79 | 31 | 73 | 7A | 61 | 4E | 38 | 4F |
|
|
[16] 77 | 79 | 38 | 74 | 51 | 78 | 6C | 39 | 72 | 49 | 72 | 52 | 6A | 39 | 68 | 4F |
|
|
[32] 71 | 4B | 37 | 4B | 67 | 59 | 59 | 47 | 68 | 39 | 45 | 3D |
|
|
CryptDecode(CRYPT_BASE64,base64,dummy,data)=32 / ok
|
|
Raw data to decipher (after de-base64):
|
|
[00] 01 | 0B | AF | 54 | 2A | 12 | CB | 5B | 33 | 68 | DF | 0E | C3 | 2F | 2D | 43 |
|
|
[16] 19 | 7D | AC | 8A | D1 | 8F | D8 | 4E | A8 | AE | CA | 81 | 86 | 06 | 87 | D1 |
|
|
CryptDecode(method,data,key,result)=32 / ok
|
|
Text restored:
|
|
Let's encrypt this message
|
|
|
|
...
|
|
|
|
- CRYPT_HASH_MD5, key required: false
|
|
File=MQL5Book/clock10.htm.MD5 / ok
|
|
FileLoad(File,data)=16 / ok
|
|
WARNING: hashes can not be used to restore data! CryptDecode will fail.
|
|
CryptDecode(method,data,key,result)=0 / INVALID_PARAMETER(4003)
|
|
|
|
*/
|
|
//+------------------------------------------------------------------+
|