我在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????
最佳答案
我可以立即看到的一个问题(可能还有更多)是在解密功能中,您对加密数据使用了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];