我用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????
答案 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;
}
现在,您的代码还存在其他问题:
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;
}