Encrypt a SQLite Database with SQLCipher

Read a plain SQLite file's bytes, then encrypt it with SQLCipher to hide them.

Introduction

30 Second Summary

A database feels like a vault. In SQLite, it is one ordinary file sitting on your disk, and anyone who copies that file can open it in a text editor.

In this project, you will build a small SQLite database, read your own rows straight out of the raw file, then encrypt it with SQLCipher and watch that trick stop working.

What You'll Build

Two database files holding identical rows, side by side, where you can pull a name and an email out of one with a single command and get nothing but noise out of the other.

By the end of this project, you'll have:

  • A plaintext database whose secrets you can read yourself by running strings over the file, with your own test rows staring back at you.
  • An encrypted database that returns the same rows when you query it with the key, and binary noise when anyone digs through the file without one.
  • A short script you can run twice to prove the point. Right key, your rows print. Wrong key, it refuses.
  • Secret Mission: Take your existing plaintext database and migrate its rows into an encrypted copy, so nothing readable is left behind.

Does this cost anything?

No. The SQLCipher community edition is BSD licensed and free, and everything here runs locally on your machine.

You'll see paid tiers advertised alongside it, like commercial SQLCipher at $999 a year and the SQLite Encryption Extension at $2,000. You don't need either one for this project.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters. You'll watch a plain SQLite file hand over its rows to anyone who opens it, then lock that same data away with SQLCipher.

Build Your Plaintext Database

A SQLite database lives as a single file on your disk. Whoever can copy that file has your data.

Before you can prove how exposed that file is, you need something worth reading inside it. In this step you build a small database of names and emails, then query them back to confirm they saved.

In this step, get ready to:
  • Create a project folder and a plaintext.db database file.
  • Add a users table and insert three rows of real-looking data.
  • Query those rows back in the shell to confirm they saved.
Create your project folder

Both database files in this project need to sit side by side so you can compare them later. One folder keeps that comparison honest.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir sqlite-lockdown
cd sqlite-lockdown
  • Confirm you are standing in the new folder by running:
pwd
  • You should see a path ending in /sqlite-lockdown.
Create the database and its users table

SQLite has no server to start and no database to provision. You hand the command line a filename and it hands you a shell.

  • Open a database called plaintext.db by running this command:
sqlite3 plaintext.db

Where is the file?

Your prompt changes to sqlite>, but nothing has been written to disk yet.

SQLite only creates the file once there is something to store in it. The table you write next is what brings it into existence.

  • Create the users table by running this statement at the sqlite> prompt:
CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name TEXT,
  email TEXT
);

What does this code do?

  • id INTEGER PRIMARY KEY gives every row a unique number that SQLite fills in for you.
  • name TEXT and email TEXT hold the human-readable values you will go hunting for in the raw file later.
  • Confirm the table exists by running:
.tables
  • You should see users printed back to you.

Nothing happened when you pressed Enter?

SQLite waits for the semicolon that ends a statement before it runs anything. If your prompt changed and your next line seems to be ignored, type a single ; and press Enter.

Still stuck? Why is my SQLite statement not running?

Insert rows and read them back

An empty table proves nothing. You need names and emails that you would recognise instantly if they turned up somewhere they should not be.

  • Add three rows by running this statement at the sqlite> prompt:
INSERT INTO users (name, email) VALUES
  ('Jane Doe', 'jane@example.com'),
  ('Raj Patel', 'raj@example.com'),
  ('Mia Chen', 'mia@example.com');

What does this code do?

  • The statement lists only name and email, so SQLite numbers the id column itself.
  • The values are deliberately memorable. A name like Jane Doe is easy to spot in a wall of binary output.

Before you run the next command, what do you expect three saved rows to look like coming back out of the shell?

  • Read your rows back by running:
SELECT * FROM users;
  • You should see three lines, each one an id, a name and an email joined by |, starting with 1|Jane Doe|jane@example.com.

No rows came back?

  • Check the insert actually ran. If you missed the closing semicolon, the shell swallowed the statement and is still waiting.
  • Check you opened the database from inside sqlite-lockdown. Launching from another folder creates a second, empty plaintext.db there.

Why is my SELECT returning nothing?

  • Leave the SQLite shell by running:
.quit
  • Confirm the database file now exists on disk by running:
