【Cocos2d-x】数据加密解密

本文介绍了在Cocos2d-x中进行数据加密解密的方法,包括C++的Base64算法实现、Android平台的加密解密以及在数据库数据项中的应用。在iOS和Win32平台上,通过添加base64库并修改LocalStorage类来实现加密。然而,这种方法存在一些问题,如可被逆向工程破解和读写效率降低。为提高安全性,提出了使用wxsqlite3进行数据库加密的解决方案,它在初始化时加密,运行时解密,保持高效的数据读写。
摘要由CSDN通过智能技术生成


C++的Base64算法实现


/*
 * base64.h
 *
 *  Created on: 30/04/2011
 *      Author: nicholas
 */

#ifndef BASE64_H_
#define BASE64_H_
#include 
   
   
    
    

namespace base64
{

class encode_t
{
private:
	enum
	{
		zero = 0,
		two,
		four
	} state;
	unsigned int remainder;
	std::string encoded;
public:
	encode_t(std::string::size_type size);
	void operator() (std::string::value_type c);
	std::string str();
};

class decode_t
{
private:
	enum
	{
		zero = 0,
		six,
		four,
		two
	} state;
	unsigned int remainder;
	std::string decoded;
public:
	decode_t(std::string::size_type size);
	void operator() (std::string::value_type c);
	std::string str() const;
};

/*
 * Encode the given string @str into its base64 representation
 */
std::string encode(const std::string& str);

/*
 * Decode the base64 encoded string @str
 */
std::string decode(const std::string& str);

}

#endif /* BASE64_H_ */
/*
 * base64.cpp
 *
 *  Created on: 30/04/2011
 *      Author: nicholas
 */

#include "base64.h"
#include 
    
    
     
     
//#include 
     
     
      
      
#include 
      
      
       
       

