HMAC verification failed for page nnnn

I have a signal-desktop sqlite database that was running on Ubuntu 22.04. I backed up the entire signal folder (~/.config/Signal) after quitting Signal, upgraded my OS to Ubuntu 24.04 (clean install), restored my backup. When I try to open Signal, it throws the following error:

2024-09-06 15:41:34.201: ERROR CORE sqlcipher_page_cipher: hmac check failed for pgno=1
2024-09-06 15:41:34.201: ERROR CORE sqlite3Codec: error decrypting page 1 data: 1
2024-09-06 15:41:34.201: ERROR CORE sqlcipher_codec_ctx_set_error 1
{"level":40,"time":"2024-09-06T22:41:34.201Z","msg":"MainSQL: Database log code=26: file is not a database in \"PRAGMA journal_mode = WAL\""}
{"level":30,"time":"2024-09-06T22:41:34.201Z","msg":"MainSQL: migrateDatabase: Migration without cipher change failed"}
2024-09-06 15:41:34.235: ERROR CORE sqlcipher_page_cipher: hmac check failed for pgno=1
2024-09-06 15:41:34.235: ERROR CORE sqlite3Codec: error decrypting page 1 data: 1
2024-09-06 15:41:34.235: ERROR CORE sqlcipher_codec_ctx_set_error 1
{"level":40,"time":"2024-09-06T22:41:34.235Z","msg":"MainSQL: Database log code=26: statement aborts at 2: [PRAGMA user_version] file is not a database"}
{"level":50,"time":"2024-09-06T22:41:34.236Z","msg":"MainSQL: Database startup error: SqliteError: file is not a database\n    at Database.pragma ([REDACTED]/node_modules/@signalapp/better-sqlite3/lib/methods/pragma.js:11:31)\n    at getUserVersion ([REDACTED]/ts/sql/util.js:132:13)\n    at migrateSchemaVersion ([REDACTED]/ts/sql/Server.js:397:54)\n    at openAndMigrateDatabase ([REDACTED]/ts/sql/Server.js:429:5)\n    at openAndSetUpSQLCipher ([REDACTED]/ts/sql/Server.js:451:14)\n    at initialize ([REDACTED]/ts/sql/Server.js:489:10)\n    at MessagePort.<anonymous> ([REDACTED]/ts/sql/mainWorker.js:69:41)\n    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:820:20)\n    at MessagePort.<anonymous> (node:internal/per_context/messageport:23:28)"}
{"level":50,"time":"2024-09-06T22:41:34.236Z","msg":"Failed to get zoom factor {\"name\":\"SqliteError\"}"}
{"level":30,"time":"2024-09-06T22:41:34.539Z","msg":"got fast theme-setting value system"}
{"level":50,"time":"2024-09-06T22:41:34.978Z","msg":"sql.initialize was unsuccessful; returning early"}
{"level":30,"time":"2024-09-06T22:41:34.978Z","msg":"close event {\"readyForShutdown\":false,\"shouldQuit\":false}"}
{"level":30,"time":"2024-09-06T22:41:34.979Z","msg":"maybeRequestCloseConfirmation: Checking to see if close confirmation is needed"}
{"level":50,"time":"2024-09-06T22:41:36.515Z","msg":"onDatabaseError: Quitting application"}
{"level":30,"time":"2024-09-06T22:41:36.516Z","msg":"main window closed event"}
{"level":30,"time":"2024-09-06T22:41:36.517Z","msg":"quit event {\"hasEventBeenPrevented\":false,\"windowCount\":0,\"mainWindowExists\":false}"}
{"level":50,"time":"2024-09-06T22:41:36.518Z","msg":"Error occurred in handler for 'sql-channel:read': {\"name\":\"SqliteError\"}"}

I attempted to open the ~/.config/Signal/sql/db.sqlite database using SQLCipher. After specifying the key using PRAGMA key = "x'{very long string of letters and numbers}'", if I run .tables, I get the following error:

2024-09-06 15:44:08.714: sqlcipher_page_cipher: hmac check failed for pgno=1
2024-09-06 15:44:08.714: sqlite3Codec: error decrypting page 1 data: 1
2024-09-06 15:44:08.714: sqlcipher_codec_ctx_set_error 1
Error: file is not a database