ls
  • You should see plaintext.db listed in your folder.

Your rows are saved and they read back cleanly. Next up, you open that same file as raw bytes and see how much of it a text editor can already understand.

Read the Raw Bytes of Your Database

You just watched SQLite hand your rows back cleanly. A name, an email, all sitting in a table that only answers to SQL queries.

That feeling of safety comes from the SQLite client, not from the file. A database is just bytes on disk. Anyone who copies plaintext.db can skip the client entirely.

In this step, you play the part of somebody who stole the file. No password, no SQL, just a look at the raw bytes.

In this step, get ready to:
  • Pull the readable text out of your database file without opening SQLite.
  • Find your own names and emails sitting in the raw bytes.
  • Look at the file in a hex viewer to see where that text lives.
Pull the readable text out of the file

The strings command walks through any file and prints out runs of characters that look like human text. It knows nothing about SQLite.

Before you run it, what do you think comes back? A jumble of binary noise, or the names and emails you typed in?

  • Read the text hiding inside your database by running this command:
strings plaintext.db

What does this command do?

It scans every byte of the file and prints any sequence of printable characters it finds.

The rest of the file is structure that SQLite uses to organise pages, so it gets skipped as noise.

Your table name, your column names, and every name and email you inserted come back in plain, readable text.

Command not found?

On macOS, strings ships with the Xcode command line tools. On Linux it comes from the binutils package.

If you cannot install it, skip ahead to the hex viewer below. It shows you the same thing.

Why does my terminal say strings is not installed?

Narrow the output down to your own rows

That output mixes your data with SQLite's own bookkeeping. Filtering it makes the point sharper.

  • Pull out only the lines containing an email address by running this command:
strings plaintext.db | grep example.com

What does this command do?

The pipe hands the readable text from strings straight to grep, which keeps only the lines that match.

This is exactly how someone would hunt for credentials in a stolen file.

You get the email addresses you inserted, and nothing else. No SQL, no client, no key.

No matches came back?

Check that the emails you inserted actually end in example.com. If you used a different domain, swap it into the command.

Confirm you are in the same folder as plaintext.db. A missing file gives you an empty result rather than a loud error here.

Why is my grep returning nothing from this file?

See where the text sits inside the file

A hex viewer shows you every byte, with the readable characters printed alongside. This is the closest you get to looking at the disk itself.

Before you run it, do you expect your rows to be scattered through the file, or clustered together in one region?

  • Dump the file byte by byte and scroll to the end by running this command:
xxd plaintext.db | tail -20

What does this command do?

The left columns are the raw bytes in hexadecimal. The right column is those same bytes shown as characters, with dots standing in for anything unprintable.

SQLite writes table data from the end of a page backwards, so your rows land near the bottom of the file.

Look down the right hand column. Your names and emails read straight across, sitting in one cluster near the end.

Don't have xxd?

Try hexdump -C plaintext.db | tail -20 instead. It prints the same two column layout.

If neither tool is available, your strings output from earlier already proves the point.

How do I view a file in hex on my machine?

Why SQLite has no password

SQLite is a file format, not a server. There is no process guarding access, so there is nobody to check a password against.

Protection has to come from somewhere else. Either the filesystem keeps people away from the file, or the bytes themselves are encrypted.

You have proved the gap. The next step closes it with SQLCipher, which encrypts every page before it touches the disk.

Encrypt a Second Database with SQLCipher

In the last step you ran strings over plaintext.db and read your own names and emails straight out of the raw file. No password, no query, no SQLite involved at all.

Plain SQLite has no encryption setting to switch on, so the fix is a different build of SQLite. SQLCipher is a community build that encrypts every page of the database file before it touches disk.

In this step you build a second database called encrypted.db that holds the same three rows behind a key.

In this step, get ready to:
  • Install SQLCipher and confirm the sqlcipher client runs.
  • Create encrypted.db and unlock it with a key.
  • Insert the same three rows and query them back.
Install SQLCipher

SQLCipher ships its own command line client, sqlcipher, which sits alongside the sqlite3 client you have been using. It speaks the same SQL and understands one extra thing: keys.

Do I have to pay for SQLCipher?

No. The community edition you install here is BSD licensed and free to use.

There are paid tiers around it, a commercial SQLCipher licence at $999 a year and the SQLite Encryption Extension at $2,000. You need neither of them for anything in this project.

  • Check whether you already have SQLCipher by running this command:
