AES encrypt/decrypt 文本

AES encrypt/decrypt text

我有一个包含电子邮件、用户名和密码的文本,我使用 AES 算法对其进行了加密。

我加密的时候好像没问题,但是解密的时候只有一部分(fist 48bytes = 3x 16byte chunks)没问题,剩下的就是一些垃圾

我试过使用 unsigned char 而不是 string,但它有同样的问题。

我不知道问题出在我的算法还是字符集中,但算法对我来说似乎没问题。

如果字符串包含空终止符,会不会导致 string.size 出现问题?我不知道 AES 的密码是否可以包含空终止字符。

代码如下:

    int  aes_set_key( aes_context *ctx, uint8 *key, int nbits ); //Prototype
    void aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); //Prototype
    void aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); //Prototype
    char Buffer[255];
    memset(Buffer, 0, sizeof(Buffer));
    sprintf_s(Buffer, "%s\r\n%s\r\n%s", RegisterEdits[0], RegisterEdits[1], /*PasswordHash.c_str()*/RegisterEdits[2]); // Save email, username and password to buffer
    MSGBOX(Buffer);
    aes_context ctx;
    unsigned char key[] = "0123456789ABCDEF"; // Encrypting/Decrypting key
    unsigned char outputEnc[20];
    unsigned char outputDec[20];
    string CipherData; // Hold whole encrypted text
    string Decrypted; // Hold whole decrypted text
    memset(outputEnc, 0, sizeof(outputEnc));
    memset(outputDec, 0, sizeof(outputDec));
    aes_set_key(&ctx, key, 256);

    int Step = 0;
    char Temp[18];
    do 
    {
        memset(Temp, 0, sizeof(Temp));
        _snprintf(Temp, 16, &Buffer[Step]);//Take first 16 bytes from Buffer at address 0 and copy them into Temp
        Step += strlen(Temp); // Append the Temp size to stepper

        memset(outputEnc, 0, sizeof(outputEnc));
        aes_encrypt(&ctx, reinterpret_cast<unsigned char*>(Temp), outputEnc); // encrypt 16 bytes
        CipherData += reinterpret_cast<char*>(outputEnc); //append the 16 encrypted bytes to string
    } 
    while (Step < strlen(Buffer));
    MSGBOX((LPSTR)CipherData.c_str()); //Let me see the cipher (seems to be ok)

    //Trying little different algorithm than "do while" for decrypting
    MSGBOX("Entering");
    Step = 0;
    for(int i = CipherData.size(); i >= 0; i-=16) //At the start we have cipher size
    {
        if(i < 16) // If we have less than 16 bytes in string left...*
        {
            Beep(1000, 100);
            memset(Temp, 0, sizeof(Temp));
            memcpy(Temp, &CipherData.c_str()[Step], CipherData.size()); // *...copy only the bytes that left.
            MSGBOX(Temp);
            aes_decrypt(&ctx, reinterpret_cast<unsigned char*>(Temp), outputDec);
            Decrypted += reinterpret_cast<char*>(outputDec);
            MSGBOX((LPSTR)Decrypted.c_str());
            break;
        }
        else
        {
            //if we do have more than 16 bytes left in the string...
            memset(Temp, 0, sizeof(Temp)); 
            memcpy(Temp, &CipherData.c_str()[Step], 16); // ...Copy 16 bytes again (#)
            MSGBOX(Temp);
            aes_decrypt(&ctx, reinterpret_cast<unsigned char*>(Temp), outputDec); //decrypt 16 bytes
            Decrypted += reinterpret_cast<char*>(outputDec); //append 16 decrypted bytes
            CipherData = SubstractLastn(CipherData, 16); // IMPORTANT! Remove 16 bytes from the end of the string
            Step += 16; // Append decrypted size to stepper
            MSGBOX((LPSTR)Decrypted.c_str());
            //FIX ME! - in 3rd iteration of this loop the CipherData seems to be corrupted in the part marked with (#)
        }
    }

我会感谢你们的任何帮助!

您将加密数据视为终止字符串。 AES 加密可以而且经常会发出一个 0x00 八位字节,这样一来,任何旨在将以 null 结尾的字节序列视为过早无价值的算法(可以这么说)。

你的问题的核心是:

CipherData += reinterpret_cast<char*>(outputEnc);

这有效地触发了 std::basic_string<char>operator +=(const char*) 成员,它将附加您的输出编码,就好像已命中终止符一样。不好。

我不会尝试修改您的代码,只是因为我一开始就不会这样做。下面是一个简单的(我强调简单)的字符串加密方法。

int main()
{
    unsigned char key[] = "0123456789ABCDEF";
    aes_context ctx = {};
    aes_set_key(&ctx, key, 128);

    // some simple message to encrypt
    std::string str = "some simple message to encrypt";

    // will hold out encrypted message
    std::vector<uint8> encryptedBytes;

    // encrypt the data.
    for (auto it = str.begin(); it != str.end();)
    {
        uint8 plain[16] = {0}, enc[16] = {0};
        size_t i = 0;
        for (; it != str.end() && i < 16; ++i,++it)
            plain[i] = *it;
        aes_encrypt(&ctx, plain, enc);
        encryptedBytes.insert(encryptedBytes.end(), enc, enc+16);
    }

    // now decrypt (not sure if this api requires resetting the
    //  key schedule, but it seems it can't hurt).
    aes_set_key(&ctx, key, 128);
    std::vector<uint8> decrypted;
    for (auto it = encryptedBytes.begin(); it != encryptedBytes.end(); it = std::next(it,16))
    {
        uint8 tmp[16];
        aes_decrypt(&ctx, &(*it), tmp);
        decrypted.insert(decrypted.end(), tmp, tmp+16);
    }

    // rebuild string from data. stop at the terminator or end.
    auto last = std::find(decrypted.begin(), decrypted.end(), 0);
    std::string res(decrypted.begin(), last);

    // show all three (original, cipher, decrypted)
    std::cout << str << '\n';
    print_hex(encryptedBytes.begin(), encryptedBytes.end());
    std::cout << res << '\n';
}

这利用了一个脑死亡的十六进制转储,它做出了大量假设,因此请自行决定使用:

template<class Iter>
void print_hex(Iter beg, Iter end)
{
    std::cout << std::hex << std::setfill('0');
    unsigned int x = 0;
    while (beg != end)
    {
        std::cout << std::setw(2) << static_cast<unsigned int>(*beg) << ' ';
        if (++beg != end && ++x % 16 == 0)
            std::cout << '\n';
    }
    std::cout << '\n';
}

以上 运行 使用您的 AES 加密代码的输出如下:

some simple message to encrypt
82 56 5b a7 a5 b5 6a e9 e5 a4 a6 9d bb ee 14 db 
6b 1e 54 b8 9d 7f 8c 16 18 c6 33 47 1c f1 48 25 
some simple message to encrypt

最后,有几点需要注意。首先,这迫切需要一个填充方案。一个常用的是 PKCS7 padding,这将很容易实现并确保解密文本的确切数量与原始加密相匹配。

其次,您在此代码中看到的每个 16 值都应与一个清单常量交换,该常量是所使用算法的块大小。魔术数字编程很糟糕。不要像我那样做;做你应该做的。

祝你好运。