/** * Derive an encryption key for a cipher contex key based on the raw password. * * If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill * the key space (i.e 64 hex chars for a 256 bit key) then the key data will be used directly. * * Otherwise, a key data will be derived using PBKDF2 * * returns SQLITE_OK if initialization was successful * returns SQLITE_NOMEM if the key could't be derived (for instance if pass is null or pass_sz is 0) */ static int codec_key_derive(codec_ctx ctx, cipher_ctx c_ctx) { CODEC_TRACE("codec_key_derive: entered c_ctx.pass=%s, c_ctx.pass_sz=%d ctx.iv=%d ctx.iv_sz=%d c_ctx.kdf_iter=%d c_ctx.key_sz=%d\n", c_ctx.pass, c_ctx.pass_sz, c_ctx.iv, c_ctx.iv_sz, c_ctx.key_sz); if (c_ctx.pass != null && c_ctx.pass_sz > 0) { // if pass is not null if ((c_ctx.pass_sz == (c_ctx.key_sz * 2) + 3) && c_ctx.pass.StartsWith("x'", StringComparison.InvariantCultureIgnoreCase)) { int n = c_ctx.pass_sz - 3; /* adjust for leading x' and tailing ' */ string z = c_ctx.pass.Substring(2); // + 2; /* adjust lead offset of x' */ CODEC_TRACE("codec_key_derive: deriving key from hex\n"); c_ctx.key = sqlite3HexToBlob(null, z, n); } else { CODEC_TRACE("codec_key_derive: deriving key using AES256\n"); Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(c_ctx.pass, c_ctx.iv, 2010); c_ctx.key_sz = 32; c_ctx.key = k1.GetBytes(c_ctx.key_sz); } #if NET_2_0 Aes.BlockSize = 0x80; Aes.FeedbackSize = 8; Aes.KeySize = 0x100; Aes.Mode = CipherMode.CBC; #endif c_ctx.encryptor = Aes.CreateEncryptor(c_ctx.key, c_ctx.iv); c_ctx.decryptor = Aes.CreateDecryptor(c_ctx.key, c_ctx.iv); return(SQLITE_OK); } ; return(SQLITE_ERROR); }
/** * Derive an encryption key for a cipher contex key based on the raw password. * * If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill * the key space (i.e 64 hex chars for a 256 bit key) then the key data will be used directly. * * Otherwise, a key data will be derived using PBKDF2 * * returns SQLITE_OK if initialization was successful * returns SQLITE_NOMEM if the key could't be derived (for instance if pass is null or pass_sz is 0) */ static int codec_key_derive(codec_ctx ctx, cipher_ctx c_ctx) { CODEC_TRACE("codec_key_derive: entered c_ctx.pass=%s, c_ctx.pass_sz=%d ctx.iv=%d ctx.iv_sz=%d c_ctx.kdf_iter=%d c_ctx.key_sz=%d\n", c_ctx.pass, c_ctx.pass_sz, c_ctx.iv, c_ctx.iv_sz, c_ctx.key_sz); if (c_ctx.pass != null && c_ctx.pass_sz > 0) { // if pass is not null if ((c_ctx.pass_sz == (c_ctx.key_sz * 2) + 3) && sqlite3StrNICmp(c_ctx.pass, "x'", 2) == 0) { int n = c_ctx.pass_sz - 3; /* adjust for leading x' and tailing ' */ string z = c_ctx.pass.Substring(2); // + 2; /* adjust lead offset of x' */ CODEC_TRACE("codec_key_derive: deriving key from hex\n"); c_ctx.key = sqlite3HexToBlob(null, z, n); } else { CODEC_TRACE("codec_key_derive: deriving key using AES256\n"); Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(c_ctx.pass, c_ctx.iv, 2010); c_ctx.key_sz = 32; c_ctx.key = k1.GetBytes(c_ctx.key_sz); } c_ctx.encryptor = Aes.CreateEncryptor(c_ctx.key, c_ctx.iv); c_ctx.decryptor = Aes.CreateDecryptor(c_ctx.key, c_ctx.iv); return(SQLITE_OK); } ; return(SQLITE_ERROR); }
static void sqlite3FreeCodecArg(ref codec_ctx pCodecArg) { if (pCodecArg == null) { return; } codec_ctx_free(ref pCodecArg); // wipe and free allocated memory for the context }
/** * Free and wipe memory associated with a cipher_ctx, including the allocated * read_ctx and write_ctx. */ static void codec_ctx_free(ref codec_ctx iCtx) { codec_ctx ctx = iCtx; CODEC_TRACE("codec_ctx_free: entered iCtx=%d\n", iCtx); cipher_ctx_free(ref ctx.read_ctx); cipher_ctx_free(ref ctx.write_ctx); iCtx = new codec_ctx();//codec_free(ctx, sizeof(codec_ctx); }
static void sqlite3pager_sqlite3PagerSetCodec( Pager pPager, dxCodec xCodec, dxCodecSizeChng xCodecSizeChng, dxCodecFree xCodecFree, codec_ctx pCodec ) { sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec); }
static int sqlite3CodecAttach(sqlite3 db, int nDb, string zKey, int nKey) { Db pDb = db.aDb[nDb]; CODEC_TRACE("sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, zKey, nKey); //activate_openssl(); if (zKey != null && pDb.pBt != null) { Aes.KeySize = 256; #if !SQLITE_SILVERLIGHT Aes.Padding = PaddingMode.None; #endif codec_ctx ctx; int rc; //Pager pPager = pDb.pBt.pBt.pPager; //sqlite3_file fd; ctx = new codec_ctx();//sqlite3Malloc(sizeof(codec_ctx); //if(ctx == null) return SQLITE_NOMEM; //memset(ctx, 0, sizeof(codec_ctx); /* initialize all pointers and values to 0 */ ctx.pBt = pDb.pBt; /* assign pointer to database btree structure */ if ((rc = cipher_ctx_init(ref ctx.read_ctx)) != SQLITE_OK) { return(rc); } if ((rc = cipher_ctx_init(ref ctx.write_ctx)) != SQLITE_OK) { return(rc); } /* pre-allocate a page buffer of PageSize bytes. This will * be used as a persistent buffer for encryption and decryption * operations to avoid overhead of multiple memory allocations*/ ctx.buffer = sqlite3MemMalloc(sqlite3BtreeGetPageSize(ctx.pBt));//sqlite3Malloc(sqlite3BtreeGetPageSize(ctx.pBt); //if(ctx.buffer == null) return SQLITE_NOMEM; /* allocate space for salt data. Then read the first 16 bytes header as the salt for the key derivation */ ctx.read_ctx.iv_sz = FILE_HEADER_SZ; ctx.read_ctx.iv = new byte[ctx.read_ctx.iv_sz];//sqlite3Malloc( ctx.iv_sz ); Buffer.BlockCopy(Encoding.UTF8.GetBytes(SQLITE_FILE_HEADER), 0, ctx.read_ctx.iv, 0, FILE_HEADER_SZ); sqlite3pager_sqlite3PagerSetCodec(sqlite3BtreePager(pDb.pBt), sqlite3Codec, null, sqlite3FreeCodecArg, ctx); codec_set_cipher_name(db, nDb, CIPHER, 0); codec_set_pass_key(db, nDb, zKey, nKey, 0); cipher_ctx_copy(ctx.write_ctx, ctx.read_ctx); //sqlite3BtreeSetPageSize( ctx.pBt, sqlite3BtreeGetPageSize( ctx.pBt ), MAX_IV_LENGTH, 0 ); } return(SQLITE_OK); }
public codec_ctx Copy() { codec_ctx c = new codec_ctx(); c.mode_rekey = mode_rekey; c.buffer = sqlite3MemMalloc(buffer.Length); c.pBt = pBt; if (read_ctx != null) { c.read_ctx = read_ctx.Copy(); } if (write_ctx != null) { c.write_ctx = write_ctx.Copy(); } return(c); }
static void sqlite3CodecGetKey(sqlite3 db, int nDb, out string zKey, out int nKey) { Db pDb = db.aDb[nDb]; CODEC_TRACE("sqlite3CodecGetKey: entered db=%d, nDb=%d\n", db, nDb); if (pDb.pBt != null) { codec_ctx ctx = null; sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx); if (ctx != null) { /* if the codec has an attached codec_context user the raw key data */ zKey = ctx.read_ctx.pass; nKey = ctx.read_ctx.pass_sz; return; } } zKey = null; nKey = 0; }
static int codec_set_pass_key(sqlite3 db, int nDb, string zKey, int nKey, int for_ctx) { Db pDb = db.aDb[nDb]; CODEC_TRACE("codec_set_pass_key: entered db=%d nDb=%d cipher_name=%s nKey=%d for_ctx=%d\n", db, nDb, zKey, nKey, for_ctx); if (pDb.pBt != null) { codec_ctx ctx = null; cipher_ctx c_ctx; sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx); c_ctx = for_ctx != 0 ? ctx.write_ctx : ctx.read_ctx; cipher_ctx_set_pass(c_ctx, zKey, nKey); c_ctx.derive_key = true; if (for_ctx == 2) { cipher_ctx_copy(for_ctx != 0 ? ctx.read_ctx : ctx.write_ctx, c_ctx); } return(SQLITE_OK); } return(SQLITE_ERROR); }
/** * * when for_ctx == 0 then it will change for read * when for_ctx == 1 then it will change for write * when for_ctx == 2 then it will change for both */ private static int codec_set_cipher_name(sqlite3 db, int nDb, string cipher_name, int for_ctx) { var pDb = db.aDb[nDb]; CODEC_TRACE("codec_set_cipher_name: entered db=%d nDb=%d cipher_name=%s for_ctx=%d\n", db, nDb, cipher_name, for_ctx); if (pDb.pBt != null) { codec_ctx ctx = null; cipher_ctx c_ctx; sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx); c_ctx = for_ctx != 0 ? ctx.write_ctx : ctx.read_ctx; c_ctx.derive_key = true; if (for_ctx == 2) { cipher_ctx_copy(for_ctx != 0 ? ctx.read_ctx : ctx.write_ctx, c_ctx); } return(SQLITE_OK); } return(SQLITE_ERROR); }
/* sqlite3_rekey ** Given a database, this will reencrypt the database using a new key. ** There are two possible modes of operation. The first is rekeying ** an existing database that was not previously encrypted. The second ** is to change the key on an existing database. ** ** The proposed logic for this function follows: ** 1. Determine if there is already a key present ** 2. If there is NOT already a key present, create one and attach a codec (key would be null) ** 3. Initialize a ctx.rekey parameter of the codec ** ** Note: this will require modifications to the sqlite3Codec to support rekey ** */ public static int sqlite3_rekey(sqlite3 db, string pKey, int nKey) { CODEC_TRACE("sqlite3_rekey: entered db=%d pKey=%s, nKey=%d\n", db, pKey, nKey); //activate_openssl(); if (db != null && pKey != null) { Db pDb = db.aDb[0]; CODEC_TRACE("sqlite3_rekey: database pDb=%d\n", pDb); if (pDb.pBt != null) { codec_ctx ctx = null; int rc; Pgno page_count = 0; Pgno pgno; PgHdr page = null; Pager pPager = pDb.pBt.pBt.pPager; sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx); if (ctx == null) { CODEC_TRACE("sqlite3_rekey: no codec attached to db, attaching now\n"); /* there was no codec attached to this database,so attach one now with a null password */ sqlite3CodecAttach(db, 0, pKey, nKey); sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx); /* prepare this setup as if it had already been initialized */ Buffer.BlockCopy(Encoding.UTF8.GetBytes(SQLITE_FILE_HEADER), 0, ctx.read_ctx.iv, 0, FILE_HEADER_SZ); ctx.read_ctx.key_sz = ctx.read_ctx.iv_sz = ctx.read_ctx.pass_sz = 0; } //if ( ctx.read_ctx.iv_sz != ctx.write_ctx.iv_sz ) //{ // string error = ""; // CODEC_TRACE( "sqlite3_rekey: updating page size for iv_sz change from %d to %d\n", ctx.read_ctx.iv_sz, ctx.write_ctx.iv_sz ); // db.nextPagesize = sqlite3BtreeGetPageSize( pDb.pBt ); // pDb.pBt.pBt.pageSizeFixed = false; /* required for sqlite3BtreeSetPageSize to modify pagesize setting */ // sqlite3BtreeSetPageSize( pDb.pBt, db.nextPagesize, MAX_IV_LENGTH, 0 ); // sqlite3RunVacuum( ref error, db ); //} codec_set_pass_key(db, 0, pKey, nKey, 1); ctx.mode_rekey = 1; /* do stuff here to rewrite the database ** 1. Create a transaction on the database ** 2. Iterate through each page, reading it and then writing it. ** 3. If that goes ok then commit and put ctx.rekey into ctx.key ** note: don't deallocate rekey since it may be used in a subsequent iteration */ rc = sqlite3BtreeBeginTrans(pDb.pBt, 1); /* begin write transaction */ sqlite3PagerPagecount(pPager, out page_count); for (pgno = 1; rc == SQLITE_OK && pgno <= page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */ if (0 == sqlite3pager_is_mj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */ rc = sqlite3PagerGet(pPager, pgno, ref page); if (rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */ rc = sqlite3PagerWrite(page); //printf("sqlite3PagerWrite(%d)\n", pgno); if (rc == SQLITE_OK) { sqlite3PagerUnref(page); } } } } /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */ if (rc == SQLITE_OK) { CODEC_TRACE("sqlite3_rekey: committing\n"); db.nextPagesize = sqlite3BtreeGetPageSize(pDb.pBt); rc = sqlite3BtreeCommit(pDb.pBt); if (ctx != null) { cipher_ctx_copy(ctx.read_ctx, ctx.write_ctx); } } else { CODEC_TRACE("sqlite3_rekey: rollback\n"); sqlite3BtreeRollback(pDb.pBt); } ctx.mode_rekey = 0; } return(SQLITE_OK); } return(SQLITE_ERROR); }
/* ** Set or retrieve the codec for this pager */ static void sqlite3PagerSetCodec( Pager pPager, dxCodec xCodec, //void *(*xCodec)(void*,void*,Pgno,int), dxCodecSizeChng xCodecSizeChng, //void (*xCodecSizeChng)(void*,int,int), dxCodecFree xCodecFree, //void (*xCodecFree)(void*), codec_ctx pCodec ) { if ( pPager.xCodecFree != null ) pPager.xCodecFree( ref pPager.pCodec ); pPager.xCodec = (pPager.memDb!=0) ? null : xCodec; pPager.xCodecSizeChng = xCodecSizeChng; pPager.xCodecFree = xCodecFree; pPager.pCodec = pCodec; pagerReportSize( pPager ); }
public codec_ctx Copy( ) { codec_ctx c = new codec_ctx(); c.mode_rekey = mode_rekey; c.buffer = sqlite3MemMalloc( buffer.Length ); c.pBt = pBt; if ( read_ctx != null ) c.read_ctx = read_ctx.Copy(); if ( write_ctx != null ) c.write_ctx = write_ctx.Copy(); return c; }
/* * sqlite3Codec can be called in multiple modes. * encrypt mode - expected to return a pointer to the * encrypted data without altering pData. * decrypt mode - expected to return a pointer to pData, with * the data decrypted in the input buffer */ static byte[] sqlite3Codec(codec_ctx iCtx, byte[] data, Pgno pgno, int mode) { codec_ctx ctx = (codec_ctx)iCtx; int pg_sz = sqlite3BtreeGetPageSize(ctx.pBt); int offset = 0; byte[] pData = data; CODEC_TRACE("sqlite3Codec: entered pgno=%d, mode=%d, ctx.mode_rekey=%d, pg_sz=%d\n", pgno, mode, ctx.mode_rekey, pg_sz); /* derive key on first use if necessary */ if (ctx.read_ctx.derive_key) { codec_key_derive(ctx, ctx.read_ctx); ctx.read_ctx.derive_key = false; } if (ctx.write_ctx.derive_key) { if (cipher_ctx_cmp(ctx.write_ctx, ctx.read_ctx) == 0) { cipher_ctx_copy(ctx.write_ctx, ctx.read_ctx); // the relevant parameters are the same, just copy read key } else { codec_key_derive(ctx, ctx.write_ctx); ctx.write_ctx.derive_key = false; } } CODEC_TRACE("sqlite3Codec: switch mode=%d offset=%d\n", mode, offset); if (ctx.buffer.Length != pg_sz) { ctx.buffer = sqlite3MemMalloc(pg_sz); } switch (mode) { case SQLITE_DECRYPT: codec_cipher(ctx.read_ctx, pgno, CIPHER_DECRYPT, pg_sz, pData, ctx.buffer); if (pgno == 1) { Buffer.BlockCopy(Encoding.UTF8.GetBytes(SQLITE_FILE_HEADER), 0, ctx.buffer, 0, FILE_HEADER_SZ); // memcpy( ctx.buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ ); /* copy file header to the first 16 bytes of the page */ } Buffer.BlockCopy(ctx.buffer, 0, pData, 0, pg_sz); //memcpy( pData, ctx.buffer, pg_sz ); /* copy buffer data back to pData and return */ return(pData); case SQLITE_ENCRYPT_WRITE_CTX: /* encrypt */ if (pgno == 1) { Buffer.BlockCopy(ctx.write_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ);//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */ } codec_cipher(ctx.write_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer); return(ctx.buffer); /* return persistent buffer data, pData remains intact */ case SQLITE_ENCRYPT_READ_CTX: if (pgno == 1) { Buffer.BlockCopy(ctx.read_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ);//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */ } codec_cipher(ctx.read_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer); return(ctx.buffer); /* return persistent buffer data, pData remains intact */ default: return(pData); } }
static void sqlite3pager_sqlite3PagerSetCodec( Pager pPager, dxCodec xCodec, dxCodecSizeChng xCodecSizeChng, dxCodecFree xCodecFree, codec_ctx pCodec ) { sqlite3PagerSetCodec( pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec ); }
/* BEGIN CRYPTO */ static void sqlite3pager_get_codec( Pager pPager, ref codec_ctx ctx ) { ctx = pPager.pCodec; }
/* BEGIN CRYPTO */ static void sqlite3pager_get_codec(Pager pPager, ref codec_ctx ctx) { ctx = pPager.pCodec; }
/** * Free and wipe memory associated with a cipher_ctx, including the allocated * read_ctx and write_ctx. */ static void codec_ctx_free( ref codec_ctx iCtx ) { codec_ctx ctx = iCtx; CODEC_TRACE( "codec_ctx_free: entered iCtx=%d\n", iCtx ); cipher_ctx_free( ref ctx.read_ctx ); cipher_ctx_free( ref ctx.write_ctx ); iCtx = new codec_ctx();//codec_free(ctx, sizeof(codec_ctx); }
/** * Derive an encryption key for a cipher contex key based on the raw password. * * If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill * the key space (i.e 64 hex chars for a 256 bit key) then the key data will be used directly. * * Otherwise, a key data will be derived using PBKDF2 * * returns SQLITE_OK if initialization was successful * returns SQLITE_NOMEM if the key could't be derived (for instance if pass is null or pass_sz is 0) */ static int codec_key_derive( codec_ctx ctx, cipher_ctx c_ctx ) { CODEC_TRACE( "codec_key_derive: entered c_ctx.pass=%s, c_ctx.pass_sz=%d ctx.iv=%d ctx.iv_sz=%d c_ctx.kdf_iter=%d c_ctx.key_sz=%d\n", c_ctx.pass, c_ctx.pass_sz, c_ctx.iv, c_ctx.iv_sz, c_ctx.key_sz ); if ( c_ctx.pass != null && c_ctx.pass_sz > 0 ) { // if pass is not null if ( ( c_ctx.pass_sz == ( c_ctx.key_sz * 2 ) + 3 ) && sqlite3StrNICmp( c_ctx.pass, "x'", 2 ) == 0 ) { int n = c_ctx.pass_sz - 3; /* adjust for leading x' and tailing ' */ string z = c_ctx.pass.Substring( 2 );// + 2; /* adjust lead offset of x' */ CODEC_TRACE( "codec_key_derive: deriving key from hex\n" ); c_ctx.key = sqlite3HexToBlob( null, z, n); } else { CODEC_TRACE( "codec_key_derive: deriving key using AES256\n" ); Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes( c_ctx.pass, c_ctx.iv, 2010 ); c_ctx.key_sz = 32; c_ctx.key = k1.GetBytes( c_ctx.key_sz ); } c_ctx.encryptor = Aes.CreateEncryptor( c_ctx.key, c_ctx.iv ); c_ctx.decryptor = Aes.CreateDecryptor( c_ctx.key, c_ctx.iv ); return SQLITE_OK; }; return SQLITE_ERROR; }
/* * sqlite3Codec can be called in multiple modes. * encrypt mode - expected to return a pointer to the * encrypted data without altering pData. * decrypt mode - expected to return a pointer to pData, with * the data decrypted in the input buffer */ static byte[] sqlite3Codec(codec_ctx iCtx, byte[] data, Pgno pgno, int mode) { codec_ctx ctx = (codec_ctx)iCtx; int pg_sz = sqlite3BtreeGetPageSize(ctx.pBt); int offset = 0; byte[] pData = data; CODEC_TRACE("sqlite3Codec: entered pgno=%d, mode=%d, ctx.mode_rekey=%d, pg_sz=%d\n", pgno, mode, ctx.mode_rekey, pg_sz); /* derive key on first use if necessary */ if (ctx.read_ctx.derive_key) { codec_key_derive(ctx, ctx.read_ctx); ctx.read_ctx.derive_key = false; } if (ctx.write_ctx.derive_key) { if (cipher_ctx_cmp(ctx.write_ctx, ctx.read_ctx) == 0) { cipher_ctx_copy(ctx.write_ctx, ctx.read_ctx); // the relevant parameters are the same, just copy read key } else { codec_key_derive(ctx, ctx.write_ctx); ctx.write_ctx.derive_key = false; } } // bug from csharp project port // fix from original: https://github.com/sqlcipher/sqlcipher/blob/master/src/crypto.c // original // if(pgno == 1) offset = FILE_HEADER_SZ; /* adjust starting pointers in data page for header offset on first page*/ CODEC_TRACE("sqlite3Codec: switch mode=%d offset=%d\n", mode, offset); if (ctx.buffer.Length != pg_sz) { ctx.buffer = sqlite3MemMalloc(pg_sz); } switch (mode) { case SQLITE_DECRYPT: // original // if(pgno == 1) memcpy(buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ); /* copy file header to the first 16 bytes of the page */ // rc = sqlcipher_page_cipher(ctx, CIPHER_READ_CTX, pgno, CIPHER_DECRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset); // if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc); // memcpy(pData, buffer, page_sz); /* copy buffer data back to pData and return */ // return pData; // c-sharp project // codec_cipher( ctx.read_ctx, pgno, CIPHER_DECRYPT, pg_sz, pData, ctx.buffer ); // if ( pgno == 1 ) // Buffer.BlockCopy( Encoding.UTF8.GetBytes( SQLITE_FILE_HEADER ), 0, ctx.buffer, 0, FILE_HEADER_SZ );// memcpy( ctx.buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ ); /* copy file header to the first 16 bytes of the page */ // Buffer.BlockCopy( ctx.buffer, 0, pData, 0, pg_sz ); //memcpy( pData, ctx.buffer, pg_sz ); /* copy buffer data back to pData and return */ // return pData; // my fix: if (pgno == 1) { byte[] hdr = Encoding.UTF8.GetBytes(SQLITE_FILE_HEADER); Buffer.BlockCopy(hdr, 0, ctx.buffer, 0, FILE_HEADER_SZ);// memcpy( ctx.buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ ); /* copy file header to the first 16 bytes of the page */ byte[] tmpOut = new byte[pg_sz - FILE_HEADER_SZ]; byte[] tmpData = new byte[pg_sz - FILE_HEADER_SZ]; Buffer.BlockCopy(pData, FILE_HEADER_SZ, tmpData, 0, pg_sz - FILE_HEADER_SZ); codec_cipher(ctx.read_ctx, pgno, CIPHER_DECRYPT, pg_sz - FILE_HEADER_SZ, tmpData, tmpOut); Buffer.BlockCopy(tmpOut, 0, ctx.buffer, FILE_HEADER_SZ, pg_sz - FILE_HEADER_SZ); Buffer.BlockCopy(ctx.buffer, 0, pData, 0, pg_sz); } else { codec_cipher(ctx.read_ctx, pgno, CIPHER_DECRYPT, pg_sz, pData, ctx.buffer); Buffer.BlockCopy(ctx.buffer, 0, pData, 0, pg_sz); } return(pData); case SQLITE_ENCRYPT_WRITE_CTX: /* encrypt */ // original // if(pgno == 1) memcpy(buffer, kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ // rc = sqlcipher_page_cipher(ctx, CIPHER_WRITE_CTX, pgno, CIPHER_ENCRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset); // if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc); // return buffer; /* return persistent buffer data, pData remains intact */ // c-sharp project // if ( pgno == 1 ) // Buffer.BlockCopy( ctx.write_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ );//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */ // codec_cipher( ctx.write_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer ); // return ctx.buffer; /* return persistent buffer data, pData remains intact */ // my fix if (pgno == 1) { Buffer.BlockCopy(ctx.write_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ);//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */ byte[] tmpOut = new byte[pg_sz - FILE_HEADER_SZ]; byte[] tmpData = new byte[pg_sz - FILE_HEADER_SZ]; Buffer.BlockCopy(pData, FILE_HEADER_SZ, tmpData, 0, pg_sz - FILE_HEADER_SZ); codec_cipher(ctx.write_ctx, pgno, CIPHER_ENCRYPT, pg_sz - FILE_HEADER_SZ, tmpData, tmpOut); Buffer.BlockCopy(tmpOut, 0, ctx.buffer, FILE_HEADER_SZ, pg_sz - FILE_HEADER_SZ); } else { codec_cipher(ctx.write_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer); } return(ctx.buffer); /* return persistent buffer data, pData remains intact */ case SQLITE_ENCRYPT_READ_CTX: // original // if(pgno == 1) memcpy(buffer, kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ // rc = sqlcipher_page_cipher(ctx, CIPHER_READ_CTX, pgno, CIPHER_ENCRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset); // if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc); // return buffer; /* return persistent buffer data, pData remains intact */ // c-sharp project // if ( pgno == 1 ) // Buffer.BlockCopy( ctx.read_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ );//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */ // codec_cipher( ctx.read_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer ); // return ctx.buffer; /* return persistent buffer data, pData remains intact */ // my fix if (pgno == 1) { Buffer.BlockCopy(ctx.read_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ);//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */ byte[] tmpOut = new byte[pg_sz - FILE_HEADER_SZ]; byte[] tmpData = new byte[pg_sz - FILE_HEADER_SZ]; Buffer.BlockCopy(pData, FILE_HEADER_SZ, tmpData, 0, pg_sz - FILE_HEADER_SZ); codec_cipher(ctx.read_ctx, pgno, CIPHER_ENCRYPT, pg_sz - FILE_HEADER_SZ, tmpData, tmpOut); Buffer.BlockCopy(tmpOut, 0, ctx.buffer, FILE_HEADER_SZ, pg_sz - FILE_HEADER_SZ); } else { codec_cipher(ctx.read_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer); } return(ctx.buffer); /* return persistent buffer data, pData remains intact */ default: return(pData); } }
static void sqlite3FreeCodecArg( ref codec_ctx pCodecArg ) { if ( pCodecArg == null ) return; codec_ctx_free( ref pCodecArg ); // wipe and free allocated memory for the context }
static int sqlite3CodecAttach( sqlite3 db, int nDb, string zKey, int nKey ) { Db pDb = db.aDb[nDb]; CODEC_TRACE( "sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, zKey, nKey ); //activate_openssl(); if ( zKey != null && pDb.pBt != null ) { Aes.KeySize = 256; #if !SQLITE_SILVERLIGHT Aes.Padding = PaddingMode.None; #endif codec_ctx ctx; int rc; Pager pPager = pDb.pBt.pBt.pPager; sqlite3_file fd; ctx = new codec_ctx();//sqlite3Malloc(sizeof(codec_ctx); //if(ctx == null) return SQLITE_NOMEM; //memset(ctx, 0, sizeof(codec_ctx); /* initialize all pointers and values to 0 */ ctx.pBt = pDb.pBt; /* assign pointer to database btree structure */ if ( ( rc = cipher_ctx_init( ref ctx.read_ctx ) ) != SQLITE_OK ) return rc; if ( ( rc = cipher_ctx_init( ref ctx.write_ctx ) ) != SQLITE_OK ) return rc; /* pre-allocate a page buffer of PageSize bytes. This will be used as a persistent buffer for encryption and decryption operations to avoid overhead of multiple memory allocations*/ ctx.buffer = sqlite3MemMalloc(sqlite3BtreeGetPageSize( ctx.pBt ));//sqlite3Malloc(sqlite3BtreeGetPageSize(ctx.pBt); //if(ctx.buffer == null) return SQLITE_NOMEM; /* allocate space for salt data. Then read the first 16 bytes header as the salt for the key derivation */ ctx.read_ctx.iv_sz = FILE_HEADER_SZ; ctx.read_ctx.iv = new byte[ctx.read_ctx.iv_sz];//sqlite3Malloc( ctx.iv_sz ); Buffer.BlockCopy( Encoding.UTF8.GetBytes( SQLITE_FILE_HEADER ), 0, ctx.read_ctx.iv, 0, FILE_HEADER_SZ ); sqlite3pager_sqlite3PagerSetCodec( sqlite3BtreePager( pDb.pBt ), sqlite3Codec, null, sqlite3FreeCodecArg, ctx ); codec_set_cipher_name( db, nDb, CIPHER, 0 ); codec_set_pass_key( db, nDb, zKey, nKey, 0 ); cipher_ctx_copy( ctx.write_ctx, ctx.read_ctx ); //sqlite3BtreeSetPageSize( ctx.pBt, sqlite3BtreeGetPageSize( ctx.pBt ), MAX_IV_LENGTH, 0 ); } return SQLITE_OK; }
/* * sqlite3Codec can be called in multiple modes. * encrypt mode - expected to return a pointer to the * encrypted data without altering pData. * decrypt mode - expected to return a pointer to pData, with * the data decrypted in the input buffer */ static byte[] sqlite3Codec( codec_ctx iCtx, byte[] data, Pgno pgno, int mode ) { codec_ctx ctx = (codec_ctx)iCtx; int pg_sz = sqlite3BtreeGetPageSize( ctx.pBt ); int offset = 0; byte[] pData = data; CODEC_TRACE( "sqlite3Codec: entered pgno=%d, mode=%d, ctx.mode_rekey=%d, pg_sz=%d\n", pgno, mode, ctx.mode_rekey, pg_sz ); /* derive key on first use if necessary */ if ( ctx.read_ctx.derive_key ) { codec_key_derive( ctx, ctx.read_ctx ); ctx.read_ctx.derive_key = false; } if ( ctx.write_ctx.derive_key ) { if ( cipher_ctx_cmp( ctx.write_ctx, ctx.read_ctx ) == 0 ) { cipher_ctx_copy( ctx.write_ctx, ctx.read_ctx ); // the relevant parameters are the same, just copy read key } else { codec_key_derive( ctx, ctx.write_ctx ); ctx.write_ctx.derive_key = false; } } CODEC_TRACE( "sqlite3Codec: switch mode=%d offset=%d\n", mode, offset ); if ( ctx.buffer.Length != pg_sz ) ctx.buffer = sqlite3MemMalloc(pg_sz); switch ( mode ) { case SQLITE_DECRYPT: codec_cipher( ctx.read_ctx, pgno, CIPHER_DECRYPT, pg_sz, pData, ctx.buffer); if ( pgno == 1 ) Buffer.BlockCopy( Encoding.UTF8.GetBytes( SQLITE_FILE_HEADER ), 0, ctx.buffer, 0, FILE_HEADER_SZ );// memcpy( ctx.buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ ); /* copy file header to the first 16 bytes of the page */ Buffer.BlockCopy( ctx.buffer, 0, pData, 0, pg_sz ); //memcpy( pData, ctx.buffer, pg_sz ); /* copy buffer data back to pData and return */ return pData; case SQLITE_ENCRYPT_WRITE_CTX: /* encrypt */ if ( pgno == 1 ) Buffer.BlockCopy( ctx.write_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ );//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */ codec_cipher( ctx.write_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer); return ctx.buffer; /* return persistent buffer data, pData remains intact */ case SQLITE_ENCRYPT_READ_CTX: if ( pgno == 1 ) Buffer.BlockCopy( ctx.read_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ );//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */ codec_cipher( ctx.read_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer); return ctx.buffer; /* return persistent buffer data, pData remains intact */ default: return pData; } }