sqlcipher --version

✔️ I see a version number

SQLCipher is already installed and your shell can find it. Carry on to the next substep and create your encrypted database.

ⓧ Command not found

SQLCipher is not installed yet. Pick your platform below and install it.

macOS

  • Install SQLCipher with Homebrew by running this command:
brew install sqlcipher
  • Confirm the install landed by running the version check again:
sqlcipher --version

You should see a version number printed back.

Windows

SQLCipher installs cleanly inside Windows Subsystem for Linux, which also gives you the same shell tools the rest of this project uses.

sudo apt install sqlcipher

The installer asks you to confirm before it downloads anything. Type `y` and press Enter.

  • Confirm the install landed by running the version check again:
sqlcipher --version

You should see a version number printed back.

Linux

  • Install SQLCipher on Debian or Ubuntu by running this command:
sudo apt install sqlcipher

The installer asks you to confirm before it downloads anything. Type `y` and press Enter.

  • Confirm the install landed by running the version check again:
sqlcipher --version

You should see a version number printed back.

Still seeing command not found?

Close your terminal window and open a new one. A shell that was already running often does not pick up a binary installed underneath it.

Why can't my terminal find sqlcipher after installing it?

Create the encrypted database and unlock it

A SQLCipher database gets its key at the moment you open it, not when the file is created. The key has to be the first thing you send on the connection, before any other SQL.

The sqlcipher client opens an interactive SQL session, so the next command takes over your terminal until you close it.

  • Create a new database file and open it by running this command:
sqlcipher encrypted.db

Your terminal now shows a SQL prompt waiting for input. Everything you type goes to the database until you close the session.

  • Set the key for this session by running this as the very first statement:
PRAGMA key = 'correct-horse-battery-staple';

What does PRAGMA key do?

It hands SQLCipher the passphrase it derives the encryption key from. Every page read or written on this connection goes through that key.

Run any other statement first and SQLCipher treats the file as an ordinary SQLite database. This is the single most common way people end up with an unencrypted file they believed was protected.

  • Build the same table you created in plaintext.db by running this statement:
CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name TEXT,
  email TEXT
);
  • Confirm the table exists by running:
.tables

You should see users printed back. The file on disk is now a real encrypted database.

Nothing happens when you press Enter?

The client waits for more input until a statement is finished. Type a semicolon and press Enter to close it off.

Why is my SQL prompt not running my statement?

Insert the same rows and read them back

The proof that encryption worked is boring on purpose. With the key supplied, the encrypted database behaves exactly like the plain one.

  • Add the same three people you put into plaintext.db by running these statements:
INSERT INTO users (name, email) VALUES ('Ada Lovelace', 'ada@example.com');
INSERT INTO users (name, email) VALUES ('Grace Hopper', 'grace@example.com');
INSERT INTO users (name, email) VALUES ('Alan Turing', 'alan@example.com');
  • Swap in your own names and emails if you used different ones earlier, so both files hold identical rows.

What does this code do?

Each `INSERT` writes a row through the key you set at the top of the session.

SQLCipher encrypts every page on its way to disk. Nothing readable ever reaches the file, including the table names and column names.

Before you run the next command, what do you expect back: readable names and emails, or the scrambled bytes now sitting in the file?

  • Read the rows back by running this query:
SELECT * FROM users;

All three rows come back as ordinary readable text. SQLCipher decrypts each page in memory as it reads, so a keyed session feels no different from a plain one.

  • Close the session by running:
.quit
  • Confirm both database files now sit side by side by running:
ls

You should see encrypted.db and plaintext.db listed together.

Query came back empty?

Check that your inserts ran in the same session as your key statement. Closing the client drops the key, so a fresh session needs it again before any other SQL.

Why does my encrypted database look empty when I query it?

✔️ Awesome, I've got everything!

Great, your encrypted.db holds all three rows under the key.

ⓧ I'd like to double check the full code

Here is the full session in order, from setting the key to reading the rows back.

PRAGMA key = 'correct-horse-battery-staple';

CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name TEXT,
  email TEXT
);

INSERT INTO users (name, email) VALUES ('Ada Lovelace', 'ada@example.com');
INSERT INTO users (name, email) VALUES ('Grace Hopper', 'grace@example.com');
INSERT INTO users (name, email) VALUES ('Alan Turing', 'alan@example.com');

