🌍 Python · subject

Python Password Manager Project Syllabus

The Password Manager Project syllabus for Python in full: 6 chapters, 11 topics and 22 sub-topics, every one listed below, plus 50 Password Manager Project flashcards with answers.

6Chapters
11Topics
22Sub-topics
50Flashcards

Password Manager Project syllabus: all 6 chapters

Expand any chapter to see its topics and sub-topics.

  1. Setup Environment

    2 topics
    • Install Required Libraries
      • Install cryptography library
      • Install SQLite library
    • Create Project Structure
      • Create main Python file
      • Create a directory for storing database file
  2. Database Setup

    1 topic
    • Initialize SQLite Database
      • Create connection to SQLite database
      • Create table for storing passwords
  3. Encryption and Decryption

    3 topics
    • Setup Encryption
      • Generate encryption key
      • Store encryption key securely
    • Encrypt Passwords
      • Encrypt passwords before storing in database
    • Decrypt Passwords
      • Decrypt passwords when retrieving from database
  4. User Interface

    1 topic
    • Command-Line Interface
      • Create function to add new password
      • Create function to retrieve password
      • Create function to list all stored accounts
  5. Testing and Debugging

    2 topics
    • Test Encryption and Decryption
      • Verify passwords are encrypted before storage
      • Verify passwords are correctly decrypted
    • Test Database Operations
      • Check adding new passwords
      • Check retrieving passwords
      • Check listing all accounts
  6. Finalization

    2 topics
    • Secure Storage
      • Ensure encryption key is stored securely
      • Implement additional security measures if necessary
    • Documentation
      • Document code and usage
      • Create README file

Python Password Manager Project flashcards — 50 questions with answers

  1. Which Python library is the standard choice for symmetric encryption in a password manager project, and how is it installed?

    The `cryptography` library. Install it with `pip install cryptography`. It provides the `Fernet` class used for authenticated symmetric encryption.

  2. What pip command installs all three common dependencies for a CLI password manager (encryption, env config, and tabular output)?

    `pip install cryptography python-dotenv tabulate` — `cryptography` for Fernet encryption, `python-dotenv` to load secrets from a `.env` file, and `tabulate` to print stored entries as a table.

  3. Why is the `sqlite3` module not listed in `requirements.txt` for the password manager?

    Because `sqlite3` is part of the Python standard library (built into CPython), so it does not need to be installed via pip and should not appear in `requirements.txt`.

  4. What is the purpose of a `requirements.txt` file in the project structure?

    It lists the project's third-party dependencies (with optional pinned versions) so the environment can be reproduced exactly with `pip install -r requirements.txt`.

  5. In a typical password manager project structure, what is the role of a `main.py` (or `cli.py`) file?

    It is the entry point that parses command-line arguments and dispatches to the add/get/list/delete functions, tying together the database and encryption modules.

  6. Why should encryption logic be separated into its own module (e.g., `crypto.py`) from database logic (`db.py`)?

    Separation of concerns: it keeps responsibilities isolated, makes each module independently testable, and lets you change the storage or encryption implementation without affecting the other.

  7. What is the benefit of creating and activating a Python virtual environment before building the project?

    It isolates the project's dependencies from the global Python installation, preventing version conflicts and making the project reproducible. Created with `python -m venv venv`.

  8. Which Python standard-library module is used to connect to and operate on the SQLite database?

    The `sqlite3` module. You create a connection with `sqlite3.connect('passwords.db')` and obtain a cursor to execute SQL.

  9. Write the SQL statement to create a `passwords` table storing an id, service name, username, and an encrypted password.

    $$\texttt{CREATE TABLE IF NOT EXISTS passwords (id INTEGER PRIMARY KEY AUTOINCREMENT, service TEXT NOT NULL, username TEXT NOT NULL, password BLOB NOT NULL);}$$

  10. After executing INSERT, UPDATE, or DELETE statements with sqlite3, what method must you call to persist the changes?

    `conn.commit()` — without committing, the changes remain in the transaction and are lost when the connection closes.

  11. Why is the `IF NOT EXISTS` clause used in the `CREATE TABLE` statement during database initialization?

    It makes initialization idempotent: the table is created only if it does not already exist, so running the init routine multiple times does not raise an error or overwrite data.

  12. What SQLite column type should store the encrypted password bytes, and why?

    `BLOB`, because Fernet output is raw bytes (a token). Storing it as BLOB preserves the binary token exactly; alternatively the token can be decoded to text and stored as TEXT.

  13. Why should you use parameterized queries (e.g., `cursor.execute(sql, (value,))`) instead of string formatting in SQL?

    Parameterized queries prevent SQL injection by safely binding values, and they correctly handle quoting and special characters in the data.

  14. What is symmetric encryption, and why is it appropriate for a personal password manager?

    Symmetric encryption uses the same single key to encrypt and decrypt data. It is appropriate because a single user holds the one key for both storing and retrieving their own passwords.

  15. What does the `Fernet` class in the `cryptography` library provide?

    Fernet provides authenticated symmetric encryption: it encrypts data with AES-128 in CBC mode, adds an HMAC for integrity, includes a timestamp, and produces a URL-safe base64 token.

  16. How do you generate a new Fernet encryption key in Python?

    `from cryptography.fernet import Fernet` then `key = Fernet.generate_key()`. This returns a 32-byte, URL-safe base64-encoded key.

  17. How is a Fernet cipher object instantiated from an existing key?

    `cipher = Fernet(key)` where `key` is the previously generated base64-encoded key (as bytes). The same key must be reused to decrypt previously encrypted data.

  18. What underlying symmetric cipher and mode does Fernet use, and what key size?

    Fernet uses AES in CBC mode with a 128-bit ($128$-bit) key for encryption, plus HMAC-SHA256 for authentication. The full Fernet key is 256 bits split into a signing key and an encryption key.

  19. What is the danger of losing the Fernet key after passwords have been encrypted with it?

    Without the key, the encrypted data is permanently unrecoverable — decryption is computationally infeasible. There is no recovery, so the key must be backed up securely.

  20. Which Fernet method encrypts data, and what input type does it require?

    `cipher.encrypt(data)` — it requires the plaintext as `bytes`. A string must first be encoded, e.g. `password.encode()`.

