diff --git a/uppsrc/plugin/sqlite3/Sqlite3upp.cpp b/uppsrc/plugin/sqlite3/Sqlite3upp.cpp index 5ae80f4b0..b85d4068e 100644 --- a/uppsrc/plugin/sqlite3/Sqlite3upp.cpp +++ b/uppsrc/plugin/sqlite3/Sqlite3upp.cpp @@ -1,6 +1,6 @@ #include #include -#include "lib/sqlite3.h" +#include "lib/sqleet.h" #include "Sqlite3.h" namespace Upp { diff --git a/uppsrc/plugin/sqlite3/sqlite3.c b/uppsrc/plugin/sqlite3/lib.c similarity index 84% rename from uppsrc/plugin/sqlite3/sqlite3.c rename to uppsrc/plugin/sqlite3/lib.c index b8ce61c9f..be02ce122 100644 --- a/uppsrc/plugin/sqlite3/sqlite3.c +++ b/uppsrc/plugin/sqlite3/lib.c @@ -5,4 +5,4 @@ #define SQLITE_ENABLE_JSON1 1 #define SQLITE_ENABLE_RBU 1 -#include "lib/sqlite3.c" +#include "lib/sqleet.c" diff --git a/uppsrc/plugin/sqlite3/lib/sqlite3.c b/uppsrc/plugin/sqlite3/lib/sqleet.c similarity index 99% rename from uppsrc/plugin/sqlite3/lib/sqlite3.c rename to uppsrc/plugin/sqlite3/lib/sqleet.c index 4729f4572..b6dbb98e2 100644 --- a/uppsrc/plugin/sqlite3/lib/sqlite3.c +++ b/uppsrc/plugin/sqlite3/lib/sqleet.c @@ -1,3 +1,40 @@ +#define SQLITE3_H_OMIT +/* + * sqleet configuration. + * + * # SKIP_HEADER_BYTES + * Keep this many bytes unencrypted in the beginning of the database header. + * Value 0 produces encrypted databases that are indistinguishable from random. + * Use 24 for compatibility with the SQLite3 Encryption Extension (SEE) so that + * database settings (e.g., page size) can be read from an encrypted database. + */ +#ifndef SKIP_HEADER_BYTES +#define SKIP_HEADER_BYTES 0 +#endif + +/* + * SQLite3 configuration. + * + * # SQLITE_HAS_CODEC + * Required for compiling SQLite3 with encryption support. + * + * # SQLITE_TEMP_STORE + * - 0 Store temp files on disk + * - 1 Store temp files on disk but allow overriding with `PRAGMA temp_store` + * - 2 Store temp files in memory but allow overriding with `PRAGMA temp_store` + * - 3 Store temp files on memory + * Note that temp files are *NOT* encrypted so using either 2 or 3 is critical! + */ +#ifndef SQLITE_HAS_CODEC +#define SQLITE_HAS_CODEC 1 +#endif +#ifndef SQLITE_TEMP_STORE +#define SQLITE_TEMP_STORE 2 +#endif + +#ifndef SQLITE3_H_OMIT +#include "sqlite3.h" +#endif /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite ** version 3.27.2. By combining all the individual C code files into this @@ -221835,3 +221872,1346 @@ SQLITE_API int sqlite3_stmt_init( /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } /************************** End of sqlite3.c ******************************/ +/* +** Adjusted version of sqlite3RunVacuum() to allow reducing reserved page space. +** For this purpose the number of reserved bytes per page is passed as an extra +** parameter to the adjusted function. +** +** Change 0: Rename function to sqlite3RekeyVacuum() +** Change 1: Add parameter 'int nRes' +** Change 2: Remove local variable 'int nRes' +** Change 3: Remove initialization 'nRes = sqlite3BtreeGetOptimalReserve(pMain)' +** +** Code generated by script/rekeyvacuum.sh from SQLite v3.27.2 amalgamation. +*/ +SQLITE_PRIVATE int sqlite3RekeyVacuum( + char **pzErrMsg, /* Write error message here */ + sqlite3 *db, /* Database connection */ + int iDb, /* Which attached DB to vacuum */ + sqlite3_value *pOut /* Write results here, if not NULL */ +, int nRes){ + int rc = SQLITE_OK; /* Return code from service routines */ + Btree *pMain; /* The database being vacuumed */ + Btree *pTemp; /* The temporary database we vacuum into */ + u32 saved_mDbFlags; /* Saved value of db->mDbFlags */ + u64 saved_flags; /* Saved value of db->flags */ + int saved_nChange; /* Saved value of db->nChange */ + int saved_nTotalChange; /* Saved value of db->nTotalChange */ + u8 saved_mTrace; /* Saved trace settings */ + Db *pDb = 0; /* Database to detach at end of vacuum */ + int isMemDb; /* True if vacuuming a :memory: database */ + int nDb; /* Number of attached databases */ + const char *zDbMain; /* Schema name of database to vacuum */ + const char *zOut; /* Name of output file */ + + if( !db->autoCommit ){ + sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); + return SQLITE_ERROR; + } + if( db->nVdbeActive>1 ){ + sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); + return SQLITE_ERROR; + } + if( pOut ){ + if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ + sqlite3SetString(pzErrMsg, db, "non-text filename"); + return SQLITE_ERROR; + } + zOut = (const char*)sqlite3_value_text(pOut); + }else{ + zOut = ""; + } + + /* Save the current value of the database flags so that it can be + ** restored before returning. Then set the writable-schema flag, and + ** disable CHECK and foreign key constraints. */ + saved_flags = db->flags; + saved_mDbFlags = db->mDbFlags; + saved_nChange = db->nChange; + saved_nTotalChange = db->nTotalChange; + saved_mTrace = db->mTrace; + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; + db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; + db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder + | SQLITE_Defensive | SQLITE_CountRows); + db->mTrace = 0; + + zDbMain = db->aDb[iDb].zDbSName; + pMain = db->aDb[iDb].pBt; + isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); + + /* Attach the temporary database as 'vacuum_db'. The synchronous pragma + ** can be set to 'off' for this file, as it is not recovered if a crash + ** occurs anyway. The integrity of the database is maintained by a + ** (possibly synchronous) transaction opened on the main database before + ** sqlite3BtreeCopyFile() is called. + ** + ** An optimisation would be to use a non-journaled pager. + ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but + ** that actually made the VACUUM run slower. Very little journalling + ** actually occurs when doing a vacuum since the vacuum_db is initially + ** empty. Only the journal header is written. Apparently it takes more + ** time to parse and run the PRAGMA to turn journalling off than it does + ** to write the journal header file. + */ + nDb = db->nDb; + rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + assert( (db->nDb-1)==nDb ); + pDb = &db->aDb[nDb]; + assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); + pTemp = pDb->pBt; + if( pOut ){ + sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); + i64 sz = 0; + if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ + rc = SQLITE_ERROR; + sqlite3SetString(pzErrMsg, db, "output file already exists"); + goto end_of_vacuum; + } + } + + /* A VACUUM cannot change the pagesize of an encrypted database. */ +#ifdef SQLITE_HAS_CODEC + if( db->nextPagesize ){ + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); + int nKey; + char *zKey; + sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); + if( nKey ) db->nextPagesize = 0; + } +#endif + + sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); + sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); + sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL); + + /* Begin a transaction and take an exclusive lock on the main database + ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, + ** to ensure that we do not try to change the page-size on a WAL database. + */ + rc = execSql(db, pzErrMsg, "BEGIN"); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + + /* Do not attempt to change the page size for a WAL database */ + if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) + ==PAGER_JOURNALMODE_WAL ){ + db->nextPagesize = 0; + } + + if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) + || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) + || NEVER(db->mallocFailed) + ){ + rc = SQLITE_NOMEM_BKPT; + goto end_of_vacuum; + } + +#ifndef SQLITE_OMIT_AUTOVACUUM + sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac : + sqlite3BtreeGetAutoVacuum(pMain)); +#endif + + /* Query the schema of the main database. Create a mirror schema + ** in the temporary database. + */ + db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ + rc = execSqlF(db, pzErrMsg, + "SELECT sql FROM \"%w\".sqlite_master" + " WHERE type='table'AND name<>'sqlite_sequence'" + " AND coalesce(rootpage,1)>0", + zDbMain + ); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = execSqlF(db, pzErrMsg, + "SELECT sql FROM \"%w\".sqlite_master" + " WHERE type='index'", + zDbMain + ); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + db->init.iDb = 0; + + /* Loop through the tables in the main database. For each, do + ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy + ** the contents to the temporary database. + */ + rc = execSqlF(db, pzErrMsg, + "SELECT'INSERT INTO vacuum_db.'||quote(name)" + "||' SELECT*FROM\"%w\".'||quote(name)" + "FROM vacuum_db.sqlite_master " + "WHERE type='table'AND coalesce(rootpage,1)>0", + zDbMain + ); + assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); + db->mDbFlags &= ~DBFLAG_Vacuum; + if( rc!=SQLITE_OK ) goto end_of_vacuum; + + /* Copy the triggers, views, and virtual tables from the main database + ** over to the temporary database. None of these objects has any + ** associated storage, so all we have to do is copy their entries + ** from the SQLITE_MASTER table. + */ + rc = execSqlF(db, pzErrMsg, + "INSERT INTO vacuum_db.sqlite_master" + " SELECT*FROM \"%w\".sqlite_master" + " WHERE type IN('view','trigger')" + " OR(type='table'AND rootpage=0)", + zDbMain + ); + if( rc ) goto end_of_vacuum; + + /* At this point, there is a write transaction open on both the + ** vacuum database and the main database. Assuming no error occurs, + ** both transactions are closed by this block - the main database + ** transaction by sqlite3BtreeCopyFile() and the other by an explicit + ** call to sqlite3BtreeCommit(). + */ + { + u32 meta; + int i; + + /* This array determines which meta meta values are preserved in the + ** vacuum. Even entries are the meta value number and odd entries + ** are an increment to apply to the meta value after the vacuum. + ** The increment is used to increase the schema cookie so that other + ** connections to the same database will know to reread the schema. + */ + static const unsigned char aCopy[] = { + BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ + BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ + BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ + BTREE_USER_VERSION, 0, /* Preserve the user version */ + BTREE_APPLICATION_ID, 0, /* Preserve the application id */ + }; + + assert( 1==sqlite3BtreeIsInTrans(pTemp) ); + assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) ); + + /* Copy Btree meta values */ + for(i=0; iflags */ + db->init.iDb = 0; + db->mDbFlags = saved_mDbFlags; + db->flags = saved_flags; + db->nChange = saved_nChange; + db->nTotalChange = saved_nTotalChange; + db->mTrace = saved_mTrace; + sqlite3BtreeSetPageSize(pMain, -1, -1, 1); + + /* Currently there is an SQL level transaction open on the vacuum + ** database. No locks are held on any other files (since the main file + ** was committed at the btree level). So it safe to end the transaction + ** by manually setting the autoCommit flag to true and detaching the + ** vacuum database. The vacuum_db journal file is deleted when the pager + ** is closed by the DETACH. + */ + db->autoCommit = 1; + + if( pDb ){ + sqlite3BtreeClose(pDb->pBt); + pDb->pBt = 0; + pDb->pSchema = 0; + } + + /* This both clears the schemas and reduces the size of the db->aDb[] + ** array. */ + sqlite3ResetAllSchemasOfConnection(db); + + return rc; +} +/* This file is included by sqleet.c */ +#include +#include + +#define ROL32(x, c) (((x) << (c)) | ((x) >> (32-(c)))) +#define ROR32(x, c) (((x) >> (c)) | ((x) << (32-(c)))) + +#define LOAD32_LE(p) \ + ( ((uint32_t)((p)[0]) << 0) \ + | ((uint32_t)((p)[1]) << 8) \ + | ((uint32_t)((p)[2]) << 16) \ + | ((uint32_t)((p)[3]) << 24) \ + ) +#define LOAD32_BE(p) \ + ( ((uint32_t)((p)[3]) << 0) \ + | ((uint32_t)((p)[2]) << 8) \ + | ((uint32_t)((p)[1]) << 16) \ + | ((uint32_t)((p)[0]) << 24) \ + ) + +#define STORE32_LE(p, v) \ + (p)[0] = ((v) >> 0) & 0xFF; \ + (p)[1] = ((v) >> 8) & 0xFF; \ + (p)[2] = ((v) >> 16) & 0xFF; \ + (p)[3] = ((v) >> 24) & 0xFF; +#define STORE32_BE(p, v) \ + (p)[3] = ((v) >> 0) & 0xFF; \ + (p)[2] = ((v) >> 8) & 0xFF; \ + (p)[1] = ((v) >> 16) & 0xFF; \ + (p)[0] = ((v) >> 24) & 0xFF; +#define STORE64_BE(p, v) \ + (p)[7] = ((v) >> 0) & 0xFF; \ + (p)[6] = ((v) >> 8) & 0xFF; \ + (p)[5] = ((v) >> 16) & 0xFF; \ + (p)[4] = ((v) >> 24) & 0xFF; \ + (p)[3] = ((v) >> 32) & 0xFF; \ + (p)[2] = ((v) >> 40) & 0xFF; \ + (p)[1] = ((v) >> 48) & 0xFF; \ + (p)[0] = ((v) >> 56) & 0xFF; + +/* + * ChaCha20 stream cipher + */ +static void chacha20_block(unsigned char out[64], const uint32_t in[16]) +{ + int i; + uint32_t x[16]; + memcpy(x, in, sizeof(uint32_t) * 16); + + #define QR(x, a, b, c, d) \ + x[a] += x[b]; x[d] ^= x[a]; x[d] = ROL32(x[d], 16); \ + x[c] += x[d]; x[b] ^= x[c]; x[b] = ROL32(x[b], 12); \ + x[a] += x[b]; x[d] ^= x[a]; x[d] = ROL32(x[d], 8); \ + x[c] += x[d]; x[b] ^= x[c]; x[b] = ROL32(x[b], 7); + for (i = 0; i < 10; i++) { + /* Column round */ + QR(x, 0, 4, 8, 12) + QR(x, 1, 5, 9, 13) + QR(x, 2, 6, 10, 14) + QR(x, 3, 7, 11, 15) + /* Diagonal round */ + QR(x, 0, 5, 10, 15) + QR(x, 1, 6, 11, 12) + QR(x, 2, 7, 8, 13) + QR(x, 3, 4, 9, 14) + } + #undef QR + for (i = 0; i < 16; i++) { + const uint32_t v = x[i] + in[i]; + STORE32_LE(&out[4*i], v); + } +} + +void chacha20_xor(unsigned char *data, size_t n, const unsigned char key[32], + const unsigned char nonce[12], uint32_t counter) +{ + int i; + uint32_t state[16]; + unsigned char block[64]; + static const unsigned char sigma[16] = "expand 32-byte k"; + + state[ 0] = LOAD32_LE(sigma + 0); + state[ 1] = LOAD32_LE(sigma + 4); + state[ 2] = LOAD32_LE(sigma + 8); + state[ 3] = LOAD32_LE(sigma + 12); + + state[ 4] = LOAD32_LE(key + 0); + state[ 5] = LOAD32_LE(key + 4); + state[ 6] = LOAD32_LE(key + 8); + state[ 7] = LOAD32_LE(key + 12); + state[ 8] = LOAD32_LE(key + 16); + state[ 9] = LOAD32_LE(key + 20); + state[10] = LOAD32_LE(key + 24); + state[11] = LOAD32_LE(key + 28); + + state[12] = counter; + + state[13] = LOAD32_LE(nonce + 0); + state[14] = LOAD32_LE(nonce + 4); + state[15] = LOAD32_LE(nonce + 8); + + while (n >= 64) { + chacha20_block(block, state); + for (i = 0; i < 64; i++) + data[i] ^= block[i]; + state[12]++; + data += 64; + n -= 64; + } + + if (n > 0) { + chacha20_block(block, state); + for (i = 0; i < n; i++) + data[i] ^= block[i]; + } + return; +} + +/* + * Poly1305 authentication tags + */ +void poly1305(const unsigned char *msg, size_t n, const unsigned char key[32], + unsigned char tag[16]) +{ + uint32_t hibit, m, w; + uint32_t h0, h1, h2, h3, h4; + uint32_t r0, r1, r2, r3, r4; + uint32_t s1, s2, s3, s4; + uint64_t f0, f1, f2, f3; + uint32_t g0, g1, g2, g3, g4; + unsigned char buf[16]; + + hibit = 1 << 24; + h0 = h1 = h2 = h3 = h4 = 0; + r0 = (LOAD32_LE(key + 0) >> 0) & 0x03FFFFFF; + r1 = (LOAD32_LE(key + 3) >> 2) & 0x03FFFF03; s1 = r1 * 5; + r2 = (LOAD32_LE(key + 6) >> 4) & 0x03FFC0FF; s2 = r2 * 5; + r3 = (LOAD32_LE(key + 9) >> 6) & 0x03F03FFF; s3 = r3 * 5; + r4 = (LOAD32_LE(key + 12) >> 8) & 0x000FFFFF; s4 = r4 * 5; + while (n >= 16) { + uint64_t d0, d1, d2, d3, d4; +process_block: + h0 += (LOAD32_LE(msg + 0) >> 0) & 0x03FFFFFF; + h1 += (LOAD32_LE(msg + 3) >> 2) & 0x03FFFFFF; + h2 += (LOAD32_LE(msg + 6) >> 4) & 0x03FFFFFF; + h3 += (LOAD32_LE(msg + 9) >> 6) & 0x03FFFFFF; + h4 += (LOAD32_LE(msg + 12) >> 8) | hibit; + + #define MUL(a,b) ((uint64_t)(a) * (b)) + d0 = MUL(h0,r0) + MUL(h1,s4) + MUL(h2,s3) + MUL(h3,s2) + MUL(h4,s1); + d1 = MUL(h0,r1) + MUL(h1,r0) + MUL(h2,s4) + MUL(h3,s3) + MUL(h4,s2); + d2 = MUL(h0,r2) + MUL(h1,r1) + MUL(h2,r0) + MUL(h3,s4) + MUL(h4,s3); + d3 = MUL(h0,r3) + MUL(h1,r2) + MUL(h2,r1) + MUL(h3,r0) + MUL(h4,s4); + d4 = MUL(h0,r4) + MUL(h1,r3) + MUL(h2,r2) + MUL(h3,r1) + MUL(h4,r0); + #undef MUL + + h0 = d0 & 0x03FFFFFF; d1 += (uint32_t)(d0 >> 26); + h1 = d1 & 0x03FFFFFF; d2 += (uint32_t)(d1 >> 26); + h2 = d2 & 0x03FFFFFF; d3 += (uint32_t)(d2 >> 26); + h3 = d3 & 0x03FFFFFF; d4 += (uint32_t)(d3 >> 26); + h4 = d4 & 0x03FFFFFF; h0 += (uint32_t)(d4 >> 26) * 5; + h1 += (h0 >> 26); h0 = h0 & 0x03FFFFFF; + + msg += 16; + n -= 16; + } + if (n) { + int i; + for (i = 0; i < n; i++) buf[i] = msg[i]; + buf[i++] = 1; + while (i < 16) buf[i++] = 0; + msg = buf; + hibit = 0; + n = 16; + goto process_block; + } + *(volatile uint32_t *)&r0 = 0; + *(volatile uint32_t *)&r1 = 0; *(volatile uint32_t *)&s1 = 0; + *(volatile uint32_t *)&r2 = 0; *(volatile uint32_t *)&s2 = 0; + *(volatile uint32_t *)&r3 = 0; *(volatile uint32_t *)&s3 = 0; + *(volatile uint32_t *)&r4 = 0; *(volatile uint32_t *)&s4 = 0; + + h2 += (h1 >> 26); h1 &= 0x03FFFFFF; + h3 += (h2 >> 26); h2 &= 0x03FFFFFF; + h4 += (h3 >> 26); h3 &= 0x03FFFFFF; + h0 += (h4 >> 26) * 5; h4 &= 0x03FFFFFF; + h1 += (h0 >> 26); h0 &= 0x03FFFFFF; + + g0 = h0 + 5; + g1 = h1 + (g0 >> 26); g0 &= 0x03FFFFFF; + g2 = h2 + (g1 >> 26); g1 &= 0x03FFFFFF; + g3 = h3 + (g2 >> 26); g2 &= 0x03FFFFFF; + g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x03FFFFFF; + + w = ~(m = (g4 >> 31) - 1); + h0 = (h0 & w) | (g0 & m); + h1 = (h1 & w) | (g1 & m); + h2 = (h2 & w) | (g2 & m); + h3 = (h3 & w) | (g3 & m); + h4 = (h4 & w) | (g4 & m); + + f0 = ((h0 >> 0) | (h1 << 26)) + (uint64_t)LOAD32_LE(key + 16); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)LOAD32_LE(key + 20); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)LOAD32_LE(key + 24); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)LOAD32_LE(key + 28); + + STORE32_LE(tag + 0, f0); f1 += (f0 >> 32); + STORE32_LE(tag + 4, f1); f2 += (f1 >> 32); + STORE32_LE(tag + 8, f2); f3 += (f2 >> 32); + STORE32_LE(tag + 12, f3); +} + +int poly1305_tagcmp(const unsigned char tag1[16], const unsigned char tag2[16]) +{ + unsigned int d = 0; + d |= tag1[ 0] ^ tag2[ 0]; + d |= tag1[ 1] ^ tag2[ 1]; + d |= tag1[ 2] ^ tag2[ 2]; + d |= tag1[ 3] ^ tag2[ 3]; + d |= tag1[ 4] ^ tag2[ 4]; + d |= tag1[ 5] ^ tag2[ 5]; + d |= tag1[ 6] ^ tag2[ 6]; + d |= tag1[ 7] ^ tag2[ 7]; + d |= tag1[ 8] ^ tag2[ 8]; + d |= tag1[ 9] ^ tag2[ 9]; + d |= tag1[10] ^ tag2[10]; + d |= tag1[11] ^ tag2[11]; + d |= tag1[12] ^ tag2[12]; + d |= tag1[13] ^ tag2[13]; + d |= tag1[14] ^ tag2[14]; + d |= tag1[15] ^ tag2[15]; + return d; +} + +/* + * SHA256 hash function + */ +struct sha256 { + uint32_t state[8]; + unsigned char buffer[64]; + uint64_t n64; + int n; +}; + +void sha256_init(struct sha256 *ctx) +{ + ctx->state[0] = 0x6a09e667; /* sqrt(2) */ + ctx->state[1] = 0xbb67ae85; /* sqrt(3) */ + ctx->state[2] = 0x3c6ef372; /* sqrt(5) */ + ctx->state[3] = 0xa54ff53a; /* sqrt(7) */ + ctx->state[4] = 0x510e527f; /* sqrt(11) */ + ctx->state[5] = 0x9b05688c; /* sqrt(13) */ + ctx->state[6] = 0x1f83d9ab; /* sqrt(17) */ + ctx->state[7] = 0x5be0cd19; /* sqrt(19) */ + ctx->n64 = 0; + ctx->n = 0; +} + +static void sha256_block(uint32_t state[8], const unsigned char p[64]) +{ + uint32_t w[64], a, b, c, d, e, f, g, h; + uint32_t s0, s1, S0, S1, t1, t2; + static const uint32_t K256[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + a = state[0]; b = state[1]; c = state[2]; d = state[3]; + e = state[4]; f = state[5]; g = state[6]; h = state[7]; + + #define ROUND_CORE(i) \ + S1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25); \ + t1 = h + S1 + ((e & f) ^ (~e & g)) + K256[i] + w[i]; \ + S0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22); \ + t2 = S0 + ((a & b) ^ (a & c) ^ (b & c)); \ + h = g; g = f; f = e; e = d + t1; \ + d = c; c = b; b = a; a = t1 + t2; + + #define ROUND_0_15(i) w[i] = LOAD32_BE(p); p += 4; ROUND_CORE(i) + ROUND_0_15( 0) ROUND_0_15( 1) ROUND_0_15( 2) ROUND_0_15( 3) + ROUND_0_15( 4) ROUND_0_15( 5) ROUND_0_15( 6) ROUND_0_15( 7) + ROUND_0_15( 8) ROUND_0_15( 9) ROUND_0_15(10) ROUND_0_15(11) + ROUND_0_15(12) ROUND_0_15(13) ROUND_0_15(14) ROUND_0_15(15) + #undef ROUND_0_15 + + #define ROUND_16_19(i) \ + s0 = ROR32(w[i-15], 7) ^ ROR32(w[i-15], 18) ^ (w[i-15] >> 3); \ + s1 = ROR32(w[i-2], 17) ^ ROR32(w[i-2], 19) ^ (w[i-2] >> 10); \ + w[i] = w[i-16] + s0 + w[i-7] + s1; ROUND_CORE(i) + ROUND_16_19(16) ROUND_16_19(17) ROUND_16_19(18) ROUND_16_19(19) + ROUND_16_19(20) ROUND_16_19(21) ROUND_16_19(22) ROUND_16_19(23) + ROUND_16_19(24) ROUND_16_19(25) ROUND_16_19(26) ROUND_16_19(27) + ROUND_16_19(28) ROUND_16_19(29) ROUND_16_19(30) ROUND_16_19(31) + ROUND_16_19(32) ROUND_16_19(33) ROUND_16_19(34) ROUND_16_19(35) + ROUND_16_19(36) ROUND_16_19(37) ROUND_16_19(38) ROUND_16_19(39) + ROUND_16_19(40) ROUND_16_19(41) ROUND_16_19(42) ROUND_16_19(43) + ROUND_16_19(44) ROUND_16_19(45) ROUND_16_19(46) ROUND_16_19(47) + ROUND_16_19(48) ROUND_16_19(49) ROUND_16_19(50) ROUND_16_19(51) + ROUND_16_19(52) ROUND_16_19(53) ROUND_16_19(54) ROUND_16_19(55) + ROUND_16_19(56) ROUND_16_19(57) ROUND_16_19(58) ROUND_16_19(59) + ROUND_16_19(60) ROUND_16_19(61) ROUND_16_19(62) ROUND_16_19(63) + #undef ROUND_16_19 + #undef ROUND_CORE + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; + state[4] += e; state[5] += f; state[6] += g; state[7] += h; +} + +void sha256_update(struct sha256 *ctx, const unsigned char *data, size_t n) +{ + if (n < 64 || ctx->n) { + int i, j = (ctx->n + n < 64) ? n : 64 - ctx->n; + for (i = 0; i < j; i++) + ctx->buffer[ctx->n + i] = data[i]; + if ((ctx->n += j) < 64) + return; + sha256_block(ctx->state, ctx->buffer); + ctx->n64 += 64; + ctx->n = 0; + data += j; + n -= j; + } + + while (n >= 64) { + sha256_block(ctx->state, data); + ctx->n64 += 64; + data += 64; + n -= 64; + } + + if (n) { + int i = 0; + while (i < n) { + ctx->buffer[i] = data[i]; + i++; + } + ctx->n = n; + } +} + +static void sha256_serialize(const uint32_t state[8], unsigned char hash[32]) +{ + STORE32_BE(hash + 0, state[0]); + STORE32_BE(hash + 4, state[1]); + STORE32_BE(hash + 8, state[2]); + STORE32_BE(hash + 12, state[3]); + STORE32_BE(hash + 16, state[4]); + STORE32_BE(hash + 20, state[5]); + STORE32_BE(hash + 24, state[6]); + STORE32_BE(hash + 28, state[7]); +} + +void sha256_final(struct sha256 *ctx, unsigned char hash[32]) +{ + int i; + unsigned char buf[128]; + uint64_t nbits = (ctx->n64 + ctx->n) * 8; + buf[0] = 0x80; + for (i = 1; (ctx->n + i + 8) % 64; buf[i++] = 0); + STORE64_BE(buf+i, nbits); + sha256_update(ctx, buf, i+8); + sha256_serialize(ctx->state, hash); +} + +/* + * PBKDF2-HMAC-SHA256 key derivation optimized to reuse intermediate SHA256 + * states computed in the HMAC-SHA256 calculation of the inner and outer pad. + */ +void pbkdf2_hmac_sha256(const void *pass, size_t m, const void *salt, size_t n, + int iter, unsigned char *dk, int dklen) +{ + unsigned char keyblock[64], iblock[64], oblock[64]; + struct sha256 ctx, ictx, octx; + uint32_t I[8], O[8]; + int i, j, k, len; + + /* Initialize keyblock */ + if (m > 64) { + sha256_init(&ctx); + sha256_update(&ctx, pass, m); + sha256_final(&ctx, keyblock); + memset(keyblock+32, 0, 32); + } else { + memcpy(keyblock, pass, m); + memset(keyblock+m, 0, 64 - m); + } + + /* Prepare iblock and oblock */ + sha256_init(&ictx); + sha256_init(&octx); + for (i = 0; i < 64; i++) { + iblock[i] = 0x36 ^ keyblock[i]; + oblock[i] = 0x5C ^ keyblock[i]; + *(volatile unsigned char *)(keyblock + i) = 0; + } + sha256_update(&ictx, iblock, 64); + sha256_update(&octx, oblock, 64); + memset(iblock+32, 0, 32); + memset(oblock+32, 0, 32); + STORE32_BE(&iblock[64-4], 96*8); + STORE32_BE(&oblock[64-4], 96*8); + iblock[32] = oblock[32] = 0x80; + + /* PBKDF2 main loop */ + for (i = 1; dklen; i++) { + unsigned char ibuf[4]; + STORE32_BE(ibuf, i); + memcpy(&ctx, &ictx, sizeof(struct sha256)); + sha256_update(&ctx, salt, n); + sha256_update(&ctx, ibuf, 4); + sha256_final(&ctx, oblock); + + memcpy(O, octx.state, 32); + sha256_block(O, oblock); + sha256_serialize(O, iblock); + + len = (dklen < 32) ? dklen : 32; + memcpy(dk, iblock, len); + for (j = 1; j < iter; j++) { + memcpy(I, ictx.state, 32); + memcpy(O, octx.state, 32); + sha256_block(I, iblock); + sha256_serialize(I, oblock); + sha256_block(O, oblock); + sha256_serialize(O, iblock); + for (k = 0; k < len; k++) { + dk[k] ^= iblock[k]; + } + } + dklen -= len; + dk += len; + } + + /* Burn key material */ /* TODO: is this really necessary? */ + for (i = 0; i < 64; i++) { /* for truly paranoid people, yes */ + *(volatile unsigned char *)(iblock + i) = 0; + *(volatile unsigned char *)(oblock + i) = 0; + } +} + +/* + * Platform-specific entropy functions for seeding RNG + */ +#if defined(__unix__) || defined(__APPLE__) +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#endif + +/* Returns the number of urandom bytes read (either 0 or n) */ +static size_t read_urandom(void *buf, size_t n) +{ + size_t i; + ssize_t ret; + int fd, count; + struct stat st; + int errnold = errno; + + do { + fd = open("/dev/urandom", O_RDONLY, 0); + } while (fd == -1 && errno == EINTR); + if (fd == -1) + goto fail; + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + + /* Check the sanity of the device node */ + if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) + #ifdef __linux__ + || ioctl(fd, RNDGETENTCNT, &count) == -1 + #endif + ) { + close(fd); + goto fail; + } + + /* Read bytes */ + for (i = 0; i < n; i += ret) { + while ((ret = read(fd, (char *)buf + i, n - i)) == -1) { + if (errno != EAGAIN && errno != EINTR) { + close(fd); + goto fail; + } + } + } + close(fd); + + /* Verify that the random device returned non-zero data */ + for (i = 0; i < n; i++) { + if (((unsigned char *)buf)[i] != 0) { + errno = errnold; + return n; + } + } + + /* Tiny n may unintentionally fall through! */ + +fail: + fprintf(stderr, "bad /dev/urandom RNG\n"); + abort(); /* PANIC! */ + return 0; +} + +static size_t entropy(void *buf, size_t n) +{ + #if defined(__linux__) && defined(SYS_getrandom) + if (syscall(SYS_getrandom, buf, n, 0) == n) + return n; + #elif defined(SYS_getentropy) + if (syscall(SYS_getentropy, buf, n) == 0) + return n; + #endif + return read_urandom(buf, n); +} + +#elif defined(_WIN32) + +#include +#define RtlGenRandom SystemFunction036 +BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); +#pragma comment(lib, "advapi32.lib") + +static size_t entropy(void *buf, size_t n) +{ + return RtlGenRandom(buf, n) ? n : 0; +} + +#else +#error "Secure pseudorandom number generator unimplemented for this OS" +#endif + +/* + * ChaCha20 random number generator + */ +void chacha20_rng(void *out, size_t n) +{ + static size_t available = 0; + static uint32_t counter = UINT32_MAX; + static unsigned char key[32], nonce[12], buffer[64] = {0}; + +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG); + sqlite3_mutex_enter(mutex); +#endif + + while (n > 0) { + size_t m; + if (available == 0) { + if (counter == UINT32_MAX) { + if (entropy(key, sizeof(key)) != sizeof(key)) + abort(); + if (entropy(nonce, sizeof(nonce)) != sizeof(nonce)) + abort(); + } + chacha20_xor(buffer, sizeof(buffer), key, nonce, ++counter); + available = sizeof(buffer); + } + m = (available < n) ? available : n; + memcpy(out, buffer + (sizeof(buffer) - available), m); + out = (unsigned char *)out + m; + available -= m; + n -= m; + } + +#if SQLITE_THREADSAFE + sqlite3_mutex_leave(mutex); +#endif +} + +/* + * SQLite3 codec implementation. + */ +typedef struct codec { + struct codec *reader, *writer; + unsigned char key[32], salt[16]; + void *pagebuf; + int pagesize; + const void *zKey; + int nKey; +} Codec; + +Codec *codec_new(const char *zKey, int nKey) +{ + Codec *codec; + if ((codec = sqlite3_malloc(sizeof(Codec)))) { + codec->reader = codec->writer = codec; + memset(codec->key, 0, sizeof(codec->key)); + memset(codec->salt, 0, sizeof(codec->salt)); + codec->pagebuf = NULL; + codec->pagesize = 0; + codec->zKey = zKey; + codec->nKey = nKey; + } + return codec; +} + +Codec *codec_dup(Codec *src) +{ + Codec *codec; + if ((codec = codec_new(src->zKey, src->nKey))) { + codec->reader = (src->reader == src) ? codec : src->reader; + codec->writer = (src->writer == src) ? codec : src->writer; + memcpy(codec->salt, src->salt, 16); + memcpy(codec->key, src->key, 32); + } + return codec; +} + +static int hex_decode(const char *hex, unsigned int n, unsigned char *out) +{ + int i; + for (i = 0; i < n; i++) { + char c = hex[i]; + if (c >= '0' && c <= '9') { + c = c - '0'; + } else if (c >= 'A' && c <= 'F') { + c = c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + c = c - 'a' + 10; + } else { + const int j = (i+1) / 2; + for (i = 0; i < j; i++) { + ((volatile unsigned char *)out)[i] = 0; + } + return 0; + } + out[i/2] = (out[i/2] << 4) | c; + } + return 1; +} + +void codec_kdf(Codec *codec, const void *salt) +{ + int bypass = 0; + + /* Bypass key derivation if the key string starts with "raw:" */ + if (codec->nKey > 4 && !memcmp(codec->zKey, "raw:", 4)) { + const int nRaw = codec->nKey - 4; + const char *zRaw = (const char *)codec->zKey + 4; + switch (nRaw) { + /* Binary key (and salt) */ + case 32 + 16: + salt = memcpy(codec->salt, zRaw + 32, 16); + /* fall-through */ + case 32: + memcpy(codec->key, zRaw, 32); + bypass = 1; + break; + + /* Hex-encoded key */ + case 64: + bypass = !!hex_decode(zRaw, 64, codec->key); + break; + + /* Hex-encoded key and salt */ + case 64 + 32: + if (!hex_decode(zRaw, 64, codec->key)) + break; + if (!hex_decode(zRaw + 64, 32, codec->salt)) + break; + salt = codec->salt; + bypass = 1; + break; + + default: + break; + } + } + + if (!salt) { + /* Generate a random salt */ + chacha20_rng(codec->salt, 16); + } else if (salt != codec->salt) { + /* Save the specified salt */ + memcpy(codec->salt, salt, 16); + } + + if (!bypass) { + /* Run key-derivation algorithm on the key string with the salt */ + pbkdf2_hmac_sha256(codec->zKey, codec->nKey, + codec->salt, 16, + 12345, + codec->key, 32); + } + + codec->zKey = NULL; + codec->nKey = 0; +} + +void codec_free(void *pcodec) +{ + if (pcodec) { + int i; + volatile char *p; + Codec *codec = pcodec; + if (codec->pagebuf) { + p = codec->pagebuf; + for (i = 0; i < codec->pagesize; p[i++] = '\0'); + sqlite3_free(codec->pagebuf); + } + p = pcodec; + for (i = 0; i < sizeof(Codec); p[i++] = '\0'); + sqlite3_free(codec); + } +} + +/* + * The encrypted database page format. + * + * +----------------------------------------+----------------+----------------+ + * | Encrypted data | 16-byte nonce | 16-byte tag | + * +----------------------------------------+----------------+----------------+ + * + * As the only exception, the first page (page_no=1) starts with a plaintext + * salt contained in the first 16 bytes of the database file. The "master" key + * is derived from a user-given password with the salt and 12345 iterations of + * PBKDF-HMAC-SHA256. Future plans include switching to BLAKE2 and Argon2. + * + * - The data is encrypted by XORing with the ChaCha20 keystream produced from + * the 16-byte nonce and a 32-byte encryption key derived from the master key. + * - OK, I lied a little: ChaCha20 uses only the first 12 bytes as the nonce. + * However, ChaCha20 also requires an initial value for a counter of 4 bytes + * that encodes a block position in the output stream. We derive the counter + * value from the last 4 bytes, effectively extending the nonce to 16 bytes. + * - Specifically, counter = LOAD32_LE(nonce[12..15])^page_no is first applied + * to generate a single 64-byte block from nonce[0..11] and the master key. + * The block consists of two 32-byte one-time keys, the former is a Poly1305 + * key for the authentication tag, and the latter is a ChaCha20 key for the + * data encryption. The encryption with the one-time key uses nonce[0..11] + * and the initial counter value of counter+1. + * - The XOR with page_no prevents malicious reordering of the pages. + * + * - The nonce consists of 128 randomly generated bits, which should be enough + * to guarantee uniqueness with a secure pseudorandom number generator. + * - Given a secure PRNG, the adversary needs to observe at least 2^61 nonces + * to break Poly1305 with the birthday attack at a success rate of 1%. + * - If a nonce is reused, we lose confidentiality of the associated messages. + * Moreover, the compromised nonce can also be used to forge valid tags for + * new messages having the same nonce (basically, the one-time Poly1305 key + * can be recovered from distinct messages with identical nonces). + * + * - The tag is a Poly1305 MAC calculated over the encrypted data and the nonce + * with the one-time key generated from the master key and the nonce. + */ + +#define PAGE_NONCE_LEN 16 +#define PAGE_TAG_LEN 16 +#define PAGE_RESERVED_LEN (PAGE_NONCE_LEN + PAGE_TAG_LEN) + +void *codec_handle(void *codec, void *pdata, Pgno page, int mode) +{ + uint32_t counter; + unsigned char otk[64], tag[16], *data = pdata; + Codec *reader = ((Codec *)codec)->reader; + Codec *writer = ((Codec *)codec)->writer; + const int skip = (page == 1) ? SKIP_HEADER_BYTES : 0; + + switch (mode) { + case 0: /* Journal decryption */ + case 2: /* Reload a page */ + case 3: /* Load a page */ + if (reader) { + const int n = reader->pagesize - PAGE_RESERVED_LEN; + if (page == 1 && reader->zKey) + codec_kdf(reader, data); + + /* Generate one-time keys */ + memset(otk, 0, 64); + counter = LOAD32_LE(data + n + PAGE_NONCE_LEN-4) ^ page; + chacha20_xor(otk, 64, reader->key, data + n, counter); + + /* Verify the MAC */ + poly1305(data, n + PAGE_NONCE_LEN, otk, tag); + if (poly1305_tagcmp(data + n + PAGE_NONCE_LEN, tag) != 0) + return NULL; + + /* Decrypt */ + chacha20_xor(data + skip, n - skip, otk+32, data + n, counter+1); + if (page == 1) memcpy(data, "SQLite format 3", 16); + } + break; + + case 7: /* Encrypt a journal page (with the reader key) */ + writer = reader; + /* fall-through */ + case 6: /* Encrypt a main database page */ + if (writer) { + const int n = writer->pagesize - PAGE_RESERVED_LEN; + data = memcpy(writer->pagebuf, data, writer->pagesize); + + /* Generate one-time keys */ + memset(otk, 0, 64); + chacha20_rng(data + n, 16); + counter = LOAD32_LE(data + n + PAGE_NONCE_LEN-4) ^ page; + chacha20_xor(otk, 64, writer->key, data + n, counter); + + /* Encrypt and authenticate */ + chacha20_xor(data + skip, n - skip, otk+32, data + n, counter+1); + if (page == 1) memcpy(data, writer->salt, 16); + poly1305(data, n + PAGE_NONCE_LEN, otk, data + n + PAGE_NONCE_LEN); + } + break; + } + + return data; +} + +/* Reads page1 to trigger codec_kdf and verify the encryption key */ +static int codec_verify_page1(Codec *codec, Btree *pBt) +{ + int count, rc = SQLITE_OK; + Pager *pager = sqlite3BtreePager(pBt); + sqlite3PagerSharedLock(pager); + sqlite3PagerPagecount(pager, &count); + if (count > 0) { + DbPage *page; + rc = SQLITE_NOTADB; + sqlite3PcacheTruncate(pager->pPCache, 0); + if (sqlite3PagerGet(pager, 1, &page, 0) == SQLITE_OK) { + if (!memcmp(page->pData, "SQLite format 3", 16)) + rc = SQLITE_OK; + sqlite3PagerUnref(page); + } else { + sqlite3PagerSetCodec(pager, NULL, NULL, NULL, NULL); + } + } else if (codec && codec->zKey) { + /* Derive an encryption key for an empty database */ + codec_kdf(codec, NULL); + } + pager_unlock(pager); + return rc; +} + +/* + * Set (or unset) a codec for the pager of the specified Btree. + * + * The caller must hold the database mutex when calling this function. + * Note that the function consumes the passed-in codec structure. + */ +static int codec_set_to(Codec *codec, Btree *pBt) +{ + int pagesize; + Pager *pager = sqlite3BtreePager(pBt); + + if (!codec) { + /* Unset a codec */ + sqlite3PagerSetCodec(pager, NULL, NULL, NULL, NULL); + return SQLITE_OK; + } + + /* Allocate page buffer */ + pagesize = sqlite3BtreeGetPageSize(pBt); + if (!codec->pagebuf || codec->pagesize != pagesize) { + void *new = sqlite3_malloc(pagesize); + if (!new) { + codec_free(codec); + return SQLITE_NOMEM; + } + if (codec->pagebuf) { + int i = 0; + while (i < codec->pagesize) + ((volatile char *)codec->pagebuf)[i++] = '\0'; + sqlite3_free(codec->pagebuf); + } + codec->pagebuf = new; + codec->pagesize = pagesize; + } + + /* Force secure delete */ + sqlite3BtreeSecureDelete(pBt, 1); + + /* Adjust the page size and the reserved area */ + if (pager->nReserve != PAGE_RESERVED_LEN) { + pBt->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; + sqlite3BtreeSetPageSize(pBt, pagesize, PAGE_RESERVED_LEN, 0); + } + + /* Set pager codec and try to read page1 */ + sqlite3PagerSetCodec(pager, codec_handle, NULL, codec_free, codec); + return codec_verify_page1(codec, pBt); +} + +void sqlite3CodecGetKey(sqlite3 *db, int nDb, void **zKey, int *nKey) +{ + /* + * sqlite3.c calls this function to decide if a database attached without a + * password should use the encryption scheme of the main database. Returns + * *nKey == 1 to indicate that the main database encryption is available. + */ + *zKey = NULL; + *nKey = !!sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[nDb].pBt)); +} + +int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *zKey, int nKey) +{ + int rc; + Codec *codec; + Btree *pBt = db->aDb[nDb].pBt; + + rc = SQLITE_NOMEM; + sqlite3_mutex_enter(db->mutex); + if (!nKey) { + /* Attach with an empty key (no encryption) */ + codec_set_to(NULL, pBt); + rc = codec_verify_page1(NULL, pBt); + } else if (zKey) { + /* Attach with the provided key */ + if ((codec = codec_new(zKey, nKey))) + rc = codec_set_to(codec, pBt); + } else if (nDb != 0) { + /* Use the main database's encryption */ + codec = sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt)); + if (codec && (codec = codec_dup(codec))) { + rc = codec_set_to(codec, pBt); + } else { + /* Main database codec unavailable */ + rc = SQLITE_CANTOPEN; + } + } + sqlite3_mutex_leave(db->mutex); + + return rc; +} + +/* Returns the main database if there is no match */ +static int db_index_of(sqlite3 *db, const char *zDbName) +{ + int i; + if (zDbName) { + for (i = 0; i < db->nDb; i++) { + if (!strcmp(db->aDb[i].zDbSName, zDbName)) + return i; + } + } + return 0; +} + +int sqlite3_key_v2(sqlite3 *db, const char *zDbName, const void *zKey, int nKey) +{ + return sqlite3CodecAttach(db, db_index_of(db, zDbName), zKey, nKey); +} + +int sqlite3_key(sqlite3 *db, const void *zKey, int nKey) +{ + return sqlite3_key_v2(db, "main", zKey, nKey); +} + +int sqlite3_rekey_v2(sqlite3 *db, const char *zDbName, + const void *zKey, int nKey) +{ + char *err; + int nDb, rc; + Btree *pBt; + + if (!db || (!nKey && !zKey)) + return SQLITE_ERROR; + + rc = SQLITE_ERROR; + sqlite3_mutex_enter(db->mutex); + if ((pBt = db->aDb[(nDb = db_index_of(db, zDbName))].pBt)) { + Pgno pgno; + DbPage *page; + Codec *reader, *codec; + Pager *pager = sqlite3BtreePager(pBt); + + reader = sqlite3PagerGetCodec(pager); + if (!nKey) { + /* Decrypt */ + if (reader) { + reader->writer = NULL; + rc = sqlite3RekeyVacuum(&err, db, nDb, NULL, 0); + if (rc == SQLITE_OK) { + rc = codec_set_to(NULL, pBt); + } else { + reader->writer = reader->reader; + } + } else { + rc = codec_verify_page1(NULL, pBt); + } + goto leave; + } + + /* Create a codec for the given key */ + if ((codec = codec_new(zKey, nKey))) { + codec->pagesize = sqlite3BtreeGetPageSize(pBt); + codec->pagebuf = sqlite3_malloc(codec->pagesize); + if (codec->pagebuf) { + codec_kdf(codec, NULL); + } else { + codec_free(codec); + codec = NULL; + } + } + if (!codec) { + rc = SQLITE_NOMEM; + goto leave; + } + + if (!reader) { + /* Encrypt */ + codec->reader = NULL; + if ((rc = codec_set_to(codec, pBt)) == SQLITE_OK) { + rc = sqlite3RekeyVacuum(&err, db, nDb, NULL, PAGE_RESERVED_LEN); + if (rc == SQLITE_OK) { + codec->reader = codec->writer; + } else { + codec_set_to(NULL, pBt); + } + } + goto leave; + } + + /* Change key (re-encrypt) */ + reader->writer = codec; + rc = sqlite3BtreeBeginTrans(pBt, 1, NULL); + for (pgno = 1; rc == SQLITE_OK && pgno <= pager->dbSize; pgno++) { + /* The DB page occupied by the PENDING_BYTE is never used */ + if (pgno == PENDING_BYTE_PAGE(pager)) + continue; + if ((rc = sqlite3PagerGet(pager, pgno, &page, 0)) == SQLITE_OK) { + rc = sqlite3PagerWrite(page); + sqlite3PagerUnref(page); + } + } + if (rc == SQLITE_OK) { + sqlite3BtreeCommit(pBt); + rc = codec_set_to(codec, pBt); + } else { + reader->writer = reader; + sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); + } + } + +leave: + sqlite3_mutex_leave(db->mutex); + return rc; +} + +int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey) +{ + return sqlite3_rekey_v2(db, "main", zKey, nKey); +} + +void sqlite3_activate_see(const char *info) +{ +} diff --git a/uppsrc/plugin/sqlite3/lib/sqlite3.h b/uppsrc/plugin/sqlite3/lib/sqleet.h similarity index 99% rename from uppsrc/plugin/sqlite3/lib/sqlite3.h rename to uppsrc/plugin/sqlite3/lib/sqleet.h index 348db7466..fa9b356dc 100644 --- a/uppsrc/plugin/sqlite3/lib/sqlite3.h +++ b/uppsrc/plugin/sqlite3/lib/sqleet.h @@ -1,3 +1,37 @@ +/* + * sqleet configuration. + * + * # SKIP_HEADER_BYTES + * Keep this many bytes unencrypted in the beginning of the database header. + * Value 0 produces encrypted databases that are indistinguishable from random. + * Use 24 for compatibility with the SQLite3 Encryption Extension (SEE) so that + * database settings (e.g., page size) can be read from an encrypted database. + */ +#ifndef SKIP_HEADER_BYTES +#define SKIP_HEADER_BYTES 0 +#endif + +/* + * SQLite3 configuration. + * + * # SQLITE_HAS_CODEC + * Required for compiling SQLite3 with encryption support. + * + * # SQLITE_TEMP_STORE + * - 0 Store temp files on disk + * - 1 Store temp files on disk but allow overriding with `PRAGMA temp_store` + * - 2 Store temp files in memory but allow overriding with `PRAGMA temp_store` + * - 3 Store temp files on memory + * Note that temp files are *NOT* encrypted so using either 2 or 3 is critical! + */ +#ifndef SQLITE_HAS_CODEC +#define SQLITE_HAS_CODEC 1 +#endif +#ifndef SQLITE_TEMP_STORE +#define SQLITE_TEMP_STORE 2 +#endif + +#ifndef SQLITE3_H_OMIT /* ** 2001-09-15 ** @@ -11714,3 +11748,4 @@ struct fts5_api { #endif /* _FTS5_H */ /******** End of fts5.h *********/ +#endif diff --git a/uppsrc/plugin/sqlite3/libsee/UNLICENSE b/uppsrc/plugin/sqlite3/libsee/UNLICENSE deleted file mode 100644 index 68a49daad..000000000 --- a/uppsrc/plugin/sqlite3/libsee/UNLICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/uppsrc/plugin/sqlite3/libsee/config.c b/uppsrc/plugin/sqlite3/libsee/config.c deleted file mode 100644 index 9b3d37775..000000000 --- a/uppsrc/plugin/sqlite3/libsee/config.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * sqleet configuration. - * - * # SKIP_HEADER_BYTES - * Keep this many bytes unencrypted in the beginning of the database header. - * Value 0 produces encrypted databases that are indistinguishable from random. - * Use 24 for compatibility with the SQLite3 Encryption Extension (SEE) so that - * database settings (e.g., page size) can be read from an encrypted database. - */ -#ifndef SKIP_HEADER_BYTES -#define SKIP_HEADER_BYTES 0 -#endif - -/* - * SQLite3 configuration. - * - * # SQLITE_HAS_CODEC - * Required for compiling SQLite3 with encryption support. - * - * # SQLITE_TEMP_STORE - * - 0 Store temp files on disk - * - 1 Store temp files on disk but allow overriding with `PRAGMA temp_store` - * - 2 Store temp files in memory but allow overriding with `PRAGMA temp_store` - * - 3 Store temp files on memory - * Note that temp files are *NOT* encrypted so using either 2 or 3 is critical! - */ -#ifndef SQLITE_HAS_CODEC -#define SQLITE_HAS_CODEC 1 -#endif -#ifndef SQLITE_TEMP_STORE -#define SQLITE_TEMP_STORE 2 -#endif diff --git a/uppsrc/plugin/sqlite3/libsee/crypto.c b/uppsrc/plugin/sqlite3/libsee/crypto.c deleted file mode 100644 index 928f8f8c3..000000000 --- a/uppsrc/plugin/sqlite3/libsee/crypto.c +++ /dev/null @@ -1,585 +0,0 @@ -/* This file is included by sqleet.c */ -#include - -#define ROL32(x, c) (((x) << (c)) | ((x) >> (32-(c)))) -#define ROR32(x, c) (((x) >> (c)) | ((x) << (32-(c)))) - -#define LOAD32_LE(p) \ - ( ((uint32_t)((p)[0]) << 0) \ - | ((uint32_t)((p)[1]) << 8) \ - | ((uint32_t)((p)[2]) << 16) \ - | ((uint32_t)((p)[3]) << 24) \ - ) -#define LOAD32_BE(p) \ - ( ((uint32_t)((p)[3]) << 0) \ - | ((uint32_t)((p)[2]) << 8) \ - | ((uint32_t)((p)[1]) << 16) \ - | ((uint32_t)((p)[0]) << 24) \ - ) - -#define STORE32_LE(p, v) \ - (p)[0] = ((v) >> 0) & 0xFF; \ - (p)[1] = ((v) >> 8) & 0xFF; \ - (p)[2] = ((v) >> 16) & 0xFF; \ - (p)[3] = ((v) >> 24) & 0xFF; -#define STORE32_BE(p, v) \ - (p)[3] = ((v) >> 0) & 0xFF; \ - (p)[2] = ((v) >> 8) & 0xFF; \ - (p)[1] = ((v) >> 16) & 0xFF; \ - (p)[0] = ((v) >> 24) & 0xFF; -#define STORE64_BE(p, v) \ - (p)[7] = ((v) >> 0) & 0xFF; \ - (p)[6] = ((v) >> 8) & 0xFF; \ - (p)[5] = ((v) >> 16) & 0xFF; \ - (p)[4] = ((v) >> 24) & 0xFF; \ - (p)[3] = ((v) >> 32) & 0xFF; \ - (p)[2] = ((v) >> 40) & 0xFF; \ - (p)[1] = ((v) >> 48) & 0xFF; \ - (p)[0] = ((v) >> 56) & 0xFF; - -/* - * ChaCha20 stream cipher - */ -static void chacha20_block(unsigned char out[64], const uint32_t in[16]) -{ - int i; - uint32_t x[16]; - memcpy(x, in, sizeof(uint32_t) * 16); - - #define QR(x, a, b, c, d) \ - x[a] += x[b]; x[d] ^= x[a]; x[d] = ROL32(x[d], 16); \ - x[c] += x[d]; x[b] ^= x[c]; x[b] = ROL32(x[b], 12); \ - x[a] += x[b]; x[d] ^= x[a]; x[d] = ROL32(x[d], 8); \ - x[c] += x[d]; x[b] ^= x[c]; x[b] = ROL32(x[b], 7); - for (i = 0; i < 10; i++) { - /* Column round */ - QR(x, 0, 4, 8, 12) - QR(x, 1, 5, 9, 13) - QR(x, 2, 6, 10, 14) - QR(x, 3, 7, 11, 15) - /* Diagonal round */ - QR(x, 0, 5, 10, 15) - QR(x, 1, 6, 11, 12) - QR(x, 2, 7, 8, 13) - QR(x, 3, 4, 9, 14) - } - #undef QR - for (i = 0; i < 16; i++) { - const uint32_t v = x[i] + in[i]; - STORE32_LE(out, v); - out += 4; - } -} - -void chacha20_xor(unsigned char *data, size_t n, const unsigned char key[32], - const unsigned char nonce[12], uint32_t counter) -{ - int i; - uint32_t state[16]; - unsigned char block[64]; - static const unsigned char sigma[16] = "expand 32-byte k"; - - state[ 0] = LOAD32_LE(sigma + 0); - state[ 1] = LOAD32_LE(sigma + 4); - state[ 2] = LOAD32_LE(sigma + 8); - state[ 3] = LOAD32_LE(sigma + 12); - - state[ 4] = LOAD32_LE(key + 0); - state[ 5] = LOAD32_LE(key + 4); - state[ 6] = LOAD32_LE(key + 8); - state[ 7] = LOAD32_LE(key + 12); - state[ 8] = LOAD32_LE(key + 16); - state[ 9] = LOAD32_LE(key + 20); - state[10] = LOAD32_LE(key + 24); - state[11] = LOAD32_LE(key + 28); - - state[12] = counter; - - state[13] = LOAD32_LE(nonce + 0); - state[14] = LOAD32_LE(nonce + 4); - state[15] = LOAD32_LE(nonce + 8); - - while (n >= 64) { - chacha20_block(block, state); - for (i = 0; i < 64; i++) { - data[i] ^= block[i]; - } - state[12]++; - data += 64; - n -= 64; - } - - if (n > 0) { - chacha20_block(block, state); - for (i = 0; i < n; i++) { - data[i] ^= block[i]; - } - } - return; -} - -/* - * Poly1305 authentication tags - */ -void poly1305(const unsigned char *msg, size_t n, const unsigned char key[32], - unsigned char tag[16]) -{ - uint32_t c, m, w; - uint32_t r0, r1, r2, r3, r4; - uint32_t s1, s2, s3, s4; - uint64_t f0, f1, f2, f3; - uint32_t g0, g1, g2, g3, g4; - uint32_t h0, h1, h2, h3, h4; - unsigned char buf[16]; - int i; - - c = 1 << 24; - r0 = (LOAD32_LE(key + 0) >> 0) & 0x03FFFFFF; - r1 = (LOAD32_LE(key + 3) >> 2) & 0x03FFFF03; - r2 = (LOAD32_LE(key + 6) >> 4) & 0x03FFC0FF; - r3 = (LOAD32_LE(key + 9) >> 6) & 0x03F03FFF; - r4 = (LOAD32_LE(key + 12) >> 8) & 0x000FFFFF; - s1 = r1 * 5; s2 = r2 * 5; s3 = r3 * 5; s4 = r4 * 5; - h0 = h1 = h2 = h3 = h4 = 0; - while (n >= 16) { - uint64_t d0, d1, d2, d3, d4; -process_block: - h0 += (LOAD32_LE(msg + 0) >> 0) & 0x03FFFFFF; - h1 += (LOAD32_LE(msg + 3) >> 2) & 0x03FFFFFF; - h2 += (LOAD32_LE(msg + 6) >> 4) & 0x03FFFFFF; - h3 += (LOAD32_LE(msg + 9) >> 6) & 0x03FFFFFF; - h4 += (LOAD32_LE(msg + 12) >> 8) | c; - - #define MUL(a,b) ((uint64_t)(a) * (b)) - d0 = MUL(h0,r0) + MUL(h1,s4) + MUL(h2,s3) + MUL(h3,s2) + MUL(h4,s1); - d1 = MUL(h0,r1) + MUL(h1,r0) + MUL(h2,s4) + MUL(h3,s3) + MUL(h4,s2); - d2 = MUL(h0,r2) + MUL(h1,r1) + MUL(h2,r0) + MUL(h3,s4) + MUL(h4,s3); - d3 = MUL(h0,r3) + MUL(h1,r2) + MUL(h2,r1) + MUL(h3,r0) + MUL(h4,s4); - d4 = MUL(h0,r4) + MUL(h1,r3) + MUL(h2,r2) + MUL(h3,r1) + MUL(h4,r0); - #undef MUL - - h0 = d0 & 0x03FFFFFF; d1 += (uint32_t)(d0 >> 26); - h1 = d1 & 0x03FFFFFF; d2 += (uint32_t)(d1 >> 26); - h2 = d2 & 0x03FFFFFF; d3 += (uint32_t)(d2 >> 26); - h3 = d3 & 0x03FFFFFF; d4 += (uint32_t)(d3 >> 26); - h4 = d4 & 0x03FFFFFF; h0 += (uint32_t)(d4 >> 26) * 5; - h1 += (h0 >> 26); h0 = h0 & 0x03FFFFFF; - - msg += 16; - n -= 16; - } - if (n) { - for (i = 0; i < n; i++) buf[i] = msg[i]; - buf[i++] = 1; - while (i < 16) buf[i++] = 0; - msg = buf; - n = 16; - c = 0; - goto process_block; - } - *(volatile uint32_t *)&r0 = 0; - *(volatile uint32_t *)&r1 = 0; *(volatile uint32_t *)&s1 = 0; - *(volatile uint32_t *)&r2 = 0; *(volatile uint32_t *)&s2 = 0; - *(volatile uint32_t *)&r3 = 0; *(volatile uint32_t *)&s3 = 0; - *(volatile uint32_t *)&r4 = 0; *(volatile uint32_t *)&s4 = 0; - - h2 += (h1 >> 26); h1 &= 0x03FFFFFF; - h3 += (h2 >> 26); h2 &= 0x03FFFFFF; - h4 += (h3 >> 26); h3 &= 0x03FFFFFF; - h0 += (h4 >> 26) * 5; h4 &= 0x03FFFFFF; - h1 += (h0 >> 26); h0 &= 0x03FFFFFF; - - g0 = h0 + 5; - g1 = h1 + (g0 >> 26); g0 &= 0x03FFFFFF; - g2 = h2 + (g1 >> 26); g1 &= 0x03FFFFFF; - g3 = h3 + (g2 >> 26); g2 &= 0x03FFFFFF; - g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x03FFFFFF; - - w = ~(m = (g4 >> 31) - 1); - h0 = (h0 & w) | (g0 & m); - h1 = (h1 & w) | (g1 & m); - h2 = (h2 & w) | (g2 & m); - h3 = (h3 & w) | (g3 & m); - h4 = (h4 & w) | (g4 & m); - - f0 = ((h0 >> 0) | (h1 << 26)) + (uint64_t)LOAD32_LE(&key[16]); - f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)LOAD32_LE(&key[20]); - f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)LOAD32_LE(&key[24]); - f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)LOAD32_LE(&key[28]); - - STORE32_LE(tag + 0, f0); f1 += (f0 >> 32); - STORE32_LE(tag + 4, f1); f2 += (f1 >> 32); - STORE32_LE(tag + 8, f2); f3 += (f2 >> 32); - STORE32_LE(tag + 12, f3); -} - -int poly1305_tagcmp(const unsigned char tag1[16], const unsigned char tag2[16]) -{ - unsigned int d = 0; - d |= tag1[ 0] ^ tag2[ 0]; - d |= tag1[ 1] ^ tag2[ 1]; - d |= tag1[ 2] ^ tag2[ 2]; - d |= tag1[ 3] ^ tag2[ 3]; - d |= tag1[ 4] ^ tag2[ 4]; - d |= tag1[ 5] ^ tag2[ 5]; - d |= tag1[ 6] ^ tag2[ 6]; - d |= tag1[ 7] ^ tag2[ 7]; - d |= tag1[ 8] ^ tag2[ 8]; - d |= tag1[ 9] ^ tag2[ 9]; - d |= tag1[10] ^ tag2[10]; - d |= tag1[11] ^ tag2[11]; - d |= tag1[12] ^ tag2[12]; - d |= tag1[13] ^ tag2[13]; - d |= tag1[14] ^ tag2[14]; - d |= tag1[15] ^ tag2[15]; - return d; -} - -/* - * SHA256 hash function - */ -struct sha256 { - uint32_t state[8]; - unsigned char buffer[64]; - uint64_t n64; - int n; -}; - -void sha256_init(struct sha256 *ctx) -{ - ctx->state[0] = 0x6a09e667; /* sqrt(2) */ - ctx->state[1] = 0xbb67ae85; /* sqrt(3) */ - ctx->state[2] = 0x3c6ef372; /* sqrt(5) */ - ctx->state[3] = 0xa54ff53a; /* sqrt(7) */ - ctx->state[4] = 0x510e527f; /* sqrt(11) */ - ctx->state[5] = 0x9b05688c; /* sqrt(13) */ - ctx->state[6] = 0x1f83d9ab; /* sqrt(17) */ - ctx->state[7] = 0x5be0cd19; /* sqrt(19) */ - ctx->n64 = 0; - ctx->n = 0; -} - -static void sha256_block(uint32_t state[8], const unsigned char p[64]) -{ - uint32_t w[64], a, b, c, d, e, f, g, h; - uint32_t s0, s1, S0, S1, t1, t2; - static const uint32_t K256[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - }; - - a = state[0]; b = state[1]; c = state[2]; d = state[3]; - e = state[4]; f = state[5]; g = state[6]; h = state[7]; - - #define ROUND_CORE(i) \ - S1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25); \ - t1 = h + S1 + ((e & f) ^ (~e & g)) + K256[i] + w[i]; \ - S0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22); \ - t2 = S0 + ((a & b) ^ (a & c) ^ (b & c)); \ - h = g; g = f; f = e; e = d + t1; \ - d = c; c = b; b = a; a = t1 + t2; - - #define ROUND_0_15(i) w[i] = LOAD32_BE(p); p += 4; ROUND_CORE(i) - ROUND_0_15( 0) ROUND_0_15( 1) ROUND_0_15( 2) ROUND_0_15( 3) - ROUND_0_15( 4) ROUND_0_15( 5) ROUND_0_15( 6) ROUND_0_15( 7) - ROUND_0_15( 8) ROUND_0_15( 9) ROUND_0_15(10) ROUND_0_15(11) - ROUND_0_15(12) ROUND_0_15(13) ROUND_0_15(14) ROUND_0_15(15) - #undef ROUND_0_15 - - #define ROUND_16_19(i) \ - s0 = ROR32(w[i-15], 7) ^ ROR32(w[i-15], 18) ^ (w[i-15] >> 3); \ - s1 = ROR32(w[i-2], 17) ^ ROR32(w[i-2], 19) ^ (w[i-2] >> 10); \ - w[i] = w[i-16] + s0 + w[i-7] + s1; ROUND_CORE(i) - ROUND_16_19(16) ROUND_16_19(17) ROUND_16_19(18) ROUND_16_19(19) - ROUND_16_19(20) ROUND_16_19(21) ROUND_16_19(22) ROUND_16_19(23) - ROUND_16_19(24) ROUND_16_19(25) ROUND_16_19(26) ROUND_16_19(27) - ROUND_16_19(28) ROUND_16_19(29) ROUND_16_19(30) ROUND_16_19(31) - ROUND_16_19(32) ROUND_16_19(33) ROUND_16_19(34) ROUND_16_19(35) - ROUND_16_19(36) ROUND_16_19(37) ROUND_16_19(38) ROUND_16_19(39) - ROUND_16_19(40) ROUND_16_19(41) ROUND_16_19(42) ROUND_16_19(43) - ROUND_16_19(44) ROUND_16_19(45) ROUND_16_19(46) ROUND_16_19(47) - ROUND_16_19(48) ROUND_16_19(49) ROUND_16_19(50) ROUND_16_19(51) - ROUND_16_19(52) ROUND_16_19(53) ROUND_16_19(54) ROUND_16_19(55) - ROUND_16_19(56) ROUND_16_19(57) ROUND_16_19(58) ROUND_16_19(59) - ROUND_16_19(60) ROUND_16_19(61) ROUND_16_19(62) ROUND_16_19(63) - #undef ROUND_16_19 - #undef ROUND_CORE - - state[0] += a; state[1] += b; state[2] += c; state[3] += d; - state[4] += e; state[5] += f; state[6] += g; state[7] += h; -} - -void sha256_update(struct sha256 *ctx, const unsigned char *data, size_t n) -{ - if (n < 64 || ctx->n) { - int i, j = (ctx->n + n < 64) ? n : 64 - ctx->n; - for (i = 0; i < j; i++) { - ctx->buffer[ctx->n + i] = data[i]; - } - if ((ctx->n += j) < 64) - return; - sha256_block(ctx->state, ctx->buffer); - ctx->n64 += 64; - ctx->n = 0; - data += j; - n -= j; - } - - while (n >= 64) { - sha256_block(ctx->state, data); - ctx->n64 += 64; - data += 64; - n -= 64; - } - - if (n) { - int i = 0; - while (i < n) { - ctx->buffer[i] = data[i]; - i++; - } - ctx->n = n; - } -} - -static void sha256_serialize(const uint32_t state[8], unsigned char hash[32]) -{ - STORE32_BE(hash + 0, state[0]); - STORE32_BE(hash + 4, state[1]); - STORE32_BE(hash + 8, state[2]); - STORE32_BE(hash + 12, state[3]); - STORE32_BE(hash + 16, state[4]); - STORE32_BE(hash + 20, state[5]); - STORE32_BE(hash + 24, state[6]); - STORE32_BE(hash + 28, state[7]); -} - -void sha256_final(struct sha256 *ctx, unsigned char hash[32]) -{ - int i; - unsigned char buf[128]; - uint64_t nbits = (ctx->n64 + ctx->n) * 8; - buf[0] = 0x80; - for (i = 1; (ctx->n + i + 8) % 64; buf[i++] = 0); - STORE64_BE(buf+i, nbits); - sha256_update(ctx, buf, i+8); - sha256_serialize(ctx->state, hash); -} - -/* - * PBKDF2-HMAC-SHA256 key derivation optimized to reuse intermediate SHA256 - * states computed in the HMAC-SHA256 calculation of the inner and outer pad. - */ -void pbkdf2_hmac_sha256(const void *pass, size_t m, const void *salt, size_t n, - int iter, unsigned char *dk, int dklen) -{ - unsigned char keyblock[64], iblock[64], oblock[64]; - struct sha256 ctx, ictx, octx; - uint32_t I[8], O[8]; - int i, j, k, len; - - /* Initialize keyblock */ - if (m > 64) { - sha256_init(&ctx); - sha256_update(&ctx, pass, m); - sha256_final(&ctx, keyblock); - memset(keyblock+32, 0, 32); - } else { - memcpy(keyblock, pass, m); - memset(keyblock+m, 0, 64 - m); - } - - /* Prepare iblock and oblock */ - sha256_init(&ictx); - sha256_init(&octx); - for (i = 0; i < 64; i++) { - iblock[i] = 0x36 ^ keyblock[i]; - oblock[i] = 0x5C ^ keyblock[i]; - *(volatile unsigned char *)(keyblock + i) = 0; - } - sha256_update(&ictx, iblock, 64); - sha256_update(&octx, oblock, 64); - memset(iblock+32, 0, 32); - memset(oblock+32, 0, 32); - STORE32_BE(&iblock[64-4], 96*8); - STORE32_BE(&oblock[64-4], 96*8); - iblock[32] = oblock[32] = 0x80; - - /* PBKDF2 main loop */ - for (i = 1; dklen; i++) { - unsigned char ibuf[4]; - STORE32_BE(ibuf, i); - memcpy(&ctx, &ictx, sizeof(struct sha256)); - sha256_update(&ctx, salt, n); - sha256_update(&ctx, ibuf, 4); - sha256_final(&ctx, oblock); - - memcpy(O, octx.state, 32); - sha256_block(O, oblock); - sha256_serialize(O, iblock); - - len = (dklen < 32) ? dklen : 32; - memcpy(dk, iblock, len); - for (j = 1; j < iter; j++) { - memcpy(I, ictx.state, 32); - memcpy(O, octx.state, 32); - sha256_block(I, iblock); - sha256_serialize(I, oblock); - sha256_block(O, oblock); - sha256_serialize(O, iblock); - for (k = 0; k < len; k++) { - dk[k] ^= iblock[k]; - } - } - dklen -= len; - dk += len; - } - - /* Burn key material */ /* TODO: is this really necessary? */ - for (i = 0; i < 64; i++) { /* for truly paranoid people, yes */ - *(volatile unsigned char *)(iblock + i) = 0; - *(volatile unsigned char *)(oblock + i) = 0; - } -} - -/* - * Platform-specific entropy functions for seeding RNG - */ -#if defined(__unix__) || defined(__APPLE__) -#define _GNU_SOURCE -#include -#include - -#ifdef __linux__ -#include -#include -#endif - -/* Returns the number of urandom bytes read (either 0 or n) */ -static size_t read_urandom(void *buf, size_t n) -{ - size_t i; - ssize_t ret; - int fd, count; - struct stat st; - int errnold = errno; - - do { - fd = open("/dev/urandom", O_RDONLY, 0); - } while (fd == -1 && errno == EINTR); - if (fd == -1) - goto fail; - fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); - - /* Check the sanity of the device node */ - if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) - #ifdef __linux__ - || ioctl(fd, RNDGETENTCNT, &count) == -1 - #endif - ) { - close(fd); - goto fail; - } - - /* Read bytes */ - for (i = 0; i < n; i += ret) { - while ((ret = read(fd, (char *)buf + i, n - i)) == -1) { - if (errno != EAGAIN && errno != EINTR) { - close(fd); - goto fail; - } - } - } - close(fd); - - /* Verify that the random device returned non-zero data */ - for (i = 0; i < n; i++) { - if (((unsigned char *)buf)[i] != 0) { - errno = errnold; - return n; - } - } - - /* Tiny n may unintentionally fall through! */ - -fail: - fprintf(stderr, "bad /dev/urandom RNG)\n"); - abort(); /* PANIC! */ - return 0; -} - -static size_t entropy(void *buf, size_t n) -{ - #if defined(__linux__) && defined(SYS_getrandom) - if (syscall(SYS_getrandom, buf, n, 0) == n) - return n; - #elif defined(SYS_getentropy) - if (syscall(SYS_getentropy, buf, n) == 0) - return n; - #endif - return read_urandom(buf, n); -} - -#elif defined(_WIN32) - -#include -#define RtlGenRandom SystemFunction036 -BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); -#pragma comment(lib, "advapi32.lib") - -static size_t entropy(void *buf, size_t n) -{ - return RtlGenRandom(buf, n) ? n : 0; -} - -#else -#error "Secure pseudorandom number generator unimplemented for this OS" -#endif - -/* - * ChaCha20 random number generator - */ -void chacha20_rng(void *out, size_t n) -{ - static size_t available = 0; - static uint32_t counter = 0xFFFFFFFF; - static unsigned char key[32], nonce[12], buffer[64]; - sqlite3_mutex *mutex; - size_t m; - - mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG); - sqlite3_mutex_enter(mutex); - while (n > 0) { - if (available == 0) { - if (counter == 0xFFFFFFFF) { - if (entropy(key, sizeof(key)) != sizeof(key)) - abort(); - if (entropy(nonce, sizeof(nonce)) != sizeof(nonce)) - abort(); - counter = 0; - } - chacha20_xor(buffer, sizeof(buffer), key, nonce, ++counter); - available = sizeof(buffer); - } - m = (available < n) ? available : n; - memcpy(out, buffer + (sizeof(buffer) - available), m); - out = (unsigned char *)out + m; - available -= m; - n -= m; - } - sqlite3_mutex_leave(mutex); -} diff --git a/uppsrc/plugin/sqlite3/libsee/rekeyvacuum.c b/uppsrc/plugin/sqlite3/libsee/rekeyvacuum.c deleted file mode 100644 index ba4f72b84..000000000 --- a/uppsrc/plugin/sqlite3/libsee/rekeyvacuum.c +++ /dev/null @@ -1,259 +0,0 @@ -/* -** Adjusted version of sqlite3RunVacuum to allow reducing or removing reserved page space -** For this purpose the number of reserved bytes per page for the target database is -** passed as a parameter to the adjusted function. -** -** NOTE: When upgrading to a new version of SQLite3 it is strongly recommended to check -** the original function sqlite3RunVacuum of the new version for relevant changes, and -** to incorporate them in the adjusted function below. -** -** The code below is based on SQLite version 3.25.2. -*/ - -/* -** This routine implements the OP_Vacuum opcode of the VDBE. -*/ -/* CHANGE 1 of 3: Add function parameter nRes */ -SQLITE_PRIVATE int sqlite3RunVacuumForRekey(char **pzErrMsg, sqlite3 *db, int iDb, int nRes){ - int rc = SQLITE_OK; /* Return code from service routines */ - Btree *pMain; /* The database being vacuumed */ - Btree *pTemp; /* The temporary database we vacuum into */ - u16 saved_mDbFlags; /* Saved value of db->mDbFlags */ - u32 saved_flags; /* Saved value of db->flags */ - int saved_nChange; /* Saved value of db->nChange */ - int saved_nTotalChange; /* Saved value of db->nTotalChange */ - u8 saved_mTrace; /* Saved trace settings */ - Db *pDb = 0; /* Database to detach at end of vacuum */ - int isMemDb; /* True if vacuuming a :memory: database */ - /* CHANGE 2 of 3: Do not define local variable nRes */ - /*int nRes;*/ /* Bytes of reserved space at the end of each page */ - int nDb; /* Number of attached databases */ - const char *zDbMain; /* Schema name of database to vacuum */ - - if( !db->autoCommit ){ - sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); - return SQLITE_ERROR; - } - if( db->nVdbeActive>1 ){ - sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); - return SQLITE_ERROR; - } - - /* Save the current value of the database flags so that it can be - ** restored before returning. Then set the writable-schema flag, and - ** disable CHECK and foreign key constraints. */ - saved_flags = db->flags; - saved_mDbFlags = db->mDbFlags; - saved_nChange = db->nChange; - saved_nTotalChange = db->nTotalChange; - saved_mTrace = db->mTrace; - db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; - db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; - db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows); - db->mTrace = 0; - - zDbMain = db->aDb[iDb].zDbSName; - pMain = db->aDb[iDb].pBt; - isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); - - /* Attach the temporary database as 'vacuum_db'. The synchronous pragma - ** can be set to 'off' for this file, as it is not recovered if a crash - ** occurs anyway. The integrity of the database is maintained by a - ** (possibly synchronous) transaction opened on the main database before - ** sqlite3BtreeCopyFile() is called. - ** - ** An optimisation would be to use a non-journaled pager. - ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but - ** that actually made the VACUUM run slower. Very little journalling - ** actually occurs when doing a vacuum since the vacuum_db is initially - ** empty. Only the journal header is written. Apparently it takes more - ** time to parse and run the PRAGMA to turn journalling off than it does - ** to write the journal header file. - */ - nDb = db->nDb; - rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db"); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - assert( (db->nDb-1)==nDb ); - pDb = &db->aDb[nDb]; - assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); - pTemp = pDb->pBt; - - /* The call to execSql() to attach the temp database has left the file - ** locked (as there was more than one active statement when the transaction - ** to read the schema was concluded. Unlock it here so that this doesn't - ** cause problems for the call to BtreeSetPageSize() below. */ - sqlite3BtreeCommit(pTemp); - - /* CHANGE 3 of 3: Do not call sqlite3BtreeGetOptimalReserve */ - /*nRes = sqlite3BtreeGetOptimalReserve(pMain);*/ - - /* A VACUUM cannot change the pagesize of an encrypted database. */ -#ifdef SQLITE_HAS_CODEC - if( db->nextPagesize ){ - extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); - int nKey; - char *zKey; - sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); - if( nKey ) db->nextPagesize = 0; - } -#endif - - sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); - sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); - sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL); - - /* Begin a transaction and take an exclusive lock on the main database - ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, - ** to ensure that we do not try to change the page-size on a WAL database. - */ - rc = execSql(db, pzErrMsg, "BEGIN"); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = sqlite3BtreeBeginTrans(pMain, 2, 0); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - - /* Do not attempt to change the page size for a WAL database */ - if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) - ==PAGER_JOURNALMODE_WAL ){ - db->nextPagesize = 0; - } - - if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) - || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) - || NEVER(db->mallocFailed) - ){ - rc = SQLITE_NOMEM_BKPT; - goto end_of_vacuum; - } - -#ifndef SQLITE_OMIT_AUTOVACUUM - sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac : - sqlite3BtreeGetAutoVacuum(pMain)); -#endif - - /* Query the schema of the main database. Create a mirror schema - ** in the temporary database. - */ - db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ - rc = execSqlF(db, pzErrMsg, - "SELECT sql FROM \"%w\".sqlite_master" - " WHERE type='table'AND name<>'sqlite_sequence'" - " AND coalesce(rootpage,1)>0", - zDbMain - ); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = execSqlF(db, pzErrMsg, - "SELECT sql FROM \"%w\".sqlite_master" - " WHERE type='index'", - zDbMain - ); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - db->init.iDb = 0; - - /* Loop through the tables in the main database. For each, do - ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy - ** the contents to the temporary database. - */ - rc = execSqlF(db, pzErrMsg, - "SELECT'INSERT INTO vacuum_db.'||quote(name)" - "||' SELECT*FROM\"%w\".'||quote(name)" - "FROM vacuum_db.sqlite_master " - "WHERE type='table'AND coalesce(rootpage,1)>0", - zDbMain - ); - assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); - db->mDbFlags &= ~DBFLAG_Vacuum; - if( rc!=SQLITE_OK ) goto end_of_vacuum; - - /* Copy the triggers, views, and virtual tables from the main database - ** over to the temporary database. None of these objects has any - ** associated storage, so all we have to do is copy their entries - ** from the SQLITE_MASTER table. - */ - rc = execSqlF(db, pzErrMsg, - "INSERT INTO vacuum_db.sqlite_master" - " SELECT*FROM \"%w\".sqlite_master" - " WHERE type IN('view','trigger')" - " OR(type='table'AND rootpage=0)", - zDbMain - ); - if( rc ) goto end_of_vacuum; - - /* At this point, there is a write transaction open on both the - ** vacuum database and the main database. Assuming no error occurs, - ** both transactions are closed by this block - the main database - ** transaction by sqlite3BtreeCopyFile() and the other by an explicit - ** call to sqlite3BtreeCommit(). - */ - { - u32 meta; - int i; - - /* This array determines which meta meta values are preserved in the - ** vacuum. Even entries are the meta value number and odd entries - ** are an increment to apply to the meta value after the vacuum. - ** The increment is used to increase the schema cookie so that other - ** connections to the same database will know to reread the schema. - */ - static const unsigned char aCopy[] = { - BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ - BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ - BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ - BTREE_USER_VERSION, 0, /* Preserve the user version */ - BTREE_APPLICATION_ID, 0, /* Preserve the application id */ - }; - - assert( 1==sqlite3BtreeIsInTrans(pTemp) ); - assert( 1==sqlite3BtreeIsInTrans(pMain) ); - - /* Copy Btree meta values */ - for(i=0; iflags */ - db->init.iDb = 0; - db->mDbFlags = saved_mDbFlags; - db->flags = saved_flags; - db->nChange = saved_nChange; - db->nTotalChange = saved_nTotalChange; - db->mTrace = saved_mTrace; - sqlite3BtreeSetPageSize(pMain, -1, -1, 1); - - /* Currently there is an SQL level transaction open on the vacuum - ** database. No locks are held on any other files (since the main file - ** was committed at the btree level). So it safe to end the transaction - ** by manually setting the autoCommit flag to true and detaching the - ** vacuum database. The vacuum_db journal file is deleted when the pager - ** is closed by the DETACH. - */ - db->autoCommit = 1; - - if( pDb ){ - sqlite3BtreeClose(pDb->pBt); - pDb->pBt = 0; - pDb->pSchema = 0; - } - - /* This both clears the schemas and reduces the size of the db->aDb[] - ** array. */ - sqlite3ResetAllSchemasOfConnection(db); - - return rc; -} diff --git a/uppsrc/plugin/sqlite3/libsee/sqleet.c b/uppsrc/plugin/sqlite3/libsee/sqleet.c deleted file mode 100644 index 319567aed..000000000 --- a/uppsrc/plugin/sqlite3/libsee/sqleet.c +++ /dev/null @@ -1,410 +0,0 @@ -#include "config.c" -//#include "sqlite3.c" -#include "rekeyvacuum.c" -#include "crypto.c" - -/* - * SQLite3 codec implementation. - */ -typedef struct codec { - struct codec *reader, *writer; - unsigned char key[32], salt[16]; - void *pagebuf; - int pagesize; - const void *zKey; - int nKey; -} Codec; - -Codec *codec_new(const char *zKey, int nKey) -{ - Codec *codec; - if ((codec = sqlite3_malloc(sizeof(Codec)))) { - codec->reader = codec->writer = codec; - memset(codec->key, 0, sizeof(codec->key)); - memset(codec->salt, 0, sizeof(codec->salt)); - codec->pagebuf = NULL; - codec->pagesize = 0; - codec->zKey = zKey; - codec->nKey = nKey; - } - return codec; -} - -Codec *codec_dup(Codec *src) -{ - Codec *codec; - if ((codec = codec_new(src->zKey, src->nKey))) { - codec->reader = (src->reader == src) ? codec : src->reader; - codec->writer = (src->writer == src) ? codec : src->writer; - memcpy(codec->salt, src->salt, 16); - memcpy(codec->key, src->key, 32); - } - return codec; -} - -void codec_kdf(Codec *codec) -{ - pbkdf2_hmac_sha256(codec->zKey, codec->nKey, codec->salt, 16, 12345, - codec->key, 32); - codec->zKey = NULL; - codec->nKey = 0; -} - -void codec_free(void *pcodec) -{ - if (pcodec) { - int i; - volatile char *p; - Codec *codec = pcodec; - if (codec->pagebuf) { - p = codec->pagebuf; - for (i = 0; i < codec->pagesize; p[i++] = '\0'); - sqlite3_free(codec->pagebuf); - } - p = pcodec; - for (i = 0; i < sizeof(Codec); p[i++] = '\0'); - sqlite3_free(codec); - } -} - -/* - * The encrypted database page format. - * - * +----------------------------------------+----------------+----------------+ - * | Encrypted data | 16-byte nonce | 16-byte tag | - * +----------------------------------------+----------------+----------------+ - * - * As the only exception, the first page (page_no=1) starts with a plaintext - * salt contained in the first 16 bytes of the database file. The "master" key - * is derived from a user-given password with the salt and 12345 iterations of - * PBKDF-HMAC-SHA256. Future plans include switching to BLAKE2 and Argon2. - * - * - The data is encrypted by XORing with the ChaCha20 keystream produced from - * the 16-byte nonce and a 32-byte encryption key derived from the master key. - * - OK, I lied a little: ChaCha20 uses only the first 12 bytes as the nonce. - * However, ChaCha20 also requires an initial value for a counter of 4 bytes - * that encodes a block position in the output stream. We derive the counter - * value from the last 4 bytes, effectively extending the nonce to 16 bytes. - * - Specifically, counter = LOAD32_LE(nonce[12..15])^page_no is first applied - * to generate a single 64-byte block from nonce[0..11] and the master key. - * The block consists of two 32-byte one-time keys, the former is a Poly1305 - * key for the authentication tag, and the latter is a ChaCha20 key for the - * data encryption. The encryption with the one-time key uses nonce[0..11] - * and the initial counter value of counter+1. - * - The XOR with page_no prevents malicious reordering of the pages. - * - * - The nonce consists of 128 randomly generated bits, which should be enough - * to guarantee uniqueness with a reasonable pseudorandom number generator. - * - Given a perfect RNG, the adversary needs to observe at least 2^61 nonces - * to break Poly1305 with the birthday attack at a success rate of 1%. - * - If a nonce is reused, we lose confidentiality of the associated messages. - * Moreover, the compromised nonce can also be used to forge valid tags for - * new messages having the same nonce (basically, the one-time Poly1305 key - * can be recovered from distinct messages with identical nonces). - * - * - The tag is a Poly1305 MAC calculated over the encrypted data and the nonce - * with the one-time key generated from the master key and the nonce. - */ - -#define PAGE_NONCE_LEN 16 -#define PAGE_TAG_LEN 16 -#define PAGE_RESERVED_LEN (PAGE_NONCE_LEN + PAGE_TAG_LEN) - -void *codec_handle(void *codec, void *pdata, Pgno page, int mode) -{ - uint32_t counter; - unsigned char otk[64], tag[16], *data = pdata; - Codec *reader = ((Codec *)codec)->reader; - Codec *writer = ((Codec *)codec)->writer; - const int skip = (page == 1) ? SKIP_HEADER_BYTES : 0; - - switch (mode) { - case 0: /* Journal decryption */ - case 2: /* Reload a page */ - case 3: /* Load a page */ - if (reader) { - int n = reader->pagesize - PAGE_RESERVED_LEN; - if (page == 1 && reader->zKey) { - memcpy(reader->salt, data, 16); - codec_kdf(reader); - } - - /* Generate one-time keys */ - memset(otk, 0, 64); - counter = LOAD32_LE(data + n + PAGE_NONCE_LEN-4) ^ page; - chacha20_xor(otk, 64, reader->key, data + n, counter); - - /* Verify the MAC */ - poly1305(data, n + PAGE_NONCE_LEN, otk, tag); - if (poly1305_tagcmp(data + n + PAGE_NONCE_LEN, tag) != 0) - return NULL; - - /* Decrypt */ - chacha20_xor(data + skip, n - skip, otk+32, data + n, counter+1); - if (page == 1) memcpy(data, "SQLite format 3", 16); - } - break; - - case 7: /* Encrypt a journal page (with the reader key) */ - writer = reader; - /* fall-through */ - case 6: /* Encrypt a main database page */ - if (writer) { - int n = writer->pagesize - PAGE_RESERVED_LEN; - data = memcpy(writer->pagebuf, data, writer->pagesize); - - /* Generate one-time keys */ - memset(otk, 0, 64); - chacha20_rng(data + n, 16); - counter = LOAD32_LE(data + n + PAGE_NONCE_LEN-4) ^ page; - chacha20_xor(otk, 64, writer->key, data + n, counter); - - /* Encrypt and authenticate */ - chacha20_xor(data + skip, n - skip, otk+32, data + n, counter+1); - if (page == 1) memcpy(data, writer->salt, 16); - poly1305(data, n + PAGE_NONCE_LEN, otk, data + n + PAGE_NONCE_LEN); - } - break; - } - - return data; -} - -/* Reads page1 to trigger codec_kdf and verify the encryption key */ -static int codec_verify_page1(Codec *codec, Btree *pBt) -{ - int count, rc = SQLITE_OK; - Pager *pager = sqlite3BtreePager(pBt); - sqlite3PagerSharedLock(pager); - sqlite3PagerPagecount(pager, &count); - if (count > 0) { - DbPage *page; - rc = SQLITE_NOTADB; - sqlite3PcacheTruncate(pager->pPCache, 0); - if (sqlite3PagerGet(pager, 1, &page, 0) == SQLITE_OK) { - if (!memcmp(page->pData, "SQLite format 3", 16)) - rc = SQLITE_OK; - sqlite3PagerUnref(page); - } else { - sqlite3PagerSetCodec(pager, NULL, NULL, NULL, NULL); - } - } else if (codec && codec->zKey) { - /* Generate a salt and derive an encryption key for an empty database */ - chacha20_rng(codec->salt, 16); - codec_kdf(codec); - } - pager_unlock(pager); - return rc; -} - -/* - * Set (or unset) a codec for the pager of the specified Btree. - * - * The caller must hold the database mutex when calling this function. - * Note that the function consumes the passed-in codec structure. - */ -static int codec_set_to(Codec *codec, Btree *pBt) -{ - int pagesize; - Pager *pager = sqlite3BtreePager(pBt); - - if (!codec) { - /* Unset a codec */ - sqlite3PagerSetCodec(pager, NULL, NULL, NULL, NULL); - return SQLITE_OK; - } - - /* Allocate page buffer */ - pagesize = sqlite3BtreeGetPageSize(pBt); - if (!codec->pagebuf || codec->pagesize != pagesize) { - void *new = sqlite3_malloc(pagesize); - if (!new) { - codec_free(codec); - return SQLITE_NOMEM; - } - if (codec->pagebuf) { - int i = 0; - while (i < codec->pagesize) - ((volatile char *)codec->pagebuf)[i++] = '\0'; - sqlite3_free(codec->pagebuf); - } - codec->pagebuf = new; - codec->pagesize = pagesize; - } - - /* Force secure delete */ - sqlite3BtreeSecureDelete(pBt, 1); - - /* Adjust the page size and the reserved area */ - if (pager->nReserve != PAGE_RESERVED_LEN) { - pBt->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; - sqlite3BtreeSetPageSize(pBt, pagesize, PAGE_RESERVED_LEN, 0); - } - - /* Set pager codec and try to read page1 */ - sqlite3PagerSetCodec(pager, codec_handle, NULL, codec_free, codec); - return codec_verify_page1(codec, pBt); -} - -void sqlite3CodecGetKey(sqlite3 *db, int nDb, void **zKey, int *nKey) -{ - /* - * sqlite3.c calls this function to decide if a database attached without a - * password should use the encryption scheme of the main database. Returns - * *nKey == 1 to indicate that the main database encryption is available. - */ - *zKey = NULL; - *nKey = !!sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[nDb].pBt)); -} - -int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *zKey, int nKey) -{ - int rc; - Codec *codec; - Btree *pBt = db->aDb[nDb].pBt; - - rc = SQLITE_NOMEM; - sqlite3_mutex_enter(db->mutex); - if (!nKey) { - /* Attach with an empty key (no encryption) */ - codec_set_to(NULL, pBt); - rc = codec_verify_page1(NULL, pBt); - } else if (zKey) { - /* Attach with the provided key */ - if ((codec = codec_new(zKey, nKey))) - rc = codec_set_to(codec, pBt); - } else if (nDb != 0) { - /* Use the main database's encryption */ - codec = sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt)); - if (codec && (codec = codec_dup(codec))) { - rc = codec_set_to(codec, pBt); - } else { - /* Main database codec unavailable */ - rc = SQLITE_CANTOPEN; - } - } - sqlite3_mutex_leave(db->mutex); - - return rc; -} - -/* Returns the main database if there is no match */ -static int db_index_of(sqlite3 *db, const char *zDbName) -{ - int i; - if (zDbName) { - for (i = 0; i < db->nDb; i++) { - if (!strcmp(db->aDb[i].zDbSName, zDbName)) - return i; - } - } - return 0; -} - -int sqlite3_key_v2(sqlite3 *db, const char *zDbName, const void *zKey, int nKey) -{ - return sqlite3CodecAttach(db, db_index_of(db, zDbName), zKey, nKey); -} - -int sqlite3_key(sqlite3 *db, const void *zKey, int nKey) -{ - return sqlite3_key_v2(db, "main", zKey, nKey); -} - -int sqlite3_rekey_v2(sqlite3 *db, const char *zDbName, - const void *zKey, int nKey) -{ - char *err; - int nDb, rc; - Btree *pBt; - - if (!db || (!nKey && !zKey)) - return SQLITE_ERROR; - - rc = SQLITE_ERROR; - sqlite3_mutex_enter(db->mutex); - if ((pBt = db->aDb[(nDb = db_index_of(db, zDbName))].pBt)) { - Pgno pgno; - DbPage *page; - Codec *reader, *codec; - Pager *pager = sqlite3BtreePager(pBt); - - reader = sqlite3PagerGetCodec(pager); - if (!nKey) { - /* Decrypt */ - if (reader) { - reader->writer = NULL; - rc = sqlite3RunVacuumForRekey(&err, db, nDb, 0); - if (rc == SQLITE_OK) { - rc = codec_set_to(NULL, pBt); - } else { - reader->writer = reader->reader; - } - } else { - rc = codec_verify_page1(NULL, pBt); - } - goto leave; - } - - /* Create a codec for the given key */ - if ((codec = codec_new(zKey, nKey))) { - codec->pagesize = sqlite3BtreeGetPageSize(pBt); - if ((codec->pagebuf = sqlite3_malloc(codec->pagesize))) { - chacha20_rng(codec->salt, 16); - codec_kdf(codec); - } - } - if (!codec || !codec->pagebuf) { - codec_free(codec); - rc = SQLITE_NOMEM; - goto leave; - } - - if (!reader) { - /* Encrypt */ - codec->reader = NULL; - if ((rc = codec_set_to(codec, pBt)) == SQLITE_OK) { - rc = sqlite3RunVacuumForRekey(&err, db, nDb, PAGE_RESERVED_LEN); - if (rc == SQLITE_OK) { - codec->reader = codec->writer; - } else { - codec_set_to(NULL, pBt); - } - } - goto leave; - } - - /* Change key (re-encrypt) */ - reader->writer = codec; - rc = sqlite3BtreeBeginTrans(pBt, 1, NULL); - for (pgno = 1; rc == SQLITE_OK && pgno <= pager->dbSize; pgno++) { - /* The DB page occupied by the PENDING_BYTE is never used */ - if (pgno == PENDING_BYTE_PAGE(pager)) - continue; - if ((rc = sqlite3PagerGet(pager, pgno, &page, 0)) == SQLITE_OK) { - rc = sqlite3PagerWrite(page); - sqlite3PagerUnref(page); - } - } - if (rc == SQLITE_OK) { - sqlite3BtreeCommit(pBt); - rc = codec_set_to(codec, pBt); - } else { - reader->writer = reader; - sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); - } - } - -leave: - sqlite3_mutex_leave(db->mutex); - return rc; -} - -int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey) -{ - return sqlite3_rekey_v2(db, "main", zKey, nKey); -} - -void sqlite3_activate_see(const char *info) -{ -} diff --git a/uppsrc/plugin/sqlite3/sqlite3.upp b/uppsrc/plugin/sqlite3/sqlite3.upp index 15acfc3fa..a40401a09 100644 --- a/uppsrc/plugin/sqlite3/sqlite3.upp +++ b/uppsrc/plugin/sqlite3/sqlite3.upp @@ -14,10 +14,9 @@ options options(SQLITE_HAS_CODEC) -DSQLITE_HAS_CODEC; file - Wrapper readonly separator, Sqlite3.h, Sqlite3Schema.h, Sqlite3upp.cpp, - sqlite3.c, + lib.c, Copying;