SELECT * FROM users;

Two database files now hold the same three rows, one of them behind a key. Next up, you'll run strings over the encrypted one and see exactly what somebody gets when they copy the file without your key.

Prove the Encrypted File Resists Reading

A moment ago encrypted.db handed over its rows without complaint, because you gave SQLCipher the key first.

A database that opens with the key is only half the proof. The other half is watching it shut out everybody else.

So now you turn the same two tricks that exposed plaintext.db against the encrypted file.

In this step, get ready to:
  • Run strings over encrypted.db and hunt for your row data.
  • Open encrypted.db with the plain sqlite3 client and read the error it returns.
Search the encrypted file for your rows

The strings tool walks a file byte by byte and prints every run of readable characters it finds. That was all it took to spill names and emails out of plaintext.db.

Before you point it at the encrypted file, what do you expect back: the same names, a few broken fragments, or nothing you recognise?

  • Send the encrypted file through strings by running this command:
strings encrypted.db

You get back a short run of random-looking characters. None of the names or emails you inserted show up anywhere in it.

Why the file reads as noise

SQLCipher encrypts every page of the database, not only the columns holding your text.

That leaves no readable header and no readable rows for strings to latch onto. The only bytes it can print are meaningless scraps of ciphertext.

  • Search that same output for one of the names you inserted by running this command:
strings encrypted.db | grep [[SAMPLE_NAME="one of the names you inserted"]]

The grep command prints nothing and drops you straight back to your prompt. Empty output is the pass here.

Seeing readable names anyway?

  • Check the filename in your command. Running strings against plaintext.db shows the rows in the clear, which is exactly what you proved earlier.
  • Confirm you inserted the rows through the sqlcipher client rather than the plain one.

Why can I still read text inside my SQLCipher database file?

Open the encrypted file with plain sqlite3

The strings tool is a blunt instrument. The tougher test is the official SQLite client, which knows the file format inside out.

Before you run this, do you think sqlite3 opens the file and shows you an empty table, or refuses it outright?

  • Ask the plain sqlite3 client for your rows by running this command:
sqlite3 encrypted.db "SELECT * FROM users;"

The query never runs. The client refuses the file with an error saying file is not a database.

Why sqlite3 gives up at the first byte

Plain sqlite3 checks the start of a file to confirm it is looking at a database before it reads anything else.

SQLCipher encrypts that region along with every page behind it. The client finds bytes that match nothing it recognises, so it rejects the file instead of returning your rows.

That error is the win. Your three rows are sitting in that file, intact, and the standard client cannot pull out a single one of them.

Getting rows back instead of an error?

  • Check that you ran sqlite3 and not sqlcipher. The SQLCipher client can open this file once you supply the key.
  • Check the filename. Pointing the command at plaintext.db returns your three readable rows.

Why did plain sqlite3 open my encrypted database instead of erroring?

Two attacks, two dead ends. Next up, you'll write a short script that opens encrypted.db with the key, then watch it refuse the moment the key is wrong.

Script Access to the Encrypted Database

Last step you watched encrypted.db shrug off two attacks. strings gave you nothing readable, and the plain sqlite3 client refused to open the file at all.

A database nobody can read is not much use. Real applications open the encrypted file in code, hand over the key, then read rows like normal.

In this step you write that code in Python, then break it on purpose by feeding it the wrong key.

In this step, get ready to:
  • Install a Python driver that speaks SQLCipher.
  • Write read_encrypted.py to open encrypted.db with your key and print the users rows.
  • Run the script with a wrong key and watch it refuse.
Install a Python driver for SQLCipher

Python ships with a built-in sqlite3 module, and it links against plain SQLite. That is the exact library that just refused your file.

To read encrypted.db from code you need a driver built against SQLCipher instead.

  • Check that Python 3 is on your machine by running this command:
python3 --version

✔️ I see a version number

Python is ready. Next you add the SQLCipher driver on top of it.

ⓧ Command not found

  • Open the Python downloads page in your browser.
  • Download the Python 3 installer for your operating system.
  • Run the installer and accept the defaults.
  • Close your terminal window, then open a new one so it picks up the new install.
  • Confirm Python is now available by running this command again:
