Skip to content

Commit 6073fd3

Browse files
committed
Add plaintext header option to some ciphers
The option to keep the database header partially unencrypted was added to the following cipher schemes to address issue #209: - chacha20 - ascon128 - aegis The option works in the same way as for the cipher scheme sqlcipher.
1 parent 72c1786 commit 6073fd3

File tree

3 files changed

+137
-39
lines changed

3 files changed

+137
-39
lines changed

src/cipher_aegis.c

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,11 @@ SQLITE_PRIVATE const AegisCryptFunctions mcAegisCryptFunctions[] =
115115

116116
SQLITE_PRIVATE CipherParams mcAegisParams[] =
117117
{
118-
{ "tcost", AEGIS_TCOST_DEFAULT, AEGIS_TCOST_DEFAULT, 1, 0x7fffffff },
119-
{ "mcost", AEGIS_MCOST_DEFAULT, AEGIS_MCOST_DEFAULT, 1, 0x7fffffff },
120-
{ "pcost", AEGIS_PCOST_DEFAULT, AEGIS_PCOST_DEFAULT, 1, 0x7fffffff },
121-
{ "algorithm", AEGIS_ALGORITHM_DEFAULT, AEGIS_ALGORITHM_DEFAULT, AEGIS_ALGORITHM_MIN, AEGIS_ALGORITHM_MAX },
118+
{ "tcost", AEGIS_TCOST_DEFAULT, AEGIS_TCOST_DEFAULT, 1, 0x7fffffff },
119+
{ "mcost", AEGIS_MCOST_DEFAULT, AEGIS_MCOST_DEFAULT, 1, 0x7fffffff },
120+
{ "pcost", AEGIS_PCOST_DEFAULT, AEGIS_PCOST_DEFAULT, 1, 0x7fffffff },
121+
{ "algorithm", AEGIS_ALGORITHM_DEFAULT, AEGIS_ALGORITHM_DEFAULT, AEGIS_ALGORITHM_MIN, AEGIS_ALGORITHM_MAX },
122+
{ "plaintext_header_size", 0, 0, 0, 100 /* restrict to db header size */ },
122123
CIPHER_PARAMS_SENTINEL
123124
};
124125

@@ -151,6 +152,7 @@ typedef struct _aegisCipher
151152
int m_argon2Mcost;
152153
int m_argon2Pcost;
153154
int m_aegisAlgorithm;
155+
int m_plaintextHeaderSize;
154156
int m_keyLength;
155157
int m_nonceLength;
156158
uint8_t m_key[KEYLENGTH_AEGIS_MAX];
@@ -185,6 +187,8 @@ AllocateAegisCipher(sqlite3* db)
185187
aegisCipher->m_keyLength = KEYLENGTH_AEGIS_256;
186188
aegisCipher->m_nonceLength = PAGE_NONCE_LEN_AEGIS_256;
187189
}
190+
int plaintextHeaderSize = sqlite3mcGetCipherParameter(cipherParams, "plaintext_header_size");
191+
aegisCipher->m_plaintextHeaderSize = (plaintextHeaderSize >=0 && plaintextHeaderSize <= 100 && plaintextHeaderSize % 16 == 0) ? plaintextHeaderSize : 0;
188192
}
189193
return aegisCipher;
190194
}
@@ -208,6 +212,7 @@ CloneAegisCipher(void* cipherTo, void* cipherFrom)
208212
aegisCipherTo->m_argon2Pcost = aegisCipherFrom->m_argon2Pcost;
209213

210214
aegisCipherTo->m_aegisAlgorithm = aegisCipherFrom->m_aegisAlgorithm;
215+
aegisCipherTo->m_plaintextHeaderSize = aegisCipherFrom->m_plaintextHeaderSize;
211216
aegisCipherTo->m_keyLength = aegisCipherFrom->m_keyLength;
212217
aegisCipherTo->m_nonceLength = aegisCipherFrom->m_nonceLength;
213218

@@ -347,12 +352,28 @@ EncryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int
347352
int nReserved = (reserved == 0) ? 0 : GetReservedAegisCipher(cipher);
348353
int n = len - nReserved;
349354
uint64_t mlen = n;
355+
int usePlaintextHeader = 0;
350356

351357
/* Generate one-time keys */
352358
uint8_t otk[OTK_LEN_MAX_AEGIS];
353-
int offset;
359+
int offset = 0;
354360
memset(otk, 0, OTK_LEN_MAX_AEGIS);
355361

362+
/* Check whether a plaintext header should be used */
363+
if (page == 1)
364+
{
365+
int plaintextHeaderSize = aegisCipher->m_plaintextHeaderSize;
366+
if (plaintextHeaderSize > 0)
367+
{
368+
usePlaintextHeader = 1;
369+
offset = (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET;
370+
}
371+
else
372+
{
373+
offset = CIPHER_PAGE1_OFFSET;
374+
}
375+
}
376+
356377
/* Check whether number of required reserved bytes and actually reserved bytes match */
357378
if (nReserved > reserved)
358379
{
@@ -368,13 +389,12 @@ EncryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int
368389
AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength,
369390
data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength, page);
370391

371-
offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
372392
mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].encrypt(
373393
data + offset, data + n, PAGE_TAG_LEN_AEGIS,
374394
data + offset, mlen - offset,
375395
NULL, 0, otk + aegisCipher->m_keyLength, otk);
376396

