C ++ Openssl Encryption例程在每次运行时生成不同的输出

时间:2017-11-14 16:37:15

标签: c++ encryption openssl

我有一个必须加密数据的应用程序。

但是,当我运行以下命令时,它会在同一个执行中返回不同的输出。当我重复执行时,输出模式完全相同,请参阅我的问题的结尾。

int Encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) {
    EVP_CIPHER_CTX *ctx;
    int len;
    int ciphertext_len;
    if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
    if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cfb(), NULL, key, iv)) {
        handleErrors();
        }
    if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) {
        handleErrors();
        }
    ciphertext_len = len;
    if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
        handleErrors();
        }
    ciphertext_len += len;
    EVP_CIPHER_CTX_free(ctx);
    return ciphertext_len;
    }
string EncryptThis(string Data, string Key, string IV, long long Buffer) {
    unsigned char *key = (unsigned char *)Key.c_str();
    unsigned char *iv = (unsigned char *)IV.c_str();
    unsigned char *plaintext = (unsigned char *)Data.c_str();
    unsigned char* ciphertext = new unsigned char[Buffer];
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    //cout << Data << endl; //ALWAYS THE SAME
    //cout << Key << endl; //ALWAYS THE SAME
    //cout << IV << endl; //ALWAYS THE SAME


    int ciphertext_len = Encrypt(plaintext, (int)strlen((char *)plaintext), key, iv, ciphertext);
    string Encrypted = base64_encode(reinterpret_cast<const unsigned char *>(ciphertext), ciphertext_len);
    EVP_cleanup();
    ERR_free_strings();
    return Encrypted;
    }
int main() {
    cout << EncryptThis("ThisisATest", "Test", "Test2", 11) << endl;
    cout << EncryptThis("ThisisATest", "Test", "Test2", 11) << endl;
    cout << EncryptThis("ThisisATest", "Test", "Test2", 11) << endl;
    }

在此测试中结果如下:

mJOjOk2wIe5D4oA=
GTvRQb8IZtFYbLI=
plOJA083gOSfVrs=

但是,当我再次运行相同的应用程序时,即使按相同的顺序,它也会返回完全相同的输出。所以在执行脚本时重复似乎是一个问题?

澄清。当这个应用程序被称为Test.exe并且我执行该应用程序三次时,它将输出以下内容:

//execute Test.exe
mJOjOk2wIe5D4oA=
GTvRQb8IZtFYbLI=
plOJA083gOSfVrs=

//Execute Test.exe
mJOjOk2wIe5D4oA=
GTvRQb8IZtFYbLI=
plOJA083gOSfVrs=

//execute Test.exe
mJOjOk2wIe5D4oA=
GTvRQb8IZtFYbLI=
plOJA083gOSfVrs=

这怎么可能,我的错误在哪里?

1 个答案:

答案 0 :(得分:5)

关键和IV要简短。 EVP_aes_256_cfb的密钥需要为256位(32字节),IV需要为块大小,AES为128位(16字节)。

由于键和IV要短,额外的长度以某种方式组成,没有标准定义。对于其中一个或两个使用的字节。在调用main时,每次存储器都是相同的(可能为零),因此结果相同。在内部调用中,内存已通过执行更改,但每次都以相同的方式更改输出。

缓冲区太短。它需要是要加密的数据的长度+块长度:11 + 16 - > 27.最好是加密函数(Encrypt)创建缓冲区而不是调用者。 EVP_EncryptUpdate函数将返回加密+填充的最终长度。

解决方案:使用密钥和IV的全长值,并在内部使用正确的长度处理缓冲区。

提示1:CBC模式更常用于CFB模式。

提示2:使用随机IV,只需在加密数据前加上IV用于解密,它不需要保密。这样,用户无需提供IV。

注意:如果您对全长密钥存在问题,并且IV更新问题并在EVP_EncryptUpdate之后和之后的电话中提供评估。