If I run PRAGMA cipher_integrity_check, it throws several HMAC verification failed for page nnnn.

Does this mean the database is corrupt? Is there any way I can recover the db? Any advise would very much appreciated.

It was an issue with the key. I corrected that, and now I’m able to access the database using sqlcipher. However, Signal still throws the following:

{"level":40,"time":"2024-09-07T03:47:13.760Z","msg":"MainSQL: Database log code=283: recovered 359 frames from WAL file [REDACTED]/sql/db.sqlite-wal"}
{"level":40,"time":"2024-09-07T03:47:13.765Z","msg":"MainSQL: Database log code=11: database corruption at line 72957 of [c9c2ab54ba]"}
{"level":40,"time":"2024-09-07T03:47:13.765Z","msg":"MainSQL: Database log code=11: database corruption at line 73107 of [c9c2ab54ba]"}
{"level":40,"time":"2024-09-07T03:47:13.765Z","msg":"MainSQL: Database log code=11: statement aborts at 11: [] database disk image is malformed"}
{"level":30,"time":"2024-09-07T03:47:13.765Z","msg":"MainSQL: updateSchema:\n  Current user_version: 1150;\n  Most recent db schema: 1170;\n  SQLite version: 3.46.1;\n  SQLCipher version: 4.6.1 community;\n  (deprecated) schema_version: 490;\n"}
{"level":30,"time":"2024-09-07T03:47:13.767Z","msg":"got fast theme-setting value system"}
{"level":30,"time":"2024-09-07T03:47:13.768Z","msg":"got fast spellcheck setting true"}
{"level":30,"time":"2024-09-07T03:47:13.768Z","msg":"Initializing BrowserWindow config: {\"show\":false,\"width\":1850,\"height\":1016,\"minWidth\":300,\"minHeight\":200,\"autoHideMenuBar\":true,\"titleBarStyle\":\"default\",\"backgroundColor\":\"#121212\",\"webPreferences\":{\"devTools\":false,\"spellcheck\":true,\"enableBlinkFeatures\":\"CSSPseudoDir,CSSLogical\",\"enablePreferredSizeMode\":true,\"nodeIntegration\":false,\"nodeIntegrationInWorker\":false,\"sandbox\":false,\"contextIsolation\":true,\"preload\":\"[REDACTED]/preload.bundle.js\",\"backgroundThrottling\":true,\"disableBlinkFeatures\":\"Accelerated2dCanvas,AcceleratedSmallCanvases\"},\"icon\":\"[REDACTED]/images/signal-logo-desktop-linux.png\",\"x\":70,\"y\":1144}"}
{"level":30,"time":"2024-09-07T03:47:13.950Z","msg":"spellcheck: user locales: [\"en-US\",\"en\"]"}
{"level":30,"time":"2024-09-07T03:47:13.950Z","msg":"spellcheck: available spellchecker languages: [\"af\",\"bg\",\"ca\",\"cs\",\"cy\",\"da\",\"de\",\"de-DE\",\"el\",\"en\",\"en-AU\",\"en-CA\",\"en-GB\",\"en-GB-oxendict\",\"en-US\",\"es\",\"es-419\",\"es-AR\",\"es-ES\",\"es-MX\",\"es-US\",\"et\",\"fa\",\"fo\",\"fr\",\"fr-FR\",\"he\",\"hi\",\"hr\",\"hu\",\"hy\",\"id\",\"it\",\"it-IT\",\"ko\",\"lt\",\"lv\",\"nb\",\"nl\",\"pl\",\"pt\",\"pt-BR\",\"pt-PT\",\"ro\",\"ru\",\"sh\",\"sk\",\"sl\",\"sq\",\"sr\",\"sv\",\"ta\",\"tg\",\"tr\",\"uk\",\"vi\"]"}
{"level":30,"time":"2024-09-07T03:47:13.950Z","msg":"spellcheck: setting languages to: [\"en-US\",\"en\"]"}
{"level":30,"time":"2024-09-07T03:47:13.950Z","msg":"MainSQL: updateToSchemaVersion1160: success!"}
{"level":40,"time":"2024-09-07T03:47:13.950Z","msg":"MainSQL: Database log code=11: database corruption at line 76284 of [c9c2ab54ba]"}
{"level":40,"time":"2024-09-07T03:47:13.950Z","msg":"MainSQL: Database log code=11: statement aborts at 26: [DROP INDEX IF EXISTS messages_callHistory_markReadBefore;] database disk image is malformed"}
{"level":50,"time":"2024-09-07T03:47:13.950Z","msg":"MainSQL: Database startup error: SqliteError: database disk image is malformed\n    at Database.exec ([REDACTED]/node_modules/@signalapp/better-sqlite3/lib/methods/wrappers.js:9:14)\n    at [REDACTED]/ts/sql/migrations/1170-update-call-history-unread-index.js:39:8\n    at sqliteTransaction ([REDACTED]/node_modules/@signalapp/better-sqlite3/lib/methods/transaction.js:65:24)\n    at updateToSchemaVersion1170 ([REDACTED]/ts/sql/migrations/1170-update-call-history-unread-index.js:41:5)\n    at updateSchema ([REDACTED]/ts/sql/migrations/index.js:1824:5)\n    at initialize ([REDACTED]/ts/sql/Server.js:494:42)\n    at MessagePort.<anonymous> ([REDACTED]/ts/sql/mainWorker.js:69:41)\n    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:820:20)\n    at MessagePort.<anonymous> (node:internal/per_context/messageport:23:28)"}
{"level":50,"time":"2024-09-07T03:47:14.008Z","msg":"Failed to get zoom factor {\"name\":\"SqliteError\"}"}
{"level":30,"time":"2024-09-07T03:47:14.372Z","msg":"got fast theme-setting value system"}
{"level":50,"time":"2024-09-07T03:47:14.852Z","msg":"sql.initialize was unsuccessful; returning early"}
{"level":30,"time":"2024-09-07T03:47:14.853Z","msg":"close event {\"readyForShutdown\":false,\"shouldQuit\":false}"}
{"level":30,"time":"2024-09-07T03:47:14.853Z","msg":"maybeRequestCloseConfirmation: Checking to see if close confirmation is needed"}
{"level":50,"time":"2024-09-07T03:47:18.309Z","msg":"onDatabaseError: Quitting application"}
{"level":30,"time":"2024-09-07T03:47:18.311Z","msg":"main window closed event"}
{"level":30,"time":"2024-09-07T03:47:18.312Z","msg":"quit event {\"hasEventBeenPrevented\":false,\"windowCount\":0,\"mainWindowExists\":false}"}
{"level":50,"time":"2024-09-07T03:47:18.315Z","msg":"Error occurred in handler for 'sql-channel:read': {\"name\":\"SqliteError\"}"}

