Cocos2dx遊戲資源加密之XXTEA
在手機遊戲當中,遊戲的資源加密保護是一件很重要的事情。
我花了兩天的時間整理了自己在遊戲當中的資源加密問題,實現了跨平臺的資源流加密,這個都是巨人的肩膀之上的。
大概的思路是這樣的,遊戲資源通過XXTEA加密方法對流的加密方式,有自己的金鑰和標識,通過標識可知是否有加密,金鑰是自己程式當中的。除非有金鑰,否則很難通過解出正確的檔案。經過加密後,加密檔案也就是遊戲資源放在resource的自己資料夾中,否則在xcode編譯到趁機是會識別不了檔案。在程式中cocos2dx底層加入解密過程,就可以把檔案正確讀取出來,讓程式顯示。經試驗,已經可以讀取,png,plist,json檔案。
現在記錄下實現的步驟
連結: http://pan.baidu.com/s/1ntx98VZ 密碼: qyqe 去下載加密資源的指令碼,這個是quick-cocos2d-x提取出來的打包工具。
pack_files.sh
-i olddir -o newdir -ek XXTEA -es decodetest
把ResourcesDecode和xxtea四個檔案加入到cocos2dx/platform下;
把platform/ResourcesDecode.cpp \
platform/xxtea.c \加入到cocos2dx/platform的android.mk檔案中,加入android編譯。
寫一個單例用來儲存密碼和對流解密過程,程式碼如下:
CCAssert(buf != NULL,"decodeData buf not NULL");unsignedchar* buffer = NULL;ResourcesDecode* decode =ResourcesDecode::sharedDecode();bool isXXTEA = decode && decode->m_xxteaEnabled;for(unsignedint i =0; isXXTEA && i < decode->m_xxteaSignLen && i < size;++i){
isXXTEA = buf[i]== decode->m_xxteaSign[i];}if(isXXTEA){//decrypt XXTEA
xxtea_long len =0;
buffer = xxtea_decrypt(buf+decode->m_xxteaSignLen,(xxtea_long)size -(xxtea_long)decode->m_xxteaSignLen,(unsignedchar*)decode->m_xxteaKey,(xxtea_long)decode->m_xxteaKeyLen,&len);delete[] buf;
buf = NULL;
size = len;}else{
buffer = buf;}if(pSize){*pSize = size;}return buffer;
buffer就是經過XXTEA解密後正確的流。
在CCFileUtils::getFileData()當中return返回之前呼叫解密pBuffer =ResourcesDecode::sharedDecode()->decodeData(pBuffer, size, pSize);這裡是跨平臺的讀取資源的方法。
在ZipFile::getFileData()當中也加入解密方法pBuffer =ResourcesDecode::sharedDecode()->decodeData(pBuffer, fileInfo.uncompressed_size, pSize);這個是android讀取plist的地方,我也不太清楚為什麼android會在這裡讀取資源。
在bool CCSAXParser::parse(const char *pszFile)中把原先的rt改為rb : char* pBuffer = (char*)CCFileUtils::sharedFileUtils()->getFileData(pszFile,/*"rt"*/"rb", &size);
ios的修改地方 不一樣
在CCFileUtilsIOS中的createCCDictionaryWithContentsOfFile修改如下,註釋掉的是原先的,後面是新增的。
CCDictionary*CCFileUtilsIOS::createCCDictionaryWithContentsOfFile(const std::string& filename){
std::string fullPath =CCFileUtils::sharedFileUtils()->fullPathForFilename(filename.c_str());// NSString* pPath = [NSString stringWithUTF8String:fullPath.c_str()];// NSDictionary* pDict = [NSDictionary dictionaryWithContentsOfFile:pPath];unsignedlong fileSize =0;unsignedchar* pFileData =CCFileUtils::sharedFileUtils()->getFileData(fullPath.c_str(),"rb",&fileSize);NSData*data =[[[NSData alloc] initWithBytes:pFileData length:fileSize] autorelease];delete[]pFileData;NSPropertyListFormat format;NSString*error;NSMutableDictionary*pDict =(NSMutableDictionary*)[NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&error];
在CCImage.mm當中修改,同樣是註釋是原先的,後面是新增的。
staticbool _initWithFile(constchar* path, tImageInfo *pImageinfo){CGImageRefCGImage;UIImage*jpg;UIImage*png;bool ret;// convert jpg to png before loading the texture// NSString *fullPath = [NSString stringWithUTF8String:path];// jpg = [[UIImage alloc] initWithContentsOfFile: fullPath];unsignedlong fileSize =0;unsignedchar* pFileData = cocos2d::CCFileUtils::sharedFileUtils()->getFileData(path,"rb",&fileSize);NSData*adata =[[NSData alloc] initWithBytes:pFileData length:fileSize];delete[]pFileData;
jpg =[[UIImage alloc] initWithData:adata];
android平臺
在CCImageCommon_cpp當中修改如下
boolCCImage::initWithImageFileThreadSafe(constchar*fullpath,EImageFormat imageType){bool bRet =false;unsignedlong nSize =0;#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)CCFileUtilsAndroid*fileUitls =(CCFileUtilsAndroid*)CCFileUtils::sharedFileUtils();// unsigned char *pBuffer = fileUitls->getFileDataForAsync(fullpath, "rb", &nSize);unsignedchar* pBuffer =CCFileUtils::sharedFileUtils()->getFileData(fullpath,"rb",&nSize);
到此,基本結束了。
在自己程式當中加入資源前把設定金鑰和標識和自己加密資源時的一樣:ResourcesDecode::sharedDecode()->setXXTeaKey("XXTEA",strlen("XXTEA"),"decodetest",strlen("decodetest"));
其它就正常的讀取和顯示。
參考網址:http://my.oschina.net/SunLightJuly/blog/184061
http://my.oschina.net/SunLightJuly/blog/189971
http://my.oschina.net/SunLightJuly/blog/184179