~ubuntu-branches/debian/sid/botan/sid

« back to all changes in this revision

Viewing changes to src/contrib/sqlite/codecext.c

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2018-03-01 22:23:25 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20180301222325-7p7vc45gu3hta34d
Tags: 2.4.0-2
* Don't remove .doctrees from the manual if it doesn't exist.
* Don't specify parallel to debhelper.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Encryption codec implementation
 
3
 * (C) 2010 Olivier de Gaalon
 
4
 *
 
5
 * Botan is released under the Simplified BSD License (see license.txt)
 
6
 */
 
7
 
 
8
#ifndef SQLITE_OMIT_DISKIO
 
9
#ifdef SQLITE_HAS_CODEC
 
10
 
 
11
#include "codec_c_interface.h"
 
12
 
 
13
Bool HandleError(void *pCodec)
 
14
{
 
15
    const char *error = GetAndResetError(pCodec);
 
16
    if (error) {
 
17
        sqlite3Error((sqlite3*)GetDB(pCodec), SQLITE_ERROR, "Botan Error: %s", error);
 
18
        return 1;
 
19
    }
 
20
    return 0;
 
21
}
 
22
 
 
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)
 
26
{
 
27
    InitializeBotan();
 
28
}
 
29
 
 
30
// Free the encryption codec, called from pager.c (address passed in sqlite3PagerSetCodec)
 
31
void sqlite3PagerFreeCodec(void *pCodec)
 
32
{
 
33
    if (pCodec)
 
34
        DeleteCodec(pCodec);
 
35
}
 
36
 
 
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)
 
39
{
 
40
    SetPageSize(pCodec, pageSize);
 
41
}
 
42
 
 
43
// Encrypt/Decrypt functionality, called by pager.c
 
44
void* sqlite3Codec(void *pCodec, void *data, Pgno nPageNum, int nMode)
 
45
{
 
46
    if (pCodec == NULL) //Db not encrypted
 
47
        return data;
 
48
 
 
49
    switch(nMode)
 
50
    {
 
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);
 
56
        break;
 
57
    case 6: // Encrypt a page for the main database file
 
58
        if (HasWriteKey(pCodec))
 
59
            data = Encrypt(pCodec, nPageNum, (unsigned char*) data, 1);
 
60
        break;
 
61
    case 7: // Encrypt a page for the journal file
 
62
    /*
 
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.
 
70
    */
 
71
        if (HasReadKey(pCodec))
 
72
            data = Encrypt(pCodec, nPageNum, (unsigned char*) data, 0);
 
73
        break;
 
74
    }
 
75
    
 
76
    HandleError(pCodec);
 
77
 
 
78
    return data;
 
79
}
 
80
 
 
81
int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *zKey, int nKey)
 
82
{
 
83
    void *pCodec = NULL;
 
84
 
 
85
    if (zKey == NULL || nKey <= 0)
 
86
    {
 
87
        // No key specified, could mean either use the main db's encryption or no encryption
 
88
        if (nDb != 0 && nKey < 0)
 
89
        {
 
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)
 
93
            {
 
94
                pCodec = InitializeFromOtherCodec(pMainCodec, db);
 
95
                sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),
 
96
                                    sqlite3Codec,
 
97
                                    sqlite3CodecSizeChange,
 
98
                                    sqlite3PagerFreeCodec, pCodec);
 
99
            }
 
100
        }
 
101
    }
 
102
    else
 
103
    {
 
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),
 
109
                            sqlite3Codec,
 
110
                            sqlite3CodecSizeChange,
 
111
                            sqlite3PagerFreeCodec, pCodec);
 
112
    }
 
113
 
 
114
    if (HandleError(pCodec))
 
115
        return SQLITE_ERROR;
 
116
 
 
117
    return SQLITE_OK;
 
118
}
 
119
 
 
120
void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey)
 