Show the other 30 Password Manager Project flashcards
  1. Write the two-line Python pattern to encrypt a plaintext password string into a Fernet token.

    ``` token = cipher.encrypt(password.encode()) # token is bytes; store in the database ```

  2. What does a Fernet token contain besides the ciphertext?

    A version byte, a timestamp (when the token was created), the 16-byte IV, the AES-CBC ciphertext, and a 32-byte HMAC signature — all base64url-encoded together.

  3. Why must a string be encoded with `.encode()` before passing it to `Fernet.encrypt()`?

    Because `Fernet.encrypt()` operates on `bytes`, not `str`. `.encode()` converts the string to UTF-8 bytes; passing a `str` raises a `TypeError`.

  4. Which Fernet method decrypts a token, and what does it return?

    `cipher.decrypt(token)` returns the original plaintext as `bytes`. Call `.decode()` to convert it back to a string.

  5. Write the Python pattern to decrypt a stored Fernet token back into a readable password string.

    ``` plaintext = cipher.decrypt(token).decode() ```

  6. What exception does Fernet raise when a token is invalid, tampered with, or decrypted with the wrong key?

    `cryptography.fernet.InvalidToken`. It is raised when the HMAC verification fails or the token is malformed, which protects against tampering and wrong-key use.

  7. How does Fernet guarantee that decrypted data has not been tampered with?

    It verifies the HMAC-SHA256 signature before decrypting. If the signature does not match the ciphertext, it raises `InvalidToken` and never returns altered plaintext — providing authenticated encryption.

  8. What is the relationship between the key used to encrypt and the key used to decrypt in Fernet?

    They must be identical. Fernet is symmetric, so the exact same key that encrypted a token is required to decrypt it; any other key raises `InvalidToken`.

  9. What does a command-line interface (CLI) provide as the user-facing layer of the password manager?

    A text-based interface where the user runs commands (add, get, list, delete) with arguments in the terminal to manage stored credentials without a GUI.

  10. Which standard-library module is recommended for parsing CLI arguments, and what is its main class?

    The `argparse` module. Its main class is `argparse.ArgumentParser`, which defines arguments/subcommands and produces a parsed namespace via `parser.parse_args()`.

  11. How do you set up multiple commands like `add`, `get`, and `list` using argparse?

    Use subparsers: `subparsers = parser.add_subparsers(dest='command')`, then `subparsers.add_parser('add')`, etc. Each subparser can define its own arguments.

  12. Why should the master password or key be read using `getpass.getpass()` rather than `input()` in the CLI?

    `getpass.getpass()` reads input without echoing it to the terminal, preventing the master password from being displayed on screen or captured in shell history.

  13. In the CLI, what is the typical flow when a user runs the `add` command?

    Read the service, username, and password; encrypt the password with Fernet; insert the service, username, and encrypted token into the SQLite table; then commit the transaction.

  14. In the CLI, what is the typical flow when a user runs the `get` command for a service?

    Query the database for the row matching the service; retrieve the encrypted token; decrypt it with the Fernet cipher; then display the username and decrypted password.

  15. What is a round-trip test for encryption and decryption?

    A test that encrypts a known plaintext and then decrypts the resulting token, asserting that the decrypted output equals the original plaintext: `decrypt(encrypt(p)) == p`.

  16. Write an assertion that verifies Fernet encryption/decryption round-trips correctly for the password "S3cret!".

    ``` assert cipher.decrypt(cipher.encrypt(b"S3cret!")) == b"S3cret!" ```

  17. When testing encryption, why should you assert that the ciphertext is NOT equal to the plaintext?

    To confirm the data was actually transformed (encrypted) rather than stored in plain form: `assert token != b"S3cret!"` guards against an accidental no-op encryption.

  18. How do you write a test asserting that decrypting with a wrong key raises an error?

    Use `pytest.raises(InvalidToken)`: encrypt with one key, then call `Fernet(other_key).decrypt(token)` inside the context manager and assert that `InvalidToken` is raised.

  19. Why is it useful to encrypt the same plaintext twice and observe that the tokens differ?

    Fernet includes a random 16-byte IV and a timestamp, so encrypting identical plaintext yields different tokens each time. This non-determinism prevents attackers from detecting repeated passwords.

  20. What is the advantage of using an in-memory SQLite database (`sqlite3.connect(':memory:')`) in tests?

    It is fast, requires no file cleanup, and gives each test an isolated, fresh database that disappears when the connection closes — avoiding interference between tests.

  21. Describe a basic test for the database insert-and-retrieve operation.

    Insert a known row (service, username, encrypted password), query it back by service, and assert the returned values match what was inserted — verifying the storage layer works end to end.

  22. Why should each database test start with a freshly initialized schema?

    To ensure test isolation and repeatability: a fresh schema (e.g., in-memory DB or setup fixture) prevents leftover data from previous tests causing false passes or failures.

  23. What pytest fixture pattern is commonly used to provide a clean database connection to each test?

    A fixture decorated with `@pytest.fixture` that creates an in-memory connection, initializes the schema, `yield`s the connection to the test, and closes it afterward for teardown.

  24. What does "secure storage" mean in the context of this password manager?

    Passwords are never written to disk in plaintext — only encrypted Fernet tokens are stored in the database, and the encryption key is kept separate from that database.

  25. Why should the encryption key NOT be stored in the same SQLite database as the encrypted passwords?

    Because anyone who obtains the database file would then have both the ciphertext and the key, defeating the encryption. The key must be stored separately (e.g., a protected key file, environment variable, or OS keyring).

  26. How can `python-dotenv` and a `.env` file contribute to secure storage of the key?

    The key (or its path) is placed in a `.env` file loaded at runtime via `load_dotenv()`, keeping it out of source code. The `.env` file is added to `.gitignore` so it is never committed.

  27. Why must files like `.env`, the key file, and `*.db` be added to `.gitignore`?

    To prevent accidentally committing secrets and personal password data to version control, where they could be exposed publicly or in the repository history.

  28. What file permission practice helps protect a key file on a Unix system?

    Restrict it to owner-only read/write with `chmod 600 keyfile` (octal $600$), so other users on the system cannot read the encryption key.

  29. What two essential pieces of information should the project README/documentation explain for a new user?

    How to install dependencies and set up the key (installation/setup), and how to use each CLI command (add, get, list, delete) — typically with example commands.

  30. Why is documenting the key backup and recovery procedure critical for a password manager?

    Because losing the encryption key makes all stored passwords permanently unrecoverable. The docs must warn users to back up the key safely, since there is no reset or recovery path.

Python Password Manager Project FAQ

What is in the Python Password Manager Project syllabus?

Python Password Manager Project is split into 6 chapters: Setup Environment, Database Setup, Encryption and Decryption, User Interface, Testing and Debugging and Finalization. Together they contain 11 topics and 22 sub-topics.

How many chapters are in Python Password Manager Project?

6 chapters, containing 11 topics and 22 sub-topics. The largest chapter is Encryption and Decryption, with 3 topics.

Are there flashcards for Python Password Manager Project?

Yes — a 50-card Password Manager Project deck, printed in full in the flashcards section of this page and available in the Examius app with spaced repetition. The free plan covers one exam of your choice, including its flashcards; Examius Pro, a one-time purchase, unlocks every other exam and deck.