- Обзор доступных методов преобразования информации
- Шифрование, хэширование и упаковка данных: CryptEncode
- Дешифрование и распаковка данных: CryptDecode
Дешифрование и распаковка данных: CryptDecode
Для выполнения операций дешифрования и распаковки данных в MQL5 предусмотрена функция CryptDecode.
Функция CryptDecode производит обратное преобразование данных массива data в приемный массив result, используя указанный метод.
int CryptDecode(ENUM_CRYPT_METHOD method, const uchar &data[], const uchar &key[], uchar &result[])
Обратите внимание, что получение хэш-сумм, выполняемое, в частности, функцией CryptEncode, является односторонним преобразованием: из хэшей нельзя восстановить исходные данные.
Функция возвращает количество байтов, помещенных в массив-приемник или 0 в случае ошибки. Код ошибки попадет в _LastError. Это может быть, например, INVALID_PARAMETER (4003), если пытаться декодировать хэш (method равен одной из CRYPT_HASH-констант) или INVALID_ARRAY (4006), если ключ дешифрования недостаточной длины или отсутствует.
Если ключ неправильный (отличается от того, который использовался при шифровке), получим абракадабру в результате вместо закодированных исходных данных, но код ошибки при этом — нулевой. Это штатное поведение функции.
Проверим работу CryptDecode с помощью одноименного скрипта CryptDecode.mq5.
Во входных параметрах можно указать текст или файл для преобразования. Текст всегда подразумевается в кодировке Base64, так как все закодированные данные имеют двоичный формат и не поддерживаются в input-ах. Метод преобразования выбирается в списке Method.
input string Text; // Text (base64, or empty to process File)
|
Для методов шифрования необходим ключ, который можно ввести как строку в поле CustomKey, если GenerateKey содержит опцию DUMMY_KEY_CUSTOM, или сгенерировать демо-ключ требуемой длины из перечисления DUMMY_KEY_LENGTH (оно такое же, как в скрипте CryptEncode.mq5).
input DUMMY_KEY_LENGTH GenerateKey = DUMMY_KEY_CUSTOM; // GenerateKey (длина, или из CustomKey)
|
В GenerateKey и CustomKey нужно выбирать те же значения, что и при запуске CryptEncode.mq5.
Алгоритм в OnStart начинается с описания требуемых массивов и получения ключа из строки или путем незатейливой генерации (только для демо, для генерации рабочего криптостойкого ключа используйте специальный софт или алгоритмы).
void OnStart()
|
Далее мы считываем содержимое файла или декодируем Base64 из поля Text (в зависимости от того, что заполнено), чтобы получить данные для обработки.
method = (ENUM_CRYPT_METHOD)Method;
|
Если пользователь пытается восстановить данные из хэша, выдаем предупреждение, что ничего не получится.
if(IS_HASH(method))
|
Наконец, выполняем непосредственно расшифровку или распаковку. В случае текста полученный результат просто выводится в журнал. В случае файла мы добавляем к имени расширение ".dec" и записываем новый файл: его можно будет сравнить с исходным, который обрабатывался скриптом CryptEncode.mq5.
ResetLastError();
|
Если запустить скрипт с настройками по умолчанию, он попытается раскодировать файл MQL5Book/clock10.htm.BASE64. Предполагается, что такой был создан в ходе экспериментов в предыдущем разделе, поэтому процесс должен пройти успешно.
- CRYPT_BASE64, key required: false
|
Полученный файл clock10.htm.BASE64.dec полностью совпадает с исходным clock10.htm. То же самое должно произойти, если расшифровывать файлы с расширениями AES128, AES256, DES, при условии, что вы укажете тот же ключ, что и при шифровании.
Для наглядности проверим дешифровку текста. Так, шифрование известной фразы методом AES128 выдало нам ранее двоичный результат, превращенный для удобства в такую Base64-строку.
AQuvVCoSy1szaN8Owy8tQxl9rIrRj9hOqK7KgYYGh9E= |
Введем её в поле Text, а в выпадающем списке Method выберем AES128. Увидим в журнале следующее.
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 |
Сообщение успешно расшифровано.
Если при том же входном тексте выбрать генерацию произвольного ключа (хоть и достаточной длины), вместо сообщения получится тарабарщина.
Key (bytes): [00] 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 0A | 0B | 0C | 0D | 0E | 0F | - 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: ��� �L�� ��J Q+�]�v�9�����n?N�Ű |
Аналогично поведет себя программа и если перепутать метод шифрования.
Выбирать методы "расхэширования" не имеет смысла — INVALID_PARAMETER (4003).
- CRYPT_HASH_MD5, key required: false
|
А вот попытка выполнить распаковку (CRYPT_ARCH_ZIP) того, что не является упакованным блоком "deflate", приведет к INTERNAL_ERROR (4001). Такую же ошибку можно получить, если включить опцию пропуска CRC для "архива" без неё или, наоборот, разжимать данные без опции, хотя упаковка делалась с ней.