数据库数据项加密用于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;

}