【加密】Cocos2d-x PNG图片资源加密(修改版)

【说明】

这篇文章是对上一篇 【Cocos2d-x PNG图片资源加密】的补充和扩展,那篇文章转自【旧时尘安】的博客,文中已经对原理和使用讲解的很清晰,这里只是根据我自己的使用情况做一些小小的功能扩展,也是自己做个整理,以便日后使用。如有侵权,请联系删除。


【链接】

原文地址:http://www.cnblogs.com/zhangpanyi/p/4560297.html

原始工程:https://github.com/zhangpanyi/EncryptPNG


【使用】

修改后的使用有所调整,原文的使用更简洁,这里主要是依照我个人的习惯作出的调整。我在代码中添加了设置密钥和扩展名的接口。

1. 在 cocos 目录下新建文件夹 ext ,将 CCAES.cpp、CCAES.h、CCDecryptImage.cpp、CCDecryptImage.h 拷贝到其中。

2. 在Xcode项目中引用 ext 目录。

注:这里可能会报错,为此我耽误了半天,结果居然是Xcode没有自动引用导致的,我已记录到 【这里】

3. Android项目需要修改 cocos/Android.mk 文件,将两个cpp文件添加进去即可。

4. 在 CCImage 中调用解密代码,方法与原文一样,这里略有修改,代码见附录。

注:我将对 CCDecryptImage.h 的引用放在了 CCImage.h ,是为了在项目中设置密钥时不需要再引用此头文件。

5. 在项目中设置密钥和扩展名,我是在 AppDelegate.cpp 中设置。

注:如果修改扩展名,需要加密端也做修改,保证两边扩展名一致。

[cpp]  view plain  copy
  1. // 设置密钥  
  2. const ext::aes_key key = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};  
  3. ext::DecryptImageConfig(key, ".epng");  

【代码】

[cpp]  view plain  copy
  1. CCImage.cpp  

[cpp]  view plain  copy
  1. bool Image::initWithImageFile(const std::string& path)  
  2. {  
  3.     ......  
  4.   
  5.     if (!data.isNull())  
  6.     {  
  7.         // 图片文件解密  
  8.         if (ext::AnalyzeExtension(path)[1] == ext::TARGET_EXTENSION)  
  9.         {  
  10.             auto image_data = ext::DecryptImage(path, data);  
  11.             ret = initWithImageData(&image_data[0], image_data.size());  
  12.         }  
  13.         else  
  14.         {  
  15.             ret = initWithImageData(data.getBytes(), data.getSize());  
  16.         }  
  17.     }  
  18. #endif // EMSCRIPTEN  
  19.   
  20.     return ret;  
  21. }  
  22.   
  23. bool Image::initWithImageFileThreadSafe(const std::string& fullpath)  
  24. {  
  25.     ......  
  26.   
  27.     if (!data.isNull())  
  28.     {  
  29.         // 图片文件解密  
  30.         if (ext::AnalyzeExtension(fullpath)[1] == ext::TARGET_EXTENSION)  
  31.         {  
  32.             auto image_data = ext::DecryptImage(fullpath, data);  
  33.             ret = initWithImageData(&image_data[0], image_data.size());  
  34.         }  
  35.         else  
  36.         {  
  37.             ret = initWithImageData(data.getBytes(), data.getSize());  
  38.         }  
  39.     }  
  40.   
  41.     return ret;  
  42. }  

[cpp]  view plain  copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;">CCDecryptImage.h</span>  