377-
if (page == 1)
397+
if (page == 1 && usePlaintextHeader == 0)
378398
{
379399
memcpy(data, aegisCipher->m_salt, SALTLENGTH_AEGIS);
380400
}
@@ -388,13 +408,12 @@ EncryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int
388408
nonce, aegisCipher->m_nonceLength, page);
389409

390410
/* Encrypt */
391-
offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
392411
mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].encryptNoTag(
393412
data + offset,
394413
data + offset, mlen - offset,
395414
otk + aegisCipher->m_keyLength, otk);
396415

397-
if (page == 1)
416+
if (page == 1 && usePlaintextHeader == 0)
398417
{
399418
memcpy(data, aegisCipher->m_salt, SALTLENGTH_AEGIS);
400419
}
@@ -412,12 +431,28 @@ DecryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int
412431
int n = len - nReserved;
413432
uint64_t clen = n;
414433
int tagOk;
434+
int usePlaintextHeader = 0;
415435

416436
/* Generate one-time keys */
417437
uint8_t otk[OTK_LEN_MAX_AEGIS];
418-
int offset;
438+
int offset = 0;
419439
memset(otk, 0, OTK_LEN_MAX_AEGIS);
420440

441+
/* Check whether a plaintext header should be used */
442+
if (page == 1)
443+
{
444+
int plaintextHeaderSize = aegisCipher->m_plaintextHeaderSize;
445+
if (plaintextHeaderSize > 0)
446+
{
447+
usePlaintextHeader = 1;
448+
offset = (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET;
449+
}
450+
else
451+
{
452+
offset = CIPHER_PAGE1_OFFSET;
453+
}
454+
}
455+
421456
/* Check whether number of required reserved bytes and actually reserved bytes match */
422457
if (nReserved > reserved)
423458
{
@@ -431,8 +466,6 @@ DecryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int
431466
data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength, page);
432467

433468
/* Determine MAC and decrypt */
434-
offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
435-
436469
if (hmacCheck != 0)
437470
{
438471
/* Verify the MAC */
@@ -461,7 +494,7 @@ DecryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int
461494
otk + aegisCipher->m_keyLength, otk);
462495
}
463496

464-
if (page == 1 && rc == SQLITE_OK)
497+
if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK)
465498
{
466499
memcpy(data, SQLITE_FILE_HEADER, 16);
467500
}
@@ -475,13 +508,12 @@ DecryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int
475508
nonce, aegisCipher->m_nonceLength, page);
476509

477510
/* Decrypt */
478-
offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
479511
mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decryptNoTag(
480512
data + offset,
481513
data + offset, clen - offset,
482514
otk + aegisCipher->m_keyLength, otk);
483515

484-
if (page == 1)
516+
if (page == 1 && usePlaintextHeader == 0)
485517
{
486518
memcpy(data, SQLITE_FILE_HEADER, 16);
487519
}

src/cipher_ascon.c

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929

3030
SQLITE_PRIVATE CipherParams mcAscon128Params[] =
3131
{
32-
{ "kdf_iter", ASCON128_KDF_ITER_DEFAULT, ASCON128_KDF_ITER_DEFAULT, 1, 0x7fffffff },
32+
{ "kdf_iter", ASCON128_KDF_ITER_DEFAULT, ASCON128_KDF_ITER_DEFAULT, 1, 0x7fffffff },
33+
{ "plaintext_header_size", 0, 0, 0, 100 /* restrict to db header size */ },
3334
CIPHER_PARAMS_SENTINEL
3435
};
3536

