最近在進行cocos2dx的項目,涉及到文件加密的問題,而解密實在游戲加載的時候進行。 因此在加密功能之上還必須要求盡可能快速。所以選擇了tea加密算法。
而加密過程使用window的commond 項目,進行針對文件夾或者文件加密。
閒話少說,直接上代碼。
加密部分,由於對於win commond line 項目不是很熟悉, 所以做的比較粗糙。
// tea.cpp : 定義控制台應用程序的入口點。
//
#include "stdafx.h"
#include "Tea/TeaEd.h"
#include <fstream>
#include <string>
#include <iostream>
#include<io.h>
#include <windows.h>
#include <cstring>
#include <fstream>
using namespace std;
//判斷是一個文件夾
inline bool IsFolder(const string & strWorkSpace, string &fileName, string & filePath)
{
bool bCheck = false;
fileName = strWorkSpace;
filePath = "";
size_t pos = strWorkSpace.find_last_of("\\");
if (pos != std::string::npos)
{
filePath = strWorkSpace.substr(0, pos + 1);
fileName = strWorkSpace.substr(pos + 1);
pos = fileName.find_last_of(".");
if (pos == std::string::npos)
{
bCheck = true;
fileName = "";
filePath = strWorkSpace;
}
}
return bCheck;
}
int doMethod(const string & str)
{
//測試選項。輸入輸入1,則是解密一個文件,並輸出到解密之後的內容
if (str == "1")
{
cout << "將要解密的文件投入:" << endl;
string strFileNameTmp;
cin >> strFileNameTmp;
string str1;
string str2;
bool bCheck = IsFolder(strFileNameTmp, str1, str2);
if (bCheck)
{
cout << "測試解密的必須是一個文件,請按下回車繼續操作" << endl;
system("PAUSE");
cout << "- 選擇解密某個文件進行測試請輸入 1 回車" << endl;
cout << "- 選擇進行加密請輸入 其他字符 回車" << endl;
string strInputTmp;
cin >> strInputTmp;
doMethod(strInputTmp);
return 0;
}
//這是一個單例加密類。負責加密和解密
GetCryTool()->deCryWithFileName(strFileNameTmp, "");
return 0;
}
cout << "1.拖入為文件" << endl;
cout << "將在該文件同目錄下創建一個以 [文件名 + '_cryfile'] 為規則的文件夾" << endl;
cout << endl;
cout << "2.拖入為文件夾" << endl;
cout << "將在該文件夾同級目錄下創建一個cryfolder文件夾,加密之後的文件都在這裡" << endl;
cout << "\n\n將文件或者文件夾拖入下方 :" << endl;
string strWorkPath;
cin >> strWorkPath;
string strFileName = "";
string strFilePath = "";
cout << "Path : " << strWorkPath << endl;
bool bCheck = IsFolder(strWorkPath, strFileName, strFilePath);
if (bCheck)
{
do
{
//write path and create cry file folder
size_t pos = strFilePath.find_last_of("\\");
if (pos != std::string::npos)
{
strFilePath = strFilePath.substr(0, pos + 1);
}
strFilePath.append("cryfolder");
string strCreateForderCMD = "md ";
strCreateForderCMD.append(strFilePath);
system(strCreateForderCMD.c_str());
} while (0);
//如果是一個文件夾, 則要判斷這個文件夾下所有文件,並寫入allFiles.txt文件中。然後按行讀取這個文件,得到每個要加密文件的路徑
vector<string> oVecLines;
string sline;
do
{
//create record file txt named allFiles
//and del it
string strAllFilePath = strFilePath;
strAllFilePath.append("\\allFiles.txt");
string strCmd = "cmd /c dir ";
strCmd.append(strWorkPath);
strCmd.append("\\*.* /a-d /b /s >");
strCmd.append(strAllFilePath);
cout << strCmd << endl;
system(strCmd.c_str());
ifstream ifs(strAllFilePath);
while (ifs && getline(ifs, sline))
{
cout << sline << endl;
oVecLines.push_back(sline);
}
ifs.close();
string strDelCMD = "del ";
strDelCMD.append(strAllFilePath);
system(strDelCMD.c_str());
} while (0);
//遍歷文件路徑。依次加密。
for (size_t i = 0; i < oVecLines.size(); i++)
{
sline = oVecLines[i];
string strTmpfileName = "";
string strTmpFilePath = "";
bool bCheck = IsFolder(sline, strTmpfileName, strTmpFilePath);
if (!bCheck)
{
string strOutFilePath = strFilePath;
strOutFilePath.append("\\");
strOutFilePath.append(strTmpfileName);
GetCryTool()->enCryWithFileName(sline, strOutFilePath);
}
}
}
else
{
string strTmpWirtePath = strFilePath;
do
{
//write path and create cry file folder
size_t pos = strFilePath.find_last_of("\\");
if (pos != std::string::npos)
{
strFilePath = strFilePath.substr(0, pos + 1);
}
size_t szPos = strFileName.find_last_of(".");
if (szPos != std::string::npos)
{
strTmpWirtePath.append(strFileName.substr(0, szPos));
strTmpWirtePath.append("_cryfile");
}
string strCreateForderCMD = "md ";
strCreateForderCMD.append(strTmpWirtePath);
system(strCreateForderCMD.c_str());
} while (0);
strTmpWirtePath.append("\\");
strTmpWirtePath.append(strFileName);
GetCryTool()->enCryWithFileName(strWorkPath, strTmpWirtePath);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char buf[1000];
GetModuleFileNameA(NULL, buf, 1000);
string strKeyPath(buf);
string strKeyfilepath = strKeyPath;
size_t szPos = strKeyfilepath.find_last_of("\\");
if (szPos != std::string::npos)
{
strKeyfilepath = strKeyfilepath.substr(0, szPos + 1);
}
string strKeyPrePath = strKeyfilepath;
//key_prepared.txt是用來存儲明文密碼的文件。 在加密項目下
strKeyPrePath.append("key_prepared.txt");
//key_result.txt是將key加密之後的密碼。同樣也在加密項目下
strKeyfilepath.append("key_result.txt");
string strKeyPre = "";
do
{
ifstream ifs(strKeyPrePath);
while (ifs && getline(ifs, strKeyPre))
{
break;
}
ifs.close();
} while (0);
if (strKeyPre.empty())
{
cout << "沒有輸入密碼,請在" << strKeyPrePath << " 中寫入密碼" << endl;
return 0;
}
string str;
cout << "[ 當前密碼為 :" << strKeyPre <<" ]"<< endl;
cout << "- 修改密碼請輸入'key'回車" << endl;
cout << "- 選擇解密某個文件進行測試請輸入1回車" << endl;
cout << "- 選擇進行加密請輸入其他回車" << endl;
cin >> str;
//判斷是否要修改密碼
if (str == "KEY" || str == "key")
{
system("cls");
string strNewKeyStr;
cout << "請輸入新密碼 :" << endl;
cin >> strNewKeyStr;
GetCryTool()->setUpTea(strNewKeyStr, strKeyfilepath);
cout << "密碼已經修改.請繼續操作" << endl;
cout << "- 選擇解密某個文件進行測試請輸入1回車" << endl;
cout << "- 選擇進行加密請輸入其他回車" << endl;
cin >> str;
doMethod(str);
}
else
{
GetCryTool()->setUpTea(strKeyPre, strKeyfilepath);
doMethod(str);
}
system("PAUSE");
return 0;
}
這面的代碼是主函數部分。
然後放上加密解密的核心部分。
在TeaEd.h中
class TeaEd
{
public:
/*
isNetByte is unuseful param in this project.
*/
TeaEd(const byte * key, int round = 32, bool isNetByte = false);
TeaEd(const TeaEd &rhs);
TeaEd & operator = (const TeaEd &rsh);
void encrypt(const byte * in, byte * out);
void decrypt(const byte * in, byte * out);
private:
void encrypt(const ulong * in, ulong * out);
void decrypt(const ulong * in , ulong * out);
//the method under is use for net data.
//not useful.
ulong ntoh(ulong netlong){return _isNetByte ? /*ntohl(netlong)*/netlong : netlong;}
ulong hton(ulong hostlong){ return _isNetByte ? /*htonl(hostlong)*/hostlong : hostlong; }
protected:
int _round;//iteration round to encrypt or decrypt
// Not useful in this project.
bool _isNetByte;//whether input bytes come from network.
byte _key[16];//encrypt or decrypt key
};
在TeaEd.cpp文件中
TeaEd::TeaEd(const byte * key, int round/*= 32*/, bool isNetByte/*false*/):
_round(round),
_isNetByte(false/*isNetByte*/)
{
if (key != 0)
{
memcpy(_key,key,16);
}else
{
memset(_key,0,16);
}
}
TeaEd::TeaEd(const TeaEd &rhs):
_round(rhs._round),
_isNetByte(/*rhs._isNetByte*/false)
{
memcpy(_key,rhs._key,16);
}
TeaEd & TeaEd::operator = (const TeaEd &rsh)
{
if (&rsh != this)
{
_round = rsh._round;
_isNetByte = /*rsh._isNetByte*/false;
memcpy(_key, rsh._key, 16);
}
return *this;
}
void TeaEd::encrypt(const byte * in, byte * out)
{
encrypt((const ulong*)in, (ulong*)out);
}
void TeaEd::decrypt(const byte * in, byte * out)
{
decrypt((const ulong*)in, (ulong*)out);
}
void TeaEd::encrypt(const ulong * in, ulong * out)
{
ulong * k = (ulong*)_key;
register ulong y = in[0];//ntoh(in[0]);
register ulong z = in[1];//ntoh(in[1]);
register ulong a = k[0];//ntoh(k[0]);
register ulong b = k[1];//ntoh(k[1]);
register ulong c = k[2];//ntoh(k[2]);
register ulong d = k[3];//ntoh(k[3]);
register ulong delta = 0x9E3779B9; /* (sqrt(5)-1)/2*2^32 */
register int round = _round;
register ulong sum = 0;
while (round--)
{
/* basic cycle start */
sum += delta;
y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
}/* end cycle */
out[0] = y;//ntoh(y);
out[1] = z;//ntoh(z);
}
void TeaEd::decrypt(const ulong * in , ulong * out)
{
ulong *k = (ulong*)_key;
register ulong y = in[0];//ntoh(in[0]);
register ulong z = in[1];//ntoh(in[1]);
register ulong a = k[0];//ntoh(k[0]);
register ulong b = k[1];//ntoh(k[1]);
register ulong c = k[2];//ntoh(k[2]);
register ulong d = k[3];//ntoh(k[3]);
register ulong delta = 0x9E3779B9; /* (sqrt(5)-1)/2*2^32 */
register int round = _round;
register ulong sum = 0;
if (round == 32)
sum = 0xC6EF3720; /* delta << 5*/
else if (round == 16)
sum = 0xE3779B90; /* delta << 4*/
else
sum = delta << static_cast<int>(logbase(2, round));
while (round--)
{
/* basic cycle start */
z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
sum -= delta;
}/* end cycle */
out[0] = y;//ntoh(y);
out[1] = z;//ntoh(z);
}
因為加密解密需要在全局使用一個密碼。所以我們用一個單例類管理加密解密功能。
同樣都在TeaEd.h 和TeaEd.cpp中。
頭文件的單例管理類部分。由於在測試的時候嘗試了很多很多辦法。 所以有很多無用的接口。真正使用到的接口只有
void enCryWithFileName(const string & strFile,const string & strOutFile);
void deCryWithFileName(const string & strFileName,const string& strOutfile);
這兩個接口。 其中decry 部分使用到的第二個參數無用。
單例類在構造之初就通過密碼創建了Tea對象,由於工作比較忙, 先不詳細介紹了。。