图片资源的加密和cocos2d-x中的解密

主要处理png图片,其他格式图片也是一样的原理。阅读前可以简略了解一下png格式图片的Data trunck。

     首先使用python脚本去掉png的PNG SIG(8 bytes) 以及末尾的PNGIEND(12 bytes)。然后图片剩余数据的每一个字节和秘钥字符串的每一个字符做不进位加(按位异或,解密的原理就是 a ^ b ^ b = a)。通过改写cpp工程里的 Image::initWithImageData(const unsigned char * data, ssize_t dataLen),来进行还原图片数据,也就是解密,过程就是对每一位加密后的数据按秘钥做异或运算还原数据,然后加上PNGSIG和PNGIEND。

加密脚本:(这个脚本会生成加密后的图片替换原始图片)

  1 # -*- coding:UTF-8 -*-
  2 #该脚本用于加密png图片 使用python3以上版本解释执行
  3 __author__ = "ChenGuanzhou"
  4 
  5 import os
  6 import time
  7 CUR_DIR = os.getcwd();
  8 print("cur_dir:",CUR_DIR)
  9 #CUR_DIR = 'C:\\Users\\chenguanzhou\\Desktop'
 10 _KEY = 'jiaozi2013' #指定加密秘钥,英文
 11 _ENCRYSIG = 'jiaozhi'
 12 _PNGSIG = bytes([0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a])
 13 _PNGIEND = bytes([0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82])
 14 #获取filesig是否是png
 15 def isPNGSig(bytes_8):
 16     return bytes_8 == _PNGSIG
 17 
 18 def isPNG(absPath):#判断是否是PNG图片
 19     """
 20     :param absPath: 文件的绝对路径
 21     :return: {Bool}
 22     """
 23     isFile = os.path.isfile(absPath)
 24     hasPNGSig = False
 25     fileExt = os.path.splitext(absPath)[1]
 26     isPngExt = (fileExt == ".png" or fileExt == ".PNG")
 27     if isFile and isPngExt:
 28         with open(absPath,"rb") as file:
 29             hasPNGSig = isPNGSig(file.read(8)[:8])
 30     return isFile and isPngExt and hasPNGSig
 31 
 32 def preProcessPng(pngData):#预处理图片数据
 33     """
 34     剪掉png的signature(8bytes),IEND(12Bytes)
 35     :param pngData:
 36     :return:
 37     """
 38     assert type(pngData) == bytes
 39     lostHeadData = pngData[8:]
 40     iendData = lostHeadData[-12:]
 41     if iendData == _PNGIEND:#防止Png已经进行过外部软件的压缩,丢掉了IEND
 42         return lostHeadData[:-12]
 43     else:
 44         return lostHeadData
 45 
 46 def encryption(fileData,key):#加密操作 ascii占一个字节
 47     """
 48     加密png数据
 49     :param fileData:{bytes}预处理后的png数据
 50     :param key:{str}秘钥
 51     :return:{bytes}加密后的数据
 52     """
 53     assert type(key) is str
 54     k = bytes(key,"utf8")
 55     klen= len(k)
 56     kindex = 0
 57     fileData = bytearray(fileData)
 58     for i,v in enumerate(fileData):
 59         if kindex >= klen:
 60             kindex = 0
 61         fileData[i] = v ^ k[kindex]#加密
 62         kindex = kindex + 1
 63     return bytes(_ENCRYSIG,"utf8") + fileData
 64 
 65 #处理图片
 66 def processPNG(filePath):
 67     global filenum
 68     fileData = None
 69     with open(filePath,'rb') as file:
 70         fileData = encryption(preProcessPng(file.read()),_KEY)
 71     os.remove(filePath)
 72     with open(filePath,'wb') as file: #覆盖新文件
 73         file.write(fileData)
 74     filenum = filenum + 1
 75 
 76 
 77 
 78 def traverseDir(absDir):#遍历当前目录以及递归的子目录,找到所有的png图片
 79     """
 80     :param absDir: 要遍历的路径
 81     :return: None
 82     """
 83     assert (os.path.isdir(absDir) and os.path.isabs(absDir))
 84     dirName = absDir
 85     for fileName in os.listdir(absDir):
 86         absFileName = os.path.join(dirName,fileName)
 87         if os.path.isdir(absFileName):#递归查找文件夹
 88             traverseDir(absFileName)
 89         elif isPNG(absFileName):
 90             processPNG(absFileName)
 91         else:
 92             pass
 93 
 94 
 95 #------------------- 主函数-------------------------#
 96 start_clock = time.clock()
 97 filenum = 0
 98 #traverseDir(os.path.join(CUR_DIR,"png2"))
 99 traverseDir(CUR_DIR)
100 end_clock = time.clock()
101 time = (end_clock - start_clock)*1000
102 print("encrypt %d Png Pictures"%filenum)
103 print("use time %fms"%time)

解密的cpp文件

1.新增图片类型

 enum class Format
    {
        //! JPEG
        JPG,
        //! PNG
        PNG,
        //! ENCRYPTEDPNG
        ENCRYPTEDPNG, //加密后的Png图片
        //! TIFF
        TIFF,
        //! WebP
        WEBP,
        //! PVR
        PVR,
        //! ETC
        ETC,
        //! S3TC
        S3TC,
        //! ATITC
        ATITC,
        //! TGA
        TGA,
        //! Raw Data
        RAW_DATA,
        //! Unknown format
        UNKNOWN
    };