python3 --version

You should see a version number printed back.

  • Install the SQLCipher driver for Python by running this command:
pip install sqlcipher3

What are you installing?

sqlcipher3 is a Python driver that mirrors the built-in sqlite3 module. Same method names, same cursor pattern, but compiled against SQLCipher.

The wheel ships with SQLCipher statically linked inside it. That means the driver works even if Python cannot find a system copy of the library.

  • Confirm the driver imports by running this command:
python3 -c "from sqlcipher3 import dbapi2 as sqlite; print('driver ready')"

You should see driver ready printed back.

Install or import not working?

  • An error saying pip cannot be found usually means your Python install named it pip3 instead. Run the same install command with that name.
  • An error saying the module cannot be found means pip installed into a different Python than the one python3 points at. Reinstalling with pip3 usually lines the two up.
  • Still stuck? Help me get the SQLCipher Python driver installed.
Write the script that opens the encrypted file
  • Create the script file next to your databases by running this command:
touch read_encrypted.py
  • Confirm the file landed in the right folder by running:
ls

You should see read_encrypted.py listed alongside encrypted.db and plaintext.db.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • In VS Code, click File in the top menu bar.
  • Click Open File.
  • Select read_encrypted.py, then click Open.
  • Open the encrypted file and hand over the key by copying this into read_encrypted.py:
from sqlcipher3 import dbapi2 as sqlite

# Open the encrypted database file
conn = sqlite.connect("encrypted.db")
cursor = conn.cursor()

# SQLCipher expects the key before any other statement on this connection
cursor.execute("PRAGMA key = 'correct-horse-battery-staple';")

print("Connection open. Key handed to SQLCipher.")

What does this code do?

  • from sqlcipher3 import dbapi2 as sqlite pulls in the SQLCipher driver under a familiar name, so every call below reads like ordinary SQLite code.
  • sqlite.connect opens the file on disk. Nothing has been decrypted yet.
  • PRAGMA key hands SQLCipher your passphrase. It has to run before any other statement on the connection, otherwise SQLCipher treats the file as unencrypted.
  • Save read_encrypted.py.
  • Run the script by running this command in your terminal:
python3 read_encrypted.py

You should see Connection open. Key handed to SQLCipher. printed in your terminal.

The key has not been checked yet

SQLCipher stores your passphrase on the connection and moves on. It has no way of knowing whether the passphrase is correct until something actually reads a page from the file.

That moment arrives in the next chunk, when you run your first query.

Script did not run?

  • An error saying the file cannot be opened means your terminal is not in the folder holding the script. Run ls and check the script is listed.
  • A traceback pointing at the import line means the driver installed into a different Python. Rerun the import check from the last substep.
  • Neither of those? Help me work out why my Python script will not run.
  • Read the rows out of the encrypted file by adding this to the bottom of read_encrypted.py:
# The key is only tested when SQLCipher actually reads a page from the file
try:
    cursor.execute("SELECT id, name, email FROM users;")
    for row in cursor.fetchall():
        print(row)
except sqlite.DatabaseError as error:
    print("Could not read the database:", error)

conn.close()

What does this code do?

  • SELECT id, name, email FROM users; is the first statement that touches real data. This is the moment your key gets tested.
  • cursor.fetchall() pulls every matching row back into Python. The loop prints one row per line.
  • The except sqlite.DatabaseError branch catches a rejected key and prints a readable message instead of dumping a traceback.
  • Save read_encrypted.py.
  • Run the script again by running this command:
python3 read_encrypted.py

Your three rows print out, names and emails and all, straight out of the file that strings showed you as noise.

Getting a database error instead of rows?

  • A message ending in file is not a database means the passphrase in your script does not match the one you built the file with.
  • Check the passphrase is spelled exactly correct-horse-battery-staple, hyphens included.
  • A message about no such table means the script opened a different file. Confirm the connect line names encrypted.db.

✔️ Awesome, I've got everything!

Great, double check you've saved read_encrypted.py.

ⓧ I'd like to double check the full code

from sqlcipher3 import dbapi2 as sqlite

# Open the encrypted database file
conn = sqlite.connect("encrypted.db")
cursor = conn.cursor()

# SQLCipher expects the key before any other statement on this connection
cursor.execute("PRAGMA key = 'correct-horse-battery-staple';")