[cpp]  view plain  copy
  1. #ifndef __CC_DECRYPT_IMAGE_H__  
  2. #define __CC_DECRYPT_IMAGE_H__  
  3.   
  4. #include <array>  
  5. #include <vector>  
  6. #include "CCData.h"  
  7. #include "CCAES.h"  
  8.   
  9. namespace ext  
  10. {  
  11.     /* 解密扩展名 */  
  12.     static std::string TARGET_EXTENSION = ".epng";  
  13.       
  14.     /* 解密密钥 */  
  15.     static aes_key SECRET_KEY = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 };  
  16.       
  17.     /** 
  18.      * 设置解密秘钥 
  19.      * @param key   秘钥(AES的16位秘钥) 
  20.      * @param exten 文件扩展名(需要解密的文件扩展名,如".png") 
  21.      */  
  22.     void DecryptImageConfig(const aes_key &key, const std::string &exten = TARGET_EXTENSION);  
  23.       
  24.     /** 
  25.      * 解密图片文件(在CCImage中调用) 
  26.      * @param filename 文件名称 
  27.      * @param data 文件数据 
  28.      */  
  29.     std::vector<unsigned char> DecryptImage(const std::string &filename, cocos2d::Data &data);  
  30.       
  31.     /** 
  32.      * 分解文件名的扩展名(在CCImage中调用) 
  33.      * @param file_path 文件名 
  34.      */  
  35.     std::array<std::string, 2> AnalyzeExtension(const std::string &file_path);  
  36.       
  37. }  
  38.   
  39. #endif  

[cpp]  view plain  copy
  1. CCDecryptImage.cpp  
