예제 #1
0
        /*
         * ctx - codec context
         * pgno - page number in database
         * size - size in bytes of input and output buffers
         * mode - 1 to encrypt, 0 to decrypt
         * in - pointer to input bytes
         * out - pouter to output bytes
         */
        static int codec_cipher(cipher_ctx ctx, Pgno pgno, int mode, int size, byte[] bIn, byte[] bOut)
        {
            int iv;
            int tmp_csz, csz;

            CODEC_TRACE("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size);

            /* just copy raw data from in to out when key size is 0
             * i.e. during a rekey of a plaintext database */
            if (ctx.key_sz == 0)
            {
                Array.Copy(bIn, bOut, bIn.Length);  //memcpy(out, in, size);
                return(SQLITE_OK);
            }

            MemoryStream dataStream = new MemoryStream();
            CryptoStream encryptionStream;

            if (mode == CIPHER_ENCRYPT)
            {
                encryptionStream = new CryptoStream(dataStream, ctx.encryptor, CryptoStreamMode.Write);
            }
            else
            {
                encryptionStream = new CryptoStream(dataStream, ctx.decryptor, CryptoStreamMode.Write);
            }
            encryptionStream.Write(bIn, 0, size);
            encryptionStream.FlushFinalBlock();
            dataStream.Position = 0;

            dataStream.Read(bOut, 0, (int)dataStream.Length);
            encryptionStream.Close();
            dataStream.Close();



            return(SQLITE_OK);
        }
예제 #2
0
        /* 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
        **
        */
        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);
        }
예제 #3
0
        /*
         * 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);
            }
        }
예제 #4
0
 static int sqlite3pager_is_mj_pgno(Pager pPager, Pgno pgno)
 {
     return((PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0);
 }