当我们做完一个游戏以后,需要对自己图片资源做一定的加密保护,不让别人轻易的破解。cocos官方没有提供资源加密功能,下面提供一种交简单的加解密方案。
一、 生成加密脚本
加密脚本:encode.py(这个脚本会生成加密后的图片替换原始图片)
# -*- coding:UTF-8 -*-
#该脚本用于加密png图片 使用python3以上版本解释执行
__author__ = "ChenGuanzhou"
import os
import time
CUR_DIR = os.getcwd() + "\\build\\jsb-link\\assets" # 编译后资源所在的目录,这里是link模式。
print("cur_dir:",CUR_DIR)
_KEY = "xxxxxxxx" #指定加密秘钥,英文
_ENCRYSIG = 'jiaozhi' #添加于文件开头用于判断是否是加密文件
_PNGSIG = bytes([0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a])
_PNGIEND = bytes([0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82])
#获取filesig是否是png
def isPNGSig(bytes_8):
return bytes_8 == _PNGSIG
def isPNG(absPath):#判断是否是PNG图片
"""
:param absPath: 文件的绝对路径
:return: {Bool}
"""
isFile = os.path.isfile(absPath)
hasPNGSig = False
fileExt = os.path.splitext(absPath)[1]
isPngExt = (fileExt == ".png" or fileExt == ".PNG")
if isFile and isPngExt:
with open(absPath,"rb") as file:
hasPNGSig = isPNGSig(file.read(8)[:8])
return isFile and isPngExt and hasPNGSig
def preProcessPng(pngData):#预处理图片数据
"""
剪掉png的signature(8bytes),IEND(12Bytes)
:param pngData:
:return:
"""
assert type(pngData) == bytes
lostHeadData = pngData[8:]
iendData = lostHeadData[-12:]
if iendData == _PNGIEND:#防止Png已经进行过外部软件的压缩,丢掉了IEND
return lostHeadData[:-12]
else:
return lostHeadData
def encryption(fileData,key):#加密操作 ascii占一个字节
"""
加密png数据
:param fileData:{bytes}预处理后的png数据
:param key:{str}秘钥
:return:{bytes}加密后的数据
"""
assert type(key) is str
k = bytes(key,"utf8")
klen= len(k)
kindex = 0
fileData = bytearray(fileData)
for i,v in enumerate(fileData):
if kindex >= klen:
kindex = 0
fileData[i] = v ^ k[kindex]#加密
kindex = kindex + 1
return bytes(_ENCRYSIG,"utf8") + fileData
#处理图片
def processPNG(filePath):
global filenum
fileData = None
with open(filePath,'rb') as file:
fileData = encryption(preProcessPng(file.read()),_KEY)
os.remove(filePath)
with open(filePath,'wb') as file: #覆盖新文件
file.write(fileData)
filenum = filenum + 1
def traverseDir(absDir):#遍历当前目录以及递归的子目录,找到所有的png图片
"""
:param absDir: 要遍历的路径
:return: None
"""
assert (os.path.isdir(absDir) and os.path.isabs(absDir))
dirName = absDir
for fileName in os.listdir(absDir):
absFileName = os.path.join(dirName,fileName)
print("isPNG:",absFileName)
if os.path.isdir(absFileName):#递归查找文件夹
print("absFileName:",absFileName)
traverseDir(absFileName)
elif isPNG(absFileName):
print("isPNG:",absFileName)
processPNG(absFileName)
else:
pass
#------------------- 主函数-------------------------#
start_clock = time.clock()
filenum = 0
traverseDir(CUR_DIR)
end_clock = time.clock()
time = (end_clock - start_clock)*1000
print("encrypt %d Png Pictures"%filenum)
print("use time %fms"%time)
接下来做成一个批处理文件: encode.bat
python jm.py
pause
把encode.py 和 encode.bat 一起放到项目根目录下。
二、修改引擎c代码
这里以cocosDashboard 中 creator2.4.3为例。
修改的代码文件位置:
CocosDashboard\resources.editors\Creator\2.4.3\resources\cocos2d-x\cocos\platform中的CCImage.h和CCImage.c
CCImage.h添加:
1、Format 增加文件类型:
/** Supported formats for Image */
enum class Format
{
//! JPEG
JPG,
//! PNG
PNG,
//! ENCRYPTEDPNG,下面这行是新加的
ENCRYPTEDPNG, //加密后的Png图片
//! TIFF
TIFF,
//! WebP
WEBP,
//! PVR
PVR,
//! ETC
ETC,
//! ETC2
ETC2,
//! S3TC
S3TC,
//! ATITC
// ATITC,
//! TGA
TGA,
//! Raw Data
RAW_DATA,
//! Unknown format
UNKNOWN
};
2、增加两个方法的定义:
//判断是否是加密图片
bool isEncryptedPng(const unsigned char *data, ssize_t dataLen);
//解密
void deEncryptPng(unsigned char **copyData, const char *key, ssize_t dataLen);
CCImage.c添加:
1、实现Image::isEncryptedPng方法:
bool Image::isEncryptedPng(const unsigned char *data, ssize_t dataLen)
{
if (dataLen <= 7 || memcmp("jiaozhi", data, 7) != 0) {
return false;
}
return true;
}
2、实现Image::deEncryptPng解密方法:
void Image::deEncryptPng(unsigned char **copyData, const char *key, ssize_t dataLen) {
static const unsigned char PNG_SIGNATURE[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
static const unsigned char PNG_IEND[] = { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };
unsigned char* data = *copyData;
memcpy(data, PNG_SIGNATURE, 8);
memcpy(data + (dataLen - 12), PNG_IEND, 12);
unsigned char* destart = data + 8;
unsigned char* de_end = data + dataLen - 13;
ssize_t keyLen = strlen(key);
ssize_t keyIndex = 0;
for(; destart <= de_end; destart++, keyIndex++) {
if (keyIndex >= keyLen)
keyIndex = 0;
*destart ^= key[keyIndex];
}
}
3、修改检测图片类型的Image::detectFormat方法:
Image::Format Image::detectFormat(const unsigned char * data, ssize_t dataLen)
{
if (isPng(data, dataLen))
{
return Format::PNG;
}
//新增判断
else if (isEncryptedPng(data, dataLen)) {
return Format::ENCRYPTEDPNG;
}
else if (isJpg(data, dataLen))
{
return Format::JPG;
}
else if (isTiff(data, dataLen))
{
return Format::TIFF;
}
else if (isWebp(data, dataLen))
{
return Format::WEBP;
}
else if (isPvr(data, dataLen))
{
return Format::PVR;
}
else if (isEtc(data, dataLen))
{
return Format::ETC;
}
else if (isS3TC(data, dataLen))
{
return Format::S3TC;
}
else
{
return Format::UNKNOWN;
}
}
4、修改Image::initWithImageData,进行解密png
bool Image::initWithImageData(const unsigned char * data, ssize_t dataLen)
{
bool ret = false;
do
{
CC_BREAK_IF(! data || dataLen <= 0);
unsigned char* unpackedData = nullptr;
ssize_t unpackedLen = 0;
//detect and unzip the compress file
if (ZipUtils::isCCZBuffer(data, dataLen))
{
unpackedLen = ZipUtils::inflateCCZBuffer(data, dataLen, &unpackedData);
}
else if (ZipUtils::isGZipBuffer(data, dataLen))
{
unpackedLen = ZipUtils::inflateMemory(const_cast<unsigned char*>(data), dataLen, &unpackedData);
}
else
{
unpackedData = const_cast<unsigned char*>(data);
unpackedLen = dataLen;
}
_fileType = detectFormat(unpackedData, unpackedLen);
switch (_fileType)
{
//这个case块是增加的内容
case Format::ENCRYPTEDPNG:
{
unsigned char* copyData = new unsigned char[unpackedLen + 13]; // 8 + 12 - 7
memcpy(copyData + 8, unpackedData + 7, unpackedLen - 7);
deEncryptPng(©Data, "xxxxxxxx", unpackedLen + 13); //注意这个"xxxxxxxx"是加密时设定的key
ret = initWithPngData(copyData, unpackedLen + 13);
delete [] copyData;
}
break;
case Format::PNG:
ret = initWithPngData(unpackedData, unpackedLen);
break;
case Format::JPG:
ret = initWithJpgData(unpackedData, unpackedLen);
break;
case Format::TIFF:
ret = initWithTiffData(unpackedData, unpackedLen);
break;
case Format::WEBP:
ret = initWithWebpData(unpackedData, unpackedLen);
break;
case Format::PVR:
ret = initWithPVRData(unpackedData, unpackedLen);
break;
case Format::ETC:
ret = initWithETCData(unpackedData, unpackedLen);
break;
case Format::S3TC:
ret = initWithS3TCData(unpackedData, unpackedLen);
break;
default:
{
// load and detect image format
tImageTGA* tgaData = tgaLoadBuffer(unpackedData, unpackedLen);
if (tgaData != nullptr && tgaData->status == TGA_OK)
{
ret = initWithTGAData(tgaData);
}
else
{
CCLOG("Image: unsupported image format!");
}
free(tgaData);
break;
}
}
if(unpackedData != data)
{
free(unpackedData);
}
} while (0);
return ret;
}
三、加密操作
1、构建项目生成build文件夹。
2、双击encode.bat 。
3、加密完成,可以进行编译。
文章参考自:http://www.cnblogs.com/pixs-union/p/6226337.html