It seems there is some corruption in the database. Running pragma integrity_check; outputs the following:

*** in database main ***
Tree 3 page 3 cell 26: Child page depth differs
Tree 3 page 3 cell 25: Child page depth differs
2nd reference to page 49481
Page 141: never used
Runtime error: database disk image is malformed (11)

Any suggestions on how to fix this?

bump

Any advice would be greatly appreciated. Thank you.

Hello @ms3318 - thanks for getting in touch. I’m sorry to hear about the trouble. While Signal does use SQLCipher, we don’t support it as an application.

It sounds like the database is corrupted. If you want to try to recover your data, you could try to use the .recover command (see Recovering Data From A Corrupt SQLite Database) to get data out.

Otherwise, I would contact Signal for support on how to reset the database.

Thank you for your response.

Would you be so kind as to provide me the steps to perform a recover on an encrypted db? I assume I cannot just use sqlite3 to attempt a .recover since the database is encrypted. Attempting to run a .recover within an interactive sqlcipher session results in a

sqlite> .recover
2024-09-12 21:38:28.242: sqlcipher_page_cipher: hmac check failed for pgno=1
2024-09-12 21:38:28.242: sqlite3Codec: error decrypting page 1 data: 1
2024-09-12 21:38:28.242: sqlcipher_codec_ctx_set_error 1
sql error: file is not a database (26)

However, within the same interactive session, if I run a .tables command, I can see the list of tables, which seems to indicate that I entered the correct key. In addition, a .dump works, although unlike recover, it quits somewhere half way through when it runs into an error.