diff --git a/src/cipher_common.c b/src/cipher_common.c index 88dc38a..7e10c68 100644 --- a/src/cipher_common.c +++ b/src/cipher_common.c @@ -25,6 +25,7 @@ static CipherParams commonParams[] = { { "cipher", CODEC_TYPE, CODEC_TYPE, 1, CODEC_TYPE_MAX }, { "hmac_check", 1, 1, 0, 1 }, + { "mc_legacy_wal", 0, 0, 0, 1 }, CIPHER_PARAMS_SENTINEL }; @@ -205,6 +206,7 @@ sqlite3mcCodecInit(Codec* codec) { codec->m_isEncrypted = 0; codec->m_hmacCheck = 1; + codec->m_walLegacy = 0; codec->m_hasReadCipher = 0; codec->m_readCipherType = CODEC_TYPE_UNKNOWN; @@ -264,6 +266,7 @@ sqlite3mcCodecSetup(Codec* codec, int cipherType, char* userPassword, int passwo CipherParams* globalParams = sqlite3mcGetCipherParams(codec->m_db, 0); codec->m_isEncrypted = 1; codec->m_hmacCheck = sqlite3mcGetCipherParameter(globalParams, "hmac_check"); + codec->m_walLegacy = sqlite3mcGetCipherParameter(globalParams, "mc_legacy_wal"); codec->m_hasReadCipher = 1; codec->m_hasWriteCipher = 1; codec->m_readCipherType = cipherType; @@ -292,6 +295,7 @@ sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int } codec->m_isEncrypted = 1; codec->m_hmacCheck = sqlite3mcGetCipherParameter(globalParams, "hmac_check"); + codec->m_walLegacy = sqlite3mcGetCipherParameter(globalParams, "mc_legacy_wal"); codec->m_hasWriteCipher = 1; codec->m_writeCipherType = cipherType; codec->m_writeCipher = codecDescriptorTable[codec->m_writeCipherType-1]->m_allocateCipher(codec->m_db); @@ -475,6 +479,7 @@ sqlite3mcCodecCopy(Codec* codec, Codec* other) int rc = SQLITE_OK; codec->m_isEncrypted = other->m_isEncrypted; codec->m_hmacCheck = other->m_hmacCheck; + codec->m_walLegacy = other->m_walLegacy; codec->m_hasReadCipher = other->m_hasReadCipher; codec->m_hasWriteCipher = other->m_hasWriteCipher; codec->m_readCipherType = other->m_readCipherType; diff --git a/src/cipher_common.h b/src/cipher_common.h index 2f1b37b..200250d 100644 --- a/src/cipher_common.h +++ b/src/cipher_common.h @@ -39,6 +39,7 @@ typedef struct _Codec { int m_isEncrypted; int m_hmacCheck; + int m_walLegacy; /* Read cipher */ int m_hasReadCipher; int m_readCipherType; diff --git a/src/cipher_config.c b/src/cipher_config.c index 9aae555..9c94614 100644 --- a/src/cipher_config.c +++ b/src/cipher_config.c @@ -656,6 +656,7 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault) int skipLegacy = 0; /* Set global parameters (cipher and hmac_check) */ int hmacCheck = sqlite3_uri_boolean(dbFileName, "hmac_check", 1); + int walLegacy = sqlite3_uri_boolean(dbFileName, "mc_legacy_wal", 0); if (configDefault) { sqlite3mc_config(db, "default:cipher", globalCodecParameterTable[j].m_id); @@ -668,6 +669,7 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault) { sqlite3mc_config(db, "hmac_check", hmacCheck); } + sqlite3mc_config(db, "mc_legacy_wal", walLegacy); #if HAVE_CIPHER_SQLCIPHER /* Special handling for SQLCipher */ @@ -794,6 +796,13 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) ((char**)pArg)[0] = sqlite3_mprintf("%d", value); rc = SQLITE_OK; } + else if (sqlite3StrICmp(pragmaName, "mc_legacy_wal") == 0) + { + int walLegacy = (pragmaValue != NULL) ? sqlite3GetBoolean(pragmaValue, 0) : -1; + int value = sqlite3mc_config(db, "mc_legacy_wal", walLegacy); + ((char**)pArg)[0] = sqlite3_mprintf("%d", value); + rc = SQLITE_OK; + } else if (sqlite3StrICmp(pragmaName, "key") == 0) { rc = sqlite3_key_v2(db, zDbName, pragmaValue, -1); diff --git a/src/sqlite3mc_version.h b/src/sqlite3mc_version.h index 43cf453..9857579 100644 --- a/src/sqlite3mc_version.h +++ b/src/sqlite3mc_version.h @@ -14,8 +14,8 @@ #define SQLITE3MC_VERSION_MAJOR 1 #define SQLITE3MC_VERSION_MINOR 3 -#define SQLITE3MC_VERSION_RELEASE 1 +#define SQLITE3MC_VERSION_RELEASE 2 #define SQLITE3MC_VERSION_SUBRELEASE 0 -#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.3.1" +#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.3.2" #endif /* SQLITE3MC_VERSION_H_ */ diff --git a/src/sqlite3mc_vfs.c b/src/sqlite3mc_vfs.c index 4455fcf..8b9459e 100644 --- a/src/sqlite3mc_vfs.c +++ b/src/sqlite3mc_vfs.c @@ -281,7 +281,7 @@ SQLITE_PRIVATE void* sqlite3mcPagerCodec(PgHdr* pPg) { sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile; Codec* codec = mcFile->codec; - if (codec != 0 && sqlite3mcIsEncrypted(codec)) + if (codec != 0 && codec->m_walLegacy == 0 && sqlite3mcIsEncrypted(codec)) { aData = sqlite3mcCodec(codec, pPg->pData, pPg->pgno, 6); } @@ -676,7 +676,19 @@ static int mcReadWal(sqlite3_file* pFile, const void* buffer, int count, sqlite3 */ if (pageNo != 0) { - void* bufferDecrypted = sqlite3mcCodec(codec, (char*) buffer, pageNo, 3); + void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer, pageNo, 3); + } + } + else if (codec->m_walLegacy != 0 && count == pageSize + walFrameHeaderSize) + { + int pageNo = sqlite3Get4byte(buffer); + + /* + ** Decrypt page content if page number is valid + */ + if (pageNo != 0) + { + void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 3); } } } @@ -905,7 +917,7 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile; Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0; - if (codec != 0 && sqlite3mcIsEncrypted(codec)) + if (codec != 0 && codec->m_walLegacy != 0 && sqlite3mcIsEncrypted(codec)) { const int pageSize = sqlite3mcGetPageSize(codec); @@ -921,7 +933,7 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite ** immediately before writing the corresponding page content. ** Page numbers and checksums are written to file independently. ** Therefore it is necessary to explicitly read the page number - ** on writing to file the contetn of a page. + ** on writing to file the content of a page. */ rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), ac, 4, offset - walFrameHeaderSize); if (rc == SQLITE_OK) @@ -945,6 +957,26 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset); } } + else if (count == pageSize + walFrameHeaderSize) + { + int pageNo = sqlite3Get4byte(buffer); + if (pageNo != 0) + { + /* + ** Encrypt the page buffer, but only if the page number is valid + */ + void* bufferEncrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 7); + rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, walFrameHeaderSize, offset); + rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), bufferEncrypted, pageSize, offset+walFrameHeaderSize); + } + else + { + /* + ** Write buffer without encryption if the page number could not be determined + */ + rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset); + } + } else { /* @@ -1014,7 +1046,7 @@ static int mcIoWrite(sqlite3_file* pFile, const void* buffer, int count, sqlite3 */ } #endif -#if 0 +#if 1 /* ** The page content is encrypted in memory in the WAL journal handler. ** This provides for compatibility with legacy applications using the