namespace base64
{

namespace
{

static const std::string BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

size_t encoded_size(size_t raw)
{
	switch((raw*8)%6)
	{
		case 0:
			return (raw*8)/6;
		case 2:
			return ((raw*8)/6) + 3;
		case 4:
			return ((raw*8)/6) + 2;
	}
	return raw;
}

size_t decoded_size(size_t unpadded)
{
	return (unpadded*6)/8;
}

int base64_index(std::string::value_type c)
{
	if(c >= 'A' && c <= 'Z')
		return c-'A';
	else if(c >= 'a' && c <= 'z')
		return c-'a' + 26;
	else if(c >= '0' && c <= '9')
		return c-'0' + 52;
	else if(c == '+')
		return 62;
	else if(c == '/')
		return 63;
	else
		return -1;
}

}

encode_t::encode_t(std::string::size_type size)
 : state(zero), remainder(0)
{
	encoded.reserve(encoded_size(size));
}

/*
State zero
	8 bits input, zero remaining from last
	6 bits consumed, 2 remaining
	=> two
State two
	8 bits input, 2 remaining from last
	4 bits consumed, 4 remaining
	=> four
State four
	8 bits input, 4 remaining from last
	2 bits consumed, 6 remaining
	6 bits input, 6 remaining from last
	6 bits consumed, 0 remaining
	=> zero
 */
void encode_t::operator() (std::string::value_type c)
{
	unsigned char value(0);
	switch(state)
	{
		case zero:
			value = (c & 0xfc) >> 2;
			remainder = c & 0x3;
			encoded.push_back(BASE64_CHARS[value]);
			state = two;
			break;
		case two:
			value = (remainder << 4) | ((c & 0xf0) >> 4);
			remainder = c & 0xf;
			encoded.push_back(BASE64_CHARS[value]);
			state = four;
			break;
		case four:
			value = (remainder << 2) | ((c & 0xc0) >> 6);
			remainder = c & 0x3f;
			encoded.push_back(BASE64_CHARS[value]);
			value = remainder;
			encoded.push_back(BASE64_CHARS[value]);
			state = zero;
			break;
	}
}

std::string encode_t::str()
{
	unsigned char value(0);
	switch(state)
	{
		case zero:
			break;
		case two:
			value = remainder << 4;
			encoded.push_back(BASE64_CHARS[value]);
			encoded.push_back('=');
			encoded.push_back('=');
			state = zero;
			break;
		case four:
			value = remainder << 2;
			encoded.push_back(BASE64_CHARS[value]);
			encoded.push_back('=');
			state = zero;
			break;
	}
	return encoded;
}

decode_t::decode_t(std::string::size_type size)
 : state(zero), remainder(0)
{
	decoded.reserve(decoded_size(size));
}

/*
State zero
	6 bits input, zero remaining from last
	6 bits consumed, zero remaining
	=> six
State six
	6 bits input, 6 remaining from last
	write 1 byte, 4 remaining
	=> four
State four
	6 bits input, 4 remaining from last
	write 1 byte, 2 remaining
	=> two
State two
	6 bits input, 2 remaining from last
	write 1 byte, 0 remaining
	=> zero
 */
void decode_t::operator() (std::string::value_type c)
{
	unsigned char value(0);
	int index = base64_index(c);
	if(index == -1)
		return;
	switch(state)
	{
		case zero:
			remainder = index;
			state = six;
			break;
		case six:
			value = (remainder << 2) | ((index & 0x30) >> 4);
			remainder = index & 0xf;
			decoded.push_back(value);
			state = four;
			break;
		case four:
			value = (remainder << 4) | ((index & 0x3c) >> 2);
			remainder = index & 0x3;
			decoded.push_back(value);
			state = two;
			break;
		case two:
			value = (remainder << 6) | index;
			decoded.push_back(value);
			state = zero;
			break;
	}
}

std::string decode_t::str() const
{
	return decoded;
}

std::string encode(const std::string& str)
{
	return std::for_each(str.begin(), str.end(), encode_t(str.size())).str();
}

std::string decode(const std::string& str)
{
	size_t unpadded_size = str.size();
	if(str.size() > 0 && str[str.size()-1] == '=')
		unpadded_size -= 1;
	if(str.size() > 1 && str[str.size()-2] == '=')
		unpadded_size -= 1;

	return std::for_each(str.begin(), str.end(), decode_t(unpadded_size)).str();
}

}
#include
       
       
         #include"base64.h" using namespace std; int main () { string str = "abcdefghijklmn."; string out = base64::encode(str); cout<<"src:"< 
        
          < 
          
         
       
      
      
     
     
    
    
   
   



Android平台下使用Base64算法加密解密数据


import com.example.base64.R;
import android.app.Activity;
import android.os.Bundle;
import android.util.Base64;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		String src = "abcdefjhijklmn.";
		// 加密数据
		String encode = Base64.encodeToString(src.getBytes(), Base64.DEFAULT);
		// 解密数据
		String decode = new String(Base64.decode(encode, Base64.DEFAULT));

		System.out.println("src:" + src);
		System.out.println("encode:" + encode);
		System.out.println("decode:" + decode);
	}
}




数据库数据项加密


cocos2d-x中操作数据库的实现都封装在LocalStorage这个类中。使用的是sqlite3。

IOS、Win32平台的加密


1.base64.h和base64.cpp添加项目Classes目录下。


2.右键libExtensions项目,附加包含目录,把base64库所在目录添加到包含目录中,具体路径根据自己项目结构而定



3.修改localStorageSetItem方法,保存数据时加密数据,这里在win32平台下忽略加密操作是因为一般win32平台版本是用于内部测试的