2,修改检测图片类型的Image::detectFormat

1 bool Image::isEncryptedPng(const unsigned char * data, ssize_t dataLen){
2     if (dataLen <= 7 || memcmp("jiaozhi", data, 7) != 0){
3         return false;
4     }
5     return true;
6 }

 

 1 mage::Format Image::detectFormat(const unsigned char * data, ssize_t dataLen)
 2 {
 3     if (isPng(data, dataLen))
 4     {
 5         return Format::PNG;
 6     }
 7     else if(isEncryptedPng(data,dataLen)){
 8         return Format::ENCRYPTEDPNG;
 9     }
10     else if (isJpg(data, dataLen))
11     {
12         return Format::JPG;
13     }
14     else if (isTiff(data, dataLen))
15     {
16         return Format::TIFF;
17     }
18     else if (isWebp(data, dataLen))
19     {
20         return Format::WEBP;
21     }
22     else if (isPvr(data, dataLen))
23     {
24         return Format::PVR;
25     }
26     else if (isEtc(data, dataLen))
27     {
28         return Format::ETC;
29     }
30     else if (isS3TC(data, dataLen))
31     {
32         return Format::S3TC;
33     }
34     else if (isATITC(data, dataLen))
35     {
36         return Format::ATITC;
37     }
38     else
39     {
40         return Format::UNKNOWN;
41     }
42 }

3.修改Image::initWithImageData,进行解密png

 1 bool Image::initWithImageData(const unsigned char * data, ssize_t dataLen)
 2 {
 3     bool ret = false;
 4     do
 5     {
 6         CC_BREAK_IF(! data || dataLen <= 0);
 7         
 8         unsigned char* unpackedData = nullptr;
 9         ssize_t unpackedLen = 0;
10         
11         //detect and unzip the compress file
12         if (ZipUtils::isCCZBuffer(data, dataLen))
13         {
14             unpackedLen = ZipUtils::inflateCCZBuffer(data, dataLen, &unpackedData);
15         }
16         else if (ZipUtils::isGZipBuffer(data, dataLen))
17         {
18             unpackedLen = ZipUtils::inflateMemory(const_cast<unsigned char*>(data), dataLen, &unpackedData);
19         }
20         else
21         {
22             unpackedData = const_cast<unsigned char*>(data);
23             unpackedLen = dataLen;
24         }
25 
26         _fileType = detectFormat(unpackedData, unpackedLen);
27 
28         switch (_fileType)
29         {
30         case Format::ENCRYPTEDPNG:
31         {
32             unsigned char* copyData = new unsigned char[unpackedLen+13];//8+12-7
33             memcpy(copyData + 8, unpackedData+7, unpackedLen-7);
34             deEncryptPng(&copyData, "jiaozi2013", unpackedLen + 13);
35             ret = initWithPngData(copyData, unpackedLen + 13);
36             delete[] copyData;
37 
38         }
39             break;
40         case Format::PNG:
41             ret = initWithPngData(unpackedData, unpackedLen);
42             break;
43         case Format::JPG:
44             ret = initWithJpgData(unpackedData, unpackedLen);
45             break;
46         case Format::TIFF:
47             ret = initWithTiffData(unpackedData, unpackedLen);
48             break;
49         case Format::WEBP:
50             ret = initWithWebpData(unpackedData, unpackedLen);
51             break;
52         case Format::PVR:
53             ret = initWithPVRData(unpackedData, unpackedLen);
54             break;
55         case Format::ETC:
56             ret = initWithETCData(unpackedData, unpackedLen);
57             break;
58         case Format::S3TC:
59             ret = initWithS3TCData(unpackedData, unpackedLen);
60             break;
61         case Format::ATITC:
62             ret = initWithATITCData(unpackedData, unpackedLen);
63             break;
64         default:
65             {
66                 // load and detect image format
67                 tImageTGA* tgaData = tgaLoadBuffer(unpackedData, unpackedLen);
68                 
69                 if (tgaData != nullptr && tgaData->status == TGA_OK)
70                 {
71                     ret = initWithTGAData(tgaData);
72                 }
73                 else
74                 {
75                     CCLOG("cocos2d: unsupported image format!");
76                 }
77                 
78                 free(tgaData);
79                 break;
80             }
81         }
82         
83         if(unpackedData != data)
84         {
85             free(unpackedData);
86         }
87     } while (0);
88     
89     return ret;
90 }

4.新增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* de_start = _data + 8;
    unsigned char* de_end = _data + dataLen - 13;
    ssize_t keyLen = strlen(key);
    ssize_t keyIndex = 0;
    for (; de_start <= de_end;de_start++,keyIndex++){
        if (keyIndex >= keyLen)
            keyIndex = 0;
        *de_start ^= key[keyIndex];
    }
}

最后加一句:python大法好。

posted @ 2016-12-27 16:19  GameSprite  阅读(13927)  评论(11编辑  收藏  举报