Repository files navigation

🔐 PyVault

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.


✨ Features

CLI — python main.py

  • 🔑 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)

Web — docs/

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

Platform support

  • 🪟 Windows benefits from DPAPI key protection
  • 🖥️ macOS and Linux are supported by the same clear-screen helper logic

🧠 Why PyVault?

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.


🏗️ Architecture

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
Loading

CURRENT = already implemented

PLANNED = planned for a future version


📁 Current Project Structure

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.py and decrypt.py now store passwords in a SQLite database (secret/passwords.db). The search.py and delete.py commands still operate on the legacy per-website files in secret/.


🔐 Current Encryption System

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).


📊 Benchmark

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:

PyVault Encryption / Decryption Benchmark

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.


🚀 Installation

Clone the repository:

git clone https://github.com/KirobotDev/PyVault.git
cd PyVault

Create a virtual environment:

Windows

python -m venv .venv
.venv\Scripts\activate

Linux / macOS

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

▶️ Usage

CLI

Start PyVault:

python main.py

You 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: 

Generate a key

Choose:

0

PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).

Add a password

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).

List saved entries

Choose:

2

PyVault will display every website stored in the database.

Decrypt a password

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

Web tool (browser)

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.


🧪 Running Tests

Unit tests are available in the tests/ folder.

Run them with:

python -m unittest tests.test_system_info

You 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.


📊 Running the Benchmark

The benchmark is available as a Jupyter Notebook.

Install Jupyter if necessary:

pip install jupyter

Start Jupyter:

jupyter notebook

Then open:

tests/benchmark.ipynb

The benchmark measures:

  • Encryption speed
  • Decryption speed
  • Different data sizes (1 B → 1 MB)
  • Average execution time
  • Performance scaling

🛠️ Roadmap

Phase 1 — Prototype

  • Generate Fernet key
  • Save key locally
  • Encrypt passwords
  • Store encrypted data
  • Store website information
  • Basic CLI
  • Decrypt passwords
  • List saved entries

Phase 2 — Vault

  • 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

Phase 3 — Security

  • DPAPI key protection on Windows
  • Master password
  • KDF-based key derivation
  • Vault locking
  • Failed-attempt protection
  • Security tests
  • Security policy (SECURITY.md)

Phase 4 — Database

  • SQLite
  • Database models
  • Encrypted database fields
  • Data validation
  • Database migrations
  • Migrate search and delete to the database

Phase 5 — API

  • Local API
  • FastAPI
  • Authentication
  • API documentation

Phase 6 — Interface

  • Full web interface
  • Vault dashboard
  • Password manager UI
  • API integration

Phase 7 — Open Source

  • Complete documentation
  • Automated tests
  • GitHub Pages deployment (CI/CD)
  • Security review
  • PyPI package

🔒 Security

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.


🌍 Website

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

📚 Development Story

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.


🧪 Status

Current version:0.2.0-dev

PyVault is currently an experimental project.

The project is actively being developed and its architecture may change significantly.


🤝 Contributing

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.


📄 License

PyVault is released under the MIT License.

See LICENSE for more information.


👤 Author

xql

GitHub: https://github.com/KirobotDev


Built with Python 🐍 & JavaScript ⚡

Learning by building.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

🔐 PyVault

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.


✨ Features

CLI — python main.py

  • 🔑 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)

Web — docs/

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

Platform support

  • 🪟 Windows benefits from DPAPI key protection
  • 🖥️ macOS and Linux are supported by the same clear-screen helper logic

🧠 Why PyVault?

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.


🏗️ Architecture

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
Loading

CURRENT = already implemented

PLANNED = planned for a future version


📁 Current Project Structure

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.py and decrypt.py now store passwords in a SQLite database (secret/passwords.db). The search.py and delete.py commands still operate on the legacy per-website files in secret/.


🔐 Current Encryption System

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).


📊 Benchmark

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:

PyVault Encryption / Decryption Benchmark

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.


🚀 Installation

Clone the repository:

git clone https://github.com/KirobotDev/PyVault.git
cd PyVault

Create a virtual environment:

Windows

python -m venv .venv
.venv\Scripts\activate

Linux / macOS

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

▶️ Usage

CLI

Start PyVault:

python main.py

You 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: 

Generate a key

Choose:

0

PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).