@@ -42,6 +43,7 @@ SQLITE_PRIVATE CipherParams mcAscon128Params[] =
4243
typedef struct _ascon128Cipher
4344
{
4445
int m_kdfIter;
46+
int m_plaintextHeaderSize;
4547
int m_keyLength;
4648
uint8_t m_key[KEYLENGTH_ASCON128];
4749
uint8_t m_salt[SALTLENGTH_ASCON128];
@@ -62,6 +64,8 @@ AllocateAscon128Cipher(sqlite3* db)
6264
{
6365
CipherParams* cipherParams = sqlite3mcGetCipherParams(db, CIPHER_NAME_ASCON128);
6466
ascon128Cipher->m_kdfIter = sqlite3mcGetCipherParameter(cipherParams, "kdf_iter");
67+
int plaintextHeaderSize = sqlite3mcGetCipherParameter(cipherParams, "plaintext_header_size");
68+
ascon128Cipher->m_plaintextHeaderSize = (plaintextHeaderSize >=0 && plaintextHeaderSize <= 100 && plaintextHeaderSize % 16 == 0) ? plaintextHeaderSize : 0;
6569
}
6670
return ascon128Cipher;
6771
}
@@ -80,6 +84,7 @@ CloneAscon128Cipher(void* cipherTo, void* cipherFrom)
8084
Ascon128Cipher* ascon128CipherTo = (Ascon128Cipher*) cipherTo;
8185
Ascon128Cipher* ascon128CipherFrom = (Ascon128Cipher*) cipherFrom;
8286
ascon128CipherTo->m_kdfIter = ascon128CipherFrom->m_kdfIter;
87+
ascon128CipherTo->m_plaintextHeaderSize = ascon128CipherFrom->m_plaintextHeaderSize;
8388
ascon128CipherTo->m_keyLength = ascon128CipherFrom->m_keyLength;
8489
memcpy(ascon128CipherTo->m_key, ascon128CipherFrom->m_key, KEYLENGTH_ASCON128);
8590
memcpy(ascon128CipherTo->m_salt, ascon128CipherFrom->m_salt, SALTLENGTH_ASCON128);
@@ -210,10 +215,26 @@ EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len,
210215
int nReserved = (reserved == 0) ? 0 : GetReservedAscon128Cipher(cipher);
211216
int n = len - nReserved;
212217
uint64_t mlen = n;
218+
int usePlaintextHeader = 0;
213219

214220
/* Generate one-time keys */
215221
uint8_t otk[ASCON_HASH_BYTES];
216-
int offset;
222+
int offset = 0;
223+
224+
/* Check whether a plaintext header should be used */
225+
if (page == 1)
226+
{
227+
int plaintextHeaderSize = ascon128Cipher->m_plaintextHeaderSize;
228+
if (plaintextHeaderSize > 0)
229+
{
230+
usePlaintextHeader = 1;
231+
offset = (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET;
232+
}
233+
else
234+
{
235+
offset = CIPHER_PAGE1_OFFSET;
236+
}
237+
}
217238

218239
/* Check whether number of required reserved bytes and actually reserved bytes match */
219240
if (nReserved > reserved)
@@ -229,11 +250,10 @@ EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len,
229250
chacha20_rng(data + n + PAGE_TAG_LEN_ASCON128, PAGE_NONCE_LEN_ASCON128);
230251
AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page);
231252

232-
offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
233253
ascon_aead_encrypt(data + offset, data + n, data + offset, mlen - offset,
234254
NULL /* ad */, 0 /* adlen*/,
235255
data + n + PAGE_TAG_LEN_ASCON128, otk);
236-
if (page == 1)
256+
if (page == 1 && usePlaintextHeader == 0)
237257
{
238258
memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128);
239259
}
@@ -249,11 +269,10 @@ EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len,
249269
AsconGenOtk(otk, ascon128Cipher->m_key, nonce, page);
250270

251271
/* Encrypt */
252-
offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
253272
ascon_aead_encrypt(data + offset, dummyTag, data + offset, mlen - offset,
254273
NULL /* ad */, 0 /* adlen*/,
255274
nonce, otk);
256-
if (page == 1)
275+
if (page == 1 && usePlaintextHeader == 0)
257276
{
258277
memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128);
259278
}
@@ -271,10 +290,26 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len,
271290
int n = len - nReserved;
272291
uint64_t clen = n;
273292
int tagOk;
293+
int usePlaintextHeader = 0;
274294

275295
/* Generate one-time keys */
276296
uint8_t otk[ASCON_HASH_BYTES];
277-
int offset;
297+
int offset = 0;
298+
299+
/* Check whether a plaintext header should be used */
300+
if (page == 1)
301+
{
302+
int plaintextHeaderSize = ascon128Cipher->m_plaintextHeaderSize;
303+
if (plaintextHeaderSize > 0)
304+
{
305+
usePlaintextHeader = 1;
306+
offset = (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET;
307+
}
308+
else
309+
{
310+
offset = CIPHER_PAGE1_OFFSET;
311+
}
312+
}
278313

279314
/* Check whether number of required reserved bytes and actually reserved bytes match */
280315
if (nReserved > reserved)
@@ -289,7 +324,6 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len,
289324
AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page);
290325

291326
/* Determine MAC and decrypt */
292-
offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
293327
tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset,
294328
NULL /* ad */, 0 /* adlen */,
295329
data + n, data + n + PAGE_TAG_LEN_ASCON128, otk);
@@ -310,7 +344,7 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len,
310344
rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT;
311345
}
312346
}
313-
if (page == 1 && rc == SQLITE_OK)
347+
if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK)
314348
{
315349
memcpy(data, SQLITE_FILE_HEADER, 16);
316350
}
@@ -326,11 +360,10 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len,
326360
AsconGenOtk(otk, ascon128Cipher->m_key, nonce, page);
327361

328362
/* Decrypt */
329-
offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
330363
tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset,
331364
NULL /* ad */, 0 /* adlen */,
332365
dummyTag, nonce, otk);
333-
if (page == 1)
366+
if (page == 1 && usePlaintextHeader == 0)
334367
{
335368
memcpy(data, SQLITE_FILE_HEADER, 16);
336369
}

0 commit comments

Comments
 (0)