注意:本篇代码已经发现存在严重问题!给您带来麻烦真的不好意思。您可以看C/C++对字串简单进行可逆加密(2)
加密字串当然是为了安全,废话不多说,直接进入!
要想进行可逆加密,目前我只知道用或者,或对字符进行移位。
新建一个控制台工程。
简单用密钥对明文进行异或运算。异或运算不改变字串的长度。
#include <iostream.h>
#include <windows.h>
#include <tchar.h>
void EncodeString(LPTSTR lpszText, LPCTSTR lpszKey)
{
int nTextLen = ::_tcslen(lpszText);
int nKeyLen = ::_tcslen(lpszKey);
int i = 0;
int k = 0;
for(; i < nTextLen; i++)
{
lpszText[i] = lpszText[i] ^ lpszKey[k];
k++;
if(k >= nKeyLen)
k = 0;
}
}
int main(int argc, char* argv[])
{
char strText[] = "Hello world!";
cout<<strText<<endl;
cout<<"========================================"<<endl;
EncodeString(strText, "Zimmerk"); // 加密
cout<<strText<<endl;
cout<<"========================================"<<endl;
EncodeString(strText, "Zimmerk"); // 解密
cout<<strText<<endl;
return 0;
}
运行发现加密,解密都正常。
但测试中发现,随着明文的增加,会出现解密不完整的情况,比如加密“Hello world! I'm zimmerk. I'm a boy. What's your name?”,这是因为加密得到的密文中含有特殊字符,导致_tcslen函数提前中止,获取字串长度不正确。这种上情况的解决方法可以是自己计算字串结尾。但如果字串中间出现\0,那就用不了了。
还有一种方法就是自己添加字串的中止标记。
这样无法确定字串长度,只好自己在函数内申请内存(当然你也可以用string)
我们设定在密文末尾加密自定的终止标记“==\0”
所以有以下代码
int nTextLen = 0;
char *cPos = NULL;
char *pDest = NULL;
if(!lpszReturn) // 加密
{
nTextLen = ::_tcslen(lpszText);
pDest = (LPTSTR)lpszText;
}
else // 解密
{
cPos = ::_tcsstr(lpszText, _T("==\0")); // 查找自定的中止标记
if(!cPos) // 没有找到结束标记,也不是加密
return;
nTextLen = cPos - lpszText;
pDest = new char[nTextLen + 3]; // ==\0
}
但测试发现,随着字串长度的增加,::_tcsstr同样会无法正确获取到我们自定的终止标记,那只好自己搜索了。
#include <iostream.h>
#include <windows.h>
#include <tchar.h>
void EncodeString(LPCTSTR lpszText, LPTSTR *lpszReturn, LPCTSTR lpszKey)
{
int nTextLen = 0;
char *cPos = NULL;
char *pDest = NULL;
if(!lpszReturn) // 加密
{
nTextLen = ::_tcslen(lpszText);
pDest = (LPTSTR)lpszText;
}
else // 解密
{
// 查找自定的中止标记
cPos = (LPTSTR)lpszText;
while(true) // 从这里可以看到,除非搜索到我们自定的中止标记,否则会一直搜索下去
{
if(*cPos == '=')
if(cPos[1] == '=')
if(cPos[2] == '\0')
break;
cPos++;
}
if(!cPos) // 没有找到结束标记,也不是加密
return;
nTextLen = cPos - lpszText;
pDest = new char[nTextLen + 3]; // ==\0
}
int nKeyLen = ::_tcslen(lpszKey);
int i = 0;
int k = 0;
for(; i < nTextLen; i++)
{
pDest[i] = lpszText[i] ^ lpszKey[k];
k++;
if(k >= nKeyLen)
k = 0;
}
if(!cPos)
memcpy(pDest + nTextLen, _T("==\0"), 3 * sizeof(TCHAR));
else
{
memset(pDest + nTextLen, _T('\0'), sizeof(TCHAR));
*lpszReturn = pDest;
}
}
int main(int argc, char* argv[])
{
char strText[] = "Hello world! I'm zimmerk. I'm a boy. What's your name?";
char *lpszDest = NULL;
cout<<strText<<endl;
cout<<"========================================"<<endl;
EncodeString(strText , NULL, "Zimmerk"); // 加密
cout<<strText<<endl;
cout<<"========================================"<<endl;
EncodeString(strText, &lpszDest, "Zimmerk"); // 解密
if(*lpszDest)
{
cout<<lpszDest<<endl;
delete [] lpszDest;
}
else
cout<<_T("(NULL)")<<endl;
return 0;
}
在测试中发现,再长的字串也能正常解密。
但还发现一个问题,如果知道密钥的一部分,密文就能解出一部分来,这样试下去,密钥不难被试出来。如果才能增大试出密钥的难度能,现在已经晚了,等下一篇文章吧。呵呵.
以上代码在Windows 2003 Server + VC6.0下编译通过