Add a password

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).

List saved entries

Choose:

2

PyVault will display every website stored in the database.

Decrypt a password

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

Web tool (browser)

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.


🧪 Running Tests

Unit tests are available in the tests/ folder.

Run them with:

python -m unittest tests.test_system_info

You 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.


📊 Running the Benchmark

The benchmark is available as a Jupyter Notebook.

Install Jupyter if necessary:

pip install jupyter

Start Jupyter:

jupyter notebook

Then open:

tests/benchmark.ipynb

The benchmark measures:

  • Encryption speed
  • Decryption speed
  • Different data sizes (1 B → 1 MB)
  • Average execution time
  • Performance scaling

🛠️ Roadmap

Phase 1 — Prototype

  • Generate Fernet key
  • Save key locally
  • Encrypt passwords
  • Store encrypted data
  • Store website information
  • Basic CLI
  • Decrypt passwords
  • List saved entries

Phase 2 — Vault

  • 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

Phase 3 — Security

  • DPAPI key protection on Windows
  • Master password
  • KDF-based key derivation
  • Vault locking
  • Failed-attempt protection
  • Security tests
  • Security policy (SECURITY.md)

Phase 4 — Database

  • SQLite
  • Database models
  • Encrypted database fields
  • Data validation
  • Database migrations
  • Migrate search and delete to the database

Phase 5 — API

  • Local API
  • FastAPI
  • Authentication
  • API documentation

Phase 6 — Interface

  • Full web interface
  • Vault dashboard
  • Password manager UI
  • API integration

Phase 7 — Open Source

  • Complete documentation
  • Automated tests
  • GitHub Pages deployment (CI/CD)
  • Security review
  • PyPI package

🔒 Security

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.


🌍 Website

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

📚 Development Story

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.


🧪 Status

Current version:0.2.0-dev

PyVault is currently an experimental project.

The project is actively being developed and its architecture may change significantly.


🤝 Contributing

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.


📄 License

PyVault is released under the MIT License.

See LICENSE for more information.


👤 Author

xql

GitHub: https://github.com/KirobotDev


Built with Python 🐍 & JavaScript ⚡

Learning by building.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

🔐 PyVault

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.


✨ Features

CLI — python main.py

  • 🔑 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)

Web — docs/

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

Platform support

  • 🪟 Windows benefits from DPAPI key protection
  • 🖥️ macOS and Linux are supported by the same clear-screen helper logic

🧠 Why PyVault?

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.


🏗️ Architecture

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
Loading

CURRENT = already implemented

PLANNED = planned for a future version


📁 Current Project Structure

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.py and decrypt.py now store passwords in a SQLite database (secret/passwords.db). The search.py and delete.py commands still operate on the legacy per-website files in secret/.


🔐 Current Encryption System

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).


📊 Benchmark

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:

PyVault Encryption / Decryption Benchmark

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.


🚀 Installation

Clone the repository:

git clone https://github.com/KirobotDev/PyVault.git
cd PyVault

Create a virtual environment:

Windows

python -m venv .venv
.venv\Scripts\activate

Linux / macOS

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

▶️ Usage

CLI

Start PyVault:

python main.py

You 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: 

Generate a key

Choose:

0

PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).

Add a password

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).

List saved entries

Choose:

2

PyVault will display every website stored in the database.

Decrypt a password

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

Web tool (browser)

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.


🧪 Running Tests

Unit tests are available in the tests/ folder.

Run them with:

python -m unittest tests.test_system_info

You 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.


📊 Running the Benchmark

The benchmark is available as a Jupyter Notebook.

Install Jupyter if necessary:

pip install jupyter

Start Jupyter:

jupyter notebook

Then open:

tests/benchmark.ipynb

The benchmark measures:

  • Encryption speed
  • Decryption speed
  • Different data sizes (1 B → 1 MB)
  • Average execution time
  • Performance scaling

🛠️ Roadmap

Phase 1 — Prototype

  • Generate Fernet key
  • Save key locally
  • Encrypt passwords
  • Store encrypted data
  • Store website information
  • Basic CLI
  • Decrypt passwords
  • List saved entries

Phase 2 — Vault

  • 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

Phase 3 — Security

  • DPAPI key protection on Windows
  • Master password
  • KDF-based key derivation
  • Vault locking
  • Failed-attempt protection
  • Security tests
  • Security policy (SECURITY.md)

