$ genqr-wifi.sh mynetworkname
Wi-Fi network: mynetworkname
█████████████████████████████████████████
█████████████████████████████████████████
████ ▄▄▄▄▄ █   █▄▄█ ▄▀▄  █▀ ▄█ ▄▄▄▄▄ ████
████ █   █ █ ▀▄ █ █▀█▄▀▄▀▀ ▀██ █   █ ████
████ █▄▄▄█ █▀██▀▀▄▀ ▄▀█ ▀▀▄█▄█ █▄▄▄█ ████
████▄▄▄▄▄▄▄█▄▀▄█ █▄█▄█▄▀ ▀ ▀ █▄▄▄▄▄▄▄████
████▄▄██▄ ▄█▀▀▀▄▀  █▀▄█▄ ██▀▀█▀ █ ▄▄▄████
████ ▀▄  █▄▄▄█▀ ▄ ▄█▄█▄▀ █▀█▄ ▀▄▀▄ ▄▀████
████▄█▀▀ ▄▄█▄▀▄█▄  ██▄▀ █▄▀██▀ ▀ ▀▀█▄████
████ ▄▄▀██▄▄ ▀▀█▀▄▄▄ █▄▀▀█▀▄▀ ▀▄▀▄█  ████
████▀ ▄ ▀▄▄▀█ ▄▄▀ ██▄▄▀▄█▄▄███▄▄▀▀█ █████
████▀█▀▀█▀▄▀█▀  ▄▄ ▄▄▀▄▀ ▀▀█▀▄▀█▀█▄ █████
████▀▄█▄█ ▄▄ █▄█▄▀ ███▄  █ █▀██ ▀█ ▀▄████
██████ ▀ ▄▄  ▄▀█▀▄▄▄ ▀█▀█▀█▄▀ ▀▄▀█ ▀▀████
████▄▄█▄▄█▄▄▀ █▄  ██ █  █▄ █ ▄▄▄ █ ▄▀████
████ ▄▄▄▄▄ █▀██ █▄█▄▄█▄▀ ▀ █ █▄█ ▀  █████
████ █   █ █▄▀ ▀▀ ▄▀▀█ ▄███▄▄  ▄  ▀▀ ████
████ █▄▄▄█ █▀ ▀█▄ ▀▄█▀▄ ▀███▀▀▄▄█▀██▀████
████▄▄▄▄▄▄▄█▄█████▄█▄█▄▄█████▄███▄█▄▄████
█████████████████████████████████████████
█████████████████████████████████████████

Cool, huh!? 😎

Concepts and security concerns

Credentials management

Firstly, I'd like to highlight the value of generating something locally on your machine rather than a random app or site. Entering credentials in online QR code generators come with significant risks as you basically enter them on an untrusted website. Even if they promise generating them in a local Javascript-only fashion, I consider it a bad practice to enter these credentials in a browser window. This post is about generating the QR code locally (with qrencode) and credentials won't leave your system.

Secondly, the use of a local password manager application that allows for integration in shell scripts. I use pass, and I have the passwords for Wi-Fi networks and keys for Wireguard tunnels in there. The use of this as the password manager allows for easy integration in shell scripts in its design. But technically you could use any password store that allows you to obtain the secrets needed in shell scripts.

In this post I'll demo two example applications for this: Wi-Fi passwords (phones typically support that nowadays) and setting up a Wireguard tunnel (as supported by the Wireguard app for Android).

At work

This could also be very useful in the office to quickly on-board a new team member for example!

QR codes specification

Technically, it's possible to encode anything as a QR code, it's basically just freeform with respect to QR. What's more important, though, is how to encode the text you feed the QR-encoder.

For Wi-Fi access there's a standard on how it's structured; it is available in the Wi-Fi Alliance specification document section 7.

Some examples of the WIFI URI format are as follows:

  1. WIFI:T:WPA;S:MyNet;P:MyPassword;;

    • STA that supports WPA3-Personal might use SAE or PSK (WPA3-Personal transition mode)
    • STA that does not support WPA3-Personal uses PSK (WPA2-Personal)

For Wireguard tunnels in the app it's just the whole configuration file (that you'd normally use with wg setconf) contents itself.

With the text you want to encode ready, you can then use any QR code generator. One example is LibreOffice Writer (Menu InsertObjectQR Code).

Scripts

