apsw-sqlite3mc 3.48.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- apsw-sqlite3mc-3.48.0.0/LICENSE +28 -0
- apsw-sqlite3mc-3.48.0.0/MANIFEST.in +38 -0
- apsw-sqlite3mc-3.48.0.0/PKG-INFO +249 -0
- apsw-sqlite3mc-3.48.0.0/README.rst +222 -0
- apsw-sqlite3mc-3.48.0.0/apsw/__init__.pyi +4749 -0
- apsw-sqlite3mc-3.48.0.0/apsw/__main__.py +9 -0
- apsw-sqlite3mc-3.48.0.0/apsw/bestpractice.py +129 -0
- apsw-sqlite3mc-3.48.0.0/apsw/ext.py +2533 -0
- apsw-sqlite3mc-3.48.0.0/apsw/fts5.py +3216 -0
- apsw-sqlite3mc-3.48.0.0/apsw/fts5aux.py +290 -0
- apsw-sqlite3mc-3.48.0.0/apsw/fts5query.py +1075 -0
- apsw-sqlite3mc-3.48.0.0/apsw/fts_test_strings +87 -0
- apsw-sqlite3mc-3.48.0.0/apsw/ftstests.py +2993 -0
- apsw-sqlite3mc-3.48.0.0/apsw/mcall.py +154 -0
- apsw-sqlite3mc-3.48.0.0/apsw/mctests.py +323 -0
- apsw-sqlite3mc-3.48.0.0/apsw/py.typed +0 -0
- apsw-sqlite3mc-3.48.0.0/apsw/shell.py +3654 -0
- apsw-sqlite3mc-3.48.0.0/apsw/speedtest.py +623 -0
- apsw-sqlite3mc-3.48.0.0/apsw/tests.py +11455 -0
- apsw-sqlite3mc-3.48.0.0/apsw/trace.py +401 -0
- apsw-sqlite3mc-3.48.0.0/apsw/unicode.py +1763 -0
- apsw-sqlite3mc-3.48.0.0/apsw_sqlite3mc.egg-info/PKG-INFO +249 -0
- apsw-sqlite3mc-3.48.0.0/apsw_sqlite3mc.egg-info/SOURCES.txt +64 -0
- apsw-sqlite3mc-3.48.0.0/apsw_sqlite3mc.egg-info/dependency_links.txt +1 -0
- apsw-sqlite3mc-3.48.0.0/apsw_sqlite3mc.egg-info/entry_points.txt +2 -0
- apsw-sqlite3mc-3.48.0.0/apsw_sqlite3mc.egg-info/top_level.txt +1 -0
- apsw-sqlite3mc-3.48.0.0/checksums +37 -0
- apsw-sqlite3mc-3.48.0.0/pyproject.toml +16 -0
- apsw-sqlite3mc-3.48.0.0/setup.apsw +9 -0
- apsw-sqlite3mc-3.48.0.0/setup.cfg +4 -0
- apsw-sqlite3mc-3.48.0.0/setup.py +991 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/Makefile.in +1051 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/README +11 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/compile +348 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/config.guess +1754 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/config.sub +1890 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/configure +17030 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/install-sh +541 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/ltmain.sh +11436 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/missing +215 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/sqlite3.c +3 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/configure/sqlite3.pc.in +13 -0
- apsw-sqlite3mc-3.48.0.0/sqlite3/sqlite3.c +358632 -0
- apsw-sqlite3mc-3.48.0.0/src/_unicodedb.c +154121 -0
- apsw-sqlite3mc-3.48.0.0/src/apsw.c +2087 -0
- apsw-sqlite3mc-3.48.0.0/src/apsw.docstrings +4136 -0
- apsw-sqlite3mc-3.48.0.0/src/apswversion.h +1 -0
- apsw-sqlite3mc-3.48.0.0/src/argparse.c +496 -0
- apsw-sqlite3mc-3.48.0.0/src/backup.c +395 -0
- apsw-sqlite3mc-3.48.0.0/src/blob.c +703 -0
- apsw-sqlite3mc-3.48.0.0/src/connection.c +5894 -0
- apsw-sqlite3mc-3.48.0.0/src/constants.c +1219 -0
- apsw-sqlite3mc-3.48.0.0/src/cursor.c +1854 -0
- apsw-sqlite3mc-3.48.0.0/src/exceptions.c +338 -0
- apsw-sqlite3mc-3.48.0.0/src/faultinject.c +162 -0
- apsw-sqlite3mc-3.48.0.0/src/faultinject.h +2699 -0
- apsw-sqlite3mc-3.48.0.0/src/fts.c +1537 -0
- apsw-sqlite3mc-3.48.0.0/src/pyutil.c +310 -0
- apsw-sqlite3mc-3.48.0.0/src/statementcache.c +487 -0
- apsw-sqlite3mc-3.48.0.0/src/stringconstants.c +182 -0
- apsw-sqlite3mc-3.48.0.0/src/testextension.c +50 -0
- apsw-sqlite3mc-3.48.0.0/src/traceback.c +77 -0
- apsw-sqlite3mc-3.48.0.0/src/unicode.c +2700 -0
- apsw-sqlite3mc-3.48.0.0/src/util.c +464 -0
- apsw-sqlite3mc-3.48.0.0/src/vfs.c +3290 -0
- apsw-sqlite3mc-3.48.0.0/src/vtable.c +2845 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Copyright (c) 2004-2025 Roger Binns <rogerb@rogerbinns.com>
|
|
2
|
+
|
|
3
|
+
All code and documentation is provided under this license:
|
|
4
|
+
|
|
5
|
+
This software is provided 'as-is', without any express or implied
|
|
6
|
+
warranty. In no event will the authors be held liable for any damages
|
|
7
|
+
arising from the use of this software.
|
|
8
|
+
|
|
9
|
+
Permission is granted to anyone to use this software for any purpose,
|
|
10
|
+
including commercial applications, and to alter it and redistribute it
|
|
11
|
+
freely, subject to the following restrictions:
|
|
12
|
+
|
|
13
|
+
1. The origin of this software must not be misrepresented; you must not
|
|
14
|
+
claim that you wrote the original software. If you use this software
|
|
15
|
+
in a product, an acknowledgment in the product documentation would be
|
|
16
|
+
appreciated but is not required.
|
|
17
|
+
|
|
18
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
|
19
|
+
misrepresented as being the original software.
|
|
20
|
+
|
|
21
|
+
3. This notice may not be removed or altered from any source
|
|
22
|
+
distribution.
|
|
23
|
+
|
|
24
|
+
Alternatively you may strike the license above and use it under any
|
|
25
|
+
OSI approved open source license such as those listed at
|
|
26
|
+
https://opensource.org/licenses/alphabetical
|
|
27
|
+
|
|
28
|
+
SPDX-License-Identifier: any-OSI
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# The C source
|
|
2
|
+
include src/*.c
|
|
3
|
+
include src/faultinject.h
|
|
4
|
+
include src/apswversion.h
|
|
5
|
+
include src/apsw.docstrings
|
|
6
|
+
include sqlite3/sqlite3.c
|
|
7
|
+
|
|
8
|
+
# other files
|
|
9
|
+
include apsw/__init__.pyi
|
|
10
|
+
include apsw/py.typed
|
|
11
|
+
include apsw/shell.py
|
|
12
|
+
include apsw/speedtest.py
|
|
13
|
+
include apsw/trace.py
|
|
14
|
+
include apsw/tests.py
|
|
15
|
+
include apsw/mctests.py
|
|
16
|
+
include apsw/ext.py
|
|
17
|
+
|
|
18
|
+
# data
|
|
19
|
+
include apsw/fts_test_strings
|
|
20
|
+
|
|
21
|
+
# top level
|
|
22
|
+
include LICENSE
|
|
23
|
+
include checksums
|
|
24
|
+
include setup.py
|
|
25
|
+
|
|
26
|
+
# Long description comes from this
|
|
27
|
+
include README.rst
|
|
28
|
+
|
|
29
|
+
include setup.apsw
|
|
30
|
+
|
|
31
|
+
# configure
|
|
32
|
+
include sqlite3/configure/*
|
|
33
|
+
# remove generated detritus
|
|
34
|
+
exclude sqlite3/configure/config.log
|
|
35
|
+
exclude sqlite3/configure/config.status
|
|
36
|
+
exclude sqlite3/configure/libtool
|
|
37
|
+
exclude sqlite3/configure/Makefile
|
|
38
|
+
exclude sqlite3/configure/sqlite3.pc
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: apsw-sqlite3mc
|
|
3
|
+
Version: 3.48.0.0
|
|
4
|
+
Summary: SQLite3 Multiple Ciphers combined with Another Python SQLite Wrapper
|
|
5
|
+
Home-page: https://github.com/utelle/apsw-sqlite3mc
|
|
6
|
+
Author: Ulrich Telle
|
|
7
|
+
Author-email: github@telle-online.de
|
|
8
|
+
License: OSI Approved
|
|
9
|
+
Project-URL: Documentation (APSW), https://rogerbinns.github.io/apsw/
|
|
10
|
+
Project-URL: Documentation (MultipleCiphers), https://utelle.github.io/SQLite3MultipleCiphers/
|
|
11
|
+
Project-URL: Documentation (SQLite), https://sqlite.org/lang.html
|
|
12
|
+
Project-URL: Support/Discussions, https://github.com/utelle/apsw-sqlite3mc?tab=readme-ov-file#supportdiscussions
|
|
13
|
+
Project-URL: Issue Tracker, https://github.com/utelle/apsw-sqlite3mc/issues
|
|
14
|
+
Project-URL: Code, https://github.com/utelle/apsw-sqlite3mc
|
|
15
|
+
Keywords: database,sqlite,encryption
|
|
16
|
+
Platform: any
|
|
17
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
18
|
+
Classifier: Intended Audience :: Developers
|
|
19
|
+
Classifier: License :: OSI Approved
|
|
20
|
+
Classifier: Programming Language :: C
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Topic :: Database :: Front-Ends
|
|
23
|
+
Classifier: Topic :: Security :: Cryptography
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Description-Content-Type: text/x-rst
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
|
|
28
|
+
.. image:: https://raw.githubusercontent.com/utelle/apsw-sqlite3mc/sqlite3mc/apsw-sqlite3mc-logo.jpg
|
|
29
|
+
:width: 512 px
|
|
30
|
+
:alt: APSW SQLite Multiple Cipher logo - links to documentation
|
|
31
|
+
:target: https://utelle.github.io/SQLite3MultipleCiphers/
|
|
32
|
+
|
|
33
|
+
.. contents:: Contents
|
|
34
|
+
|
|
35
|
+
About
|
|
36
|
+
-----
|
|
37
|
+
|
|
38
|
+
This project packages 3 things together
|
|
39
|
+
|
|
40
|
+
`APSW <https://rogerbinns.github.io/apsw/>`__
|
|
41
|
+
|
|
42
|
+
Another Python SQLite wrapper, providing complete access to SQLite3
|
|
43
|
+
from Python.
|
|
44
|
+
|
|
45
|
+
`SQLite 3 <https://www.sqlite.org/>`__
|
|
46
|
+
|
|
47
|
+
Small, fast, self-contained, high-reliability, full-featured, SQL
|
|
48
|
+
database engine. SQLite is configured with `secure delete
|
|
49
|
+
<https://www.sqlite.org/pragma.html#pragma_secure_delete>`__ turned
|
|
50
|
+
on, and to use `memory for temporary storage
|
|
51
|
+
<https://www.sqlite.org/tempfiles.html#the_sqlite_temp_store_compile_time_parameter_and_pragma>`__.
|
|
52
|
+
|
|
53
|
+
`SQLite3 Multiple Ciphers <https://utelle.github.io/SQLite3MultipleCiphers/>`__
|
|
54
|
+
|
|
55
|
+
Extends SQLite 3 to allow reading and writing encrypted databases.
|
|
56
|
+
|
|
57
|
+
The distribution is entirely self contained, and does not use or alter
|
|
58
|
+
any existing SQLite you may already have on your system.
|
|
59
|
+
|
|
60
|
+
Installation
|
|
61
|
+
------------
|
|
62
|
+
|
|
63
|
+
Available from `PyPi <https://pypi.org/project/apsw-sqlite3mc/>`__.
|
|
64
|
+
Binaries are included for most platforms, and pip will build from
|
|
65
|
+
source for the rest.::
|
|
66
|
+
|
|
67
|
+
pip install apsw-sqlite3mc
|
|
68
|
+
|
|
69
|
+
Usage
|
|
70
|
+
-----
|
|
71
|
+
|
|
72
|
+
Use as you would regular `APSW
|
|
73
|
+
<https://rogerbinns.github.io/apsw/>`__. You can check the version of
|
|
74
|
+
SQLite3 Multiple Ciphers with ``apsw.mc_version``.
|
|
75
|
+
|
|
76
|
+
For encrypted databases you need to use the relevant `pragmas
|
|
77
|
+
<https://utelle.github.io/SQLite3MultipleCiphers/docs/configuration/config_sql_pragmas/>`__
|
|
78
|
+
to set a passphrase based key, or a binary bytes based key::
|
|
79
|
+
|
|
80
|
+
connection.pragma("key", "my secret passphrase")
|
|
81
|
+
connection.pragma("hexkey", b"\xfe\x23\x9e\x77".hex())
|
|
82
|
+
|
|
83
|
+
Setting the key on a new database is the only change needed to your code.
|
|
84
|
+
|
|
85
|
+
.. code-block:: pycon
|
|
86
|
+
|
|
87
|
+
>>> import apsw
|
|
88
|
+
>>> print(apsw.mc_version)
|
|
89
|
+
SQLite3 Multiple Ciphers 2.0.2
|
|
90
|
+
>>> con = apsw.Connection("database.sqlite3")
|
|
91
|
+
>>> con.pragma("key", "my secret passphrase")
|
|
92
|
+
ok
|
|
93
|
+
|
|
94
|
+
**Note**: The ``ok`` means the pragma was understood. It does not mean
|
|
95
|
+
the key is correct or has been applied to an empty database. See the
|
|
96
|
+
next section on best practice to check and apply the key.
|
|
97
|
+
|
|
98
|
+
**Note**: ``key`` only sets the key for following reads and writes. If
|
|
99
|
+
the database already has content, and you want to encrypt it then use
|
|
100
|
+
``rekey`` which will modify the database to apply the supplied key.
|
|
101
|
+
|
|
102
|
+
Alternately you can use `URI parameters
|
|
103
|
+
<https://utelle.github.io/SQLite3MultipleCiphers/docs/configuration/config_uri/>`__.
|
|
104
|
+
You need to correctly encode the filename and parameters, and tell
|
|
105
|
+
SQLite that you are using a URI name:
|
|
106
|
+
|
|
107
|
+
.. code-block:: python
|
|
108
|
+
|
|
109
|
+
import urllib.parse
|
|
110
|
+
import apsw
|
|
111
|
+
|
|
112
|
+
uri_filename = urllib.parse.quote("my db filename.sqlite3")
|
|
113
|
+
uri_parameters = urllib.parse.urlencode(
|
|
114
|
+
{
|
|
115
|
+
"cipher": "aes256cbc",
|
|
116
|
+
"kdf_iter": 8192,
|
|
117
|
+
"key": "it's a secret",
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
con = apsw.Connection(
|
|
121
|
+
f"file:{uri_filename}?{uri_parameters}",
|
|
122
|
+
flags=apsw.SQLITE_OPEN_URI
|
|
123
|
+
| apsw.SQLITE_OPEN_CREATE
|
|
124
|
+
| apsw.SQLITE_OPEN_READWRITE,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
Best practice
|
|
128
|
+
-------------
|
|
129
|
+
|
|
130
|
+
SQLite has various quirks in how it operates. For example database
|
|
131
|
+
files are not populated until the first write. SQLite3MultipleCiphers
|
|
132
|
+
can't check keys are correct until the first access, and the database
|
|
133
|
+
is populated. You shouldn't set or change keys while in a
|
|
134
|
+
transaction. In order to ensure files are populated, and the keys and
|
|
135
|
+
cipher configuration provided are correct, use the following method with
|
|
136
|
+
example usage shown at the end.
|
|
137
|
+
|
|
138
|
+
.. code-block:: python
|
|
139
|
+
|
|
140
|
+
import apsw
|
|
141
|
+
|
|
142
|
+
def apply_encryption(db, **kwargs):
|
|
143
|
+
"""You must include an argument for keying, and optional cipher configurations"""
|
|
144
|
+
|
|
145
|
+
if db.in_transaction:
|
|
146
|
+
raise Exception("Won't update encryption while in a transaction")
|
|
147
|
+
|
|
148
|
+
# the order of pragmas matters
|
|
149
|
+
def pragma_order(item):
|
|
150
|
+
# pragmas are case insensitive
|
|
151
|
+
pragma = item[0].lower()
|
|
152
|
+
# cipher must be first
|
|
153
|
+
if pragma == "cipher":
|
|
154
|
+
return 1
|
|
155
|
+
# old default settings reset configuration next
|
|
156
|
+
if pragma == "legacy":
|
|
157
|
+
return 2
|
|
158
|
+
# then anything with legacy in the name
|
|
159
|
+
if "legacy" in pragma:
|
|
160
|
+
return 3
|
|
161
|
+
# all except keys
|
|
162
|
+
if pragma not in {"key", "hexkey", "rekey", "hexrekey"}:
|
|
163
|
+
return 3
|
|
164
|
+
# keys are last
|
|
165
|
+
return 100
|
|
166
|
+
|
|
167
|
+
# check only ome key present
|
|
168
|
+
if 1 != sum(1 if pragma_order(item) == 100 else 0 for item in kwargs.items()):
|
|
169
|
+
raise ValueError("Exactly one key must be provided")
|
|
170
|
+
|
|
171
|
+
for pragma, value in sorted(kwargs.items(), key=pragma_order):
|
|
172
|
+
# if the pragma was understood and in range we get the value
|
|
173
|
+
# back, while key related ones return 'ok'
|
|
174
|
+
expected = "ok" if pragma_order((pragma, value)) == 100 else str(value)
|
|
175
|
+
if db.pragma(pragma, value) != expected:
|
|
176
|
+
raise ValueError(f"Failed to configure {pragma=}")
|
|
177
|
+
|
|
178
|
+
# Try to read from the database. If the database is encrypted and
|
|
179
|
+
# the cipher/key information is wrong you will get NotADBError
|
|
180
|
+
# because the file looks like random noise
|
|
181
|
+
db.pragma("user_version")
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
# try to set the user_version to the value it already has
|
|
185
|
+
# which has a side effect of populating an empty database
|
|
186
|
+
with db:
|
|
187
|
+
# done inside a transaction to avoid race conditions
|
|
188
|
+
db.pragma("user_version", db.pragma("user_version"))
|
|
189
|
+
except apsw.ReadOnlyError:
|
|
190
|
+
# can't make changes - that is ok
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
con = apsw.Connection("database.sqlite3")
|
|
195
|
+
|
|
196
|
+
apply_encryption(con, key="my secret key")
|
|
197
|
+
|
|
198
|
+
# you can also do more sophisticated operations. Here we change the cipher,
|
|
199
|
+
# kdf rounds, and the key
|
|
200
|
+
apply_encryption(con, rekey="new key", cipher="ascon128", kdf_iter=1000)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
Verification
|
|
204
|
+
------------
|
|
205
|
+
|
|
206
|
+
You can verify your database is encrypted with a hex viewer. Regular database files
|
|
207
|
+
start with `SQLite format 3` while encrypted database files are random.
|
|
208
|
+
|
|
209
|
+
.. code-block:: console
|
|
210
|
+
|
|
211
|
+
$ hexdump -C database.sqlite3 | head
|
|
212
|
+
00000000 e1 3e f0 7c 5e 66 4c 20 19 85 9d de 04 d9 e8 e7 |.>.|^fL ........|
|
|
213
|
+
00000010 10 00 01 01 20 40 20 20 29 2e cb 95 ef 4e 4e 67 |.... @ )....NNg|
|
|
214
|
+
00000020 22 a1 5a 8f 18 1a fa a1 cf b3 a8 ba b1 80 07 b5 |".Z.............|
|
|
215
|
+
00000030 2f 68 4d 8a 13 26 fd 6a 0c 99 5a a4 2c a7 f3 a7 |/hM..&.j..Z.,...|
|
|
216
|
+
00000040 d9 ae ef 24 dd 1c d1 9c cc 91 4b e8 58 00 96 62 |...$......K.X..b|
|
|
217
|
+
00000050 b2 aa 51 bf 57 8e 9a a9 d7 6d b2 75 58 84 f6 7d |..Q.W....m.uX..}|
|
|
218
|
+
00000060 c9 fd a9 57 88 05 ca 60 7f db d1 73 40 ad 98 59 |...W...`...s@..Y|
|
|
219
|
+
00000070 c2 a0 4c 76 f5 88 31 d3 d7 6f 9e ef f6 c1 c4 88 |..Lv..1..o......|
|
|
220
|
+
00000080 92 ed 8a 3e 00 ce 35 ef 4b 0d 38 33 9a 61 88 8a |...>..5.K.83.a..|
|
|
221
|
+
00000090 34 37 72 70 4b 33 f3 1d a2 4b 86 5f c5 59 02 c6 |47rpK3...K._.Y..|
|
|
222
|
+
|
|
223
|
+
$ hexdump -C regular.db | head
|
|
224
|
+
00000000 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 |SQLite format 3.|
|
|
225
|
+
00000010 10 00 02 02 00 40 20 20 00 00 00 95 00 09 22 e6 |.....@ ......".|
|
|
226
|
+
00000020 00 08 eb 8f 00 00 ff 8c 00 00 03 d5 00 00 00 04 |................|
|
|
227
|
+
00000030 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 |................|
|
|
228
|
+
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
|
229
|
+
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 95 |................|
|
|
230
|
+
00000060 00 2e 7a 70 0d 09 30 00 09 08 c9 00 0f a9 0e d5 |..zp..0.........|
|
|
231
|
+
00000070 0e 70 0d f7 0d 8c 08 c9 0c 67 0b 2f 09 71 08 db |.p.......g./.q..|
|
|
232
|
+
00000080 08 db 08 db 03 ae 03 55 03 55 03 55 03 55 03 55 |.......U.U.U.U.U|
|
|
233
|
+
00000090 03 55 03 55 03 55 03 55 03 55 03 55 03 55 03 55 |.U.U.U.U.U.U.U.U|
|
|
234
|
+
|
|
235
|
+
Support/Discussions
|
|
236
|
+
-------------------
|
|
237
|
+
|
|
238
|
+
For SQLite questions, support, and issues, use the `SQLite
|
|
239
|
+
Forum <https://sqlite.org/forum/forum>`__.`
|
|
240
|
+
|
|
241
|
+
For APSW questions, support, and issues, see `your
|
|
242
|
+
choices <https://rogerbinns.github.io/apsw/about.html#mailing-lists-contacts>`__.
|
|
243
|
+
|
|
244
|
+
For SQLite3MultipleCiphers questions, support, and issues see `the
|
|
245
|
+
project page <https://github.com/utelle/SQLite3MultipleCiphers>`__.
|
|
246
|
+
|
|
247
|
+
For APSW together with SQLite3MultipleCiphers questions, support, and
|
|
248
|
+
issues see `the project page
|
|
249
|
+
<https://github.com/utelle/apsw-sqlite3mc>`__.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
.. image:: https://raw.githubusercontent.com/utelle/apsw-sqlite3mc/sqlite3mc/apsw-sqlite3mc-logo.jpg
|
|
2
|
+
:width: 512 px
|
|
3
|
+
:alt: APSW SQLite Multiple Cipher logo - links to documentation
|
|
4
|
+
:target: https://utelle.github.io/SQLite3MultipleCiphers/
|
|
5
|
+
|
|
6
|
+
.. contents:: Contents
|
|
7
|
+
|
|
8
|
+
About
|
|
9
|
+
-----
|
|
10
|
+
|
|
11
|
+
This project packages 3 things together
|
|
12
|
+
|
|
13
|
+
`APSW <https://rogerbinns.github.io/apsw/>`__
|
|
14
|
+
|
|
15
|
+
Another Python SQLite wrapper, providing complete access to SQLite3
|
|
16
|
+
from Python.
|
|
17
|
+
|
|
18
|
+
`SQLite 3 <https://www.sqlite.org/>`__
|
|
19
|
+
|
|
20
|
+
Small, fast, self-contained, high-reliability, full-featured, SQL
|
|
21
|
+
database engine. SQLite is configured with `secure delete
|
|
22
|
+
<https://www.sqlite.org/pragma.html#pragma_secure_delete>`__ turned
|
|
23
|
+
on, and to use `memory for temporary storage
|
|
24
|
+
<https://www.sqlite.org/tempfiles.html#the_sqlite_temp_store_compile_time_parameter_and_pragma>`__.
|
|
25
|
+
|
|
26
|
+
`SQLite3 Multiple Ciphers <https://utelle.github.io/SQLite3MultipleCiphers/>`__
|
|
27
|
+
|
|
28
|
+
Extends SQLite 3 to allow reading and writing encrypted databases.
|
|
29
|
+
|
|
30
|
+
The distribution is entirely self contained, and does not use or alter
|
|
31
|
+
any existing SQLite you may already have on your system.
|
|
32
|
+
|
|
33
|
+
Installation
|
|
34
|
+
------------
|
|
35
|
+
|
|
36
|
+
Available from `PyPi <https://pypi.org/project/apsw-sqlite3mc/>`__.
|
|
37
|
+
Binaries are included for most platforms, and pip will build from
|
|
38
|
+
source for the rest.::
|
|
39
|
+
|
|
40
|
+
pip install apsw-sqlite3mc
|
|
41
|
+
|
|
42
|
+
Usage
|
|
43
|
+
-----
|
|
44
|
+
|
|
45
|
+
Use as you would regular `APSW
|
|
46
|
+
<https://rogerbinns.github.io/apsw/>`__. You can check the version of
|
|
47
|
+
SQLite3 Multiple Ciphers with ``apsw.mc_version``.
|
|
48
|
+
|
|
49
|
+
For encrypted databases you need to use the relevant `pragmas
|
|
50
|
+
<https://utelle.github.io/SQLite3MultipleCiphers/docs/configuration/config_sql_pragmas/>`__
|
|
51
|
+
to set a passphrase based key, or a binary bytes based key::
|
|
52
|
+
|
|
53
|
+
connection.pragma("key", "my secret passphrase")
|
|
54
|
+
connection.pragma("hexkey", b"\xfe\x23\x9e\x77".hex())
|
|
55
|
+
|
|
56
|
+
Setting the key on a new database is the only change needed to your code.
|
|
57
|
+
|
|
58
|
+
.. code-block:: pycon
|
|
59
|
+
|
|
60
|
+
>>> import apsw
|
|
61
|
+
>>> print(apsw.mc_version)
|
|
62
|
+
SQLite3 Multiple Ciphers 2.0.2
|
|
63
|
+
>>> con = apsw.Connection("database.sqlite3")
|
|
64
|
+
>>> con.pragma("key", "my secret passphrase")
|
|
65
|
+
ok
|
|
66
|
+
|
|
67
|
+
**Note**: The ``ok`` means the pragma was understood. It does not mean
|
|
68
|
+
the key is correct or has been applied to an empty database. See the
|
|
69
|
+
next section on best practice to check and apply the key.
|
|
70
|
+
|
|
71
|
+
**Note**: ``key`` only sets the key for following reads and writes. If
|
|
72
|
+
the database already has content, and you want to encrypt it then use
|
|
73
|
+
``rekey`` which will modify the database to apply the supplied key.
|
|
74
|
+
|
|
75
|
+
Alternately you can use `URI parameters
|
|
76
|
+
<https://utelle.github.io/SQLite3MultipleCiphers/docs/configuration/config_uri/>`__.
|
|
77
|
+
You need to correctly encode the filename and parameters, and tell
|
|
78
|
+
SQLite that you are using a URI name:
|
|
79
|
+
|
|
80
|
+
.. code-block:: python
|
|
81
|
+
|
|
82
|
+
import urllib.parse
|
|
83
|
+
import apsw
|
|
84
|
+
|
|
85
|
+
uri_filename = urllib.parse.quote("my db filename.sqlite3")
|
|
86
|
+
uri_parameters = urllib.parse.urlencode(
|
|
87
|
+
{
|
|
88
|
+
"cipher": "aes256cbc",
|
|
89
|
+
"kdf_iter": 8192,
|
|
90
|
+
"key": "it's a secret",
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
con = apsw.Connection(
|
|
94
|
+
f"file:{uri_filename}?{uri_parameters}",
|
|
95
|
+
flags=apsw.SQLITE_OPEN_URI
|
|
96
|
+
| apsw.SQLITE_OPEN_CREATE
|
|
97
|
+
| apsw.SQLITE_OPEN_READWRITE,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
Best practice
|
|
101
|
+
-------------
|
|
102
|
+
|
|
103
|
+
SQLite has various quirks in how it operates. For example database
|
|
104
|
+
files are not populated until the first write. SQLite3MultipleCiphers
|
|
105
|
+
can't check keys are correct until the first access, and the database
|
|
106
|
+
is populated. You shouldn't set or change keys while in a
|
|
107
|
+
transaction. In order to ensure files are populated, and the keys and
|
|
108
|
+
cipher configuration provided are correct, use the following method with
|
|
109
|
+
example usage shown at the end.
|
|
110
|
+
|
|
111
|
+
.. code-block:: python
|
|
112
|
+
|
|
113
|
+
import apsw
|
|
114
|
+
|
|
115
|
+
def apply_encryption(db, **kwargs):
|
|
116
|
+
"""You must include an argument for keying, and optional cipher configurations"""
|
|
117
|
+
|
|
118
|
+
if db.in_transaction:
|
|
119
|
+
raise Exception("Won't update encryption while in a transaction")
|
|
120
|
+
|
|
121
|
+
# the order of pragmas matters
|
|
122
|
+
def pragma_order(item):
|
|
123
|
+
# pragmas are case insensitive
|
|
124
|
+
pragma = item[0].lower()
|
|
125
|
+
# cipher must be first
|
|
126
|
+
if pragma == "cipher":
|
|
127
|
+
return 1
|
|
128
|
+
# old default settings reset configuration next
|
|
129
|
+
if pragma == "legacy":
|
|
130
|
+
return 2
|
|
131
|
+
# then anything with legacy in the name
|
|
132
|
+
if "legacy" in pragma:
|
|
133
|
+
return 3
|
|
134
|
+
# all except keys
|
|
135
|
+
if pragma not in {"key", "hexkey", "rekey", "hexrekey"}:
|
|
136
|
+
return 3
|
|
137
|
+
# keys are last
|
|
138
|
+
return 100
|
|
139
|
+
|
|
140
|
+
# check only ome key present
|
|
141
|
+
if 1 != sum(1 if pragma_order(item) == 100 else 0 for item in kwargs.items()):
|
|
142
|
+
raise ValueError("Exactly one key must be provided")
|
|
143
|
+
|
|
144
|
+
for pragma, value in sorted(kwargs.items(), key=pragma_order):
|
|
145
|
+
# if the pragma was understood and in range we get the value
|
|
146
|
+
# back, while key related ones return 'ok'
|
|
147
|
+
expected = "ok" if pragma_order((pragma, value)) == 100 else str(value)
|
|
148
|
+
if db.pragma(pragma, value) != expected:
|
|
149
|
+
raise ValueError(f"Failed to configure {pragma=}")
|
|
150
|
+
|
|
151
|
+
# Try to read from the database. If the database is encrypted and
|
|
152
|
+
# the cipher/key information is wrong you will get NotADBError
|
|
153
|
+
# because the file looks like random noise
|
|
154
|
+
db.pragma("user_version")
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
# try to set the user_version to the value it already has
|
|
158
|
+
# which has a side effect of populating an empty database
|
|
159
|
+
with db:
|
|
160
|
+
# done inside a transaction to avoid race conditions
|
|
161
|
+
db.pragma("user_version", db.pragma("user_version"))
|
|
162
|
+
except apsw.ReadOnlyError:
|
|
163
|
+
# can't make changes - that is ok
|
|
164
|
+
pass
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
con = apsw.Connection("database.sqlite3")
|
|
168
|
+
|
|
169
|
+
apply_encryption(con, key="my secret key")
|
|
170
|
+
|
|
171
|
+
# you can also do more sophisticated operations. Here we change the cipher,
|
|
172
|
+
# kdf rounds, and the key
|
|
173
|
+
apply_encryption(con, rekey="new key", cipher="ascon128", kdf_iter=1000)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
Verification
|
|
177
|
+
------------
|
|
178
|
+
|
|
179
|
+
You can verify your database is encrypted with a hex viewer. Regular database files
|
|
180
|
+
start with `SQLite format 3` while encrypted database files are random.
|
|
181
|
+
|
|
182
|
+
.. code-block:: console
|
|
183
|
+
|
|
184
|
+
$ hexdump -C database.sqlite3 | head
|
|
185
|
+
00000000 e1 3e f0 7c 5e 66 4c 20 19 85 9d de 04 d9 e8 e7 |.>.|^fL ........|
|
|
186
|
+
00000010 10 00 01 01 20 40 20 20 29 2e cb 95 ef 4e 4e 67 |.... @ )....NNg|
|
|
187
|
+
00000020 22 a1 5a 8f 18 1a fa a1 cf b3 a8 ba b1 80 07 b5 |".Z.............|
|
|
188
|
+
00000030 2f 68 4d 8a 13 26 fd 6a 0c 99 5a a4 2c a7 f3 a7 |/hM..&.j..Z.,...|
|
|
189
|
+
00000040 d9 ae ef 24 dd 1c d1 9c cc 91 4b e8 58 00 96 62 |...$......K.X..b|
|
|
190
|
+
00000050 b2 aa 51 bf 57 8e 9a a9 d7 6d b2 75 58 84 f6 7d |..Q.W....m.uX..}|
|
|
191
|
+
00000060 c9 fd a9 57 88 05 ca 60 7f db d1 73 40 ad 98 59 |...W...`...s@..Y|
|
|
192
|
+
00000070 c2 a0 4c 76 f5 88 31 d3 d7 6f 9e ef f6 c1 c4 88 |..Lv..1..o......|
|
|
193
|
+
00000080 92 ed 8a 3e 00 ce 35 ef 4b 0d 38 33 9a 61 88 8a |...>..5.K.83.a..|
|
|
194
|
+
00000090 34 37 72 70 4b 33 f3 1d a2 4b 86 5f c5 59 02 c6 |47rpK3...K._.Y..|
|
|
195
|
+
|
|
196
|
+
$ hexdump -C regular.db | head
|
|
197
|
+
00000000 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 |SQLite format 3.|
|
|
198
|
+
00000010 10 00 02 02 00 40 20 20 00 00 00 95 00 09 22 e6 |.....@ ......".|
|
|
199
|
+
00000020 00 08 eb 8f 00 00 ff 8c 00 00 03 d5 00 00 00 04 |................|
|
|
200
|
+
00000030 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 |................|
|
|
201
|
+
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
|
202
|
+
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 95 |................|
|
|
203
|
+
00000060 00 2e 7a 70 0d 09 30 00 09 08 c9 00 0f a9 0e d5 |..zp..0.........|
|
|
204
|
+
00000070 0e 70 0d f7 0d 8c 08 c9 0c 67 0b 2f 09 71 08 db |.p.......g./.q..|
|
|
205
|
+
00000080 08 db 08 db 03 ae 03 55 03 55 03 55 03 55 03 55 |.......U.U.U.U.U|
|
|
206
|
+
00000090 03 55 03 55 03 55 03 55 03 55 03 55 03 55 03 55 |.U.U.U.U.U.U.U.U|
|
|
207
|
+
|
|
208
|
+
Support/Discussions
|
|
209
|
+
-------------------
|
|
210
|
+
|
|
211
|
+
For SQLite questions, support, and issues, use the `SQLite
|
|
212
|
+
Forum <https://sqlite.org/forum/forum>`__.`
|
|
213
|
+
|
|
214
|
+
For APSW questions, support, and issues, see `your
|
|
215
|
+
choices <https://rogerbinns.github.io/apsw/about.html#mailing-lists-contacts>`__.
|
|
216
|
+
|
|
217
|
+
For SQLite3MultipleCiphers questions, support, and issues see `the
|
|
218
|
+
project page <https://github.com/utelle/SQLite3MultipleCiphers>`__.
|
|
219
|
+
|
|
220
|
+
For APSW together with SQLite3MultipleCiphers questions, support, and
|
|
221
|
+
issues see `the project page
|
|
222
|
+
<https://github.com/utelle/apsw-sqlite3mc>`__.
|