-
-
Notifications
You must be signed in to change notification settings - Fork 98
Closed
Description
Currently IOS pretty much always instantly kills the app on suspension when the sqlite database is stored in a shared container for app groups.
- iOS apps are terminated every time they enter the background if they share an encrypted database with an app extension. sqlcipher/sqlcipher#255
- https://github.com/groue/GRDB.swift/blob/master/GRDB/Documentation.docc/DatabaseSharing.md
- https://developer.apple.com/forums/thread/126438
- https://djangocas.dev/blog/ios-runningboard-0xdead10cc-crash-troubleshooting/
The following patch might be useful for others and it would be awesome if some form of it could be included in the main repository. The behavior is pretty similar to cipher_plaintext_header_size for sqlcipher, with the difference, basically:
- If salt is provided with a key on creation, we don't need to store the salt instead of the header (
SQLite format 3) - If the header does not include a salt, the salt is required to be provided with the key.
This currently only works only with raw keys but could surely be adapted to work for passphrases, too. Probably with a salt macro instead. I'd be happy to implement the missing pieces if you decide that this functionality belongs into the main repo.
diff --git a/src/cipher_chacha20.c b/src/cipher_chacha20.c
index 67dca9c..18b5fa5 100644
--- a/src/cipher_chacha20.c
+++ b/src/cipher_chacha20.c
@@ -53,6 +53,7 @@ typedef struct _chacha20Cipher
int m_legacyPageSize;
int m_kdfIter;
int m_keyLength;
+ int m_plaintext_header;
uint8_t m_key[KEYLENGTH_CHACHA20];
uint8_t m_salt[SALTLENGTH_CHACHA20];
} ChaCha20Cipher;
@@ -67,6 +68,7 @@ AllocateChaCha20Cipher(sqlite3* db)
chacha20Cipher->m_keyLength = KEYLENGTH_CHACHA20;
memset(chacha20Cipher->m_key, 0, KEYLENGTH_CHACHA20);
memset(chacha20Cipher->m_salt, 0, SALTLENGTH_CHACHA20);
+ chacha20Cipher->m_plaintext_header = 0;
}
if (chacha20Cipher != NULL)
{
@@ -99,6 +101,7 @@ CloneChaCha20Cipher(void* cipherTo, void* cipherFrom)
chacha20CipherTo->m_legacyPageSize = chacha20CipherFrom->m_legacyPageSize;
chacha20CipherTo->m_kdfIter = chacha20CipherFrom->m_kdfIter;
chacha20CipherTo->m_keyLength = chacha20CipherFrom->m_keyLength;
+ chacha20CipherTo->m_plaintext_header = chacha20CipherFrom->m_plaintext_header;
memcpy(chacha20CipherTo->m_key, chacha20CipherFrom->m_key, KEYLENGTH_CHACHA20);
memcpy(chacha20CipherTo->m_salt, chacha20CipherFrom->m_salt, SALTLENGTH_CHACHA20);
}
@@ -146,6 +149,11 @@ GenerateKeyChaCha20Cipher(void* cipher, char* userPassword, int passwordLength,
int bypass = 0;
int keyOnly = 1;
+ int needSalt = 0;
+ if (cipherSalt != NULL && !memcmp(cipherSalt, SQLITE_FILE_HEADER, 16))
+ {
+ needSalt = 1;
+ }
if (rekey || cipherSalt == NULL)
{
chacha20_rng(chacha20Cipher->m_salt, SALTLENGTH_CHACHA20);
@@ -165,8 +173,9 @@ GenerateKeyChaCha20Cipher(void* cipher, char* userPassword, int passwordLength,
{
/* Binary key (and salt) */
case KEYLENGTH_CHACHA20 + SALTLENGTH_CHACHA20:
- if (!keyOnly)
+ if (!keyOnly || needSalt)
{
+ chacha20Cipher->m_plaintext_header = 1;
memcpy(chacha20Cipher->m_salt, zRaw + KEYLENGTH_CHACHA20, SALTLENGTH_CHACHA20);
}
/* fall-through */
@@ -189,8 +198,9 @@ GenerateKeyChaCha20Cipher(void* cipher, char* userPassword, int passwordLength,
if (sqlite3mcIsHexKey(zRaw, nRaw) != 0)
{
sqlite3mcConvertHex2Bin(zRaw, 2 * KEYLENGTH_CHACHA20, chacha20Cipher->m_key);
- if (!keyOnly)
+ if (!keyOnly || needSalt)
{
+ chacha20Cipher->m_plaintext_header = 1;
sqlite3mcConvertHex2Bin(zRaw + 2 * KEYLENGTH_CHACHA20, 2 * SALTLENGTH_CHACHA20, chacha20Cipher->m_salt);
}
bypass = 1;
@@ -202,6 +212,18 @@ GenerateKeyChaCha20Cipher(void* cipher, char* userPassword, int passwordLength,
}
}
+ if (needSalt && !chacha20Cipher->m_plaintext_header)
+ {
+ memset(chacha20Cipher->m_key, 0, KEYLENGTH_CHACHA20);
+ memset(chacha20Cipher->m_salt, 0, SALTLENGTH_CHACHA20);
+ chacha20Cipher->m_plaintext_header = 0;
+ sqlite3_log(
+ SQLITE_ERROR,
+ "you must provide a salt via the raw key API `PRAGMA key = \"raw:...\"` for a database with plaintext header."
+ );
+ return;
+ }
+
if (!bypass)
{
fastpbkdf2_hmac_sha256((unsigned char*)userPassword, passwordLength,
@@ -246,7 +268,10 @@ EncryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len,
chacha20_xor(data + offset, n - offset, otk + 32, data + n, counter + 1);
if (page == 1)
{
- memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20);
+ if (!chacha20Cipher->m_plaintext_header)
+ {
+ memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20);
+ }
}
poly1305(data, n + PAGE_NONCE_LEN_CHACHA20, otk, data + n + PAGE_NONCE_LEN_CHACHA20);
}
@@ -264,7 +289,10 @@ EncryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len,
chacha20_xor(data + offset, n - offset, otk + 32, nonce, counter + 1);
if (page == 1)
{
- memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20);
+ if (!chacha20Cipher->m_plaintext_header)
+ {
+ memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20);
+ }
}
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels