123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /*
- * Tencent is pleased to support the open source community by making
- * WCDB available.
- *
- * Copyright (C) 2017 THL A29 Limited, a Tencent company.
- * All rights reserved.
- *
- * Licensed under the BSD 3-Clause License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * https://opensource.org/licenses/BSD-3-Clause
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "sqliterk_crypto.h"
- #include "SQLiteRepairKit.h"
- #include "sqliterk_os.h"
- #include "sqliterk_pager.h"
- #ifdef WCDB_BUILTIN_SQLCIPHER
- #include <sqlcipher/sqlite3.h>
- #else //WCDB_BUILTIN_SQLCIPHER
- #include <sqlite3.h>
- #endif //WCDB_BUILTIN_SQLCIPHER
- #include <string.h>
- // Declarations by SQLCipher.
- #define CIPHER_DECRYPT 0
- #define CIPHER_ENCRYPT 1
- #define CIPHER_READ_CTX 0
- #define CIPHER_WRITE_CTX 1
- #define CIPHER_READWRITE_CTX 2
- /* Extensions defined in crypto_impl.c */
- typedef struct codec_ctx codec_ctx;
- /* Activation and initialization */
- void sqlcipher_activate(void);
- void sqlcipher_deactivate(void);
- int sqlcipher_codec_ctx_init(
- codec_ctx **, void *, void *, void *, const void *, int);
- void sqlcipher_codec_ctx_free(codec_ctx **);
- int sqlcipher_codec_key_derive(codec_ctx *);
- int sqlcipher_codec_key_copy(codec_ctx *, int);
- /* Page cipher implementation */
- int sqlcipher_page_cipher(
- codec_ctx *, int, int, int, int, unsigned char *, unsigned char *);
- /* Context setters & getters */
- //void sqlcipher_codec_ctx_set_error(codec_ctx *, int);
- int sqlcipher_codec_ctx_set_pass(codec_ctx *, const void *, int, int);
- void sqlcipher_codec_get_keyspec(codec_ctx *, void **zKey, int *nKey);
- int sqlcipher_codec_ctx_set_pagesize(codec_ctx *, int);
- int sqlcipher_codec_ctx_get_pagesize(codec_ctx *);
- int sqlcipher_codec_ctx_get_reservesize(codec_ctx *);
- void sqlcipher_set_default_pagesize(int page_size);
- int sqlcipher_get_default_pagesize(void);
- void sqlcipher_set_default_kdf_iter(int iter);
- int sqlcipher_get_default_kdf_iter(void);
- int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *, int, int);
- int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx, int);
- void *sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx);
- int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *, int, int);
- int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *, int);
- int sqlcipher_codec_ctx_set_cipher(codec_ctx *, const char *, int);
- const char *sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx, int for_ctx);
- void *sqlcipher_codec_ctx_get_data(codec_ctx *);
- //void sqlcipher_exportFunc(sqlite3_context *, int, sqlite3_value **);
- void sqlcipher_set_default_use_hmac(int use);
- int sqlcipher_get_default_use_hmac(void);
- void sqlcipher_set_hmac_salt_mask(unsigned char mask);
- unsigned char sqlcipher_get_hmac_salt_mask(void);
- int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use);
- int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx, int for_ctx);
- int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag);
- int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag);
- int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx,
- unsigned int flag,
- int for_ctx);
- const char *sqlcipher_codec_get_cipher_provider(codec_ctx *ctx);
- //int sqlcipher_codec_ctx_migrate(codec_ctx *ctx);
- int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz);
- int sqlcipher_cipher_profile(sqlite3 *db, const char *destination);
- //static void sqlcipher_profile_callback(void *file, const char *sql, sqlite3_uint64 run_time);
- //static int sqlcipher_codec_get_store_pass(codec_ctx *ctx);
- //static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey);
- //static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value);
- int sqlcipher_codec_fips_status(codec_ctx *ctx);
- const char *sqlcipher_codec_get_provider_version(codec_ctx *ctx);
- // sqlite3_file redirector
- typedef struct {
- const struct sqlite3_io_methods *pMethods;
- sqliterk_file *fd;
- const unsigned char *kdf_salt;
- } sqlite3_file_rkredir;
- int sqliterkRead(sqlite3_file *fd, void *data, int iAmt, sqlite3_int64 iOfst)
- {
- sqlite3_file_rkredir *rkos = (sqlite3_file_rkredir *) fd;
- if (rkos->kdf_salt) {
- memcpy(data, rkos->kdf_salt, (iAmt > 16) ? 16 : iAmt);
- return SQLITE_OK;
- } else {
- sqliterk_file *f = rkos->fd;
- size_t size = iAmt;
- return sqliterkOSRead(f, (off_t) iOfst, data, &size);
- }
- }
- int sqliterkCryptoSetCipher(sqliterk_pager *pager,
- sqliterk_file *fd,
- const sqliterk_cipher_conf *conf)
- {
- codec_ctx *codec = NULL;
- int rc;
- if (conf) {
- // Check arguments.
- if (!conf->key || conf->key_len <= 0)
- return SQLITERK_MISUSE;
- // SQLite library must be initialized before calling sqlcipher_activate(),
- // or it will cause a deadlock.
- sqlite3_initialize();
- sqlcipher_activate();
- // XXX: fake BTree structure passed to sqlcipher_codec_ctx_init.
- // Member of such structure is assigned but never used by repair kit.
- int fake_db[8];
- sqlite3_file_rkredir file;
- struct sqlite3_io_methods methods = {0};
- methods.xRead = sqliterkRead;
- file.pMethods = &methods;
- file.fd = fd;
- file.kdf_salt = conf->kdf_salt;
- // Initialize codec context.
- rc = sqlcipher_codec_ctx_init(&codec, fake_db, NULL, &file, conf->key,
- conf->key_len);
- if (rc != SQLITE_OK)
- goto bail_sqlite_errstr;
- // Set cipher.
- if (conf->cipher_name) {
- rc = sqlcipher_codec_ctx_set_cipher(codec, conf->cipher_name,
- CIPHER_READWRITE_CTX);
- if (rc != SQLITE_OK)
- goto bail_sqlite_errstr;
- }
- // Set page size.
- if (conf->page_size > 0) {
- rc = sqlcipher_codec_ctx_set_pagesize(codec, conf->page_size);
- if (rc != SQLITE_OK)
- goto bail_sqlite_errstr;
- }
- // Set HMAC usage.
- if (conf->use_hmac >= 0) {
- rc = sqlcipher_codec_ctx_set_use_hmac(codec, conf->use_hmac);
- if (rc != SQLITE_OK)
- goto bail_sqlite_errstr;
- }
- // Set KDF Iteration.
- if (conf->kdf_iter > 0) {
- rc = sqlcipher_codec_ctx_set_kdf_iter(codec, conf->kdf_iter,
- CIPHER_READWRITE_CTX);
- if (rc != SQLITE_OK)
- goto bail;
- }
- // Update pager page size.
- int page_sz = sqlcipher_codec_ctx_get_pagesize(codec);
- int reserve_sz = sqlcipher_codec_ctx_get_reservesize(codec);
- pager->pagesize = page_sz;
- pager->reservedBytes = reserve_sz;
- }
- if (pager->codec) {
- sqlcipher_codec_ctx_free(&pager->codec);
- sqlcipher_deactivate();
- }
- pager->codec = codec;
- return SQLITERK_OK;
- bail_sqlite_errstr:
- sqliterkOSError(SQLITERK_CANTOPEN,
- "Failed to initialize cipher context: %s",
- sqlite3_errstr(rc));
- rc = SQLITERK_CANTOPEN;
- bail:
- if (codec)
- sqlcipher_codec_ctx_free(&codec);
- sqlcipher_deactivate();
- return rc;
- }
- void sqliterkCryptoFreeCodec(sqliterk_pager *pager)
- {
- if (!pager->codec)
- return;
- sqlcipher_codec_ctx_free(&pager->codec);
- sqlcipher_deactivate();
- }
- int sqliterkCryptoDecode(sqliterk_codec *codec, int pgno, void *data)
- {
- int rc;
- int offset = 0;
- unsigned char *pdata = (unsigned char *) data;
- int page_sz = sqlcipher_codec_ctx_get_pagesize(codec);
- unsigned char *buffer =
- (unsigned char *) sqlcipher_codec_ctx_get_data(codec);
- rc = sqlcipher_codec_key_derive(codec);
- if (rc != SQLITE_OK)
- return rc;
- if (pgno == 1) {
- offset = 16; // FILE_HEADER_SZ
- memcpy(buffer, "SQLite format 3", 16);
- }
- rc = sqlcipher_page_cipher(codec, CIPHER_READ_CTX, pgno, CIPHER_DECRYPT,
- page_sz - offset, pdata + offset,
- buffer + offset);
- if (rc != SQLITE_OK)
- goto bail;
- memcpy(pdata, buffer, page_sz);
- return SQLITERK_OK;
- bail:
- sqliterkOSError(SQLITERK_DAMAGED, "Failed to decode page %d: %s", pgno,
- sqlite3_errstr(rc));
- return rc;
- }
|