Phase 4 — Database

  • SQLite
  • Database models
  • Encrypted database fields
  • Data validation
  • Database migrations
  • Migrate search and delete to the database

Phase 5 — API

  • Local API
  • FastAPI
  • Authentication
  • API documentation

Phase 6 — Interface

  • Full web interface
  • Vault dashboard
  • Password manager UI
  • API integration

Phase 7 — Open Source

  • Complete documentation
  • Automated tests
  • GitHub Pages deployment (CI/CD)
  • Security review
  • PyPI package

🔒 Security

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.


🌍 Website

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

📚 Development Story

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.


🧪 Status

Current version:0.2.0-dev

PyVault is currently an experimental project.

The project is actively being developed and its architecture may change significantly.


🤝 Contributing

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.


📄 License

PyVault is released under the MIT License.

See LICENSE for more information.


👤 Author

xql

GitHub: https://github.com/KirobotDev


Built with Python 🐍 & JavaScript ⚡

Learning by building.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

🔐 PyVault

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.


✨ Features

CLI — python main.py

  • 🔑 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)

Web — docs/

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

Platform support

  • 🪟 Windows benefits from DPAPI key protection
  • 🖥️ macOS and Linux are supported by the same clear-screen helper logic

🧠 Why PyVault?

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.


🏗️ Architecture

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
Loading

CURRENT = already implemented

PLANNED = planned for a future version


📁 Current Project Structure

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.py and decrypt.py now store passwords in a SQLite database (secret/passwords.db). The search.py and delete.py commands still operate on the legacy per-website files in secret/.


🔐 Current Encryption System

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).


📊 Benchmark

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:

PyVault Encryption / Decryption Benchmark

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.


🚀 Installation

Clone the repository:

git clone https://github.com/KirobotDev/PyVault.git
cd PyVault

Create a virtual environment:

Windows

python -m venv .venv
.venv\Scripts\activate

Linux / macOS

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

▶️ Usage

CLI

Start PyVault:

python main.py

You 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: 

Generate a key

Choose:

0

PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).

Add a password

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).

List saved entries

Choose:

2

PyVault will display every website stored in the database.

Decrypt a password

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

Web tool (browser)

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.


🧪 Running Tests

Unit tests are available in the tests/ folder.

Run them with:

python -m unittest tests.test_system_info

You 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.


📊 Running the Benchmark

The benchmark is available as a Jupyter Notebook.

Install Jupyter if necessary:

pip install jupyter

Start Jupyter:

jupyter notebook

Then open:

tests/benchmark.ipynb

The benchmark measures:

  • Encryption speed
  • Decryption speed
  • Different data sizes (1 B → 1 MB)
  • Average execution time
  • Performance scaling

🛠️ Roadmap

Phase 1 — Prototype

  • Generate Fernet key
  • Save key locally
  • Encrypt passwords
  • Store encrypted data
  • Store website information
  • Basic CLI
  • Decrypt passwords
  • List saved entries

Phase 2 — Vault

  • 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

Phase 3 — Security

  • DPAPI key protection on Windows
  • Master password
  • KDF-based key derivation
  • Vault locking
  • Failed-attempt protection
  • Security tests
  • Security policy (SECURITY.md)

Phase 4 — Database

  • SQLite
  • Database models
  • Encrypted database fields
  • Data validation
  • Database migrations
  • Migrate search and delete to the database

Phase 5 — API

  • Local API
  • FastAPI
  • Authentication
  • API documentation

Phase 6 — Interface

  • Full web interface
  • Vault dashboard
  • Password manager UI
  • API integration

Phase 7 — Open Source

  • Complete documentation
  • Automated tests
  • GitHub Pages deployment (CI/CD)
  • Security review
  • PyPI package

🔒 Security

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.


🌍 Website

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

📚 Development Story

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.


🧪 Status

Current version:0.2.0-dev

PyVault is currently an experimental project.

The project is actively being developed and its architecture may change significantly.


🤝 Contributing

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.


📄 License

PyVault is released under the MIT License.

See LICENSE for more information.


👤 Author

xql

GitHub: https://github.com/KirobotDev


Built with Python 🐍 & JavaScript ⚡

Learning by building.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

🔐 PyVault

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.


