Picoth - 2FA Auth with Pi Pico

An easy to use yet secure 2FA gadget, using a Raspberry Pi Pico and RGB Keypad, MicroPython.

Similar projects worth following
2FA has quickly become an easy to implement solution for all online services willing to add extra safety to user accounts.
As a result, users are now overwhelmed with 2FA requests for anything.
I need them for Github, Discord, Hosting account, Online shops, bank and exchanges...

For one, I don't feel comfortable with all these keys only stored physically on my phone.
Then, It's a pain for me to unlock, open Google authenticator, scroll to the right item in the ever growing list aso...
For long, I searched some nice and ready made hardware that would allow me to handle that in a more user friendly way.

Then I saw Pimoroni's RGB Keypad. 16 keys with rgb leds...
The thing was part of the Raspberry Pi Pico addons, and the Pi Pico seemed capable enough to handle the task.
So, I picked a Keypad, a Pico Display in the hope of adding extra feedback, and the journey began...


- Easy to use

- Handle many 2FA keys, for different contexts (home/work/dev/banking)

- Reasonable safety if stolen (no clear-text key)

- Form factor allowing single handed operation

- Enough visual feedback to be sure what you do

- USB Keyboard emulation

  • Harsh decision to take

    Angainor02/18/2021 at 19:14 0 comments

    My prototype is now working, and usable no matter the mess in the current code.
    No encryption and lock/unlock yet but that I know to handle.

    The most troublesome issue is the lack of USB_HID with Micropython.
    Yes, circuit python has. But circuit python also comes with a virtual USB drive, exposing the device inner files and is targeting education, toy projects, clearly ruling out production or secure devices.

    Also, circuit python does not have the Pimoroni libs yet. Not a major obstacle, but would mean a rewrite of some parts.

    I would largely prefer to stick with default Micropython, and not rely on a specific fork.

    My options are the following:

    - Stick with mainstream Micropython, no USB_HID for the moment and hope the feature will be ported soon enough. The device is usable thanks to the screen, but frankly, would be so much more friendly with keyboard emulation... I can't imagine Micropython losing all these Pico USB projects in favor of circuit python.

    - Convert the code to circuit python, write wrappers to replicate interfaces similar to the Pimoroni libs I used, to make the port easier.

    What's your take?

    Here is a video of the current code.

    Pages are defined in a config.json file, with TOTP codes to be encrypted.
    2 Pages are defined here, one Test and one "Cryptos", with fake info.

    Every page has 10 codes (using the pad as a regular numpad, not following the Pimoroni keypad numbers)
    Bottom row, left and right of the 0 are previous page/next page.

    Every 0-9 touch is defined with a label, a color and the TOTP code.

    When selecting an Auth, the label and current code are displayed, with the remaining time shown as horizontal bar.

  • Definitive wiring

    Angainor02/10/2021 at 10:31 0 comments

    I now consider the wiring definitive.


    SDA to GPIO10 (i2c1)

    SCL to GPIO11 (i2c1)

    3V3 and GND taken from extra headers soldered on the keypad base.

    RGB Keypad: 

    Default wiring, no change

    Pico Display:

    GPIO 16 (LCD_DC) and GPIO 20 (BL_EN) unchanged

    Reset unchanged, as 3V3 and GND

    LCD_CS connected to GPIO 21

    LCD_SCLK to GPIO 22 (SPI1)

    LCD_MOSI to GPIO 26 (SPI1)


    Buttons and RGB lines, that are on the opposite row can be wired as intended: they are not used by anything else.

    Here is a preview of what it now looks like

  • First bumps on the road

    Angainor02/08/2021 at 18:46 0 comments

    It's only once you get the hardware in hand you realize the obstacles on the road :D

    This is also what makes this interesting. Technical challenges to solve? Let tackle them!

    I wanted to use Micropython because I just love Python. RP2040 port of Micropython however, is very, very young. A rocky start they say :)

    - No Native USB support yet on Micropython. Hopefully this will come soon, as circuitpython already has it

    - No RTC module yet. Not critical since for a precise time source I planned to use a DS3231 chip.

    Then I discovered more surprises along the way:

    - Official Micropython has no support for the Pimoroni C libraries (keypad and display) , and support for user c modules is broken

    - Pimoroni's fork does not have sha256

    I ended up handling yet another fork, based upon official micropython with user c modules re-enabled, sha256 and pimoroni libs.

    On the software side, HMAC and more important, SHA1 were also missing...

    Although SHA1 is deprecated, it's still used and required for TOTP...
    There, I chose to use pure python implementations of SHA1, HMAC from micropython-lib, and TOTP.

    Good news, the Raspberry Pi Pico has no ram or speed issue at all computing correct TOTP, even with some code as frozen python code and not C lib. Great!

    Then, real fun began with the hardware itself.

    Pimoroni did a really great job designing and producing all these nifty backpacks and base for the Pico. Some details don't lie, they do it with passion!
    However, one thing I'm absolutely sure they did not plan, was someone willing to use a keypad base AND a Pico display with the same Pico.
    When I first saw the things, I thought you could plug the pico into the base, and the display on top of the pico.
    How naive I was!
    The pico display is supposed to be plugged on the back on the pico, too bad!

    Well, this will not stop me: just plug it on one side with longer, folded headers, and add some wires for the other side?
    Nope!  The RGB Keypad uses i2c0 port, and well as SPI0 port, with GPIO17 as CS.
    The display uses SPI0, with the same CS, MOSI, SCLK as the base.

    Certainly not a reason to despair.
    Diving into the RP2040 docs, I checked the GPIO doc.
    The RP2040 has 2 I2C and 2 SPI ports, plus the GPIO gives some flexibility.

    I ended up with the following setup:
    - No change to the Keypad base nor lib
    - No change to the display Power, reset, BL_enable
    - Move Display SPI pins to SPI1, using free gpios 21, 26 and 27. This required a small change to the ST7789 c library

    I then needed another I2C for the DS3231 RTC. I used GPIO 10 and 11, unused by the keypad base.

    With this setup, both the extensions can be used same time, with no conflict whatsoever.
    One row of curved header physically holds the display at the right angle, and only 3 wires are needed for the TFT to work (buttons and RGB led will need more).

    Current state, with really rough Python code, is able to display the correct 2FA TOTP code from a key, using the DS3231 RTC as clock source. Time remaining before the code is invalid is shown as a shrinking colored bar.

    Next step will be to make sure the wiring is final (it should) and assemble the thing with shorter and definitive wires.
    Then it'll be on the software end:
    - handling decoding of the otp keys
    - clock settings
    - associate physical keys and colors to otp entries

View all 3 project logs

  • 1
    Frankenstein prototype

    Current state is more a quick mashup than a production ready gadget.
    Instructions will be added as soon as something close to definitive is ready.

View all instructions

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates