System.Data.SQLite
Check-in [c9d926d514]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:3.3.5 codec changes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sourceforge
Files: files | file ages | folders
SHA1: c9d926d514aacf6e7ed29057a27e7b9a213692b6
User & Date: rmsimpson 2006-04-11 19:44:59
Context
2006-04-11
19:45
64-bit changes check-in: f1667b2ff7 user: rmsimpson tags: sourceforge
19:44
3.3.5 codec changes check-in: c9d926d514 user: rmsimpson tags: sourceforge
18:06
SQLite 3.3.5 check-in: 3c0bd4f9c1 user: rmsimpson tags: sourceforge
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SQLite.Interop/crypt.c.

5
6
7
8
9
10
11



12
13
14
15
16
17
18
..
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
...
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155















156
157









158
159
160




161
162
163
164
165
166
167
168
169
170
171
172
173




174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include "src/pager.c"

#ifndef SQLITE_OMIT_DISKIO
#ifdef SQLITE_HAS_CODEC

#include <windows.h>
#include <wincrypt.h>




typedef struct _CRYPTBLOCK
{
  HCRYPTKEY hReadKey;     // Key used to read from the database and write to the journal
  HCRYPTKEY hWriteKey;    // Key used to write to the database
  DWORD     dwPageSize;   // Size of pages
  LPVOID    pvCrypt;      // A buffer for encrypting/decrypting (if necessary)
................................................................................
  // Existing cryptblocks may have a buffer, if so, delete it
  if (pBlock->pvCrypt)
  {
    sqliteFree(pBlock->pvCrypt);
    pBlock->pvCrypt = NULL;
  }

  // Figure out if this cryptographic key requires extra buffer space, and if so, allocate 
  // enough room for it
  if (CryptEncrypt(hKey, 0, TRUE, 0, NULL, &pBlock->dwCryptSize, pBlock->dwCryptSize * 2))
  {
    if (pBlock->dwCryptSize > pBlock->dwPageSize)
    {
      pBlock->pvCrypt = sqliteMalloc(pBlock->dwCryptSize);
    }
  }
  return pBlock;
}

// Destroy a cryptographic context and any buffers and keys allocated therein
static void DestroyCryptBlock(LPCRYPTBLOCK pBlock)
{
................................................................................
  }

  // All done with this cryptblock
  sqliteFree(pBlock);
}

// Encrypt/Decrypt functionality, called by pager.c
void sqlite3Codec(void *pArg, void *data, Pgno nPageNum, int nMode)
{
  LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)pArg;
  DWORD dwPageSize;
  LPVOID pvTemp;

  if (!pBlock) return;

  // Make sure the page size for the pager is still the same as the page size
  // for the cryptblock.  If the user changed it, we need to adjust!
  if (nMode != 2)
  {
    PgHdr *pageHeader;
    pageHeader = DATA_TO_PGHDR(data);
................................................................................
    if (pageHeader->pPager->pageSize != pBlock->dwPageSize)
    {
      // Update the cryptblock to reflect the new page size
      CreateCryptBlock(0, pageHeader->pPager, pBlock);
    }
  }

  /* Block ciphers often need to write extra padding beyond the 
  data block.  We don't have that luxury for a given page of data so
  we must copy the page data to a buffer that IS large enough to hold
  the padding.  We then encrypt the block and write the buffer back to
  the page without the unnecessary padding.
  We only use the special block of memory if its absolutely necessary. */
  if (pBlock->pvCrypt)
  {
    CopyMemory(pBlock->pvCrypt, data, pBlock->dwPageSize);
    pvTemp = data;
    data = pBlock->pvCrypt;
  }

  switch(nMode)
  {
  case 0: // Undo a "case 7" journal file encryption
  case 2: // Reload a page
  case 3: // Load a page
    if (!pBlock->hReadKey) break;















    dwPageSize = pBlock->dwCryptSize;
    CryptDecrypt(pBlock->hReadKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize);









    break;
  case 6: // Encrypt a page for the main database file
    if (!pBlock->hWriteKey) break;




    dwPageSize = pBlock->dwPageSize;
    CryptEncrypt(pBlock->hWriteKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize, pBlock->dwCryptSize);
    break;
  case 7: // Encrypt a page for the journal file
    /* Under normal circumstances, the readkey is the same as the writekey.  However,
    when the database is being rekeyed, the readkey is not the same as the writekey.
    The rollback journal must be written using the original key for the
    database file because it is, by nature, a rollback journal.
    Therefore, for case 7, when the rollback is being written, always encrypt using
    the database's readkey, which is guaranteed to be the same key that was used to
    read the original data.
    */
    if (!pBlock->hReadKey) break;




    dwPageSize = pBlock->dwPageSize;
    CryptEncrypt(pBlock->hReadKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize, pBlock->dwCryptSize);
    break;
  }

  // If the encryption algorithm required extra padding and we were forced to encrypt or
  // decrypt a copy of the page data to a temp buffer, then write the contents of the temp
  // buffer back to the page data minus any padding applied.
  if (pBlock->pvCrypt)
  {
    CopyMemory(pvTemp, data, pBlock->dwPageSize);
  }
}

