如果此数据将包含在myfile.bin中进行十六进制解码,则可以使用发布的 OpenSSL 语句解密以下十六进制编码的密文:
53616C7465645F5F2DC4C4867D3B9268C82E23A672D6698FB51D41EA8601367A9112623EC27CDEB18FD1444BDB8D8DE16F1A35706EC7FED266CB909D28BF6BEC
解密将导致:
The quick brown fox jumps over the lazy dog
为简单起见,直接分配密文并跳过从文件中加载密文:
unsigned char data[] = {
0x53, 0x61, 0x6C, 0x74, 0x65, 0x64, 0x5F, 0x5F, // Salted__
0x2D, 0xC4, 0xC4, 0x86, 0x7D, 0x3B, 0x92, 0x68, // Salt
0xC8, 0x2E, 0x23, 0xA6, 0x72, 0xD6, 0x69, 0x8F, 0xB5, 0x1D, 0x41, 0xEA, 0x86, 0x01, 0x36, 0x7A, // Ciphertext...
0x91, 0x12, 0x62, 0x3E, 0xC2, 0x7C, 0xDE, 0xB1, 0x8F, 0xD1, 0x44, 0x4B, 0xDB, 0x8D, 0x8D, 0xE1,
0x6F, 0x1A, 0x35, 0x70, 0x6E, 0xC7, 0xFE, 0xD2, 0x66, 0xCB, 0x90, 0x9D, 0x28, 0xBF, 0x6B, 0xEC };
int dataLength = sizeof(data) / sizeof(unsigned char);
解密需要先将盐和密文分开,例如:
int ciphertextLength = dataLength - 16;
unsigned char* salt = (unsigned char*)malloc(sizeof(unsigned char) * 8);
unsigned char* ciphertext = (unsigned char*)malloc(sizeof(unsigned char) * ciphertextLength);
memcpy(salt, data + 8, 8); // Get 8 bytes salt (starts at index 8)
memcpy(ciphertext, data + 16, ciphertextLength); // Get ciphertext (starts at index 16)
下一步是派生密钥,请参阅PKCS5_PBKDF2_HMAC
,例如:
#define KEYSIZE 16
unsigned char key[KEYSIZE];
const char* password = "'Yumi'"; // The quotation marks (') in the openssl-statement are part of the password.
int passwordLen = strlen(password);
PKCS5_PBKDF2_HMAC(password, passwordLen, salt, 8, 1, EVP_sha1(), KEYSIZE, key);
最后可以执行解密,请参见此处和此处,例如:
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_rc2_ecb(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(ctx, KEYSIZE); // RC2 is an algorithm with variable key size. Therefore the key size must generally be set.
EVP_DecryptInit_ex(ctx, NULL, NULL, key, NULL);
unsigned char* plaintext = (unsigned char*)malloc(sizeof(unsigned char) * ciphertextLength);
int length;
EVP_DecryptUpdate(ctx, plaintext, &length, ciphertext, ciphertextLength);
int plaintextLength = length;
EVP_DecryptFinal_ex(ctx, plaintext + plaintextLength, &length);
plaintextLength += length;
printf("Plaintext: "); for (int i = 0; i < plaintextLength; i++) { printf("%c", plaintext[i]); } printf("\n");
为简单起见,代码不包括异常处理和内存释放。
请注意以下事项:
- 发布的 OpenSSL 语句中使用的一些参数是不安全的,例如 ECB 模式和迭代计数为 1。相反,应使用具有 IV 的模式,如果性能允许,迭代计数为 10,000 或更大。
- OpenSSL 在加密过程中会生成一个随机的 8 字节盐,用于派生密钥。密文由Salted__的 ASCII 编码组成,后跟 8 个字节的 salt,然后是实际密文,here。发布的 OpenSSL 声明正是希望这种格式用于解密。
- RC2定义了可变密钥大小。发布的 OpenSSL 语句使用 16 个字节的大小。
- -pass pass:选项指定不带引号的密码,即在发布的 OpenSSL 语句中,引号是密码的一部分。