✨ Features

CLI — python main.py

  • 🔑 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)

Web — docs/

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

Platform support

  • 🪟 Windows benefits from DPAPI key protection
  • 🖥️ macOS and Linux are supported by the same clear-screen helper logic

🧠 Why PyVault?

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.


🏗️ Architecture

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
Loading

CURRENT = already implemented

PLANNED = planned for a future version


📁 Current Project Structure

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.py and decrypt.py now store passwords in a SQLite database (secret/passwords.db). The search.py and delete.py commands still operate on the legacy per-website files in secret/.


🔐 Current Encryption System

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).


📊 Benchmark

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:

PyVault Encryption / Decryption Benchmark

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.


🚀 Installation

Clone the repository:

git clone https://github.com/KirobotDev/PyVault.git
cd PyVault

Create a virtual environment:

Windows

python -m venv .venv
.venv\Scripts\activate

Linux / macOS

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

▶️ Usage

CLI

Start PyVault:

python main.py

You 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: 

Generate a key

Choose:

0

PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).

Add a password

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).

List saved entries

Choose:

2

PyVault will display every website stored in the database.

Decrypt a password

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

Web tool (browser)

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.


🧪 Running Tests

Unit tests are available in the tests/ folder.

Run them with:

python -m unittest tests.test_system_info

You 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.


📊 Running the Benchmark

The benchmark is available as a Jupyter Notebook.

Install Jupyter if necessary:

pip install jupyter

Start Jupyter:

jupyter notebook

Then open:

tests/benchmark.ipynb

The benchmark measures:

  • Encryption speed
  • Decryption speed
  • Different data sizes (1 B → 1 MB)
  • Average execution time
  • Performance scaling

🛠️ Roadmap

Phase 1 — Prototype

  • Generate Fernet key
  • Save key locally
  • Encrypt passwords
  • Store encrypted data
  • Store website information
  • Basic CLI
  • Decrypt passwords
  • List saved entries

Phase 2 — Vault

  • 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

Phase 3 — Security

  • DPAPI key protection on Windows
  • Master password
  • KDF-based key derivation
  • Vault locking
  • Failed-attempt protection
  • Security tests
  • Security policy (SECURITY.md)

Phase 4 — Database

  • SQLite
  • Database models
  • Encrypted database fields
  • Data validation
  • Database migrations
  • Migrate search and delete to the database

Phase 5 — API

  • Local API
  • FastAPI
  • Authentication
  • API documentation

Phase 6 — Interface

  • Full web interface
  • Vault dashboard
  • Password manager UI
  • API integration

Phase 7 — Open Source

  • Complete documentation
  • Automated tests
  • GitHub Pages deployment (CI/CD)
  • Security review
  • PyPI package

🔒 Security

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.


🌍 Website

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

📚 Development Story

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.


🧪 Status

Current version:0.2.0-dev

PyVault is currently an experimental project.

The project is actively being developed and its architecture may change significantly.


🤝 Contributing

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.


📄 License

PyVault is released under the MIT License.

See LICENSE for more information.


👤 Author

xql

GitHub: https://github.com/KirobotDev


Built with Python 🐍 & JavaScript ⚡

Learning by building.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

🔐 PyVault

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.


✨ Features

CLI — python main.py

  • 🔑 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)

Web — docs/

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

Platform support

  • 🪟 Windows benefits from DPAPI key protection
  • 🖥️ macOS and Linux are supported by the same clear-screen helper logic

🧠 Why PyVault?

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.


🏗️ Architecture

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
Loading

CURRENT = already implemented

PLANNED = planned for a future version


📁 Current Project Structure

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.py and decrypt.py now store passwords in a SQLite database (secret/passwords.db). The search.py and delete.py commands still operate on the legacy per-website files in secret/.


🔐 Current Encryption System

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).


📊 Benchmark

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:

PyVault Encryption / Decryption Benchmark

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.


🚀 Installation

Clone the repository:

git clone https://github.com/KirobotDev/PyVault.git
cd PyVault

Create a virtual environment:

Windows

python -m venv .venv
.venv\Scripts\activate

Linux / macOS

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

▶️ Usage

CLI

Start PyVault:

python main.py

You 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: 

Generate a key

Choose:

0

PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).

Add a password

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).

List saved entries

Choose:

2