[cpp]  view plain  copy
  1. #include "CCDecryptImage.h"  
  2.   
  3. #include <sstream>  
  4. #include "ccMacros.h"  
  5.   
  6. #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)  
  7. #include <WinSock.h>  
  8. #pragma comment(lib, "ws2_32.lib")  
  9. #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)  
  10. #include <netinet/in.h>  
  11. #endif  
  12.   
  13. namespace ext  
  14. {  
  15.     /* CRC码长度 */  
  16.     static const uint32_t CRC_SIZE = 4;  
  17.   
  18.     /* 文件头部 */  
  19.     static const unsigned char HEAD_DATA[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };  
  20.   
  21.     /* IEND CRC码 */  
  22.     static const unsigned char IEND_DATA[] = { 0xae, 0x42, 0x60, 0x82 };  
  23.   
  24.     /* 数据块头部(用于验证解密是否成功) */  
  25.     static const unsigned char BLOCK_HEAD[] = { 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x50, 0x4e, 0x47 };  
  26.   
  27. #pragma pack(push, 1)  
  28.   
  29.     struct Block  
  30.     {  
  31.         char name[4];  
  32.         uint32_t pos;  
  33.         uint32_t size;  
  34.     };  
  35.   
  36.     struct IHDRBlock  
  37.     {  
  38.         Block block;  
  39.         char data[13 + CRC_SIZE];  
  40.     };  
  41.   
  42. #pragma pack(pop)  
  43.   
  44.     /* 解析文件扩展名 */  
  45.     std::array<std::string, 2> AnalyzeExtension(const std::string &file_path)  
  46.     {  
  47.         std::string::size_type pos = file_path.rfind('.');  
  48.         std::array<std::string, 2> text;  
  49.         if (std::string::npos != pos)  
  50.         {  
  51.             text[1] = file_path.substr(pos);  
  52.             text[0] = file_path.substr(0, pos);  
  53.         }  
  54.         else  
  55.         {  
  56.             text[0] = file_path;  
  57.         }  
  58.         return text;  
  59.     }  
  60.   
  61.     template <int _Value, typename _Stream>  
  62.     std::array<char, _Value> ReadSome(_Stream &stream)  
  63.     {  
  64.         std::array<char, _Value> buffer;  
  65.         for (unsigned int i = 0; i < _Value; ++i) buffer[i] = stream.get();  
  66.         return buffer;  
  67.     }  
  68.   
  69.     /* 解密块 */  
  70.     void DecryptBlock(std::stringstream &ss, const aes_key &key)  
  71.     {  
  72.         const std::streamoff contents_size = ss.tellp() - ss.tellg();  
  73.         const uint32_t block_size = (uint32_t)(contents_size + AES_BLOCK_SIZE - contents_size % AES_BLOCK_SIZE);  
  74.         std::vector<uint8_t> buffer;  
  75.         buffer.resize(block_size);  
  76.         for (uint32_t i = 0; i < contents_size; ++i) buffer[i] = ss.get();  
  77.         AES::DecryptData(&buffer[0], block_size, key);  
  78.         ss.seekg(0); ss.seekp(0);  
  79.         for (uint32_t i = 0; i < block_size; ++i) ss.put(buffer[i]);  
  80.     }  
  81.   
  82.     /* 解密图片文件 */  
  83.     std::vector<unsigned char> DecryptImage(const std::string &filename, cocos2d::Data &data)  
  84.     {  
  85.         CCAssert(!data.isNull(), "data is null!");  
  86.   
  87.         // 获取数据块信息位置  
  88.         const uint32_t block_start_pos = ntohl(*reinterpret_cast<uint32_t *>(data.getBytes() + data.getSize() - sizeof(uint32_t)));  
  89.   
  90.         // 获取数据块信息  
  91.         std::stringstream block_info;  
  92.         for (uint32_t i = block_start_pos; i < data.getSize() - sizeof(uint32_t); ++i)  
  93.         {  
  94.             block_info.put(*(data.getBytes() + i));  
  95.         }  
  96.   
  97.         // 解密数据块信息  
  98.         DecryptBlock(block_info, SECRET_KEY);  
  99.   
  100.         // 验证数据块信息是否解密成功  
  101.         auto block_head = ReadSome<sizeof(BLOCK_HEAD)>(block_info);  
  102.         for (unsigned int i = 0; i < block_head.size(); ++i)  
  103.         {  
  104.             if (block_head[i] != BLOCK_HEAD[i])  
  105.             {  
  106.                 CCAssert(false"the key is wrong!");  
  107.             }  
  108.         }  
  109.   
  110.         // 写入文件头信息  
  111.         std::vector<unsigned char> image_data;  
  112.         image_data.reserve(data.getSize());  
  113.         for (auto ch : HEAD_DATA) image_data.push_back(ch);  
  114.   
  115.         // 写入数据块信息  
  116.         while (true)  
  117.         {  
  118.             Block block;  
  119.             memcpy(&block, &(ReadSome<sizeof(Block)>(block_info)[0]), sizeof(Block));  
  120.             if (block_info.eof())  
  121.             {  
  122.                 CCAssert(false"");  
  123.                 CCLOG("the %s file format error!", filename.c_str());  
  124.             }  
  125.   
  126.             // 写入数据块长度和名称  
  127.             char size_buffer[sizeof(block.size)];  
  128.             memcpy(size_buffer, &block.size, sizeof(size_buffer));  
  129.             for (auto ch : size_buffer) image_data.push_back(ch);  
  130.             for (auto ch : block.name) image_data.push_back(ch);  
  131.   
  132.             block.pos = ntohl(block.pos);  
  133.             block.size = ntohl(block.size);  
  134.   
  135.             char block_name[sizeof(block.name) + 1] = { 0 };  
  136.             memcpy(block_name, block.name, sizeof(block.name));  
  137.             if (strcmp(block_name, "IHDR") == 0)  
  138.             {  
  139.                 IHDRBlock ihdr;  
  140.                 memcpy(&ihdr, &block, sizeof(Block));  
  141.                 memcpy(((char *)&ihdr) + sizeof(Block), &ReadSome<sizeof(IHDRBlock) - sizeof(Block)>(block_info)[0], sizeof(IHDRBlock) - sizeof(Block));  
  142.                 for (auto ch : ihdr.data) image_data.push_back(ch);  
  143.             }  
  144.             else if (strcmp(block_name, "IEND") == 0)  
  145.             {  
  146.                 for (auto ch : IEND_DATA) image_data.push_back(ch);  
  147.                 CCLOG("decrypt %s success!", filename.c_str());  
  148.                 break;  
  149.             }  
  150.             else  
  151.             {  
  152.                 for (uint32_t i = 0; i < block.size + CRC_SIZE; ++i)  
  153.                 {  
  154.                     image_data.push_back(*(data.getBytes() + block.pos + i));  
  155.                 }  
  156.             }  
  157.         }  
  158.         return image_data;  
  159.     }  
  160.       
  161.     /* 配置解密秘钥和扩展名 */  
  162.     void DecryptImageConfig(const aes_key &key, const std::string &exten)  
  163.     {  
  164.         SECRET_KEY = key;  
  165.         TARGET_EXTENSION = exten;  
  166.     }  
  167. }  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值