关于Cocos2d-x数据加密解密

2015年03月17日 16:56 0 点赞 0 评论 更新于 2025-11-21 17:32

在Cocos2d-x中,操作数据库的实现都封装在LocalStorage类中,使用的是sqlite3。下面将分别介绍IOS、Win32平台以及Android平台的数据库数据项加密方法。

IOS、Win32平台的加密

步骤1:添加Base64库

base64.hbase64.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[decodeStr.size() + 1];
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;
}

作者信息

feifeila

feifeila

共发布了 3994 篇文章