XOR在C ++中返回混杂的值

时间:2018-11-23 18:01:27

标签: c++

我用C ++编写了以下函数,以使用XOR进行加密/解密。

wchar_t* encryptDecrypt(const wchar_t* toEncrypt, const wchar_t* key)
{
    int strLength = wcslen(toEncrypt);
    int keyLength = wcslen(key);
    wchar_t* output = new wchar_t[strLength];

    for (int i = 0; i < strLength; i++)
    {
        output[i] = toEncrypt[i] ^ key[i % keyLength];
    }
    return output;
}

从理论上讲,使用XOR两次加密字符串应得到原始字符串:

wprintf(L"%ls\n", encryptDecrypt(encryptDecrypt(L"Hello World", L"Key"), L"Key"));

但是,这是上面的代码行所打印的内容:

H??????????????????????

使用相同功能的ASCII版本尝试相同的事情似乎更糟。这是函数:

char* encrypt(const char* toEncrypt, const char* key)
{
    int strLength = strlen(toEncrypt);
    int keyLength = strlen(key);
    char* output = new char[strLength];

    for (int i = 0; i < strLength; i++)
    {
        output[i] = toEncrypt[i] ^ key[i % keyLength];
    }
    return output;
}

打印代码

cout << encrypt(encrypt("Hello World", "key"), "key");

并输出。

H²²²²A

关于可能是什么原因的任何想法?

编辑

如某些人所建议的那样,计算纯文本的长度并将其传入(以及输出数组),可以解决大多数问题。但是,解密后的字符串的末尾仍然有一些垃圾。

功能:

void encryptDecrypt(const wchar_t* toEncrypt, int strLength, const wchar_t* key, wchar_t* output)
{
    int keyLength = wcslen(key);
    for (int i = 0; i < strLength; i++)
    {
        output[i] = toEncrypt[i] ^ key[i % keyLength];
    }
}

主要:

const wchar_t* myString = L"Hello World";
const wchar_t* key = L"Key";
int stringLength = wcslen(myString);
wchar_t* encrypted = new wchar_t[stringLength];
encryptDecrypt(myString, stringLength, key, encrypted);
wchar_t* decrypted = new wchar_t[stringLength];
encryptDecrypt(encrypted, stringLength, key, decrypted);
wprintf(L"%ls\n", decrypted);
delete[] encrypted;
delete[] decrypted;

输出:

Hello World??ver????

2 个答案:

答案 0 :(得分:6)

我可以立即看到的一个问题(可能还有更多)是在解密功能中,您对加密数据使用了strlen()

但是,strlen()适用于所谓的“ asciiz”字符串,即以零('\0')字符结尾的字符序列。您的加密数据包含随机字节,因此不是“ asciiz”字符串。如果您的加密缓冲区包含零字节,那么strlen()将返回一个小于加密数据实际长度的数字,并且您的解密将无法正常进行。

具体来说,我注意到“ Hello World”和“ key”在第二个位置都包含一个“ e”,并且将“ e”与“ e”进行异或运算会得出零,因此,您可以在此文本上找到它和密钥将产生加密的数据,当将其视为asciiz字符串时,看起来只有一个字符长。

要解决此问题,您必须停止将加密数据视为asciiz字符串。每当您传递指向加密数据的指针时,还必须传递数据的长度,并且永远不要使用strlen()来计算数据的长度。

O / P编辑后的修改:

要修复字符串末尾的随机字符,您需要记住,您正在读取加密的字节并构造了一个asciiz字符串。因此,构造完asciiz字符串后,您需要实际上通过向其附加一个零字符来使其成为asciiz,如下所示:

decrypted[stringLength] = '\0';

此外,在分配解密的字符串时,您一定不要忘记考虑这个额外的字节。对于零终止符,asciiz字符串始终占用strlen()个字符加一个。因此,您需要这样做:

wchar_t* decrypted = new wchar_t[stringLength + 1];

答案 1 :(得分:2)

您错过了输出中的nul终止子。因此,现在,计算输入长度会导致缓冲区溢出和未定义的行为。

要快速又肮脏地修复它,

char* encrypt(const char* toEncrypt, const char* key)
{
    int strLength = strlen(toEncrypt);
    int keyLength = strlen(key);
    char* output = new char[strLength+1];

    for (int i = 0; i < strLength; i++)
    {
        output[i] = toEncrypt[i] ^ key[i % keyLength];
    }
    output[sizeof(output)-1] = '\0';
    return output;
}

现在,您的代码还存在其他问题:

  • 泄漏
  • 它不是C ++,而是带有new的C。

使用C ++及其工具。不使用Standart库就像说英语,但只有单词没有e ...

C ++简单实现:

std::string encrypt(std::string plaintext, std::string_view key)
{
    for (std::size_t i = 0; i < plaintext.size(); ++i) {
        plaintext[i] ^= key[i % key.size()];
    }
    return plaintext;
}

Live demo