主要處理png圖片,其餘格式圖片也是同樣的原理。閱讀前能夠簡略瞭解一下png格式圖片的Data trunck。python
首先使用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文件spa
1.新增圖片類型code
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::detectFormatorm
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,進行解密pngblog
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(©Data, "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大法好。圖片