121
{
 
122
    // The unencrypted password is not stored for security reasons
 
123
    // therefore always return NULL
 
124
    *zKey = NULL;
 
125
    *nKey = -1;
 
126
}
 
127
 
 
128
int sqlite3_key(sqlite3 *db, const void *zKey, int nKey)
 
129
{
 
130
    // The key is only set for the main database, not the temp database
 
131
    return sqlite3CodecAttach(db, 0, zKey, nKey);
 
132
}
 
133
 
 
134
int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey)
 
135
{
 
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);
 
141
 
 
142
    if ((zKey == NULL || nKey == 0) && pCodec == NULL)
 
143
    {
 
144
        // Database not encrypted and key not specified. Do nothing
 
145
        return SQLITE_OK;
 
146
    }
 
147
 
 
148
    if (pCodec == NULL)
 
149
    {
 
150
        // Database not encrypted, but key specified. Encrypt database
 
151
        pCodec = InitializeNewCodec(db);
 
152
        GenerateWriteKey(pCodec, (const char*) zKey, nKey);
 
153
        
 
154
        if (HandleError(pCodec))
 
155
            return SQLITE_ERROR;
 
156
 
 
157
        sqlite3PagerSetCodec(pPager, sqlite3Codec, sqlite3CodecSizeChange, sqlite3PagerFreeCodec, pCodec);
 
158
    }
 
159
    else if (zKey == NULL || nKey == 0)
 
160
    {
 
161
        // Database encrypted, but key not specified. Decrypt database
 
162
        // Keep read key, drop write key
 
163
        DropWriteKey(pCodec);
 
164
    }
 
165
    else
 
166
    {
 
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))
 
171
            return SQLITE_ERROR;
 
172
    }
 
173
 
 
174
    // Start transaction
 
175
    rc = sqlite3BtreeBeginTrans(pbt, 1);
 
176
    if (rc == SQLITE_OK)
 
177
    {
 
178
        // Rewrite all pages using the new encryption key (if specified)
 
179
        int nPageCount = -1;
 
180
        sqlite3PagerPagecount(pPager, &nPageCount);
 
181
        Pgno nPage = (Pgno) nPageCount;
 
182
 
 
183
        Pgno nSkip = PAGER_MJ_PGNO(pPager);
 
184
        DbPage *pPage;
 
185
 
 
186
        Pgno n;
 
187
        for (n = 1; rc == SQLITE_OK && n <= nPage; n++)
 
188
        {
 
189
            if (n == nSkip)
 
190
                continue;
 
191
 
 
192
            rc = sqlite3PagerGet(pPager, n, &pPage);
 
193
 
 
194
            if (!rc)
 
195
            {
 
196
                rc = sqlite3PagerWrite(pPage);
 
197
                sqlite3PagerUnref(pPage);
 
198
            }
 
199
            else
 
200
                sqlite3Error(db, SQLITE_ERROR, "%s", "Error while rekeying database page. Transaction Canceled.");
 
201
        }
 
202
    }
 
203
    else
 
204
        sqlite3Error(db, SQLITE_ERROR, "%s", "Error beginning rekey transaction. Make sure that the current encryption key is correct.");
 
205
 
 
206
    if (rc == SQLITE_OK)
 
207
    {
 
208
        // All good, commit
 
209
        rc = sqlite3BtreeCommit(pbt);
 
210
 
 
211
        if (rc == SQLITE_OK)
 
212
        {
 
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); 
 
218
        }
 
219
        else
 
220
        {
 
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.");
 
223
        }
 
224
    }
 
225
    else
 
226
    {
 
227
        // Rollback, rekey failed
 
228
        sqlite3BtreeRollback(pbt, SQLITE_ERROR);
 
229
 
 
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); 
 
235
    }
 
236
 
 
237
    return rc;
 
238
}
 
239
 
 
240
#endif // SQLITE_HAS_CODEC
 
241
 
 
242
#endif // SQLITE_OMIT_DISKIO