- 可用信息变换方法概述
- 加密、哈希和数据打包: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 中。例如,如果我们尝试解码哈希(method 等于 CRYPT_HASH 常量之一),则可能是 INVALID_PARAMETER (4003);如果解密密钥长度不足或缺失,则可能是 INVALID_ARRAY (4006)。
如果密钥不正确(与加密时使用的密钥不同),我们将得到乱码而不是编码的源数据,但错误代码为零。这是函数的正常行为。
我们使用相同的脚本 CryptDecode.mq5 来检查 CryptDecode 的工作。
在输入参数中,你可以指定要转换的文本或文件。文本始终隐含为 Base64 编码,因为所有编码后的数据都是二进制格式,并且 input 参数中不支持。转换方法从 Method 列表中选择。
input string Text; // Text (base64, or empty to process File)
|
如果 GenerateKey 包含 DUMMY_KEY_CUSTOM 选项,则加密方法需要一个密钥,该密钥可以在 CustomKey 字段中指定为字符串。你还可以从 DUMMY_KEY_LENGTH 枚举(与 CryptEncode.mq5 脚本中的相同)生成所需长度的演示密钥。
input DUMMY_KEY_LENGTH GenerateKey = DUMMY_KEY_CUSTOM; // GenerateKey (length, or from CustomKey)
|
在 GenerateKey 和 CustomKey 中,你应选择与启动 CryptEncode.mq5 时相同的值。
OnStart 中的算法首先描述所需的数组,并从字符串获取密钥或通过简单生成(仅用于演示,应使用专用软件或算法生成可工作的抗加密密钥)。
void OnStart()
|
接下来,我们读取文件内容或从 Text 字段解码 Base64(取决于填充了哪个字段)以获取要处理的数据。
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 的“存档”启用了跳过 CRC 选项,或者相反,在没有该选项的情况下解压缩数据,尽管打包时使用了该选项,也可能得到同样的错误。