SQLite3加密
使用的是开源库wxsqlite3。没有自己做编译,直接从github上下载的release编译好的sqlite3动态库,其中已经实现了sqlite3_key()
接口。将sqlite3.dll和sqlite3.lib覆盖掉自己工程使用的sqlite3.dll、sqlite3.lib。
注意:wxsqlite3提供的编译库,已经将sqlite3编译进去了,所以在工程中,只需依赖wxsqlite3提供的sqlite3库。
记添加宏定义SQLITE_HAS_CODEC
,使sqlite3打开加密接口的定义。
到此,就可以调用sqlite3.h中的sqlite3_key()
接口了。
GDAL编译-增加libspatialite支持。
编译GDAL使用的是微软开源库 vcpkg。
在之前某篇文章中,曾在vcpkg的开源库issue中提意使GDAL增加libspatialite支持,获得了成功。
所以现在使用vcpkg编译gdal变得很方便:
vcpkg install gdal[libspatialite]
问题
现在gdal虽然可以打开sqlite/spatialite 数据库,但是并不能加密后的数据库。因为gdal并没有为sqlite驱动实现调用sqlite3_key()
的方法,所以通过以下方式打开会失败。
GDALDriver* p= GetGDALDriverManager()->GetDriverByName("SQLite");// 指定使用sqlite驱动
GDALOpenInfo* pOpeninfo= new GDALOpenInfo("E://testspatialite.sqlite", GDAL_OF_READONLY,NULL);
unsigned char* header = (unsigned char*)"SQLite format 3";
pOpeninfo->pabyHeader = header;
pNaviDataset = p->pfnOpen(pOpeninfo);//此处会打开失败,pNavidataset=NULL
跟踪gdal代码发现,失败的原因是:gdal在调用sqlite3_open()打开数据库后,会尝试获取数据库系统表,以确认打开sqlite数据库成功。问题就在于,在sqlite3_open()之后,应先调用sqlite3_key()解密数据库后,再去使用数据库的其他任何功能。
一个解决方法
- 第一步:
1) 打开vcpkg安装目录下的,package文件夹,找到gdal源码包。
修改gdal关于sqlitedatasoure的源代码。增加判断,如果设置了密码参数,则认为是加密数据库并调用解密接口。
内容如下:
OGRSQLiteBaseDataSource.cpp
int OGRSQLiteBaseDataSource::OpenOrCreateDB(int flagsIn, int bRegisterOGR2SQLiteExtensions)
{
......
......//省略
if( rc != SQLITE_OK )
{
CPLError( CE_Failure, CPLE_OpenFailed,
"sqlite3_open(%s) failed: %s",
m_pszFilename, sqlite3_errmsg( hDB ) );
return FALSE;
}
if( (flagsIn & SQLITE_OPEN_CREATE) == 0 )
{
//宏定义 SQLITE_HAS_CODEC其中内容为新增添
#ifdef SQLITE_HAS_CODEC
const char* pszSqliteKey =
CPLGetConfigOption("OGR_SQLITE_KEY", nullptr);
if (pszSqliteKey != nullptr)
{
rc = sqlite3_key(&hDB, pszSqliteKey, strlen(pszSqliteKey));
}
#endif // SQLITE_HAS_CODEC
if( CPLTestBool(CPLGetConfigOption("OGR_VFK_DB_READ", "NO")) )
{
if( SQLGetInteger( hDB,
"SELECT 1 FROM sqlite_master "
"WHERE type = 'table' AND name = 'vfk_tables'",
nullptr ) )
return FALSE; /* DB is valid VFK datasource */
}
.....
.....//省略
}
2) 修改完成之后,把该文件拖进 vcpkg安装目录/download/gdal压缩包,覆盖掉压缩包中的源文件。为什么这么做呢?因为,后面想使用vcpkg install重新编译gdal,vcpkg install会重新解压gdal源码进行安装。
- 第二步:替换wxsqlite3中的sqlite3.dll与sqlite3.lib
- 第三步:重新编译gdal
先移除gdal,再重新编译
vcpkg remove gdal
vcpkg install gdal
此处会报错,提示源码压缩包hash值不正确。这是因为我们刚刚修改了压缩包中的内容。
这个对比hash的过程在vcpkg gdal的编译脚本中。我们打开vcpkg的gdal编译脚本../vcpkg/ports/gdal/profile.cmake
修改
# vcpkg portfile.cmake for GDAL
#
# NOTE: update the version and checksum for new GDAL release
include(vcpkg_common_functions)
set(GDAL_VERSION_STR "2.4.1")
set(GDAL_VERSION_PKG "241")
set(GDAL_VERSION_LIB "204")
set(GDAL_PACKAGE_SUM "d6847ff59657fe5ae30acabb3b25c8f3cc52f3c92a45d3cad132e307b7dd204484f1b82cd6f14f46f6c9e0c691be79d7b0614e2b760982c7b5a67ddb9e9497dd")
//将上面的hash值改成,报错提示中,修改后的压缩包hash值。
再重新执行vcpkg install
解释
- 修改的源码,只是增加了一个判断,宏定义
SQLITE_HAS_CODEC
其中内容为新增。读取GDAL配置项OGR_SQLITE_KEY
,如果存在,就调用sqlite3_key()
解密。 - 使用方法:
因为加密后的数据库,文件内容发生改变。gdal不能再通过读取数据库文件头部内容来确定其是否为sqlite3 数据库。因此,使用时,必须指定使用sqlite3驱动(driver)来打开加密后的数据库文件。如下:
CPLSetConfigOption("OGR_SQLITE_KEY", "123");//设置数据库的访问密码!
GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("SQLite");//指定驱动
GDALOpenInfo* pOpeninfo = new GDALOpenInfo("E://testspatialite.sqlite", GDAL_OF_UPDATE | GDAL_OF_VECTOR, NULL);//GDAL_OF_VECTOR 指定打开的是矢量数据库
unsigned char* header = (unsigned char*)"SQLite format 3";//原本该字符串是从数据库文件头部读取出来的,现在直接设定。
OGRLayer *poLayer;
pOpeninfo->pabyHeader = header;
pNaviDataset = pDriver->pfnOpen(pOpeninfo);//拿到这个数据库就可以为所欲为啦!
最后
有什么问题,在下面评论指出吧。本人也是刚刚学习使用GDAL。
转载请注明出处