C#でSQLiteパスワード(暗号化)と復号化
■はじめに
パソコン用のDBと言えばSQLite!!
SQLiteはパスワード(暗号化)出来ないと思って調べると・・・
出来ることが分かった。
Web開発ではDB設計や操作は『A5:SQL Mk-2』を使っているので今回も使いたい!!
もちろん、SQLiteは使える事に感謝しながらも(ER図からSQLite用DDL生成が未対応なのが残念)
パスワード付のSqliteを扱うとADO接続になるのでPC毎にODBC設定が必要なので不便
じゃぁ~、パスワード無しで開発して、本番リリース時にパスワード付にすれば良いと思い調べたら
新規作成時にパスワード有(暗号化)で作成する方法は、沢山見つけることが出来た。
確かにDDLを実行するプログラムを準備すればこの方法で良いのだと思う
しかぁ~し、動作検証でデータ確認するのに
ODBC設定ってPC毎の権限都合もあり大変だったりするので
SQLiteパスワード有(暗号化)←→復号化を簡単に行ったり出来ないかと思って調べて
方法がわかったので自分用のメモとして纏めてみた。
■環境情報
OS:Windows11
DB:SQLite3
開発環境:Microsoft Visual Studio Professional 2022 (64 ビット)
.net core
windows form
■NuGetで必要なものをインストール
1.Microsoft.Data.Sqlite.Core
2.Microsoft.EntityFrameworkCore
3.Microsoft.EntityFrameworkCore.Design
4.Microsoft.EntityFrameworkCore.Sqlite.Core
5.SQLitePCLRaw.bundle_e_sqlcipher
1.SQLiteのパスワード付DB作成
動作確認用に、下記のようなFormアプリを作ってみた。
テスト用にSQLite用のクラスを用意
パスワード付DBを作成するのは簡単
1.SQLiteのDBファイルを指定(今回は明示的にフルパス)
2.SqliteOpenMode.ReadWriteCreateモード
3.パスワード指定
4.コネクションを取得して開く
5.コネクションを閉じて解放
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
namespace SqliteTest001 { internal class Sqlite { private static readonly string APPLICATION_PATH = AppDomain.CurrentDomain.BaseDirectory; private readonly SqliteConnection sqlConn; /// <summary> /// DB接続コンストラクタ /// </summary> /// <param name="dbName">DB名</param> /// <param name="dbPassword">DBパスワード</param> public Sqlite(string dbName, string dbPassword) { var dataSource = APPLICATION_PATH + dbName; SqliteConnectionStringBuilder connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = dataSource, Mode = SqliteOpenMode.ReadWriteCreate, Password = dbPassword }; sqlConn = new(connectionStringBuilder.ToString()); sqlConn.Open(); } /// <summary> /// DB切断 /// </summary> public void Close() { sqlConn.Close(); sqlConn.Dispose(); } /// <summary> /// DB作成 /// </summary> public void CreateDB() { Close(); } } } |
1 2 3 4 5 6 7 8 9 10 |
/// <summary> /// 暗号化DB作成 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { Sqlite sqlite = new Sqlite("test001.db", "pass"); sqlite.CreateDB(); } |
2.テーブル作成
Sqliteクラスに下記を追加
1 2 3 4 5 6 7 8 9 10 11 |
/// <summary> /// テーブル作成 /// </summary> public void CreateTable() { SqliteCommand command = sqlConn.CreateCommand(); command.CommandText = "create table test(id INTEGER primary key autoincrement ,userid TEXT not null ,password TEXT not null)"; command.ExecuteNonQuery(); Close(); } |
1 2 3 4 5 6 7 8 9 10 |
/// <summary> /// テーブル作成 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { Sqlite sqlite = new Sqlite("test001.db", "pass"); sqlite.CreateTable(); } |
3.データ登録
Sqliteクラスに下記を追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/// <summary> /// データ登録 /// </summary> public void Insert() { using (SqliteTransaction trans = sqlConn.BeginTransaction()) { SqliteCommand command = sqlConn.CreateCommand(); command.CommandText = "INSERT INTO test (userid, password) VALUES (@userid, @password)"; command.Parameters.Add("userid", SqliteType.Text); command.Parameters.Add("password", SqliteType.Text); command.Parameters["userid"].Value = "aaaaa"; command.Parameters["password"].Value = "bbbbb"; command.ExecuteNonQuery(); trans.Commit(); } Close(); } |
1 2 3 4 5 6 7 8 9 10 |
/// <summary> /// データ登録 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button3_Click(object sender, EventArgs e) { Sqlite sqlite = new Sqlite("test001.db", "pass"); sqlite.Insert(); } |
4.データ検索
Sqliteクラスに下記を追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/// <summary> /// データ検索 /// </summary> public void Select() { SqliteCommand command = sqlConn.CreateCommand(); command.CommandText = "SELECT * FROM test"; using (var reader = command.ExecuteReader()) { while (reader.Read()) { Debug.WriteLine($"ID:{reader["id"]} ユーザーID:{reader["userid"]} パスワード:{reader["password"]}"); } } Close(); } |
1 2 3 4 5 6 7 8 9 10 |
/// <summary> /// データ検索 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button4_Click(object sender, EventArgs e) { Sqlite sqlite = new Sqlite("test001.db", "pass"); sqlite.Select(); } |
5.DB復号化
Sqliteクラスに下記を追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/// <summary> /// DB復号化 /// </summary> /// <param name="decryptDBName">復号化DB名(コピー先)</param> public void DecryptDB(string decryptDBName) { SqliteCommand command = sqlConn.CreateCommand(); var decryptDataSource = APPLICATION_PATH + decryptDBName; command.CommandText = @$"ATTACH DATABASE '{decryptDataSource}' AS plaintext KEY '';"; command.ExecuteNonQuery(); command.CommandText = @"SELECT sqlcipher_export('plaintext')"; command.ExecuteNonQuery(); Close(); } |
1 2 3 4 5 6 7 8 9 10 |
/// <summary> /// 復号化 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button5_Click(object sender, EventArgs e) { Sqlite sqlite = new Sqlite("test001.db", "pass"); sqlite.DecryptDB("decrypt.db"); } |
6.DB再暗号化
Sqliteクラスに下記を追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/// <summary> /// 再暗号化 /// </summary> /// <param name="encryptionDBName">暗号化DB名(コピー先)</param> /// <param name="password">暗号化パスワード</param> public void EncryptionDB(string encryptionDBName, string password) { SqliteCommand command = sqlConn.CreateCommand(); var encryptiontDataSource = APPLICATION_PATH + encryptionDBName; command.CommandText = @$"ATTACH DATABASE '{encryptiontDataSource}' AS plaintext KEY '{password}';"; command.ExecuteNonQuery(); command.CommandText = @"SELECT sqlcipher_export('plaintext')"; command.ExecuteNonQuery(); } |
1 2 3 4 5 6 7 8 9 10 |
/// <summary> /// 再暗号化 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button6_Click(object sender, EventArgs e) { Sqlite sqlite = new Sqlite("decrypt.db", ""); sqlite.EncryptionDB("encryption.db", "pass"); } |
7.まとめ
今、手元にある最新環境で
DBの新規作成から、復号化、再暗号化をやってみました。
自分用メモなので、細かい解説は省いてるし
あくまでも動作確認なので、エラーなど考慮して無いことが多いのでお許しを