C#sqlite加密的一些问题

首先引用一篇文章:[原链接 ]

We often field questions about how SQLCipher encryption works. In one common scenario, a developer wants to convert an existing standard SQLite database to an encrypted SQLCipher database. For example, this might be a requirement for an application that was not previously using SQLCipher, and must convert an insecure database to use SQLCipher full database encryption during an upgrade.

In such cases, developers may initially attempt to open a standard SQLite database and then call sqlite3_key or PRAGMA key , thinking that SQLCipher will open the existing database and rewrite it using encryption. That is not possible, however, and such attempts will be met with a “file is encrypted or is not a database” error (code 26 / SQLITE_NOTADB).

The reason is that SQLCipher encryption works on a per-page basis for efficiency, and sqlite3_key and PRAGMA key can only be used:

1.when opening a brand new database (i.e. for the first time), or
2.when opening an already encrypted databases.

It follows that the correct way to convert an existing database to use SQLCipher is to create a new, empty, encrypted database, then copy the data from the insecure database to the encrypted database. Once complete, an application can simply remove the original plaintext database and use the encrypted copy from then on.

SQLCipher has supported ATTACH between encrypted and plaintext databases since it’s initial release, so it has always been possible to do this conversion on an table-by-table basis. However, an even easier option was added to SQLCipher 2.0, in the form of the sqlcipher_export() convenience function.

The purpose of sqlcipher_export is a to duplicate the entire contents of one database into another attached database. It includes all database objects: the schema, triggers, virtual tables, and all data. This makes it very easy to migrate from a standard non-encrypted SQLite database to a SQLCipher encrypted database, or back in the other direction.

To use sqlcipher_export() to encrypt an existing database, first open up the standard SQLite database, but don’t provide a key. Next, ATTACH a new encrypted database, and then call the sqlcipher_export() function in a SELECT statement, passing in the name of the attached database you want to write the main database schema and data to.

$ ./sqlcipher plaintext.db
sqlite> ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'newkey';
sqlite> SELECT sqlcipher_export('encrypted');
sqlite> DETACH DATABASE encrypted;

Finally, securely delete the existing plaintext database, and then open up the new encrypted database as usual using sqlite3_key or PRAGMA key.

The same process also works in reverse to create a plaintext, fully decrypted, copy of an encrypted SQLCipher database that can be opened with standard SQLite.

$ ./sqlcipher encrypted.db
sqlite> PRAGMA key = 'testkey';
sqlite> ATTACH DATABASE 'plaintext.db' AS plaintext KEY '';  -- empty key will disable encryption
sqlite> SELECT sqlcipher_export('plaintext');
sqlite> DETACH DATABASE plaintext;

It is also possible to use the sqlcipher_export() function in specialized cases to change or customized SQLCipher database settings. These advanced concepts are covered further in the documentation.

上文描述的简单意思就是对于SQLCipher来说只能在创建时设置加密,或者打开一个加密数据库。不要想着把一个未加密数据库直接变成加密数据库,而是通过附加例如sqlcipher_export函数,上文结尾有个超链接到sqlcipher官网介绍;就是把未加密的数据库内容移动到加密的空白数据库里去。

一、使用官方加密,要2000美金

在NuGet包里导入System.Data.SQLite使用SQLiteConnection类ChangePassword加密时,会缺少依赖项System.Data.SQLite.SEE等等。导入官方的Stub.System.Data.SQLite.SEE(NuGet上也有)运行ChangePassword后则会弹出收费网址,这指的就是官方加密扩展了;需要2000美元。

官网源码据说也预留了加密接口,只是没实现留给大家了。

二、使用Microsoft.Data.Sqlite.Core创建加密,官方地址:

https://docs.microsoft.com/zh-cn/dotnet/standard/data/sqlite/encryption?tabs=netcore-cli
里面写到加密要涉及到自定义sqlite版本,Microsoft.Data.Sqlite.Core可以搭配自定义版本。官方给的加密示例就是如下2个包。(而Microsoft.Data.Sqlite默认是sqlite3,不能加密。)
官方VS示例:

Remove-Package Microsoft.Data.Sqlite
Install-Package Microsoft.Data.Sqlite.Core
Install-Package SQLitePCLRaw.bundle_e_sqlcipher

测试使用的版本都是2021年9月份之前的最新版,9月更新后会出现一些报错,暂时没做研究,别安装错版本了

Microsoft.Data.Sqlite.Core.5.0.8
SQLitePCLRaw.bundle_e_sqlcipher.2.0.3

使用SqliteConnectionStringBuilder 可从用户输入添加或更新值,并避免连接字符串注入攻击。

SqliteConnectionStringBuilder a = new SqliteConnectionStringBuilder();
a.Password = "123456";
a.DataSource= @"XX\XX.db";
a.Mode = SqliteOpenMode.ReadWriteCreate;
using (SqliteConnection sqliteConnection = new SqliteConnection(a.ToString()))
{
	sqliteConnection.Open();
	SqliteCommand command = new SqliteCommand("create table Stock(Symbol varchar(100) not null)", sqliteConnection);
	command.ExecuteNonQuery();
}

遇到的问题
1.创建的数据库要加内容进去,不然还是未加密的。
2.启动项调用另一个预先写好数据库操作方法的类库,会遇到没有SetProvider的错误,而设置好SetProvider()后又会出现找不到DLL,DLL模块错误等等不太会弄。SetProvider方法在sqlitePCL.raw里,我又找了下其他文章,用sqlitePCL来操作数据库,所有项目都要装nuget上sqlitePCL的安装包;我把相关项目都装上上文说到的两个包,还真没问题了。

目前简化处理方法就是启动项安装SQLitePCLRaw.bundle_e_sqlcipher.2.0.3并且把附带的SQLitePCLRaw.core.2.0.3更新到SQLitePCLRaw.core.2.0.4,数据库操作的类库安装Microsoft.Data.Sqlite.Core.5.0.8进行数据库操作,这样就正常了;或者都在一个程序集里操作,也就是把两个包都打在启动项里,数据库操作也直接写到启动项里面。

三、使用sqlcipher创建加密

参考github地址:https://github.com/praeclarum/sqlite-net


class Class1
{
	[PrimaryKey, AutoIncrement]
	public int id { get; set; }
	public string name { get; set; }
}
static void Main(string[] args)
{
	SQLiteConnectionString options = new SQLiteConnectionString(@"XX\XX.db", true, key: "123456");
	var encryptedDb = new SQLiteConnection(options);
	encryptedDb.CreateTable<Class1>();
	Class1 c1 = new Class1();
	c1.name = "张三";
	encryptedDb.Insert(c1);
	encryptedDb.Close();
}

一样也要往新数据库里面加内容才算加密。

四、遇到的问题

上述二、三种加密方法,有可能因为你的引用了sqlite3数据库类型的包,导致怎么创建数据库都无法是加密数据库,具体没记住是哪个引用,移除就正常了。

萌新描述的不到位,请多指教。

你可能感兴趣的:(sqlite,sqlite,c#,数据库)