print("Connection open. Key handed to SQLCipher.")

# The key is only tested when SQLCipher actually reads a page from the file
try:
    cursor.execute("SELECT id, name, email FROM users;")
    for row in cursor.fetchall():
        print(row)
except sqlite.DatabaseError as error:
    print("Could not read the database:", error)

conn.close()
Prove the key is doing the work

Your script has the right passphrase baked into it, so of course it works. The interesting question is what happens when the passphrase is wrong.

Before you change anything, what do you think a wrong key produces? Garbled rows, an empty result, or an outright error?

  • In read_encrypted.py, find this line:
cursor.execute("PRAGMA key = 'correct-horse-battery-staple';")
  • Replace the passphrase with a wrong one, so the line now looks like this:
cursor.execute("PRAGMA key = 'definitely-the-wrong-key';")
  • Save read_encrypted.py.
  • Find out what a wrong key gets you by running this command:
python3 read_encrypted.py

You should see Could not read the database: followed by a file is not a database error. No rows, no partial data, no garbled text.

Why a wrong key gives you nothing at all

SQLCipher encrypts every page of the file, including the header that SQLite reads to recognise a database. Decrypt that header with the wrong key and you get noise.

There is nothing partial to salvage. Either the key is right and you get rows, or it is wrong and you get an error.

  • Put the working passphrase back, so the line reads like this again:
cursor.execute("PRAGMA key = 'correct-horse-battery-staple';")
  • Save read_encrypted.py.
  • Confirm your rows come back by running this command:
python3 read_encrypted.py

Your three rows print again. One string in one line is the entire difference between readable data and noise.

You now have two files sitting side by side in the same folder. One hands its rows to anybody who opens it, and one needs a passphrase you control.

Secret mission

Rotate Your Encryption Key

Keys leak. Someone pastes one into a chat, or it rides along in a script pushed to a public repo. Rotate your encrypted database onto a fresh key, then watch the old one get turned away at the door.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. Everything in this project sits on your own machine, so nothing here costs money to leave in place.

Resources you used:

  • plaintext.db, the unencrypted SQLite database whose rows you read straight out of the raw file.
  • encrypted.db, the SQLCipher database holding the same three rows behind your key.
  • read_encrypted.py, the script that opens encrypted.db with the key and prints the rows.

Keep everything running

No action needed. Choose this if you're still actively building on top of the encrypted database.

  • Leave encrypted.db and read_encrypted.py where they are so you can query more rows later.
  • Move plaintext.db somewhere you won't mistake it for real data.

SQLCipher and the Python package you installed stay on your machine. Both are free to keep, so there is nothing to switch off.

Pause - I'll come back to this later

Clear away the file that leaks your rows and keep the rest ready for another day. Nothing runs in the background here, so there are no processes to shut down.

  • Delete the plaintext database by running this command (macOS/Linux):
rm plaintext.db
  • Delete the plaintext database by running this command (Windows):
del plaintext.db
  • Confirm that plaintext.db no longer appears in your folder.
  • Leave encrypted.db and read_encrypted.py in place for next time.

Delete - I don't want to use this again

Remove all three project files and start fresh. Choose this if you don't plan to come back to the databases or the script.

  • Delete both databases and the script by running this command (macOS/Linux):
rm plaintext.db encrypted.db read_encrypted.py
  • Delete both databases and the script by running this command (Windows):
del plaintext.db encrypted.db read_encrypted.py
  • Confirm that none of the three files appear in your folder any more.

Command says no such file?

Your terminal is probably sitting in a different folder from the one holding the files. Move into the folder you created the databases in, then run the delete command again.

Still stuck? Help me find where my database files are.

Nice Work!

Nice Work!

Nice work! You just proved how little a plain SQLite file protects your data. Then you locked the same rows behind a SQLCipher key and watched the raw bytes turn to noise.

You've learned how to:

  • Build a plaintext database and pull your own names and emails straight out of the raw plaintext.db file with strings.
  • Create an encrypted database with a key, query it normally, and see plain sqlite3 refuse to open encrypted.db at all.
  • Write a Python script that reads your encrypted rows with the correct key, then fails cleanly the moment the key is wrong.
  • Secret Mission: Take on an optional challenge that pushes your encryption skills further.

Ready to quiz yourself?