By looking into the sourcecode of Signal on github i found the file "GRDBDatabaseStorageAdapter" to be of interest: https://github.com/signalapp/Signal-iOS/blob/e76583ac7d521e32f5de8ba4001f1847dea19c6e/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift
Signal is storing the DB-key in the keyvalue "GRDBDatabaseCipherKeySpec". The value is randomly generated when initialising the Database for the first time. The Key and value are then stored in the keychain.
private static let keyServiceName: String = "GRDBKeyChainService" private static let keyName: String = "GRDBDatabaseCipherKeySpec" I also found out how Signal prepares and opens the DB:
configuration.prepareDatabase ={(db: Database) in let keyspec = try keyspec.fetchString() try db.execute(sql: "PRAGMA key = \"\(keyspec)\"") try db.execute(sql: "PRAGMA cipher_plaintext_header_size = 32") Using a decrypted keychain.plist i located the key "GRDBDatabaseCipherKeySpec" by searching for the keyname encoded in base64:
user@computer:/Work/Signal$ echo -n GRDBDatabaseCipherKeySpec | base64 R1JEQkRhdGFiYXNlQ2lwaGVyS2V5U3BlYw== The value found under "v_data" is the value we are looking for:
<key>v_Data</key> <data> VaVsbZDrjMKuVf3H+TUGCWcZMXn5zLGBxd9dnb/DYpAok+Q8Yw/zExRxMpGDfBee </data> The value is the decoded using base64:
user@computer:/Work/Signal$ echo -n VaVsbZDrjMKuVf3H+TUGCWcZMXn5zLGBxd9dnb/DYpAok+Q8Yw/zExRxMpGDfBee | base64 -d | xxd -p -c 48 55a56c6d90eb8cc2ae55fdc7f935060967193179f9ccb181c5df5d9dbfc362902893e43c630ff31314713291837c179e To open and decrypt the database i use sqlcipher. The version supplied via ubuntu failed in decrypting the db so i had to build sqlcipher from source.
user@computer:/Work/Signal/sqlcipher/bld$ ./sqlcipher signal.sqlite SQLCipher version 3.28.0 2019-04-16 19:49:53 Enter ".help" for usage hints. sqlite> PRAGMA key="x'55a56c6d90eb8cc2ae55fdc7f935060967193179f9ccb181c5df5d9dbfc362902893e43c630ff31314713291837c179e'"; sqlite> PRAGMA cipher_plaintext_header_size = 32; sqlite> .tables grdb_migrations keyvalue media_gallery_items model_ExperienceUpgrade model_InstalledSticker model_KnownStickerPack model_OWSContactQuery model_OWSDevice .... sqlite> ATTACH DATABASE 'signal_decrypted.sqlite' AS signal_decrypted KEY ''; sqlite> SELECT sqlcipher_export('signal_decrypted'); sqlite> DETACH DATABASE signal_decrypted; The decrypted database is now found under signal_decrypted.sqlite.
A similar procedure can be used for a previous version of Signal:
Signal is storing the DB-key in the keyvalue "OWSDatabaseCipherKeySpec" (Base64: T1dTRGF0YWJhc2VDaXBoZXJLZXlTcGVj).
The version of sqlcipher used is apparently slightly older, so the version parameters must be set accordingly. See https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283
./sqlcipher /tmp/Signal.sqlite SQLCipher version 3.30.1 2019-10-10 20:19:45 Enter ".help" for usage hints. sqlite> PRAGMA key="x'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'"; ok sqlite> PRAGMA cipher_plaintext_header_size=32; sqlite> PRAGMA cipher_page_size = 1024; sqlite> PRAGMA cipher_hmac_algorithm = HMAC_SHA1; sqlite> PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1; sqlite> .tables database2 fts_FullTextSearchFinderExtension fts_FullTextSearchFinderExtension_config fts_FullTextSearchFinderExtension_content fts_FullTextSearchFinderExtension_data .....