void localStorageSetItem( const char *key, const char *value)
{
	assert( _initialized );

	// 加密数据
	#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
		//CCLOG("key=%s src=%s", key, value);		
		std::string encodeStr = base64::encode(value);
		value = encodeStr.c_str();
		//CCLOG("key=%s encode=%s", key, value);
	#endif
	
	int ok = sqlite3_bind_text(_stmt_update, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_bind_text(_stmt_update, 2, value, -1, SQLITE_TRANSIENT);

	ok |= sqlite3_step(_stmt_update);
	
	ok |= sqlite3_reset(_stmt_update);
	
	if( ok != SQLITE_OK && ok != SQLITE_DONE)
		printf("Error in localStorage.setItem()\n");
}

4.修改localStorageGetItem方法,获取数据时解密数据

const char* localStorageGetItem( const char *key )
{
	assert( _initialized );

	int ok = sqlite3_reset(_stmt_select);

	ok |= sqlite3_bind_text(_stmt_select, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_step(_stmt_select);
	const unsigned char *ret = sqlite3_column_text(_stmt_select, 0);
	

	if( ok != SQLITE_OK && ok != SQLITE_DONE && ok != SQLITE_ROW)
		printf("Error in localStorage.getItem()\n");

	// 加密数据
	#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
		//CCLOG("decode src=%s", ret);	
		if (ret)
		{
			std::string decodeStr = base64::decode((const char*)ret);						
			
			char* c = new char;  			
			strcpy_s(c, decodeStr.size() + 1, decodeStr.c_str());  
			//CCLOG("key=%s decode=%s", key, c);			
			return c;
		}		
	#endif

	return (const char*)ret;
}


注意:c_str()方法返回的是string对象中保留的字符串指针,该指针的生命周期是跟随string对象的。也就是如果直接返回decodeStr.c_str(),返回的将是垃圾数据,因为decodeStr在函数结束后,已经被销毁了,指针所指向的是垃圾数据。


这种数据库加密方案存在以下几个问题:

1.如果别人知道我所使用的加密算法,然后通过程序计算出加密串,还是可以修改成功的。

2.数据库还是可以用相关工具打开,并查看数据表。

3.每次读写数据时,增加了加密解密的步骤,降低效率。


对于Cocos2d-x中数据库的加密有更好的解决办法,就是使用wxsqlite3,点击查看【集成wxSqlite3到Cocos2d-x】,这种数据库加密的实现是在初始化数据库的时候加密,运行时加载数据库时候调用相关api解密,加载完成后数据的读写效率和未加密时一样,相对比较高效。



Android平台的加密


从LocalStorage.cpp中使用的宏可以看出,这个实现在安卓平台下是无法使用的



安卓平台下的实现在:cocos2d-x-2.1.5\extensions\LocalStorage目录下的LocalStorageAndroid.cpp中。

从localStrorageInit的实现可以看出,它是通过jni调用了java层中org/cocos2dx/lib/Cocos2dxLocalStorage的静态方法init



在打包安卓版Cocos2d-x游戏时需要用到引擎的一个java库,在cocos2d-x-2.1.5\cocos2dx\platform\android\java目录下,Cocos2dxLocalStorage类就在这个库中。

修改这个类的setItem方法,在保存数据的时候加密
	public static void setItem(String key, String value) {
		try {
			// 加密数据
			value = Base64.encodeToString(value.getBytes(), Base64.DEFAULT);

			String sql = "replace into " + TABLE_NAME
					+ "(key,value)values(?,?)";
			mDatabase.execSQL(sql, new Object[] { key, value });
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

修改这个类的getItem方法,在获取数据的时候解密
	public static String getItem(String key) {
		String ret = null;
		try {
			String sql = "select value from " + TABLE_NAME + " where key=?";
			Cursor c = mDatabase.rawQuery(sql, new String[] { key });
			while (c.moveToNext()) {
				// only return the first value
				if (ret != null) {
					Log.e(TAG, "The key contains more than one value.");
					break;
				}
				ret = c.getString(c.getColumnIndex("value"));
			}
			c.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		// 解密数据
		if (ret != null) {
			ret = new String(Base64.decode(ret, Base64.DEFAULT));
		}
		
		return ret == null ? "" : ret;
	}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值