wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Diagnostics;
3 using System.Text;
4  
5 using u8 = System.Byte;
6 using u16 = System.UInt16;
7 using Pgno = System.UInt32;
8  
9 namespace Community.CsharpSqlite
10 {
11 using sqlite3_int64 = System.Int64;
12 using sqlite3_stmt = Sqlite3.Vdbe;
13 using System.Security.Cryptography;
14 using System.IO;
15  
16 public partial class Sqlite3
17 {
18 /*
19 *************************************************************************
20 ** Included in SQLite3 port to C#-SQLite; 2010 Noah B Hart, Diego Torres
21 ** C#-SQLite is an independent reimplementation of the SQLite software library
22 **
23 *************************************************************************
24 */
25  
26 /*
27 ** SQLCipher
28 ** crypto.c developed by Stephen Lombardo (Zetetic LLC)
29 ** sjlombardo at zetetic dot net
30 ** http://zetetic.net
31 **
32 ** Copyright (c) 2009, ZETETIC LLC
33 ** All rights reserved.
34 **
35 ** Redistribution and use in source and binary forms, with or without
36 ** modification, are permitted provided that the following conditions are met:
37 ** * Redistributions of source code must retain the above copyright
38 ** notice, this list of conditions and the following disclaimer.
39 ** * Redistributions in binary form must reproduce the above copyright
40 ** notice, this list of conditions and the following disclaimer in the
41 ** documentation and/or other materials provided with the distribution.
42 ** * Neither the name of the ZETETIC LLC nor the
43 ** names of its contributors may be used to endorse or promote products
44 ** derived from this software without specific prior written permission.
45 **
46 ** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
47 ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
48 ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
49 ** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
50 ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
51 ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52 ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
53 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 **
57 */
58 /* BEGIN CRYPTO */
59 #if SQLITE_HAS_CODEC
60  
61 //#include <assert.h>
62 //#include <openssl/evp.h>
63 //#include <openssl/rand.h>
64 //#include <openssl/hmac.h>
65 //#include "sqliteInt.h"
66 //#include "btreeInt.h"
67 //#include "crypto.h"
68  
69 #if CODEC_DEBUG || TRACE
70 //#define CODEC_TRACE(X) {printf X;fflush(stdout);}
71 static void CODEC_TRACE( string T, params object[] ap ) { if ( sqlite3PagerTrace )sqlite3DebugPrintf( T, ap ); }
72 #else
73 //#define CODEC_TRACE(X)
74 static void CODEC_TRACE( string T, params object[] ap )
75 {
76 }
77 #endif
78  
79 //void sqlite3FreeCodecArg(void *pCodecArg);
80  
81 public class cipher_ctx
82 {//typedef struct {
83 public string pass;
84 public int pass_sz;
85 public bool derive_key;
86 public byte[] key;
87 public int key_sz;
88 public byte[] iv;
89 public int iv_sz;
90 public ICryptoTransform encryptor;
91 public ICryptoTransform decryptor;
92  
93 public cipher_ctx Copy()
94 {
95 cipher_ctx c = new cipher_ctx();
96 c.derive_key = derive_key;
97 c.pass = pass;
98 c.pass_sz = pass_sz;
99 if ( key != null )
100 {
101 c.key = new byte[key.Length];
102 key.CopyTo( c.key, 0 );
103 }
104 c.key_sz = key_sz;
105 if ( iv != null )
106 {
107 c.iv = new byte[iv.Length];
108 iv.CopyTo( c.iv, 0 );
109 }
110 c.iv_sz = iv_sz;
111 c.encryptor = encryptor;
112 c.decryptor = decryptor;
113 return c;
114 }
115  
116 public void CopyTo( cipher_ctx ct )
117 {
118 ct.derive_key = derive_key;
119 ct.pass = pass;
120 ct.pass_sz = pass_sz;
121 if ( key != null )
122 {
123 ct.key = new byte[key.Length];
124 key.CopyTo( ct.key, 0 );
125 }
126 ct.key_sz = key_sz;
127 if ( iv != null )
128 {
129 ct.iv = new byte[iv.Length];
130 iv.CopyTo( ct.iv, 0 );
131 }
132 ct.iv_sz = iv_sz;
133 ct.encryptor = encryptor;
134 ct.decryptor = decryptor;
135 }
136 }
137  
138 public class codec_ctx
139 {//typedef struct {
140 public int mode_rekey;
141 public byte[] buffer;
142 public Btree pBt;
143 public cipher_ctx read_ctx;
144 public cipher_ctx write_ctx;
145  
146 public codec_ctx Copy()
147 {
148 codec_ctx c = new codec_ctx();
149 c.mode_rekey = mode_rekey;
150 c.buffer = sqlite3MemMalloc( buffer.Length );
151 c.pBt = pBt;
152 if ( read_ctx != null )
153 c.read_ctx = read_ctx.Copy();
154 if ( write_ctx != null )
155 c.write_ctx = write_ctx.Copy();
156 return c;
157 }
158 }
159  
160 const int FILE_HEADER_SZ = 16; //#define FILE_HEADER_SZ 16
161 const string CIPHER = "aes-256-cbc"; //#define CIPHER "aes-256-cbc"
162 const int CIPHER_DECRYPT = 0; //#define CIPHER_DECRYPT 0
163 const int CIPHER_ENCRYPT = 1; //#define CIPHER_ENCRYPT 1
164  
165 #if NET_2_0
166 static RijndaelManaged Aes = new RijndaelManaged();
167 #else
168 static AesManaged Aes = new AesManaged();
169 #endif
170  
171 /* BEGIN CRYPTO */
172 static void sqlite3pager_get_codec( Pager pPager, ref codec_ctx ctx )
173 {
174 ctx = pPager.pCodec;
175 }
176  
177 static int sqlite3pager_is_mj_pgno( Pager pPager, Pgno pgno )
178 {
179 return ( PAGER_MJ_PGNO( pPager ) == pgno ) ? 1 : 0;
180 }
181  
182 static sqlite3_file sqlite3Pager_get_fd( Pager pPager )
183 {
184 return ( isOpen( pPager.fd ) ) ? pPager.fd : null;
185 }
186  
187 static void sqlite3pager_sqlite3PagerSetCodec(
188 Pager pPager,
189 dxCodec xCodec,
190 dxCodecSizeChng xCodecSizeChng,
191 dxCodecFree xCodecFree,
192 codec_ctx pCodec
193 )
194 {
195 sqlite3PagerSetCodec( pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec );
196 }
197 /* END CRYPTO */
198  
199 //static void activate_openssl() {
200 // if(EVP_get_cipherbyname(CIPHER) == null) {
201 // OpenSSL_add_all_algorithms();
202 // }
203 //}
204  
205 /**
206 * Free and wipe memory
207 * If ptr is not null memory will be freed.
208 * If sz is greater than zero, the memory will be overwritten with zero before it is freed
209 */
210 static void codec_free( ref byte[] ptr, int sz )
211 {
212 if ( ptr != null )
213 {
214 if ( sz > 0 )
215 Array.Clear( ptr, 0, sz );//memset( ptr, 0, sz );
216 sqlite3_free( ref ptr );
217 }
218 }
219  
220 /**
221 * Set the raw password / key data for a cipher context
222 *
223 * returns SQLITE_OK if assignment was successfull
224 * returns SQLITE_NOMEM if an error occured allocating memory
225 * returns SQLITE_ERROR if the key couldn't be set because the pass was null or size was zero
226 */
227 static int cipher_ctx_set_pass( cipher_ctx ctx, string zKey, int nKey )
228 {
229 ctx.pass = null; // codec_free( ctx.pass, ctx.pass_sz );
230 ctx.pass_sz = nKey;
231 if ( !string.IsNullOrEmpty( zKey ) && nKey > 0 )
232 {
233 //ctx.pass = sqlite3Malloc(nKey);
234 //if(ctx.pass == null) return SQLITE_NOMEM;
235 ctx.pass = zKey;//memcpy(ctx.pass, zKey, nKey);
236 return SQLITE_OK;
237 }
238 return SQLITE_ERROR;
239 }
240  
241 /**
242 * Initialize a new cipher_ctx struct. This function will allocate memory
243 * for the cipher context and for the key
244 *
245 * returns SQLITE_OK if initialization was successful
246 * returns SQLITE_NOMEM if an error occured allocating memory
247 */
248 static int cipher_ctx_init( ref cipher_ctx iCtx )
249 {
250 iCtx = new cipher_ctx();
251 //iCtx = sqlite3Malloc( sizeof( cipher_ctx ) );
252 //ctx = *iCtx;
253 //if ( ctx == null ) return SQLITE_NOMEM;
254 //memset( ctx, 0, sizeof( cipher_ctx ) );
255 //ctx.key = sqlite3Malloc( EVP_MAX_KEY_LENGTH );
256 //if ( ctx.key == null ) return SQLITE_NOMEM;
257 return SQLITE_OK;
258 }
259  
260 /**
261 * free and wipe memory associated with a cipher_ctx
262 */
263 static void cipher_ctx_free( ref cipher_ctx ictx )
264 {
265 cipher_ctx ctx = ictx;
266 CODEC_TRACE( "cipher_ctx_free: entered ictx=%d\n", ictx );
267 ctx.pass = null;//codec_free(ctx.pass, ctx.pass_sz);
268 if ( ctx.key != null )
269 Array.Clear( ctx.key, 0, ctx.key.Length );//codec_free(ctx.key, ctx.key_sz);
270 if ( ctx.iv != null )
271 Array.Clear( ctx.iv, 0, ctx.iv.Length );
272 ictx = new cipher_ctx();// codec_free( ref ctx, sizeof( cipher_ctx ) );
273 }
274  
275 /**
276 * Copy one cipher_ctx to another. For instance, assuming that read_ctx is a
277 * fully initialized context, you could copy it to write_ctx and all yet data
278 * and pass information across
279 *
280 * returns SQLITE_OK if initialization was successful
281 * returns SQLITE_NOMEM if an error occured allocating memory
282 */
283 static int cipher_ctx_copy( cipher_ctx target, cipher_ctx source )
284 {
285 //byte[] key = target.key;
286 CODEC_TRACE( "cipher_ctx_copy: entered target=%d, source=%d\n", target, source );
287 //codec_free(target.pass, target.pass_sz);
288 source.CopyTo( target );//memcpy(target, source, sizeof(cipher_ctx);
289  
290 //target.key = key; //restore pointer to previously allocated key data
291 //memcpy(target.key, source.key, EVP_MAX_KEY_LENGTH);
292 //target.pass = sqlite3Malloc(source.pass_sz);
293 //if(target.pass == null) return SQLITE_NOMEM;
294 //memcpy(target.pass, source.pass, source.pass_sz);
295 return SQLITE_OK;
296 }
297  
298 /**
299 * Compare one cipher_ctx to another.
300 *
301 * returns 0 if all the parameters (except the derived key data) are the same
302 * returns 1 otherwise
303 */
304 static int cipher_ctx_cmp( cipher_ctx c1, cipher_ctx c2 )
305 {
306 CODEC_TRACE( "cipher_ctx_cmp: entered c1=%d c2=%d\n", c1, c2 );
307  
308 if ( c1.key_sz == c2.key_sz
309 && c1.pass_sz == c2.pass_sz
310 && c1.pass == c2.pass
311 )
312 return 0;
313 return 1;
314 }
315  
316 /**
317 * Free and wipe memory associated with a cipher_ctx, including the allocated
318 * read_ctx and write_ctx.
319 */
320 static void codec_ctx_free( ref codec_ctx iCtx )
321 {
322 codec_ctx ctx = iCtx;
323 CODEC_TRACE( "codec_ctx_free: entered iCtx=%d\n", iCtx );
324 cipher_ctx_free( ref ctx.read_ctx );
325 cipher_ctx_free( ref ctx.write_ctx );
326 iCtx = new codec_ctx();//codec_free(ctx, sizeof(codec_ctx);
327 }
328  
329 /**
330 * Derive an encryption key for a cipher contex key based on the raw password.
331 *
332 * If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill
333 * the key space (i.e 64 hex chars for a 256 bit key) then the key data will be used directly.
334 *
335 * Otherwise, a key data will be derived using PBKDF2
336 *
337 * returns SQLITE_OK if initialization was successful
338 * returns SQLITE_NOMEM if the key could't be derived (for instance if pass is null or pass_sz is 0)
339 */
340 static int codec_key_derive( codec_ctx ctx, cipher_ctx c_ctx )
341 {
342 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",
343 c_ctx.pass, c_ctx.pass_sz, c_ctx.iv, c_ctx.iv_sz, c_ctx.key_sz );
344  
345 if ( c_ctx.pass != null && c_ctx.pass_sz > 0 )
346 { // if pass is not null
347 if ( ( c_ctx.pass_sz == ( c_ctx.key_sz * 2 ) + 3 ) && c_ctx.pass.StartsWith( "x'", StringComparison.OrdinalIgnoreCase ) )
348 {
349 int n = c_ctx.pass_sz - 3; /* adjust for leading x' and tailing ' */
350 string z = c_ctx.pass.Substring( 2 );// + 2; /* adjust lead offset of x' */
351 CODEC_TRACE( "codec_key_derive: deriving key from hex\n" );
352 c_ctx.key = sqlite3HexToBlob( null, z, n );
353 }
354 else
355 {
356 CODEC_TRACE( "codec_key_derive: deriving key using AES256\n" );
357  
358 Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes( c_ctx.pass, c_ctx.iv, 2010 );
359 c_ctx.key_sz = 32;
360 c_ctx.key = k1.GetBytes( c_ctx.key_sz );
361 }
362 #if NET_2_0
363 Aes.BlockSize = 0x80;
364 Aes.FeedbackSize = 8;
365 Aes.KeySize = 0x100;
366 Aes.Mode = CipherMode.CBC;
367 #endif
368 c_ctx.encryptor = Aes.CreateEncryptor( c_ctx.key, c_ctx.iv );
369 c_ctx.decryptor = Aes.CreateDecryptor( c_ctx.key, c_ctx.iv );
370 return SQLITE_OK;
371 };
372 return SQLITE_ERROR;
373 }
374  
375 /*
376 * ctx - codec context
377 * pgno - page number in database
378 * size - size in bytes of input and output buffers
379 * mode - 1 to encrypt, 0 to decrypt
380 * in - pointer to input bytes
381 * out - pouter to output bytes
382 */
383 static int codec_cipher( cipher_ctx ctx, Pgno pgno, int mode, int size, byte[] bIn, byte[] bOut )
384 {
385 int iv;
386 int tmp_csz, csz;
387  
388 CODEC_TRACE( "codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size );
389  
390 /* just copy raw data from in to out when key size is 0
391 * i.e. during a rekey of a plaintext database */
392 if ( ctx.key_sz == 0 )
393 {
394 Array.Copy( bIn, bOut, bIn.Length );//memcpy(out, in, size);
395 return SQLITE_OK;
396 }
397  
398 MemoryStream dataStream = new MemoryStream();
399 CryptoStream encryptionStream;
400 if ( mode == CIPHER_ENCRYPT )
401 {
402 encryptionStream = new CryptoStream( dataStream, ctx.encryptor, CryptoStreamMode.Write );
403 }
404 else
405 {
406 encryptionStream = new CryptoStream( dataStream, ctx.decryptor, CryptoStreamMode.Write );
407 }
408 encryptionStream.Write( bIn, 0, size );
409 encryptionStream.FlushFinalBlock();
410 dataStream.Position = 0;
411  
412 dataStream.Read( bOut, 0, (int)dataStream.Length );
413 encryptionStream.Close();
414 dataStream.Close();
415  
416  
417  
418 return SQLITE_OK;
419 }
420  
421 /**
422 *
423 * when for_ctx == 0 then it will change for read
424 * when for_ctx == 1 then it will change for write
425 * when for_ctx == 2 then it will change for both
426 */
427 static int codec_set_cipher_name( sqlite3 db, int nDb, string cipher_name, int for_ctx )
428 {
429 Db pDb = db.aDb[nDb];
430 CODEC_TRACE( "codec_set_cipher_name: entered db=%d nDb=%d cipher_name=%s for_ctx=%d\n", db, nDb, cipher_name, for_ctx );
431  
432 if ( pDb.pBt != null )
433 {
434 codec_ctx ctx = null;
435 cipher_ctx c_ctx;
436 sqlite3pager_get_codec( pDb.pBt.pBt.pPager, ref ctx );
437 c_ctx = for_ctx != 0 ? ctx.write_ctx : ctx.read_ctx;
438  
439 c_ctx.derive_key = true;
440  
441 if ( for_ctx == 2 )
442 cipher_ctx_copy( for_ctx != 0 ? ctx.read_ctx : ctx.write_ctx, c_ctx );
443 return SQLITE_OK;
444 }
445 return SQLITE_ERROR;
446 }
447  
448 static int codec_set_pass_key( sqlite3 db, int nDb, string zKey, int nKey, int for_ctx )
449 {
450 Db pDb = db.aDb[nDb];
451 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 );
452 if ( pDb.pBt != null )
453 {
454 codec_ctx ctx = null;
455 cipher_ctx c_ctx;
456 sqlite3pager_get_codec( pDb.pBt.pBt.pPager, ref ctx );
457 c_ctx = for_ctx != 0 ? ctx.write_ctx : ctx.read_ctx;
458  
459 cipher_ctx_set_pass( c_ctx, zKey, nKey );
460 c_ctx.derive_key = true;
461  
462 if ( for_ctx == 2 )
463 cipher_ctx_copy( for_ctx != 0 ? ctx.read_ctx : ctx.write_ctx, c_ctx );
464 return SQLITE_OK;
465 }
466 return SQLITE_ERROR;
467 }
468  
469 /*
470 * sqlite3Codec can be called in multiple modes.
471 * encrypt mode - expected to return a pointer to the
472 * encrypted data without altering pData.
473 * decrypt mode - expected to return a pointer to pData, with
474 * the data decrypted in the input buffer
475 */
476 static byte[] sqlite3Codec( codec_ctx iCtx, byte[] data, Pgno pgno, int mode )
477 {
478 codec_ctx ctx = (codec_ctx)iCtx;
479 int pg_sz = sqlite3BtreeGetPageSize( ctx.pBt );
480 int offset = 0;
481 byte[] pData = data;
482  
483 CODEC_TRACE( "sqlite3Codec: entered pgno=%d, mode=%d, ctx.mode_rekey=%d, pg_sz=%d\n", pgno, mode, ctx.mode_rekey, pg_sz );
484  
485 /* derive key on first use if necessary */
486 if ( ctx.read_ctx.derive_key )
487 {
488 codec_key_derive( ctx, ctx.read_ctx );
489 ctx.read_ctx.derive_key = false;
490 }
491  
492 if ( ctx.write_ctx.derive_key )
493 {
494 if ( cipher_ctx_cmp( ctx.write_ctx, ctx.read_ctx ) == 0 )
495 {
496 cipher_ctx_copy( ctx.write_ctx, ctx.read_ctx ); // the relevant parameters are the same, just copy read key
497 }
498 else
499 {
500 codec_key_derive( ctx, ctx.write_ctx );
501 ctx.write_ctx.derive_key = false;
502 }
503 }
504  
505  
506  
507 CODEC_TRACE( "sqlite3Codec: switch mode=%d offset=%d\n", mode, offset );
508 if ( ctx.buffer.Length != pg_sz )
509 ctx.buffer = sqlite3MemMalloc( pg_sz );
510 switch ( mode )
511 {
512 case SQLITE_DECRYPT:
513 codec_cipher( ctx.read_ctx, pgno, CIPHER_DECRYPT, pg_sz, pData, ctx.buffer );
514 if ( pgno == 1 )
515 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 */
516 Buffer.BlockCopy( ctx.buffer, 0, pData, 0, pg_sz ); //memcpy( pData, ctx.buffer, pg_sz ); /* copy buffer data back to pData and return */
517 return pData;
518 case SQLITE_ENCRYPT_WRITE_CTX: /* encrypt */
519 if ( pgno == 1 )
520 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 */
521 codec_cipher( ctx.write_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer );
522 return ctx.buffer; /* return persistent buffer data, pData remains intact */
523 case SQLITE_ENCRYPT_READ_CTX:
524 if ( pgno == 1 )
525 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 */
526 codec_cipher( ctx.read_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer );
527 return ctx.buffer; /* return persistent buffer data, pData remains intact */
528 default:
529 return pData;
530 }
531 }
532  
533  
534 static int sqlite3CodecAttach( sqlite3 db, int nDb, string zKey, int nKey )
535 {
536 Db pDb = db.aDb[nDb];
537  
538 CODEC_TRACE( "sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, zKey, nKey );
539 //activate_openssl();
540  
541 if ( zKey != null && pDb.pBt != null )
542 {
543 Aes.KeySize = 256;
544 #if !SQLITE_SILVERLIGHT
545 Aes.Padding = PaddingMode.None;
546 #endif
547 codec_ctx ctx;
548 int rc;
549 ////Pager pPager = pDb.pBt.pBt.pPager;
550 sqlite3_file fd;
551  
552 ctx = new codec_ctx();//sqlite3Malloc(sizeof(codec_ctx);
553 //if(ctx == null) return SQLITE_NOMEM;
554 //memset(ctx, 0, sizeof(codec_ctx); /* initialize all pointers and values to 0 */
555  
556 ctx.pBt = pDb.pBt; /* assign pointer to database btree structure */
557  
558 if ( ( rc = cipher_ctx_init( ref ctx.read_ctx ) ) != SQLITE_OK )
559 return rc;
560 if ( ( rc = cipher_ctx_init( ref ctx.write_ctx ) ) != SQLITE_OK )
561 return rc;
562  
563 /* pre-allocate a page buffer of PageSize bytes. This will
564 be used as a persistent buffer for encryption and decryption
565 operations to avoid overhead of multiple memory allocations*/
566 ctx.buffer = sqlite3MemMalloc( sqlite3BtreeGetPageSize( ctx.pBt ) );//sqlite3Malloc(sqlite3BtreeGetPageSize(ctx.pBt);
567 //if(ctx.buffer == null) return SQLITE_NOMEM;
568  
569 /* allocate space for salt data. Then read the first 16 bytes header as the salt for the key derivation */
570 ctx.read_ctx.iv_sz = FILE_HEADER_SZ;
571 ctx.read_ctx.iv = new byte[ctx.read_ctx.iv_sz];//sqlite3Malloc( ctx.iv_sz );
572  
573 Buffer.BlockCopy( Encoding.UTF8.GetBytes( SQLITE_FILE_HEADER ), 0, ctx.read_ctx.iv, 0, FILE_HEADER_SZ );
574  
575 sqlite3pager_sqlite3PagerSetCodec( sqlite3BtreePager( pDb.pBt ), sqlite3Codec, null, sqlite3FreeCodecArg, ctx );
576  
577 codec_set_cipher_name( db, nDb, CIPHER, 0 );
578 codec_set_pass_key( db, nDb, zKey, nKey, 0 );
579 cipher_ctx_copy( ctx.write_ctx, ctx.read_ctx );
580  
581 //sqlite3BtreeSetPageSize( ctx.pBt, sqlite3BtreeGetPageSize( ctx.pBt ), MAX_IV_LENGTH, 0 );
582 }
583 return SQLITE_OK;
584 }
585  
586 static void sqlite3FreeCodecArg( ref codec_ctx pCodecArg )
587 {
588 if ( pCodecArg == null )
589 return;
590 codec_ctx_free( ref pCodecArg ); // wipe and free allocated memory for the context
591 }
592  
593 static void sqlite3_activate_see( string zPassword )
594 {
595 /* do nothing, security enhancements are always active */
596 }
597  
598 static public int sqlite3_key( sqlite3 db, string pKey, int nKey )
599 {
600 CODEC_TRACE( "sqlite3_key: entered db=%d pKey=%s nKey=%d\n", db, pKey, nKey );
601 /* attach key if db and pKey are not null and nKey is > 0 */
602 if ( db != null && pKey != null )
603 {
604 sqlite3CodecAttach( db, 0, pKey, nKey ); // operate only on the main db
605 //
606 // If we are reopening an existing database, redo the header information setup
607 //
608 BtShared pBt = db.aDb[0].pBt.pBt;
609 byte[] zDbHeader = sqlite3MemMalloc( (int)pBt.pageSize );// pBt.pPager.pCodec.buffer;
610 sqlite3PagerReadFileheader( pBt.pPager, zDbHeader.Length, zDbHeader );
611 if ( sqlite3Get4byte( zDbHeader ) > 0 ) // Existing Database, need to reset some values
612 {
613 CODEC2( pBt.pPager, zDbHeader, 2, SQLITE_DECRYPT, ref zDbHeader );
614 byte nReserve = zDbHeader[20];
615 pBt.pageSize = (uint)( ( zDbHeader[16] << 8 ) | ( zDbHeader[17] << 16 ) );
616 if ( pBt.pageSize < 512 || pBt.pageSize > SQLITE_MAX_PAGE_SIZE
617 || ( ( pBt.pageSize - 1 ) & pBt.pageSize ) != 0 )
618 pBt.pageSize = 0;
619 pBt.pageSizeFixed = true;
620 #if !SQLITE_OMIT_AUTOVACUUM
621 pBt.autoVacuum = sqlite3Get4byte( zDbHeader, 36 + 4 * 4 ) != 0;
622 pBt.incrVacuum = sqlite3Get4byte( zDbHeader, 36 + 7 * 4 ) != 0;
623 #endif
624 sqlite3PagerSetPagesize( pBt.pPager, ref pBt.pageSize, nReserve );
625 pBt.usableSize = (u16)( pBt.pageSize - nReserve );
626 }
627  
628 return SQLITE_OK;
629 }
630 return SQLITE_ERROR;
631 }
632  
633 /* sqlite3_rekey
634 ** Given a database, this will reencrypt the database using a new key.
635 ** There are two possible modes of operation. The first is rekeying
636 ** an existing database that was not previously encrypted. The second
637 ** is to change the key on an existing database.
638 **
639 ** The proposed logic for this function follows:
640 ** 1. Determine if there is already a key present
641 ** 2. If there is NOT already a key present, create one and attach a codec (key would be null)
642 ** 3. Initialize a ctx.rekey parameter of the codec
643 **
644 ** Note: this will require modifications to the sqlite3Codec to support rekey
645 **
646 */
647 static int sqlite3_rekey( sqlite3 db, string pKey, int nKey )
648 {
649 CODEC_TRACE( "sqlite3_rekey: entered db=%d pKey=%s, nKey=%d\n", db, pKey, nKey );
650 //activate_openssl();
651 if ( db != null && pKey != null )
652 {
653 Db pDb = db.aDb[0];
654 CODEC_TRACE( "sqlite3_rekey: database pDb=%d\n", pDb );
655 if ( pDb.pBt != null )
656 {
657 codec_ctx ctx = null;
658 int rc;
659 Pgno page_count = 0;
660 Pgno pgno;
661 PgHdr page = null;
662 Pager pPager = pDb.pBt.pBt.pPager;
663  
664 sqlite3pager_get_codec( pDb.pBt.pBt.pPager, ref ctx );
665  
666 if ( ctx == null )
667 {
668 CODEC_TRACE( "sqlite3_rekey: no codec attached to db, attaching now\n" );
669 /* there was no codec attached to this database,so attach one now with a null password */
670 sqlite3CodecAttach( db, 0, pKey, nKey );
671 sqlite3pager_get_codec( pDb.pBt.pBt.pPager, ref ctx );
672  
673 /* prepare this setup as if it had already been initialized */
674 Buffer.BlockCopy( Encoding.UTF8.GetBytes( SQLITE_FILE_HEADER ), 0, ctx.read_ctx.iv, 0, FILE_HEADER_SZ );
675 ctx.read_ctx.key_sz = ctx.read_ctx.iv_sz = ctx.read_ctx.pass_sz = 0;
676 }
677  
678 //if ( ctx.read_ctx.iv_sz != ctx.write_ctx.iv_sz )
679 //{
680 // string error = "";
681 // 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 );
682 // db.nextPagesize = sqlite3BtreeGetPageSize( pDb.pBt );
683 // pDb.pBt.pBt.pageSizeFixed = false; /* required for sqlite3BtreeSetPageSize to modify pagesize setting */
684 // sqlite3BtreeSetPageSize( pDb.pBt, db.nextPagesize, MAX_IV_LENGTH, 0 );
685 // sqlite3RunVacuum( ref error, db );
686 //}
687  
688 codec_set_pass_key( db, 0, pKey, nKey, 1 );
689 ctx.mode_rekey = 1;
690 /* do stuff here to rewrite the database
691 ** 1. Create a transaction on the database
692 ** 2. Iterate through each page, reading it and then writing it.
693 ** 3. If that goes ok then commit and put ctx.rekey into ctx.key
694 ** note: don't deallocate rekey since it may be used in a subsequent iteration
695 */
696 rc = sqlite3BtreeBeginTrans( pDb.pBt, 1 ); /* begin write transaction */
697 sqlite3PagerPagecount( pPager, out page_count );
698 for ( pgno = 1; rc == SQLITE_OK && pgno <= page_count; pgno++ )
699 { /* pgno's start at 1 see pager.c:pagerAcquire */
700 if ( 0 == sqlite3pager_is_mj_pgno( pPager, pgno ) )
701 { /* skip this page (see pager.c:pagerAcquire for reasoning) */
702 rc = sqlite3PagerGet( pPager, pgno, ref page );
703 if ( rc == SQLITE_OK )
704 { /* write page see pager_incr_changecounter for example */
705 rc = sqlite3PagerWrite( page );
706 //printf("sqlite3PagerWrite(%d)\n", pgno);
707 if ( rc == SQLITE_OK )
708 {
709 sqlite3PagerUnref( page );
710 }
711 }
712 }
713 }
714  
715 /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
716 if ( rc == SQLITE_OK )
717 {
718 CODEC_TRACE( "sqlite3_rekey: committing\n" );
719 db.nextPagesize = sqlite3BtreeGetPageSize( pDb.pBt );
720 rc = sqlite3BtreeCommit( pDb.pBt );
721 if ( ctx != null )
722 cipher_ctx_copy( ctx.read_ctx, ctx.write_ctx );
723 }
724 else
725 {
726 CODEC_TRACE( "sqlite3_rekey: rollback\n" );
727 sqlite3BtreeRollback( pDb.pBt );
728 }
729  
730 ctx.mode_rekey = 0;
731 }
732 return SQLITE_OK;
733 }
734 return SQLITE_ERROR;
735 }
736  
737 static void sqlite3CodecGetKey( sqlite3 db, int nDb, out string zKey, out int nKey )
738 {
739 Db pDb = db.aDb[nDb];
740 CODEC_TRACE( "sqlite3CodecGetKey: entered db=%d, nDb=%d\n", db, nDb );
741  
742 if ( pDb.pBt != null )
743 {
744 codec_ctx ctx = null;
745 sqlite3pager_get_codec( pDb.pBt.pBt.pPager, ref ctx );
746  
747 if ( ctx != null )
748 { /* if the codec has an attached codec_context user the raw key data */
749 zKey = ctx.read_ctx.pass;
750 nKey = ctx.read_ctx.pass_sz;
751 return;
752 }
753 }
754 zKey = null;
755 nKey = 0;
756 }
757 /* END CRYPTO */
758 #endif
759 const int SQLITE_ENCRYPT_WRITE_CTX = 6; /* Encode page */
760 const int SQLITE_ENCRYPT_READ_CTX = 7; /* Encode page */
761 const int SQLITE_DECRYPT = 3; /* Decode page */
762 }
763 }