2
* Encryption codec implementation
3
* (C) 2010 Olivier de Gaalon
5
* Botan is released under the Simplified BSD License (see license.txt)
8
#ifndef SQLITE_OMIT_DISKIO
9
#ifdef SQLITE_HAS_CODEC
11
#include "codec_c_interface.h"
13
Bool HandleError(void *pCodec)
15
const char *error = GetAndResetError(pCodec);
17
sqlite3Error((sqlite3*)GetDB(pCodec), SQLITE_ERROR, "Botan Error: %s", error);
23
// Guessing that "see" is related to SQLite Encryption Extension" (the semi-official, for-pay, encryption codec)
24
// Just as useful for initializing Botan.
25
void sqlite3_activate_see(const char *info)
30
// Free the encryption codec, called from pager.c (address passed in sqlite3PagerSetCodec)
31
void sqlite3PagerFreeCodec(void *pCodec)
37
// Report the page size to the codec, called from pager.c (address passed in sqlite3PagerSetCodec)
38
void sqlite3CodecSizeChange(void *pCodec, int pageSize, int nReserve)
40
SetPageSize(pCodec, pageSize);
43
// Encrypt/Decrypt functionality, called by pager.c
44
void* sqlite3Codec(void *pCodec, void *data, Pgno nPageNum, int nMode)
46
if (pCodec == NULL) //Db not encrypted
51
case 0: // Undo a "case 7" journal file encryption
52
case 2: // Reload a page
53
case 3: // Load a page
54
if (HasReadKey(pCodec))
55
Decrypt(pCodec, nPageNum, (unsigned char*) data);
57
case 6: // Encrypt a page for the main database file
58
if (HasWriteKey(pCodec))
59
data = Encrypt(pCodec, nPageNum, (unsigned char*) data, 1);
61
case 7: // Encrypt a page for the journal file
63
*Under normal circumstances, the readkey is the same as the writekey. However,
64
*when the database is being rekeyed, the readkey is not the same as the writekey.
65
*(The writekey is the "destination key" for the rekey operation and the readkey
66
*is the key the db is currently encrypted with)
67
*Therefore, for case 7, when the rollback is being written, always encrypt using
68
*the database's readkey, which is guaranteed to be the same key that was used to
69
*read and write the original data.
71
if (HasReadKey(pCodec))
72
data = Encrypt(pCodec, nPageNum, (unsigned char*) data, 0);
81
int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *zKey, int nKey)
85
if (zKey == NULL || nKey <= 0)
87
// No key specified, could mean either use the main db's encryption or no encryption
88
if (nDb != 0 && nKey < 0)
90
//Is an attached database, therefore use the key of main database, if main database is encrypted
91
void *pMainCodec = sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt));
92
if (pMainCodec != NULL)
94
pCodec = InitializeFromOtherCodec(pMainCodec, db);
95
sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),
97
sqlite3CodecSizeChange,
98
sqlite3PagerFreeCodec, pCodec);
104
// Key specified, setup encryption key for database
105
pCodec = InitializeNewCodec(db);
106
GenerateWriteKey(pCodec, (const char*) zKey, nKey);
107
SetReadIsWrite(pCodec);
108
sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),
110
sqlite3CodecSizeChange,
111
sqlite3PagerFreeCodec, pCodec);
114
if (HandleError(pCodec))
120
void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey)
122
// The unencrypted password is not stored for security reasons
123
// therefore always return NULL
128
int sqlite3_key(sqlite3 *db, const void *zKey, int nKey)
130
// The key is only set for the main database, not the temp database
131
return sqlite3CodecAttach(db, 0, zKey, nKey);
134
int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey)
136
// Changes the encryption key for an existing database.
137
int rc = SQLITE_ERROR;
138
Btree *pbt = db->aDb[0].pBt;
139
Pager *pPager = sqlite3BtreePager(pbt);
140
void *pCodec = sqlite3PagerGetCodec(pPager);
142
if ((zKey == NULL || nKey == 0) && pCodec == NULL)
144
// Database not encrypted and key not specified. Do nothing
150
// Database not encrypted, but key specified. Encrypt database
151
pCodec = InitializeNewCodec(db);
152
GenerateWriteKey(pCodec, (const char*) zKey, nKey);
154
if (HandleError(pCodec))
157
sqlite3PagerSetCodec(pPager, sqlite3Codec, sqlite3CodecSizeChange, sqlite3PagerFreeCodec, pCodec);
159
else if (zKey == NULL || nKey == 0)
161
// Database encrypted, but key not specified. Decrypt database
162
// Keep read key, drop write key
163
DropWriteKey(pCodec);
167
// Database encrypted and key specified. Re-encrypt database with new key
168
// Keep read key, change write key to new key
169
GenerateWriteKey(pCodec, (const char*) zKey, nKey);
170
if (HandleError(pCodec))
175
rc = sqlite3BtreeBeginTrans(pbt, 1);
178
// Rewrite all pages using the new encryption key (if specified)
180
sqlite3PagerPagecount(pPager, &nPageCount);
181
Pgno nPage = (Pgno) nPageCount;
183
Pgno nSkip = PAGER_MJ_PGNO(pPager);
187
for (n = 1; rc == SQLITE_OK && n <= nPage; n++)
192
rc = sqlite3PagerGet(pPager, n, &pPage);
196
rc = sqlite3PagerWrite(pPage);
197
sqlite3PagerUnref(pPage);
200
sqlite3Error(db, SQLITE_ERROR, "%s", "Error while rekeying database page. Transaction Canceled.");
204
sqlite3Error(db, SQLITE_ERROR, "%s", "Error beginning rekey transaction. Make sure that the current encryption key is correct.");
209
rc = sqlite3BtreeCommit(pbt);
213
//Database rekeyed and committed successfully, update read key
214
if (HasWriteKey(pCodec))
215
SetReadIsWrite(pCodec);
216
else //No write key == no longer encrypted
217
sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL);
221
//FIXME: can't trigger this, not sure if rollback is needed, reference implementation didn't rollback
222
sqlite3Error(db, SQLITE_ERROR, "%s", "Could not commit rekey transaction.");
227
// Rollback, rekey failed
228
sqlite3BtreeRollback(pbt, SQLITE_ERROR);
230
// go back to read key
231
if (HasReadKey(pCodec))
232
SetWriteIsRead(pCodec);
233
else //Database wasn't encrypted to start with
234
sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL);
240
#endif // SQLITE_HAS_CODEC
242
#endif // SQLITE_OMIT_DISKIO