Cocos图片加密与解密

Cocos图片加密与解密现在做的cocos项目没有对资源进行加密处理,发布出来的APK一旦被人解包,则所有图片资源都会暴露出来,为了避免图片资源被人恶意使用,所有我准备给自己项目中使用到的图片进行简单加密,这样可以防住一部分解包伸手党。我们这里采用最常见的**异或加密**,*异或加密性质:一个数异或同一个数两次,得到的是本身*。根据这个性质,我们可以采用把图片的字节流进行异或加密,只需要设置一个Key,在本地客户端使用…

大家好,又见面了,我是你们的朋友全栈君。

如果cocos项目没有对资源进行加密处理,发布出来的APK一旦被人解包,则所有图片资源都会暴露出来,为了避免图片资源被人恶意使用,所以我准备给自己项目中使用到的图片进行简单加密,这样可以防住一部分解包伸手党。

我们这里采用最常见的异或加密,异或加密性质:一个数异或同一个数两次,得到的是本身。根据这个性质,我们可以采用把图片的字节流进行异或加密,只需要设置一个Key,在本地客户端使用Key进行一次异或,然后在cocos导入文件的函数中再使用Key进行一次异或,即可还原。

同时为了兼容没有加密的图片,我们需要再加密过后的文件头上添加一下标识,比如文件头部添加N个自定字节流来表示该图片别加密过,同时除了添加的头标识外的其他字节流全部或者部分进行异或加密。

Python进行图片文件加密

根据上面的思路,首先我们需要把项目中使用到的图片进行字节流加密,这里我为了方便就采用python来做,比较简单快捷。你也用C++,java等等你擅长的语言进行文件操作。

#!/usr/bin/env python
#coding=utf-8
# 2019-12-28 by LeiTao
#
import sys
import os

FileEncrpyEnum = { 
   ".png"}  #这里填入你需要加密图片的后缀名,这里我只加密png
EncrpyKey = 58   #异或加密秘钥
HeadSize = 8	 #添加8个byte在文件头
EncrySize = 100  #为了更快的解密,只加密文件的100个字节流
def MakeEncrpy(pahtName,FileName):
	oldfile = open(os.path.join(pahtName, FileName),'rb')
	oldConten = oldfile.read()
	oldfile.close()

	li_out=[]
	#添加加密标识
	for index in range(HeadSize):
		li_out.append(chr(0x01))

	for i in range(len(oldConten)):
		if i < EncrySize:
			li_out.append(chr(ord(oldConten[i])^EncrpyKey)) #异或Key进行加密
		else:
			li_out.append(chr(ord(oldConten[i])))
	newfile = open(os.path.join(pahtName, FileName), 'wb')
	newfile.truncate()
	newfile.write(''.join(li_out))
	newfile.close()
	return
	
def main():
	dirPath = sys.argv[1]
	print dirPath
	print "==============GameEncrpy Begin"
	for root, dirs, files in os.walk(dirPath):

        # root 表示当前正在访问的文件夹路径
        # dirs 表示该文件夹下的子目录名list
        # files 表示该文件夹下的文件list
        # 遍历文件
   		for f in files:
   			ExtensionName = os.path.splitext(f)[1]
   			if ExtensionName in FileEncrpyEnum :
				MakeEncrpy(root,f)

	print "==============GameEncrpy End"


# -------------- main --------------
if __name__ == '__main__':
	try:
		main()
	except Exception as e:
		sys.exit(1)

上面的代码就能够批量对文件夹中后缀为png的图片进行处理,我这里边选择在文件头上插入8个0x01,然后对文件前100个字节进行加密。
加密前后的对比
这是加密前后的对比,加密后的图片因为里面的内容已经被改变,所以正常已经打不开了,这也就达到我们加密的目的。
在这里插入图片描述

COCOS CCFileUtils解密

图片加密过后,COCOS也是无法识别的如果直接引用则会出现错误。所以我们现在开始做COCOS部分的解密。
阅读过源代码的同学应该都知道,COCOS内最终获取图片字节流的函数是写在CCFileUtils的getDataFromFile中,不熟悉源代码的同学也可以自己断点进去调试跟踪,这里我们直接开始修改加载的代码。

static Data getData(const std::string& filename, bool forString)
{ 
   
    if (filename.empty())
    { 
   
        return Data::Null;
    }
	CCLOG("FileUtils getData Now"); 
    Data ret;
    unsigned char* buffer = nullptr;
    size_t size = 0;
    size_t readsize;
    const char* mode = nullptr;

    if (forString)
        mode = "rt";
    else
        mode = "rb";

    auto fileutils = FileUtils::getInstance();
    do
    { 
   
        // Read the file from hardware
        std::string fullPath = fileutils->fullPathForFilename(filename);
        FILE *fp = fopen(fileutils->getSuitableFOpen(fullPath).c_str(), mode);
        CC_BREAK_IF(!fp);
        fseek(fp,0,SEEK_END);
        size = ftell(fp);
        fseek(fp,0,SEEK_SET);

        if (forString)
        { 
   
            buffer = (unsigned char*)malloc(sizeof(unsigned char) * (size + 1));
            buffer[size] = '\0';
        }
        else
        { 
   
            buffer = (unsigned char*)malloc(sizeof(unsigned char) * size);
        }

        readsize = fread(buffer, sizeof(unsigned char), size, fp);
        fclose(fp);

        if (forString && readsize < size)
        { 
   
            buffer[readsize] = '\0';
        }
    } while (0);

    if (nullptr == buffer || 0 == readsize)
    { 
   
        CCLOG("Get data from file %s failed", filename.c_str());
    }
    else
    { 
   
    	//这里实际上就是最终文件读取后的buffer
    	//所以我们需要再这里进行校验文件是否需要解密
    	///
		//检查是否需要解密
		std::string::size_type index = fullPath.find_last_of(".") + 1;
		std::string fileType = fullPath.substr(index, fullPath.length() - index);
		if(fileType.compare("png")==0)  //png类型进行解密
		{ 
   
			CCLOG("Decode Now");
			unsigned char encry_head[8] = { 
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};//添加的头
			size_t HeadSize = 8;
			if (memcmp(buffer, encry_head, HeadSize) == 0) //比较是否我们添加的头,来判断是否需要解密
			{ 
   
				int Key = 58;
				int EncrySize = 100;
				
				unsigned char *new_buffer = nullptr;
				if (forString)
				{ 
   
					new_buffer = (unsigned char*)malloc(size - HeadSize + 1);
					new_buffer[size - HeadSize] = '\0';
				}
				else
				{ 
   
					new_buffer = (unsigned char*)malloc(size - HeadSize);
				}
				for (int i = HeadSize; i < size; i++) { 
   

					if (i < EncrySize + HeadSize) { 
     //加密部分进行解密
						new_buffer[i - HeadSize] = buffer[i] ^ Key; //异或Key进行解密
					}
					else { 
   
						new_buffer[i - HeadSize] = buffer[i];
					}
				}
				free(buffer);
				buffer = new_buffer;
				size = size - HeadSize;  //去掉加密头长度
			}
		}
        ret.fastSet(buffer, readsize);
    }

    return ret;
}

修改完getData函数之后,我们就可以愉快的使用我们加密后的图片啦。最后要注意的点是cocos 的跨平台性质,所以你如果你要在win32调试的话记得把CCFileUtils-win32.cpp中的也一并修改了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/151982.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月21日 上午9:16
下一篇 2022年6月21日 上午9:16


相关推荐

  • linux安装有几种方法_python安装pycharm的方法

    linux安装有几种方法_python安装pycharm的方法Linux安装Pycharm

    2025年8月1日
    5
  • JSP实现留言板「建议收藏」

    JSP实现留言板「建议收藏」JSP实现留言板submitMsg.jsp<%@pageimport=”java.util.ArrayList”%><%@pageimport=”bean.Message”%><%@pageimport=”java.util.List”%><%@pagelanguage=”java”contentType=”text/html;…

    2022年10月9日
    5
  • 敏捷项目管理的流程_敏捷开发项目管理方法

    敏捷项目管理的流程_敏捷开发项目管理方法引言:敏捷绝非某一种特定的开发方法,它只是一种应对快速变化的需求的一种软件开发能力。敏捷本身只包含了《敏捷软件开发宣言》和《敏捷软件的十二条原则》两份文档。敏捷的起源:敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发。在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视、可集成和可运行使用的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。目前很多互联网公司都在搞或者想

    2025年6月22日
    5
  • python中griddata的外插值_利用griddata进行二维插值

    python中griddata的外插值_利用griddata进行二维插值有时候会碰到这种情况:实际问题可以抽象为\(z=f(x,y)\)的形式,而你只知道有限的点\((x_i,y_i,z_i)\),你又需要局部的全数据,这时你就需要插值,一维的插值方法网上很多,不再赘述,这里仅介绍二维的插值法这里主要利用scipy.interpolate包里griddata函数griddata(points,values,xi,method=’linear’…

    2022年5月26日
    45
  • JDK卸载和彻底删除

    JDK卸载和彻底删除第一步:点击“控制面板”。第二步:点击“卸载程序”。第三步:进入到“程序和功能”界面,找到jdk的两个程序:①java8update171(64-bit);②javaSEDevelopmentKit8update171(64-bit);右击卸载即可第四步:在“运行”中输入Regedit,打开注册表编辑器,找到HKEY_LOCAL_MACHINE/SOFTWARE/JavaSo…

    2022年6月30日
    52
  • URL解码之URLEncoder

    URL解码之URLEncoder关于URL解码看到了一篇易懂文章什么是application/x-www-form-urlencoded字符串?答:它是一种编码类型。当URL地址里包含非西欧字符的字符串时,系统会将这些字符转换成application/x-www-form-urlencoded字符串。表单里提交时也是如此,当包含非西欧字符的字符串时,系统也会将这些字符转换成application/x-www-form-…

    2022年6月29日
    47

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号