PyVault will display every website stored in the database.

Decrypt a password

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

Web tool (browser)

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.


🧪 Running Tests

Unit tests are available in the tests/ folder.

Run them with:

python -m unittest tests.test_system_info

You 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.


📊 Running the Benchmark

The benchmark is available as a Jupyter Notebook.

Install Jupyter if necessary:

pip install jupyter

Start Jupyter:

jupyter notebook

Then open:

tests/benchmark.ipynb

The benchmark measures:

  • Encryption speed
  • Decryption speed
  • Different data sizes (1 B → 1 MB)
  • Average execution time
  • Performance scaling

🛠️ Roadmap

Phase 1 — Prototype

  • Generate Fernet key
  • Save key locally
  • Encrypt passwords
  • Store encrypted data
  • Store website information
  • Basic CLI
  • Decrypt passwords
  • List saved entries

Phase 2 — Vault

  • 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

Phase 3 — Security

  • DPAPI key protection on Windows
  • Master password
  • KDF-based key derivation
  • Vault locking
  • Failed-attempt protection
  • Security tests
  • Security policy (SECURITY.md)

Phase 4 — Database

  • SQLite
  • Database models
  • Encrypted database fields
  • Data validation
  • Database migrations
  • Migrate search and delete to the database

Phase 5 — API

  • Local API
  • FastAPI
  • Authentication
  • API documentation

Phase 6 — Interface

  • Full web interface
  • Vault dashboard
  • Password manager UI
  • API integration

Phase 7 — Open Source

  • Complete documentation
  • Automated tests
  • GitHub Pages deployment (CI/CD)
  • Security review
  • PyPI package

🔒 Security

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.


🌍 Website

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

📚 Development Story

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.


🧪 Status

Current version:0.2.0-dev

PyVault is currently an experimental project.

The project is actively being developed and its architecture may change significantly.


🤝 Contributing

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.


📄 License

PyVault is released under the MIT License.

See LICENSE for more information.


👤 Author

xql

GitHub: https://github.com/KirobotDev


Built with Python 🐍 & JavaScript ⚡

Learning by building.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

🔐 PyVault

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.


✨ Features

CLI — python main.py

  • 🔑 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)

Web — docs/

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

Platform support

  • 🪟 Windows benefits from DPAPI key protection
  • 🖥️ macOS and Linux are supported by the same clear-screen helper logic

🧠 Why PyVault?

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.


🏗️ Architecture

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
Loading

CURRENT = already implemented

PLANNED = planned for a future version


📁 Current Project Structure

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.py and decrypt.py now store passwords in a SQLite database (secret/passwords.db). The search.py and delete.py commands still operate on the legacy per-website files in secret/.


🔐 Current Encryption System

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).


📊 Benchmark

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:

PyVault Encryption / Decryption Benchmark

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.


🚀 Installation

Clone the repository:

git clone https://github.com/KirobotDev/PyVault.git
cd PyVault

Create a virtual environment:

Windows

python -m venv .venv
.venv\Scripts\activate

Linux / macOS

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

▶️ Usage

CLI

Start PyVault:

python main.py

You 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: 

Generate a key

Choose:

0

PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).

Add a password

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).

List saved entries

Choose:

2

PyVault will display every website stored in the database.

Decrypt a password

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

Web tool (browser)

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.


🧪 Running Tests

Unit tests are available in the tests/ folder.

Run them with:

python -m unittest tests.test_system_info

You 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.


📊 Running the Benchmark

The benchmark is available as a Jupyter Notebook.

Install Jupyter if necessary:

pip install jupyter

Start Jupyter:

jupyter notebook

Then open:

tests/benchmark.ipynb

The benchmark measures:

  • Encryption speed
  • Decryption speed
  • Different data sizes (1 B → 1 MB)
  • Average execution time
  • Performance scaling

🛠️ Roadmap

Phase 1 — Prototype

  • Generate Fernet key
  • Save key locally
  • Encrypt passwords
  • Store encrypted data
  • Store website information
  • Basic CLI
  • Decrypt passwords
  • List saved entries

Phase 2 — Vault

  • 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

Phase 3 — Security

  • DPAPI key protection on Windows
  • Master password
  • KDF-based key derivation
  • Vault locking
  • Failed-attempt protection
  • Security tests
  • Security policy (SECURITY.md)

