@@ -246940,9 +246940,9 @@ SQLITE_API void sqlite3mc_vfs_shutdown();
246940
246940
246941
246941
#define SQLITE3MC_VERSION_MAJOR 1
246942
246942
#define SQLITE3MC_VERSION_MINOR 3
246943
- #define SQLITE3MC_VERSION_RELEASE 1
246943
+ #define SQLITE3MC_VERSION_RELEASE 2
246944
246944
#define SQLITE3MC_VERSION_SUBRELEASE 0
246945
- #define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.3.1 "
246945
+ #define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.3.2 "
246946
246946
246947
246947
#endif /* SQLITE3MC_VERSION_H_ */
246948
246948
/*** End of #include "sqlite3mc_version.h" ***/
@@ -252951,7 +252951,7 @@ void RijndaelInvalidate(Rijndael* rijndael)
252951
252951
** Purpose: Header for the ciphers of SQLite3 Multiple Ciphers
252952
252952
** Author: Ulrich Telle
252953
252953
** Created: 2020-02-02
252954
- ** Copyright: (c) 2006-2020 Ulrich Telle
252954
+ ** Copyright: (c) 2006-2021 Ulrich Telle
252955
252955
** License: MIT
252956
252956
*/
252957
252957
@@ -252988,6 +252988,7 @@ typedef struct _Codec
252988
252988
{
252989
252989
int m_isEncrypted;
252990
252990
int m_hmacCheck;
252991
+ int m_walLegacy;
252991
252992
/* Read cipher */
252992
252993
int m_hasReadCipher;
252993
252994
int m_readCipherType;
@@ -253188,6 +253189,33 @@ SQLITE_PRIVATE void sqlite3mcCodecGetKey(sqlite3* db, int nDb, void** zKey, int*
253188
253189
#define SQLITE3MC_DEBUG_HEX(DESC,BUFFER,LEN)
253189
253190
#endif
253190
253191
253192
+ /*
253193
+ ** If encryption was enabled and WAL journal mode was used,
253194
+ ** SQLite3 Multiple Ciphers encrypted the WAL journal frames up to version 1.2.5
253195
+ ** within the VFS implementation. As a consequence the WAL journal file was not
253196
+ ** compatible with legacy encryption implementations (for example, System.Data.SQLite
253197
+ ** or SQLCipher). Additionally, the implementation of the WAL journal encryption
253198
+ ** was broken, because reading and writing of complete WAL frames was not handled
253199
+ ** correctly. Usually, operating in WAL journal mode worked nevertheless, but after
253200
+ ** crashes the WAL journal file could be corrupted leading to data loss.
253201
+ **
253202
+ ** Version 1.3.0 introduced a new way to handle WAL journal encryption. The advantage
253203
+ ** is that the WAL journal file is now compatible with legacy encryption implementations.
253204
+ ** Unfortunately the new implementation is not compatible with that used up to version
253205
+ ** 1.2.5. To be able to access WAL journals created by prior versions, the configuration
253206
+ ** parameter 'mc_legacy_wal' was introduced. If the parameter is set to 1, then the
253207
+ ** prior WAL journal encryption mode is used. The default of this parameter can be set
253208
+ ** at compile time by setting the symbol SQLITE3MC_LEGACY_WAL accordingly, but the actual
253209
+ ** value can also be set at runtime using the pragma or the URI parameter 'mc_legacy_wal'.
253210
+ **
253211
+ ** In principle, operating generally in WAL legacy mode is possible, but it is strongly
253212
+ ** recommended to use the WAL legacy mode only to recover WAL journals left behind by
253213
+ ** prior versions without data loss.
253214
+ */
253215
+ #ifndef SQLITE3MC_LEGACY_WAL
253216
+ #define SQLITE3MC_LEGACY_WAL 0
253217
+ #endif
253218
+
253191
253219
#endif
253192
253220
/*** End of #include "cipher_common.h" ***/
253193
253221
@@ -255040,7 +255068,7 @@ SQLITE_PRIVATE const CipherDescriptor mcRC4Descriptor =
255040
255068
** Purpose: Implementation of SQLite codecs
255041
255069
** Author: Ulrich Telle
255042
255070
** Created: 2020-02-02
255043
- ** Copyright: (c) 2006-2020 Ulrich Telle
255071
+ ** Copyright: (c) 2006-2021 Ulrich Telle
255044
255072
** License: MIT
255045
255073
*/
255046
255074
@@ -255061,8 +255089,9 @@ static unsigned char padding[] =
255061
255089
255062
255090
static CipherParams commonParams[] =
255063
255091
{
255064
- { "cipher", CODEC_TYPE, CODEC_TYPE, 1, CODEC_TYPE_MAX },
255065
- { "hmac_check", 1, 1, 0, 1 },
255092
+ { "cipher", CODEC_TYPE, CODEC_TYPE, 1, CODEC_TYPE_MAX },
255093
+ { "hmac_check", 1, 1, 0, 1 },
255094
+ { "mc_legacy_wal", SQLITE3MC_LEGACY_WAL, SQLITE3MC_LEGACY_WAL, 0, 1 },
255066
255095
CIPHER_PARAMS_SENTINEL
255067
255096
};
255068
255097
@@ -255243,6 +255272,7 @@ sqlite3mcCodecInit(Codec* codec)
255243
255272
{
255244
255273
codec->m_isEncrypted = 0;
255245
255274
codec->m_hmacCheck = 1;
255275
+ codec->m_walLegacy = 0;
255246
255276
255247
255277
codec->m_hasReadCipher = 0;
255248
255278
codec->m_readCipherType = CODEC_TYPE_UNKNOWN;
@@ -255302,6 +255332,7 @@ sqlite3mcCodecSetup(Codec* codec, int cipherType, char* userPassword, int passwo
255302
255332
CipherParams* globalParams = sqlite3mcGetCipherParams(codec->m_db, 0);
255303
255333
codec->m_isEncrypted = 1;
255304
255334
codec->m_hmacCheck = sqlite3mcGetCipherParameter(globalParams, "hmac_check");
255335
+ codec->m_walLegacy = sqlite3mcGetCipherParameter(globalParams, "mc_legacy_wal");
255305
255336
codec->m_hasReadCipher = 1;
255306
255337
codec->m_hasWriteCipher = 1;
255307
255338
codec->m_readCipherType = cipherType;
@@ -255330,6 +255361,7 @@ sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int
255330
255361
}
255331
255362
codec->m_isEncrypted = 1;
255332
255363
codec->m_hmacCheck = sqlite3mcGetCipherParameter(globalParams, "hmac_check");
255364
+ codec->m_walLegacy = sqlite3mcGetCipherParameter(globalParams, "mc_legacy_wal");
255333
255365
codec->m_hasWriteCipher = 1;
255334
255366
codec->m_writeCipherType = cipherType;
255335
255367
codec->m_writeCipher = codecDescriptorTable[codec->m_writeCipherType-1]->m_allocateCipher(codec->m_db);
@@ -255513,6 +255545,7 @@ sqlite3mcCodecCopy(Codec* codec, Codec* other)
255513
255545
int rc = SQLITE_OK;
255514
255546
codec->m_isEncrypted = other->m_isEncrypted;
255515
255547
codec->m_hmacCheck = other->m_hmacCheck;
255548
+ codec->m_walLegacy = other->m_walLegacy;
255516
255549
codec->m_hasReadCipher = other->m_hasReadCipher;
255517
255550
codec->m_hasWriteCipher = other->m_hasWriteCipher;
255518
255551
codec->m_readCipherType = other->m_readCipherType;
@@ -256377,6 +256410,7 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault)
256377
256410
int skipLegacy = 0;
256378
256411
/* Set global parameters (cipher and hmac_check) */
256379
256412
int hmacCheck = sqlite3_uri_boolean(dbFileName, "hmac_check", 1);
256413
+ int walLegacy = sqlite3_uri_boolean(dbFileName, "mc_legacy_wal", 0);
256380
256414
if (configDefault)
256381
256415
{
256382
256416
sqlite3mc_config(db, "default:cipher", globalCodecParameterTable[j].m_id);
@@ -256389,6 +256423,7 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault)
256389
256423
{
256390
256424
sqlite3mc_config(db, "hmac_check", hmacCheck);
256391
256425
}
256426
+ sqlite3mc_config(db, "mc_legacy_wal", walLegacy);
256392
256427
256393
256428
#if HAVE_CIPHER_SQLCIPHER
256394
256429
/* Special handling for SQLCipher */
@@ -256515,6 +256550,13 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg)
256515
256550
((char**)pArg)[0] = sqlite3_mprintf("%d", value);
256516
256551
rc = SQLITE_OK;
256517
256552
}
256553
+ else if (sqlite3StrICmp(pragmaName, "mc_legacy_wal") == 0)
256554
+ {
256555
+ int walLegacy = (pragmaValue != NULL) ? sqlite3GetBoolean(pragmaValue, 0) : -1;
256556
+ int value = sqlite3mc_config(db, "mc_legacy_wal", walLegacy);
256557
+ ((char**)pArg)[0] = sqlite3_mprintf("%d", value);
256558
+ rc = SQLITE_OK;
256559
+ }
256518
256560
else if (sqlite3StrICmp(pragmaName, "key") == 0)
256519
256561
{
256520
256562
rc = sqlite3_key_v2(db, zDbName, pragmaValue, -1);
@@ -267361,7 +267403,7 @@ int sqlite3_regexp_init(
267361
267403
** Purpose: Implementation of SQLite VFS for Multiple Ciphers
267362
267404
** Author: Ulrich Telle
267363
267405
** Created: 2020-02-28
267364
- ** Copyright: (c) 2020 Ulrich Telle
267406
+ ** Copyright: (c) 2020-2021 Ulrich Telle
267365
267407
** License: MIT
267366
267408
*/
267367
267409
@@ -267641,8 +267683,8 @@ SQLITE_PRIVATE void* sqlite3mcPagerCodec(PgHdr* pPg)
267641
267683
if (pFile->pMethods == &mcIoMethodsGlobal)
267642
267684
{
267643
267685
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
267644
- Codec* codec = ( mcFile->pMainDb) ? mcFile->pMainDb-> codec : 0 ;
267645
- if (codec != 0 && sqlite3mcIsEncrypted(codec))
267686
+ Codec* codec = mcFile->codec;
267687
+ if (codec != 0 && codec->m_walLegacy == 0 && sqlite3mcIsEncrypted(codec))
267646
267688
{
267647
267689
aData = sqlite3mcCodec(codec, pPg->pData, pPg->pgno, 6);
267648
267690
}
@@ -268037,7 +268079,19 @@ static int mcReadWal(sqlite3_file* pFile, const void* buffer, int count, sqlite3
268037
268079
*/
268038
268080
if (pageNo != 0)
268039
268081
{
268040
- void* bufferDecrypted = sqlite3mcCodec(codec, (char*) buffer, pageNo, 3);
268082
+ void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer, pageNo, 3);
268083
+ }
268084
+ }
268085
+ else if (codec->m_walLegacy != 0 && count == pageSize + walFrameHeaderSize)
268086
+ {
268087
+ int pageNo = sqlite3Get4byte(buffer);
268088
+
268089
+ /*
268090
+ ** Decrypt page content if page number is valid
268091
+ */
268092
+ if (pageNo != 0)
268093
+ {
268094
+ void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 3);
268041
268095
}
268042
268096
}
268043
268097
}
@@ -268266,7 +268320,7 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite
268266
268320
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
268267
268321
Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0;
268268
268322
268269
- if (codec != 0 && sqlite3mcIsEncrypted(codec))
268323
+ if (codec != 0 && codec->m_walLegacy != 0 && sqlite3mcIsEncrypted(codec))
268270
268324
{
268271
268325
const int pageSize = sqlite3mcGetPageSize(codec);
268272
268326
@@ -268282,7 +268336,7 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite
268282
268336
** immediately before writing the corresponding page content.
268283
268337
** Page numbers and checksums are written to file independently.
268284
268338
** Therefore it is necessary to explicitly read the page number
268285
- ** on writing to file the contetn of a page.
268339
+ ** on writing to file the content of a page.
268286
268340
*/
268287
268341
rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), ac, 4, offset - walFrameHeaderSize);
268288
268342
if (rc == SQLITE_OK)
@@ -268306,6 +268360,26 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite
268306
268360
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
268307
268361
}
268308
268362
}
268363
+ else if (count == pageSize + walFrameHeaderSize)
268364
+ {
268365
+ int pageNo = sqlite3Get4byte(buffer);
268366
+ if (pageNo != 0)
268367
+ {
268368
+ /*
268369
+ ** Encrypt the page buffer, but only if the page number is valid
268370
+ */
268371
+ void* bufferEncrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 7);
268372
+ rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, walFrameHeaderSize, offset);
268373
+ rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), bufferEncrypted, pageSize, offset+walFrameHeaderSize);
268374
+ }
268375
+ else
268376
+ {
268377
+ /*
268378
+ ** Write buffer without encryption if the page number could not be determined
268379
+ */
268380
+ rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
268381
+ }
268382
+ }
268309
268383
else
268310
268384
{
268311
268385
/*
@@ -268375,7 +268449,6 @@ static int mcIoWrite(sqlite3_file* pFile, const void* buffer, int count, sqlite3
268375
268449
*/
268376
268450
}
268377
268451
#endif
268378
- #if 0
268379
268452
/*
268380
268453
** The page content is encrypted in memory in the WAL journal handler.
268381
268454
** This provides for compatibility with legacy applications using the
@@ -268385,7 +268458,6 @@ static int mcIoWrite(sqlite3_file* pFile, const void* buffer, int count, sqlite3
268385
268458
{
268386
268459
rc = mcWriteWal(pFile, buffer, count, offset);
268387
268460
}
268388
- #endif
268389
268461
else
268390
268462
{
268391
268463
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
0 commit comments