// Derive an encryption key from a user-supplied buffer
static HCRYPTKEY DeriveKey(const void *pKey, int nKeyLen)
{
  HCRYPTHASH hHash = 0;
  HCRYPTKEY  hKey;







>
>
>







 







|
<


<
<
|
<







 







|





|







 







<
<
<
<
<
<
<
<
<
<
<
<
<






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>



>
>
>
>

|











>
>
>
>

|



|
<
<
<
<
<
<







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
74
75
76
77
78
79
80
81

82
83


84

85
86
87
88
89
90
91
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
129
130
131
132
133
134
135













136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197






198
199
200
201
202
203
204
#include "src/pager.c"

#ifndef SQLITE_OMIT_DISKIO
#ifdef SQLITE_HAS_CODEC

#include <windows.h>
#include <wincrypt.h>

// Extra padding before and after the cryptographic buffer
#define CRYPT_OFFSET 8

typedef struct _CRYPTBLOCK
{
  HCRYPTKEY hReadKey;     // Key used to read from the database and write to the journal
  HCRYPTKEY hWriteKey;    // Key used to write to the database
  DWORD     dwPageSize;   // Size of pages
  LPVOID    pvCrypt;      // A buffer for encrypting/decrypting (if necessary)
................................................................................
  // Existing cryptblocks may have a buffer, if so, delete it
  if (pBlock->pvCrypt)
  {
    sqliteFree(pBlock->pvCrypt);
    pBlock->pvCrypt = NULL;
  }

  // Figure out how big to make our spare crypt block

  if (CryptEncrypt(hKey, 0, TRUE, 0, NULL, &pBlock->dwCryptSize, pBlock->dwCryptSize * 2))
  {


    pBlock->pvCrypt = sqliteMalloc(pBlock->dwCryptSize + (CRYPT_OFFSET * 2));

  }
  return pBlock;
}

// Destroy a cryptographic context and any buffers and keys allocated therein
static void DestroyCryptBlock(LPCRYPTBLOCK pBlock)
{
................................................................................
  }

  // All done with this cryptblock
  sqliteFree(pBlock);
}

// Encrypt/Decrypt functionality, called by pager.c
void * sqlite3Codec(void *pArg, void *data, Pgno nPageNum, int nMode)
{
  LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)pArg;
  DWORD dwPageSize;
  LPVOID pvTemp;

  if (!pBlock) return data;

  // Make sure the page size for the pager is still the same as the page size
  // for the cryptblock.  If the user changed it, we need to adjust!
  if (nMode != 2)
  {
    PgHdr *pageHeader;
    pageHeader = DATA_TO_PGHDR(data);
................................................................................
    if (pageHeader->pPager->pageSize != pBlock->dwPageSize)
    {
      // Update the cryptblock to reflect the new page size
      CreateCryptBlock(0, pageHeader->pPager, pBlock);
    }
  }














  switch(nMode)
  {
  case 0: // Undo a "case 7" journal file encryption
  case 2: // Reload a page
  case 3: // Load a page
    if (!pBlock->hReadKey) break;

    /* Block ciphers often need to write extra padding beyond the 
    data block.  We don't have that luxury for a given page of data so
    we must copy the page data to a buffer that IS large enough to hold
    the padding.  We then encrypt the block and write the buffer back to
    the page without the unnecessary padding.
    We only use the special block of memory if its absolutely necessary. */
    if (pBlock->dwCryptSize != pBlock->dwPageSize)
    {
      CopyMemory(((LPBYTE)pBlock->pvCrypt) + CRYPT_OFFSET, data, pBlock->dwPageSize);
      pvTemp = data;
      data = ((LPBYTE)pBlock->pvCrypt) + CRYPT_OFFSET;
    }


    dwPageSize = pBlock->dwCryptSize;
    CryptDecrypt(pBlock->hReadKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize);

    // If the encryption algorithm required extra padding and we were forced to encrypt or
    // decrypt a copy of the page data to a temp buffer, then write the contents of the temp
    // buffer back to the page data minus any padding applied.
    if (pBlock->dwCryptSize != pBlock->dwPageSize)
    {
      CopyMemory(pvTemp, data, pBlock->dwPageSize);
      data = pvTemp;
    }
    break;
  case 6: // Encrypt a page for the main database file
    if (!pBlock->hWriteKey) break;

    CopyMemory(((LPBYTE)pBlock->pvCrypt) + CRYPT_OFFSET, data, pBlock->dwPageSize);
    data = ((LPBYTE)pBlock->pvCrypt) + CRYPT_OFFSET;

    dwPageSize = pBlock->dwPageSize;
    CryptEncrypt(pBlock->hWriteKey, 0, TRUE, 0, ((LPBYTE)pBlock->pvCrypt) + CRYPT_OFFSET, &dwPageSize, pBlock->dwCryptSize);
    break;
  case 7: // Encrypt a page for the journal file
    /* Under normal circumstances, the readkey is the same as the writekey.  However,
    when the database is being rekeyed, the readkey is not the same as the writekey.
    The rollback journal must be written using the original key for the
    database file because it is, by nature, a rollback journal.
    Therefore, for case 7, when the rollback is being written, always encrypt using
    the database's readkey, which is guaranteed to be the same key that was used to
    read the original data.
    */
    if (!pBlock->hReadKey) break;

    CopyMemory(((LPBYTE)pBlock->pvCrypt) + CRYPT_OFFSET, data, pBlock->dwPageSize);
    data = ((LPBYTE)pBlock->pvCrypt) + CRYPT_OFFSET;

    dwPageSize = pBlock->dwPageSize;
    CryptEncrypt(pBlock->hReadKey, 0, TRUE, 0, ((LPBYTE)pBlock->pvCrypt) + CRYPT_OFFSET, &dwPageSize, pBlock->dwCryptSize);
    break;
  }

  return data;






}

// Derive an encryption key from a user-supplied buffer
static HCRYPTKEY DeriveKey(const void *pKey, int nKeyLen)
{
  HCRYPTHASH hHash = 0;
  HCRYPTKEY  hKey;