BYOPM – Bring Your Own Password Manager [updated 2nd of November 2022]

BYOPM

BYOPM is a portable Password Manager implementation based on VaultWarden, an unofficial implementation of BitWarden and a Raspberry PI Zero. It’s a self hosted solution, with full functionality, which is activated by just plugging the device on your computer. Bitwarden’s Official browser addons and extensions are also supported, and the device has been tested both on Windows (10 and 11) and Linux (Debian Based).

Updated 2nd of November 2022

As @Vic mentioned at the comments section the device is not using an official Bitwarden docker image, but the compatible VaultWarden Rust Server by Daniel Garcia. If you have any issues which you want to report, do that in the appropriate section.

In reply to @WJCarpenter I am also attaching a gif of the device in action, where you can see the small piece of the acrylic rod which is used for covering the led indicator hole:

BYOPM in action

How it works

Plug BYOPM to your computer using a micro usb cable, after about a minute a new network device will be automatically created and appear as connected. BYOPM hosts a Vaultwarden instance which is required for managing your passwords and also emulates an ethernet network interface card in order to be accessible from your computer without any configuration. Vaultwarden is then accessbible using your browser at https://byopm.local.

Bill of Materials

1) Raspberry Pi Zero (Any version will be OK, but if you want to print the official BYOPM case avoid the H versions which include the 2.54mm pin header)
2) Tactile Push Button 6 x 6 x 6 mm (amazon.com)
3) Raspberry PI Case [optional] (thingiverse)
4) 3 x M2 x 6 mm screws [optional]
5) 3 mm length x 3 mm diameter transparent acrylic rod (if you plan to print the custom case) [amazon.com] (https://www.amazon.com/Weststone-acrylic-Transparent-Standard-Tolerance/dp/B07YMSQXKG)
BYOPM BoM

Schematic

byopm schematic

Pay special attention when soldering the tactile switch to the board. It must be aligned with top cover’s hole and you must remove all the excess of soldering material from the bottom side of the Raspberry board.

Raspi Power Switch

Preparation

The following steps executed on a Raspberry PI Zero W Rev. 1.1 (Model: 9000c1), running the official Raspberry OS Lite released on September 22nd 2022 ( 32-bit system, Debian 11, Kernel version: 5.15).

SD-Card preparation

Using the official Raspberry PI Imager tool configure your SD Card as follows:

  1. Click on CHOOSE OS
    Choose OS

  2. Select the 32 bit Image of Raspberry PI OS
    Raspberry PI OS 32 bit

  3. Connect your SD Card to your Computer, using a card reader or a USB adapter and click on CHOOSE STORAGE
    Choose Storage

  4. Select your SD CARD (WARNING: Make sure that the storage you selected is indeed your Raspberry PI’s SD Card to avoid any unwanted data loss)
    Select SD Card

  5. Click on the GEAR Button located bottom right.
    Settings Button

  6. Type byopm as hostname, enable SSH, set your own username and password and configure your wireless LAN (you can skip Wi-Fi configuration if you will configure the device using the Serial Console).
    Advanced Options

  7. Save your configuration and click the WRITE button.

  8. When your SD Card is ready the following message will appear.
    Raspberry Imager Writing Completed

  9. Finally, click CONTINUE, remove the SD card from your computer and re-plug it to appear as a USB Removable Storage.

  10. Navigate to the Removable Storage and edit the config.txt file:
    config.txt

  11. Append the following commands to enable the ShutDown Button functionality and the Serial Console [optional] (It is recommended to enable the Serial Console as a redundant communication link):

    enable_uart=1
    dtoverlay=gpio-shutdown
  12. Save the file and safely remove your SD Card.

Initial Raspberry PI Configuration

Place your SD card back to the Raspberry PI and plug the power cable. Establish a terminal connection to your Raspberry either using SSH (use byopm.local as hostname) or Serial Console.After establishing the connection and logging in:

Update your distribution using the commands :

sudo apt update
sudo apt upgrade

Install dnsmasq and nginx:

sudo apt install -y dnsmasq nginx

Install Docker:

curl -sSL https://get.docker.com | sh

Add your user to the docker group, replace your username:

sudo usermod -aG docker USERNAME_HERE

Apply the new group to the user.

exec su -l USERNAME_HERE

You will be prompted for your password in order to apply the new group.

Pull the Docker Image of Vaultwarden:

docker pull vaultwarden/server:latest

Create a self-signed certificate

This self-signed certificate will last for 730 days and will be stored in the /etc/ssl/certs/. The Private key will be store in the /etc/ssl/private/ directory. While generating the certificate you will be asked to provide some details, pick your country code from this list, skip everything else and type byopm.local as Common Name.

sudo openssl req -x509 -nodes -days 730 -newkey rsa:4096 -keyout /etc/ssl/private/nginx-bitwarden.key -out /etc/ssl/certs/nginx-bitwarden.crt

Self Singed Certificate Generation

Create a Diffie-Helman group

This is used to help improve the security of your device’s SSL connections and is the most time consuming procedure. Unfortunately due to the low resources of Raspberry PI Zero, this is taking about 20 minutes to complete.

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Configuring NGINX hosting

Nginx is the webserver which will host the Vaultwarden web interface. It was installed but currently working with the default configuration, a new configuration must created to enable Vaultwarden functionality.

Remove the default nginx configuration

sudo rm /etc/nginx/sites-enabled/default

Make a new nginx configuration

sudo nano /etc/nginx/sites-enabled/bitwarden.conf

with the following content:

server {
    listen 80;
    listen [::]:80;
    server_name byopm.local;
    return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  server_name byopm.local;

  ssl_certificate      /etc/ssl/certs/nginx-bitwarden.crt;   
  ssl_certificate_key  /etc/ssl/private/nginx-bitwarden.key; 

  ssl_dhparam /etc/ssl/certs/dhparam.pem;

  # Send functionality of BW allows up to 100MB
  client_max_body_size 128M;

  location / {
    proxy_pass http://0.0.0.0:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }

location /notifications/hub {
    proxy_pass http://0.0.0.0:3012;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }

  location /notifications/hub/negotiate {
    proxy_pass http://0.0.0.0:8080;
  }
}

Restart NGINX

sudo systemctl restart nginx.service

Configuring VaultWarden

Generate a random Admin token:

This token must kept secret as this will let anyone have full access to the Vaultwarden server.

openssl rand -base64 48

Run the Vaultwarden Docker container

Replace your Admin token and use the following command to run the Vaultwarden Docker container

sudo docker run -d --name vaultwarden \
    -e ADMIN_TOKEN=[ADMIN_TOKEN_HERE] \
    --restart=always \
    -v /bw-data/:/data/ \
    -p 127.0.0.1:8080:80 \
    -p 127.0.0.1:3012:3012 \
    vaultwarden/server:latest

Confirm that the container is running:

docker ps

Docker PS

Configure Vaultwarden’s web interface

  1. Navigate to https://byopm.local/admin, you will get a warning about the self-signed certificate. This is because browsers only trust certificates from specific authorities which can validate. Self-signed certificates is a workaround to avoid paying, while maintaining a secure connection between server and client.
  2. Click Advanced
    Self Signed Security warning
  3. Click Accept the Risk and continue
    Self Signed Security warning
  4. Enter the Admin Token you generated before and Click Enter
    Vaultwarden Admin
  5. At the General settings tab make sure that Domain URL is https://byopm.local and click Save at the end of the page.
    Vaultwarden Admin General Settings
  6. Verify that web interface will indeed use the specific domain by visiting https://byopm.local/app-id.json, and under ids the https://byopm.local exist.
    app-id.sjon
  7. Now navigate to https://byopm.local click on Create Account and create a new account.
    Bitwarden Create Account

Configure Raspberry PI to act as a Network Interface Card (Ethernet Gadget)

Raspberry PI, will act as a Network Interface Card and will also host a DNS Server using dnsmasq. Every time the device connects on a computer, it will automatically create a new Network connection and provide the computer with a specific IP.

Configure the Network Interface

sudo nano /etc/network/interfaces

and append

auto lo
iface lo inet loopback

auto usb0
allow-hotplug usb0
iface usb0 inet static
address 10.18.1.19
netmask 255.255.255.0

Configure the DHCP and DNS Server

sudo nano /etc/dnsmasq.conf

and append

dhcp-range=10.18.1.20,10.18.1.21,12h

dhcp-option=option:dns-server,10.18.1.19
port=53
domain-needed
bogus-priv
listen-address=127.0.0.1,10.18.1.19
expand-hosts
domain = local
local=/local/

Replace Server’s IP for proper resolving

sudo nano /etc/hosts

and replace

127.0.0.1   byopm

with

10.18.1.19  byopm.local byopm

Configure Raspberry to act as an Ethernet Gadget

  1. Create the gadget script.

    sudo mkdir -p /etc/novamostra
    sudo nano /etc/novamostra/gadget.sh

    and insert the following content:

    #!/bin/bash
    #October 2022
    #This file is part of BYOPM.
    #Copyright (c) novamostra.com
    GADGET_DIR="nm_ether"
    VENDOR_ID="0x1d6b"
    PRODUCT_ID="0x0104"
    HOST="00:dc:c8:f7:75:14"
    SELF="00:dd:dc:eb:6d:a1"
    modprobe libcomposite
    mkdir -p /sys/kernel/config/usb_gadget/$GADGET_DIR
    cd /sys/kernel/config/usb_gadget/$GADGET_DIR
    echo $VENDOR_ID > idVendor
    echo $PRODUCT_ID > idProduct
    echo 0x0100 > bcdDevice
    echo 0x0200 > bcdUSB
    echo 0xEF > bDeviceClass
    echo 0x02 > bDeviceSubClass
    echo 0x01 > bDeviceProtocol
    mkdir -p strings/0x409 # English language strings
    echo "nm_nic_01" > strings/0x409/serialnumber
    echo "novamostra" > strings/0x409/manufacturer
    echo "byopm" > strings/0x409/product
    mkdir -p configs/c.1/strings/0x409
    echo "Config 1: RNDIS network" > configs/c.1/strings/0x409/configuration
    echo 250 > configs/c.1/MaxPower
    echo 0x80 > configs/c.1/bmAttributes
    mkdir -p functions/rndis.usb0
    # set up mac address of remote device
    echo $HOST > functions/rndis.usb0/host_addr
    # set up local mac address
    echo $SELF > functions/rndis.usb0/dev_addr
    # Force windows configuration
    echo "1" > os_desc/use
    echo "0xcd" > os_desc/b_vendor_code
    echo "MSFT100" > os_desc/qw_sign
    mkdir -p functions/rndis.usb0/os_desc/interface.rndis
    echo RNDIS > functions/rndis.usb0/os_desc/interface.rndis/compatible_id
    echo 5162001 > functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id
    ln -s functions/rndis.usb0 configs/c.1/
    ln -s configs/c.1/ os_desc
    udevadm settle -t 5 || :
    ls /sys/class/udc > UDC
  2. Give executing permission

    sudo chmod +x /etc/novamostra/gadget.sh
  3. Create the service

    sudo nano /lib/systemd/system/nm_gadget.service

    and insert the following content

    [Unit]
    Description=Novamostra Ethernet Gadget
    Before=network-pre.target
    Wants=network-pre.target
    [Service]
    ExecStart=/usr/bin/bash /etc/novamostra/gadget.sh
    [Install]
    WantedBy=multi-user.target
  4. Enable the service to automatically start on boot.

    sudo systemctl enable nm_gadget.service
  5. Disable the DHCPCD service to avoid any network conflicts.

    sudo systemctl disable dhcpcd.service
  6. Enable the Ethernet Gadget and disable the Wi-Fi module
    In order to avoid any conflicts and keep the device as secure as possible, when the network setup finish, we have to disable the dhcpd service and the WiFi and Bluetooth connections of the device.

    sudo nano /boot/config.txt 

    and append:

    dtoverlay=dwc2
    dtoverlay=disable-wifi
    dtoverlay=disable-bt

    DWC2

  7. Power off Raspberry PI

    sudo poweroff
  8. Verify connections
    Disconnect all cables from your BYOPM device and connect only a micro USB cable from your computer to the appropriate port: (Notice that Raspberry PI has 2 micro USB ports but only one is a configured USB port, the other one is only for Powering the device).

Usage

Every time you connect the BYOPM to a computer, a new network adapter will appear as connected.
Network Connection
with the following settings:
NIC Settings

Without any further configuration you will be able to access through your browser the https://byopm.local and use your own Bitwarden instance. For better functionality I recommend installing Bitwarden’s addons to the devices you plan to use your device and configure it as follows.

Bitwarden Firefox Addon

To install the official Bitwarden Firefox Addon, go to addon’s page and click Add to Firefox
Bitwarden Firefox Addon
When the installation complete, the addon will launch automatically (if not click the image next to Firefox’s menu icon), and click Settings on the top left side of the addon.
BW Addon Configuration

In the Settings window, set the Server url to https://byopm.local, and click Save

Bitwarden Set Custom Host

Next login using the credentials of the account you created to the prior setup.

Bitwarden Addon Login

The configuration is similar for the Chrome’s Bitwarden Extension

Warning: If for any reason the addon/extension fails to login while the credentials are correct, try first login though the normal web interface (https://byopm.local) using the respective browser and then try again.

Code

The code is available on github

3d Files

BYOPM consists of 2 3d printed parts (top and bottom):
byopm 3d files
Both of them are available on thingiverse

Final Thoughts

  • After completing the configuration, your device will also be available using SSH. Just plug it on your computer and use the byopm.local hostname to access it.
  • It is recommended to always POWER OFF the device before removing it from the host computer. Use the Power Button and wait until the Status Indicator turn off.

Database Backup

WARNING: SD cards have a maximum number of read and writes. Storing your passwords on an SD card without any backup will soon result in lost passwords and possible lock outs. Always backup your database. In the current configuration is located in /bw-data/db.sqlite3

4 3 votes
Article Rating
Subscribe
Notify of
guest
19 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Tim

Wow. I was actually thinking about building a backup for my Bitwarden. That’s pretty interesting idea.

Vic

Pull the Docker Image of Bitwarden

This is not what you’re doing. You’re pulling the Docker image of Vaultwarden, which is a reimplementation of Bitwarden server, but is not a Bitwarden image.

Please refer to Vaultwarden as Vaultwarden to avoid confusion. People may report Vaultwarden bugs to the Bitwarden project, where they won’t be able to help them.

WJCarpenter

What is the acrylic rod used for? I’m trying to visualize it from the description, but I can’t quite grok it.

Alex

How to connect power? In the case, I see only a hole for the mini HDMI connector.

Chris

Is there any way to connect to an Android phone to use BYOPM to manage credentials?

Poradnik

I love it, a bit complicated for me, but I will give it a try for sure!

Dennis

How do I enable this device on a Mac? I can see the device under USB in system info but the interface doesn’t show up as a network adapter.

jorisregah

I tried this twice but never a network adapter appeared?

jorisregah

i install byopm on a zero w

jorisregah

The connected computer is windows, and I am using the USB port at the middle.

GZX

Is this compatible with the Windows Desktop Bitwarden app? I would like to use biometrics to login, this requites the desktop app in conjunction with the chrome plugin.

I get “Failed to Fetch” even though the desktop app is pointed to the local BYOPM server https://byopm.local

I am able to login to the web instance and the plugin is able to reach the local server, just not the desktop app.

Thanks