These scripts should be pretty much self-descriptive. They just format a text entry and just pipe it to qrencode --type=ANSIUTF8, so you'll have to install qrencode on your system.

Put the scripts somewhere on your PATH, make them executable (e.g. chmod +x genqr-wifi.sh) and make sure to adjust the logic to your needs and situation to obtain the credentials.

Wi-Fi

genqr-wifi.sh:

#!/usr/bin/env bash
set -e -u
set -o pipefail

# Obtain Wi-Fi password from `wifi/<SSID>` entry in passwordstore
# and print its QR-code for access on the commandline using ANSI
# terminal format.
function show_wifi_qr() {
    # TODO: figure out how to properly escape SSID and password
    # special characters.
    WPA3_FLAG=  # set "R:1;" to indicate WPA-3 compatibility
    WIFI_SSID="$1"
    WIFI_PASS="$(pass show "wifi/${WIFI_SSID}" | head -n1)"
    QR_CODE_TEXT="WIFI:T:WPA;${WPA3_FLAG}S:${WIFI_SSID};P:${WIFI_PASS};;"
    echo "Wi-Fi network: ${WIFI_SSID}"
    echo -n "${QR_CODE_TEXT}" | qrencode --type=ANSIUTF8
}

show_wifi_qr "$1"

Wireguard

This assumes a pass layout like this, but should be trivial to adjust to your needs. The entry should contain the private key as printed with wg genkey and the psk shared secret I use for additional security, contents as printed by wg genpsk.

$ pass ls
Password Store
└── wireguard
    ├── myinstance
    │   ├── mydevice
    │   ├── myotherdevice
    │   ├── myserver
    │   └── psk
[...]

genqr-wireguard.sh:

#!/usr/bin/env bash
set -e -u
set -o pipefail

function prepare_wireguard_credentials() {
    INSTANCE_NAME=$1
    DEVICE_NAME=$2
    DEVICE_IP_ADDRESS=$3
    DEVICE_DNS_SERVERS=$4
    PEER_INVENTORY_NAME=$5
    PEER_ENDPOINT=$6
    PEER_ALLOWED_IPS=$7

    DEVICE_PRIVATE_KEY=$(pass show "wireguard/${INSTANCE_NAME}/${DEVICE_NAME}" | head -n1)
    PEER_PUBLIC_KEY=$(pass show "wireguard/${INSTANCE_NAME}/${PEER_INVENTORY_NAME}" | head -n1 | wg pubkey)
    PEER_PRESHAREDKEY=$(pass show "wireguard/${INSTANCE_NAME}/psk" | head -n1)
}

function make_wireguard_config() {
    WIREGUARD_CONFIG="# ${INSTANCE_NAME} for device ${DEVICE_NAME}
[Interface]
PrivateKey = ${DEVICE_PRIVATE_KEY}
Address = ${DEVICE_IP_ADDRESS}
DNS = ${DEVICE_DNS_SERVERS}

[Peer]
PublicKey = ${PEER_PUBLIC_KEY}
PresharedKey = ${PEER_PRESHAREDKEY}
Endpoint = ${PEER_ENDPOINT}
AllowedIPs = ${PEER_ALLOWED_IPS}
"
}

function show_wireguard_qr() {
    prepare_wireguard_credentials "$@"
    make_wireguard_config
    echo "Wireguard instance: ${INSTANCE_NAME} for device ${DEVICE_NAME}"
    echo -n "${WIREGUARD_CONFIG}" | qrencode --type=ANSIUTF8
}

show_wireguard_qr myinstance mydevice 10.1.2.3/24 "8.8.8.8 9.9.9.9" \
                  myserver 11.22.33.44:51820 0.0.0.0/0

show_wireguard_qr myinstance myotherdevice 10.1.2.4/24 "8.8.8.8 9.9.9.9" \
                  myserver 11.22.33.44:51820 0.0.0.0/0

Results

Now whenever someone asks me for access on my Wi-Fi with a phone 📱, I can just type the following and it will always include the current password. ✅

For Wireguard I like it in particular just for my own phone. Whenever I change the configuration or rotate keys, I can just delete it and scan the new one with ease. 😎

At work, I create a git repository that includes the script and password store files, add the use direnv to adjust the PASSWORD_STORE_DIR and PATH and the possibilities are endless!

Share on: TwitterHacker NewsFacebookLinkedInRedditEmail


Related Posts


Published

Category

System Administration

Tags

Connect with me on...