AES|使用OpenSSL加密,使用mcrypt解密


AES | Encrypt with OpenSSL, decrypt with mcrypt

我使用以下函数通过Qt:中的OpenSSL库加密我的数据

QByteArray Crypto::Encrypt(QByteArray source, QString password)
{
  EVP_CIPHER_CTX en;
  unsigned char *key_data;
  int key_data_len;
  QByteArray ba = password.toLatin1();
  key_data = (unsigned char*)ba.data();
  key_data_len = strlen((char*)key_data);
  int nrounds = 28;
  unsigned char key[32], iv[32];
  EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), NULL, key_data, key_data_len, nrounds, key, iv);
QByteArray bkey = reinterpret_cast<const char*>(key) //EDIT: Contains the key afterwards
QByteArray biv = reinterpret_cast<const char*>(iv) //EDIT: Is Null afterwards
  EVP_CIPHER_CTX_init(&en);
  EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, key, iv);
  char *input = source.data();
  char *out;
  int len = source.size();
  int c_len = len + 16, f_len = 0;
  unsigned char *ciphertext = (unsigned char *)malloc(c_len);
  EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL);
  EVP_EncryptUpdate(&en, ciphertext, &c_len, (unsigned char *)input, len);
  EVP_EncryptFinal_ex(&en, ciphertext+c_len, &f_len);
  len = c_len + f_len;
  out = (char*)ciphertext;
  EVP_CIPHER_CTX_cleanup(&en);
  return QByteArray(out, len);
}

"source"在这种情况下是"12345678901234567890123456789012abc"
"密码""1hA!dh==sJAh48S8Ak!?skiitFi120xX"

所以。。。。如果我做对了,那么EVP_BytesToKey()应该从密码中生成一个密钥,并提供数据以稍后解密字符串。

到Base64编码,该密钥将为:"aQkrZD/zwMFU0VAqjYSWsrkfJfS28pQJXym20UEYNnE="
我不用盐,所以没有IV(应该为空)。

因此,Base64中的QByteArray bkey留给我"aQkrZD/zwMFU0VAqjYSWsrkfJfS28pQJXym20UEYNnE="
QByteArray bvi正在给我

加密文本为"CiUqILbZo+WJBr19IiovRVc1dqGvrastwo0k67TTrs51HB8AbJe8S4uxvB2D7Dkr"

现在我使用以下PHP函数再次使用生成的密钥解密密文:

<?php
function decrypt_data($data, $iv, $key) {
    $cypher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
    //if(is_null($iv)) {
    //    $ivlen = mcrypt_enc_get_iv_size($cypher);
    //    $iv = substr($data, 0, $ivlen);
    //    $data = substr($data, $ivlen);
    //}
    // initialize encryption handle
    if (mcrypt_generic_init($cypher, $key, $iv) != -1) {
            // decrypt
            $decrypted = mdecrypt_generic($cypher, $data);
            // clean up
            mcrypt_generic_deinit($cypher);
            mcrypt_module_close($cypher);
            return $decrypted;
    }
    return false;
}
$ctext = "CiUqILbZo+WJBr19IiovRVc1dqGvrastwo0k67TTrs51HB8AbJe8S4uxvB2D7Dkr";
$key = "aQkrZD/zwMFU0VAqjYSWsrkfJfS28pQJXym20UEYNnE=";
$res = decrypt_data(base64_decode($ctext), null, base64_decode($key));
echo $res;
?>

现在,我希望得到类似"12345678901234567890123456789012abc"的响应
我得到的是"7890123456789012abc"

我的字符串似乎以正确的方式解密,但它被切成两半,只显示最后19个字符。有人能帮我吗?我是加密新手,真的不知道我到底哪里出了问题。

这可能是因为您的部分误解了。你说:

我不用盐,所以没有IV(应该为空)。

但没有任何理由会出现这种情况。EVP_BytesToKey方法同时提供了密钥和IV。密钥显然是正确的,但IV不是。这将导致纯文本中出现随机字符(IV只更改第一个块)。由于此块可能包含控制字符以及其他内容,因此可能无法很好地显示。

请记住,salt和IV可能有一些共同点(不应重复,可以公开等),但它们在密码学中是完全不同的概念。

请用你的Qt代码再试一次,这次打印出IV和密钥。。。

我现在通过反复试验解决了空初始化向量的问题,尽管我根本不知道为什么以下是一个问题。也许有人可以向我解释。

更改行:int nrounds=28成功了。

如果我在其中放入28以外的任何其他数字,就会生成IV,然后当我在mcrypt中使用它时,密文就会以正确的方式解密。为什么用openssl函数EVP_BytesToKey()生成带有28轮的密钥是个问题?我现在将其减少到5轮,但我很好奇,如果密码轮组合有可能生成这样的Null-IV,这个问题是否会再次发生。

我真的不知道IV生成的过程是如何在这个函数中处理的。