Phase 4 — Database

  • SQLite
  • Database models
  • Encrypted database fields
  • Data validation
  • Database migrations
  • Migrate search and delete to the database

Phase 5 — API

  • Local API
  • FastAPI
  • Authentication
  • API documentation

Phase 6 — Interface

  • Full web interface
  • Vault dashboard
  • Password manager UI
  • API integration

Phase 7 — Open Source

  • Complete documentation
  • Automated tests
  • GitHub Pages deployment (CI/CD)
  • Security review
  • PyPI package

🔒 Security

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.


🌍 Website

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

📚 Development Story

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.


🧪 Status

Current version:0.2.0-dev

PyVault is currently an experimental project.

The project is actively being developed and its architecture may change significantly.


🤝 Contributing

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.


📄 License

PyVault is released under the MIT License.

See LICENSE for more information.


👤 Author

xql

GitHub: https://github.com/KirobotDev


Built with Python 🐍 & JavaScript ⚡

Learning by building.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

🔐 PyVault

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.


✨ Features

CLI — python main.py

  • 🔑 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)

Web — docs/

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

Platform support

  • 🪟 Windows benefits from DPAPI key protection
  • 🖥️ macOS and Linux are supported by the same clear-screen helper logic

🧠 Why PyVault?

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.


🏗️ Architecture

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
Loading

CURRENT = already implemented

PLANNED = planned for a future version


📁 Current Project Structure

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.py and decrypt.py now store passwords in a SQLite database (secret/passwords.db). The search.py and delete.py commands still operate on the legacy per-website files in secret/.


🔐 Current Encryption System

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).


📊 Benchmark

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:

PyVault Encryption / Decryption Benchmark

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.


🚀 Installation

Clone the repository:

git clone https://github.com/KirobotDev/PyVault.git
cd PyVault

Create a virtual environment:

Windows

python -m venv .venv
.venv\Scripts\activate

Linux / macOS

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

▶️ Usage

CLI

Start PyVault:

python main.py

You 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: 

Generate a key

Choose:

0

PyVault will generate a Fernet key and save it to key.txt (protected with DPAPI on Windows).

Add a password

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).

List saved entries

Choose:

2

PyVault will display every website stored in the database.

Decrypt a password

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

Web tool (browser)

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.


🧪 Running Tests

Unit tests are available in the tests/ folder.

Run them with:

python -m unittest tests.test_system_info

You 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.


📊 Running the Benchmark

The benchmark is available as a Jupyter Notebook.

Install Jupyter if necessary:

pip install jupyter

Start Jupyter:

jupyter notebook

Then open:

tests/benchmark.ipynb

The benchmark measures:

  • Encryption speed
  • Decryption speed
  • Different data sizes (1 B → 1 MB)
  • Average execution time
  • Performance scaling

🛠️ Roadmap

Phase 1 — Prototype

  • Generate Fernet key
  • Save key locally
  • Encrypt passwords
  • Store encrypted data
  • Store website information
  • Basic CLI
  • Decrypt passwords
  • List saved entries

Phase 2 — Vault

  • 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

Phase 3 — Security

  • DPAPI key protection on Windows
  • Master password
  • KDF-based key derivation
  • Vault locking
  • Failed-attempt protection
  • Security tests
  • Security policy (SECURITY.md)

Phase 4 — Database

  • SQLite
  • Database models
  • Encrypted database fields
  • Data validation
  • Database migrations
  • Migrate search and delete to the database

Phase 5 — API

  • Local API
  • FastAPI
  • Authentication
  • API documentation

Phase 6 — Interface

  • Full web interface
  • Vault dashboard
  • Password manager UI
  • API integration

Phase 7 — Open Source

  • Complete documentation
  • Automated tests
  • GitHub Pages deployment (CI/CD)
  • Security review
  • PyPI package

🔒 Security

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.


🌍 Website

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

📚 Development Story

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.


🧪 Status

Current version:0.2.0-dev

PyVault is currently an experimental project.

The project is actively being developed and its architecture may change significantly.


🤝 Contributing

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.


📄 License

PyVault is released under the MIT License.

See LICENSE for more information.


👤 Author

xql

GitHub: https://github.com/KirobotDev


Built with Python 🐍 & JavaScript ⚡

Learning by building.