我的 AES 加密/解密函数不适用于随机 ivec

发布于 2024-08-26 21:01:12 字数 4355 浏览 4 评论 0原文

我很无聊,写了一个 openSSL 的包装器来用更少的工作进行 AES 加密。如果我这样做: http://pastebin.com/V1eqz4jp (ivec = 0)
一切工作正常,但默认的ivec全为0,这存在一些安全问题。既然我无论如何都将数据作为字符串传递回来,我想,为什么不生成一个随机的 ivec 并将其粘贴到前面,当我解密字符串时将其取回呢?由于某种原因它不起作用。

事实上,它几乎可以工作。它似乎解密了字符串的中间,但不是开头 或结尾

String is: 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
Encrypting..
���l%%1u���B!
�����`pN)�ɶ���[l�ӏ��{�Q�?�2�/�HԵ�y"�=Z�Cu����l%%1u���B!

Decrypting..
String is: �%���G*�5J�0��0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF

老实说,我不知道出了什么问题。也许是一些愚蠢的错误,或者也许我遗漏了一些关于 AES 的东西?

这是代码:(经过编辑以将 Steve Jessop 的解决方案纳入我的第一个问题)

/*!
 * Simple AES
 * Brendan Long
 * March 29, 2010
 * 
 * Simplified encryption and decryption using OpenSSL's AES library.
 * Remember to compile with -lcrypto and link against the library
 * g++ (your stuff) -lcrypto simpleAes.cpp (or simpleAes.o)
 *
 * Implementation note: Using the default ivec (0) is not secure. For
 *                      the full security that AES offers, use a different
 *                      ivec each time (it does not need to be secret,
 *                      just different.
 *
 * This code is released into the public domain. Yada yada..
 * Read this for details: http://creativecommons.org/licenses/publicdomain/
 *
 * If for some reason public domain isn't good enough, you may use, alter,
 * distribute or do anything else you want with this code with no restrictions.
 */

#include <openssl/aes.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>

bool seed = true;

/*!
 * Encrypts a string using AES with a 256 bit key
 * Note: If the key is less than 32 bytes, it will be null padded.
 *       If the key is greater than 32 bytes, it will be truncated
 * \param in The string to encrypt
 * \param key The key to encrypt with
 * \return The encrypted data
 */
std::string aes_encrypt(std::string in, std::string key){

    // Seed the random number generator once
    if(seed){
        srand( (unsigned int) time(NULL));
        seed = false;
    }

    // Generate a random ivec
    unsigned char ivec[16];
    for(int i=0; i<16; i++){
        ivec[i] = (unsigned char) rand();
    }

     // Round up to AES_BLOCK_SIZE
    size_t textLength = ((in.length() / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;

    // Always pad the key to 32 bits.. because we can
    if(key.length() < 32){
        key.append(32 - key.length(), '\0');
    }

    // Get some space ready for the output
    unsigned char *output = new unsigned char[textLength];

    // Generate a key
    AES_KEY *aesKey = new AES_KEY;
    AES_set_encrypt_key((unsigned char*)key.c_str(), 256, aesKey);

    // Encrypt the data
    AES_cbc_encrypt((unsigned char*)in.c_str(), output, in.length() + 1, aesKey, ivec, AES_ENCRYPT);

    // Make the data into a string
    std::string ret((char*) output, textLength);

    // Add the ivec to the front
    ret = std::string((char*)ivec, 16) + ret;

    // Clean up
    delete output;
    delete aesKey;

    return ret;
}

/*!
 * Decrypts a string using AES with a 256 bit key
 * Note: If the key is less than 32 bytes, it will be null padded.
 *       If the key is greater than 32 bytes, it will be truncated
 * \param in The string to decrypt
 * \param key The key to decrypt with
 * \return The decrypted data
 */
std::string aes_decrypt(std::string in, std::string key){

    // Get the ivec from the front
    unsigned char ivec[16];
    for(int i=0;i<16; i++){
        ivec[i] = in[i];
    }

    in = in.substr(16);

    // Always pad the key to 32 bits.. because we can
    if(key.length() < 32){
        key.append(32 - key.length(), '\0');
    }

    // Create some space for output
    unsigned char *output = new unsigned char[in.length()]; 

    // Generate a key
    AES_KEY *aesKey = new AES_KEY;
    AES_set_decrypt_key((unsigned char*)key.c_str(), 256, aesKey); // key length is in bits, so 32 * 8 = 256

    // Decrypt the data
    AES_cbc_encrypt((unsigned char*)in.c_str(), output, in.length(), aesKey, ivec, AES_DECRYPT);

    // Make the output into a string
    std::string ret((char*) output);

    // Clean up
    delete output;
    delete aesKey;

    return ret;
}

I was bored and wrote a wrapper around openSSL to do AES encryption with less work. If I do it like this:
http://pastebin.com/V1eqz4jp (ivec = 0)
Everything works fine, but the default ivec is all 0's, which has some security problems. Since I'm passing the data back as a string anyway, I figured, why not generate a random ivec and stick it to the front, the take it back off when I decrypt the string? For some reason it doesn't work though.

Well actually, it almost works. It seems to decrypt the middle of the string, but not the beginning or end:

String is: 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
Encrypting..
���l%%1u���B!
�����`pN)�ɶ���[l�ӏ��{�Q�?�2�/�HԵ�y"�=Z�Cu����l%%1u���B!

Decrypting..
String is: �%���G*�5J�0��0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF

I honestly have no idea what's going wrong. Maybe some stupid mistake, or maybe I'm missing something about AES?

Here's the code: (Edited to incorporate Steve Jessop's solution to my first problem)

/*!
 * Simple AES
 * Brendan Long
 * March 29, 2010
 * 
 * Simplified encryption and decryption using OpenSSL's AES library.
 * Remember to compile with -lcrypto and link against the library
 * g++ (your stuff) -lcrypto simpleAes.cpp (or simpleAes.o)
 *
 * Implementation note: Using the default ivec (0) is not secure. For
 *                      the full security that AES offers, use a different
 *                      ivec each time (it does not need to be secret,
 *                      just different.
 *
 * This code is released into the public domain. Yada yada..
 * Read this for details: http://creativecommons.org/licenses/publicdomain/
 *
 * If for some reason public domain isn't good enough, you may use, alter,
 * distribute or do anything else you want with this code with no restrictions.
 */

#include <openssl/aes.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>

bool seed = true;

/*!
 * Encrypts a string using AES with a 256 bit key
 * Note: If the key is less than 32 bytes, it will be null padded.
 *       If the key is greater than 32 bytes, it will be truncated
 * \param in The string to encrypt
 * \param key The key to encrypt with
 * \return The encrypted data
 */
std::string aes_encrypt(std::string in, std::string key){

    // Seed the random number generator once
    if(seed){
        srand( (unsigned int) time(NULL));
        seed = false;
    }

    // Generate a random ivec
    unsigned char ivec[16];
    for(int i=0; i<16; i++){
        ivec[i] = (unsigned char) rand();
    }

     // Round up to AES_BLOCK_SIZE
    size_t textLength = ((in.length() / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;

    // Always pad the key to 32 bits.. because we can
    if(key.length() < 32){
        key.append(32 - key.length(), '\0');
    }

    // Get some space ready for the output
    unsigned char *output = new unsigned char[textLength];

    // Generate a key
    AES_KEY *aesKey = new AES_KEY;
    AES_set_encrypt_key((unsigned char*)key.c_str(), 256, aesKey);

    // Encrypt the data
    AES_cbc_encrypt((unsigned char*)in.c_str(), output, in.length() + 1, aesKey, ivec, AES_ENCRYPT);

    // Make the data into a string
    std::string ret((char*) output, textLength);

    // Add the ivec to the front
    ret = std::string((char*)ivec, 16) + ret;

    // Clean up
    delete output;
    delete aesKey;

    return ret;
}

/*!
 * Decrypts a string using AES with a 256 bit key
 * Note: If the key is less than 32 bytes, it will be null padded.
 *       If the key is greater than 32 bytes, it will be truncated
 * \param in The string to decrypt
 * \param key The key to decrypt with
 * \return The decrypted data
 */
std::string aes_decrypt(std::string in, std::string key){

    // Get the ivec from the front
    unsigned char ivec[16];
    for(int i=0;i<16; i++){
        ivec[i] = in[i];
    }

    in = in.substr(16);

    // Always pad the key to 32 bits.. because we can
    if(key.length() < 32){
        key.append(32 - key.length(), '\0');
    }

    // Create some space for output
    unsigned char *output = new unsigned char[in.length()]; 

    // Generate a key
    AES_KEY *aesKey = new AES_KEY;
    AES_set_decrypt_key((unsigned char*)key.c_str(), 256, aesKey); // key length is in bits, so 32 * 8 = 256

    // Decrypt the data
    AES_cbc_encrypt((unsigned char*)in.c_str(), output, in.length(), aesKey, ivec, AES_DECRYPT);

    // Make the output into a string
    std::string ret((char*) output);

    // Clean up
    delete output;
    delete aesKey;

    return ret;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

凯凯我们等你回来 2024-09-02 21:01:12

您应该在加密之前将 ivec[16] 保存到“输出”中。
就是这样......

我还想补充一点,使用 char* 而不是字符串会更简单。

You should save the ivec[16] into 'output' BEFORE encrypting.
That's it...

I'd also like to add that it'll be much simpler to work with char* instead of string.

生死何惧 2024-09-02 21:01:12

此行是错误的:

std::string ret((char*) output);

解密的数据没有 nul 终止符,因为您加密了 in.length() 字节。这说明了最后的垃圾,但没有解释开头的垃圾。还可能存在其他问题。

This line is wrong:

std::string ret((char*) output);

The decrypted data doesn't have a nul terminator, since you encrypted in.length() bytes. That accounts for the garbage at the end, but not the garbage at the beginning. There may be other problems as well.

风筝有风,海豚有海 2024-09-02 21:01:12

我的一个朋友发现了这个问题。我正在这样做:

  1. 生成随机数并将其存储在 ivec
  2. 使用 ivec 加密数据
  3. 将 ivec 附加到输出数据的开头

问题是步骤 2 更改了 ivec 的内容。我基本上是在字符串的开头存储随机数。解决方案是添加以下内容:

unsigned char ivec[16];
// set ivec to random numbers
std::string ivecString((char*) ivec, 16);
// encrypt data
return ivecString + encryptedData;

A friend of mine figured out the problem. I'm doing this:

  1. Generate random number and store it in ivec
  2. Encrypt data with ivec
  3. Append ivec to beginning of output data

The problem is that step 2 changes the contents of ivec. I was basically storing random numbers at the beginning of my string. The solution was to add this:

unsigned char ivec[16];
// set ivec to random numbers
std::string ivecString((char*) ivec, 16);
// encrypt data
return ivecString + encryptedData;
月棠 2024-09-02 21:01:12

通常,您不能将加密阶段的输出视为字符串,除非您执行附加步骤,例如对输出进行 Base 64 编码。任何输出字节都可以是 null。

In general, you cannot treat the output of the encryption stage as a string, unless you perform an additional step, such as Base 64 encoding the output. Any output byte could be a nul.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文