PyVault is a local password and secrets manager written in Python.
The goal of this project is to build a simple, private and secure way to store sensitive information locally while learning how encryption, databases, web development and application architecture work.
⚠️ PyVault is currently under development.
- 🔑 Generate Fernet encryption keys
- 🛡️ On Windows, protect the key on-disk with DPAPI (
dpapi_utils.py) instead of storing it in plain text - 🔐 Encrypt passwords using Fernet, then store them in a SQLite database (
secret/passwords.db) - 🔓 Decrypt and retrieve stored passwords (handles duplicate website entries)
- 📋 List all saved entries
- 🔎 Search stored passwords
- 🗑️ Delete passwords
- 📤 Export passwords as a zip archive
- 🖥️ Simple CLI interface with ASCII banner
- 🧪 Unit tests (
tests/) - 📊 Encryption / decryption benchmark (Jupyter notebook)
A static site deployed on GitHub Pages that mirrors PyVault's features in the browser:
- 🖥️ An interactive terminal reproducing the CLI (
python main.py) directly in the browser - 🔐 The real Fernet algorithm re-implemented in JavaScript (
fernet.js) using the Web Crypto API — data produced in the browser can be decrypted by the Python CLI and vice-versa - 💾 Vault entries stored in the browser's
localStorage - 📤 Zip export built directly in the browser
- 🌍 Bilingual Français / 日本語 interface with an i18n system
- 📄 README, ideas, tests and "about" pages rendered as a single-page site
- 🪟 Windows benefits from DPAPI key protection
- 🖥️ macOS and Linux are supported by the same clear-screen helper logic
I wanted to create a project that was more than a simple Python script.
PyVault is also a way for me to learn how different parts of a real application work together:
- Python
- Cryptography
- Databases
- Web development (HTML / CSS / JavaScript)
- APIs
- Authentication
- Security
- Software architecture
- Performance testing
Instead of only following tutorials, I want to build the project myself, encounter problems, research solutions and document the entire process.
The architecture below shows both the current project and the features planned for the future.
flowchart TD
User["👤 User"]
PyVault["🔐 PyVault"]
CLI["🖥️ CLI<br/>CURRENT"]
WebTool["🖥️ Web Tool (docs/)<br/>CURRENT"]
GenerateKey["🔑 Generate Key<br/>CURRENT"]
AddPassword["🔐 Add Password<br/>CURRENT"]
ListPasswords["📋 List Passwords<br/>CURRENT"]
DecryptPassword["🔓 Decrypt Password<br/>CURRENT"]
Fernet["🔒 Fernet Encryption<br/>CURRENT"]
JsFernet["🔒 Fernet in JS (fernet.js)<br/>CURRENT"]
KeyFile["📄 key.txt (DPAPI on Windows)<br/>CURRENT"]
Database["🗄️ SQLite (secret/passwords.db)<br/>CURRENT"]
DPAPI["🛡️ DPAPI Key Protection (win32)<br/>CURRENT"]
Search["🔎 Search Passwords<br/>CURRENT"]
Delete["🗑️ Delete Password<br/>CURRENT"]
Export["📤 Export Passwords<br/>CURRENT"]
Tests["🧪 Unit Tests<br/>CURRENT"]
Benchmark["📊 Benchmark<br/>CURRENT"]
I18n["🌍 FR / JA i18n<br/>CURRENT"]
MasterPassword["🔑 Master Password<br/>PLANNED"]
Vault["🔐 Vault System<br/>PLANNED"]
API["🌐 Local API<br/>PLANNED"]
FastAPI["⚡ FastAPI<br/>PLANNED"]
Web["🖥️ Web Interface<br/>PLANNED"]
User --> PyVault
PyVault --> CLI
PyVault --> WebTool
CLI --> GenerateKey
CLI --> AddPassword
CLI --> ListPasswords
CLI --> DecryptPassword
GenerateKey --> Fernet
GenerateKey --> KeyFile
GenerateKey --> DPAPI
AddPassword --> Fernet
Fernet --> Database
DecryptPassword --> Database
ListPasswords --> Database
CLI --> Search
CLI --> Delete
CLI --> Export
WebTool --> GenerateKey
WebTool --> AddPassword
WebTool --> ListPasswords
WebTool --> DecryptPassword
WebTool --> JsFernet
JsFernet --> I18n
MasterPassword -.-> Vault
Vault -.-> SQLite
API -.-> FastAPI
FastAPI -.-> Vault
Web -.-> API
Tests -.-> PyVault
Benchmark -.-> Fernet
CURRENT = already implemented
PLANNED = planned for a future version
PyVault/
│
├── commands/ ← CLI commands
│ ├── add.py
│ ├── decrypt.py
│ ├── delete.py
│ ├── export.py
│ ├── generate_key.py
│ ├── list.py
│ └── search.py
│
├── tests/ ← unit tests
│ ├── add_test.py
│ ├── benchmark.ipynb ← Jupyter benchmark
│ ├── decrypt_test.py
│ ├── test_system_info.py
│ └── test_unitary/
│
├── docs/ ← static website (GitHub Pages)
│ ├── index.html ← single-page site (FR / JA)
│ ├── robots.txt
│ ├── sitemap.xml
│ └── static/
│ ├── css/styles.css
│ └── js/
│ ├── fernet.js ← Fernet re-implemented in JS (Web Crypto)
│ ├── tool.js ← interactive browser terminal
│ ├── main.js ← page routing & mermaid
│ └── i18n.js ← FR / JA translations
│
├── secret/ ← password storage (DB + legacy files)
│ ├── passwords.db ← SQLite database
│ └── github.txt
│
├── images/
│ └── new_benchmark.png ← encryption/decryption benchmark
│
├── examples/
│
├── .github/workflows/ ← GitHub Pages deploy (`static.yml`)
│
├── idea/
│ └── idea.md ← ideas file
│
├── japanese/ ← Japanese version of the code
│
├── dpapi_utils.py ← DPAPI protect / unprotect helper (Windows)
├── main.py
├── system_info.py
├── key.txt ← protected Fernet key
├── SECURITY.md
├── .gitignore
├── LICENSE
└── README.md
📌 Note:
add.py,list.pyanddecrypt.pynow store passwords in a SQLite database (secret/passwords.db). Thesearch.pyanddelete.pycommands still operate on the legacy per-website files insecret/.
PyVault uses Fernet from the cryptography library.
A key is generated with:
key=Fernet.generate_key()The key is stored locally in key.txt. On Windows, the raw key is wrapped with the DPAPI functions in dpapi_utils.py (protect() / unprotect()) so it is not stored in plain text on disk. On other platforms the key is stored as-is.
When adding a password, PyVault encrypts it before storing it:
cipher=Fernet(key.encode())
encrypted=cipher.encrypt(passwd.encode())The encrypted password is then inserted into the passwords table of the SQLite database:
secret/passwords.db
The password itself is not stored in plain text.
The browser-side terminal re-implements the same Fernet scheme in JavaScript (docs/static/js/fernet.js) using the Web Crypto API (AES-CBC + HMAC-SHA256). Because it follows the Fernet token format, tokens created in the browser are compatible with the Python CLI and the other way around.
⚠️ This is an early prototype. Even with DPAPI key protection on Windows, the system is not considered secure enough for production use (no master password yet).
PyVault includes a benchmark using Jupyter Notebook to measure the performance of Fernet encryption and decryption.
The benchmark tests multiple data sizes, from a few bytes up to 1 MB, and performs multiple iterations for each size.
The results are visualized in the following graph:
The benchmark helps measure how encryption and decryption performance changes as the amount of data increases.
The benchmark notebook is located at:
tests/benchmark.ipynb
It can be used to experiment with PyVault's encryption system and compare future implementations.
Clone the repository:
git clone https://github.com/KirobotDev/PyVault.git
cd PyVaultCreate a virtual environment:
python -m venv .venv
.venv\Scripts\activatepython3 -m venv .venv
source .venv/bin/activateInstall dependencies:
pip install -r requirements.txtStart PyVault:
python main.pyYou will see:
S. [Stars Project] 0. [Generate Key (Obliged)] Q. [Leave]
1. [Add Password] 4. [Export (Zipfiles)]
2. [List Pswd] 5. [Delete Passwd]
3. [Decrypt Pswd] 6. [Search Website]
Choice: Choose:
0
PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).
Choose:
1
PyVault will ask for:
Enter the name of your website (e.g. github):
Enter your password:
The password will be encrypted and stored in the SQLite database (secret/passwords.db).
Choose:
2
PyVault will display every website stored in the database.
Choose:
3
PyVault will ask for:
Enter the name of the website:
If several passwords exist for the same website, you will be asked to pick one. It will then display:
Website: github
Your password is: your_password_here
The interactive terminal is available on the site's Test page (or by opening docs/index.html locally). It behaves exactly like the CLI but runs entirely in your browser:
0 Generate a key
1 Add a password
2 List entries
3 Decrypt a password
4 Export (zip)
5 Delete an entry
6 Search a site
s Open the GitHub repo
q Quit
help / clear
Entries are saved in the browser's localStorage. Toggle the interface between Français and 日本語 with the language button in the top bar.
Unit tests are available in the tests/ folder.
Run them with:
python -m unittest tests.test_system_infoYou can also inspect the manual sanity tests in tests/add_test.py and tests/decrypt_test.py which encrypt and decrypt a fixed password with a hardcoded key.
The benchmark is available as a Jupyter Notebook.
Install Jupyter if necessary:
pip install jupyterStart Jupyter:
jupyter notebookThen open:
tests/benchmark.ipynb
The benchmark measures:
- Encryption speed
- Decryption speed
- Different data sizes (1 B → 1 MB)
- Average execution time
- Performance scaling
- Generate Fernet key
- Save key locally
- Encrypt passwords
- Store encrypted data
- Store website information
- Basic CLI
- Decrypt passwords
- List saved entries
- Search passwords
- Delete passwords
- Export passwords
- Web tool in the browser (
docs/) - Fernet re-implemented in JavaScript (Web Crypto)
- Bilingual FR / JA website (i18n)
- Load existing key automatically
- DPAPI key protection on Windows
- Master password
- KDF-based key derivation
- Vault locking
- Failed-attempt protection
- Security tests
- Security policy (
SECURITY.md)
- SQLite
- Database models
- Encrypted database fields
- Data validation
- Database migrations
- Migrate
searchanddeleteto the database
- Local API
- FastAPI
- Authentication
- API documentation
- Full web interface
- Vault dashboard
- Password manager UI
- API integration
- Complete documentation
- Automated tests
- GitHub Pages deployment (CI/CD)
- Security review
- PyPI package
PyVault is an experimental learning project and is not intended for production use.
On Windows, the Fernet key stored in key.txt is wrapped with the DPAPI functions in dpapi_utils.py, which binds access to the Windows user account. Without a master password, however, anyone with access to the user session and files could still recover the data.
See SECURITY.md for the supported versions and how to responsibly report a vulnerability.
PyVault has a static website in the docs/ folder, automatically deployed to GitHub Pages on every push to main (see .github/workflows/static.yml).
It includes:
- An interactive browser terminal reproducing the CLI
- The README, ideas, tests and about pages
- A Français / 日本語 language switch
PyVault isn't only a software project.
I also want to document the process of building it.
The documentation will cover:
Idea
↓
First prototype
↓
Encryption
↓
Problems
↓
Research
↓
Solutions
↓
Security
↓
Testing
↓
Benchmarking
↓
Final application
The objective is to show what I learned, what went wrong and how the project evolved over time.
Current version:0.2.0-dev
PyVault is currently an experimental project.
The project is actively being developed and its architecture may change significantly.
Contributions, suggestions and bug reports are welcome.
If you find a problem, feel free to open an issue.
For larger changes, please open an issue first to discuss the idea.
Good first issues are listed in main.md, including adding a Japanese codebase, testing macOS, and creating a custom encryption algorithm.
PyVault is released under the MIT License.
See LICENSE for more information.
xql
GitHub: https://github.com/KirobotDev
Built with Python 🐍 & JavaScript ⚡
Learning by building.
