Skip to content

Commit

Permalink
v1.4.2 (#12)
Browse files Browse the repository at this point in the history
pico2_w support, update deps and doc
  • Loading branch information
virgesmith authored Nov 30, 2024
1 parent e361af2 commit 9a421e4
Show file tree
Hide file tree
Showing 16 changed files with 85 additions and 117 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ signature.json
pico_sdk_import.cmake
pico-sdk
mbedtls
relnotes.md
15 changes: 14 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ elseif(${PICO_BOARD} STREQUAL pico2)
tinyusb_board
mbedcrypto
)
elseif(${PICO_BOARD} STREQUAL pico2_w)
target_link_libraries(${PICO_IMAGE}
pico_stdlib
pico_unique_id
pico_rand
pico_sha256
hardware_flash
hardware_sync
tinyusb_device
tinyusb_board
mbedcrypto
pico_cyw43_arch_none
)
else()
target_link_libraries(${PICO_IMAGE}
pico_stdlib
Expand Down Expand Up @@ -89,7 +102,7 @@ add_executable(${PICO_RESET_PIN}
target_compile_definitions(${PICO_RESET_PIN} PRIVATE BOARD_${PICO_BOARD})
target_compile_options(${PICO_RESET_PIN} PRIVATE -Wno-psabi -Werror -Wall)

if(${PICO_BOARD} STREQUAL pico_w)
if(${PICO_BOARD} STREQUAL pico_w OR ${PICO_BOARD} STREQUAL pico2_w)
target_link_libraries(${PICO_RESET_PIN}
pico_stdlib
hardware_flash
Expand Down
109 changes: 23 additions & 86 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,19 @@ I'm not a security expert and the device/software is almost certainly not harden
- the private key is only initialised once a correct pin has been entered, and is a SHA256 hash of the (salted) unique device id. So no two devices should have the same key.
- the private key never leaves the device and is stored only in volatile memory.

Pico, Pico W, Tiny2040 and Pico2 boards are known to work. Other RP2040/RP2350 boards have not been tested but are likely to (mostly) work. E.g. the Pico W requires the wifi driver purely for the LED (which is connected to the wifi chip) to function (though neither wifi nor bluetooth are enabled.)
Pico, Pico W, Tiny2040, Pico2 and Pico2 W boards are known to work. Other RP2040/RP2350 boards have not been tested but are likely to (mostly) work. E.g. the Pico/Pico2 W requires the wifi driver purely for the LED (which is connected to the wifi chip) to function (though neither wifi nor bluetooth are enabled.)

## Update v1.4.1
## Notes/issues

- Use standard library implementation of `minstd_rand` and seed it with the TRNG from `pico_rand` (used by ECDSA).
- Minor code improvements

## Update v1.4.0
- build and install picotool separately against head of sdk (which still uses mbedtls 2), otherwise the build will try building picotool against mbedtls 3, which won't work
- Writes to the final flash block do not persist on RP2350. See [here](https://forums.raspberrypi.com/viewtopic.php?t=375912). Simple workaround is to use the penultimate block.
- Not all prebuilt RISC-V toolchains seem to work, see [here](https://forums.raspberrypi.com/viewtopic.php?t=375713). [This one](https://github.com/raspberrypi/pico-sdk-tools/releases/download/v2.0.0-1/riscv-toolchain-14-aarch64-lin.tar.gz) worked for me.

- Updates pico SDK to v2.0
- Adds support for Pico2 (both ARM and RISC-V) and compares performance
- Board configurations are now set in [`config/boards.toml`](config/boards.toml) - this allows use of multiple/different SDKs and toolchains per board
## Performance

### Performance comparison
### RP2040 vs RP2350 ARM vs RP2350 RISC-V

Performance improvement is fairly modest, Cortex M33 slightly outperforming the Hazard3 - but the bottleneck here is USB comms. Note that using hardware SHA256 only seems to improve hashing performance by about 6% for this (IO-bound) use case.
v1.4.0 introduced support for RP2350 boards. Performance improvement is fairly modest, Cortex M33 slightly outperforming the Hazard3 - but the bottleneck here is USB comms. Note that using hardware SHA256 only seems to improve hashing performance by about 6% for this (IO-bound) use case.

| | RP2040<br/>time(s) | <br/>bitrate(kbps) | RP2350(ARM)<br/>time(s) | <br/>bitrate(kbps) | <br/>speedup(%) | RP2350(RISC-V)<br/>time(s) | <br/>bitrate(kbps) | <br/>speedup(%) |
|:--------|-------------------:|-------------------:|------------------------:|-------------------:|----------------:|---------------------------:|-------------------:|----------------:|
Expand All @@ -43,35 +40,10 @@ Tests run on a single core and use a 1000kB random binary data input. Binaries c

On thing not measured or considered here is the difference in power consumption between Cortex M33 vs Hazard3...

### Notes/issues

- build and install picotool separately against head of sdk (which still uses mbedtls 2), otherwise the build will try building picotool against mbedtls 3, which won't work
- USB on pico 2 doesn't work with latest TinyUSB release (0.16). Workaround using latest Pico SDK + submodules. (I have the 2.0.0 release pointing to TinyUSB 0.16 for reproducibility)
- Writes to the final flash block do not persist. See [here](https://forums.raspberrypi.com/viewtopic.php?t=375912). Simple workaround is to use the penultimate block.
- Not all prebuilt RISC-V toolchains seem to work, see [here](https://forums.raspberrypi.com/viewtopic.php?t=375713). [This one](https://github.com/raspberrypi/pico-sdk-tools/releases/download/v2.0.0-1/riscv-toolchain-14-aarch64-lin.tar.gz) worked for me.

## Update v1.3.1

- Adds support for Pimoroni [Tiny2040](https://shop.pimoroni.com/products/tiny-2040?variant=39560012300371).
- The webauthn-style workflow example has been improved.

## Update v1.3

Adds:

- Time synchronisation between host and device
- Device info: firmware version, board type, current time
- Generation of time-based authentication tokens (like Webauthn)
- Multiple build targets: Pico and Pico W. LED now works on Pico W.
- Switch to short-form public keys.

## Update v1.2

The device pin is now configurable. See [PIN protection](#pin-protection) and the [change pin](#change-pin) example.
### USB speed

## Update v1.1

The device now uses USB CDC rather than serial to communicate with the host which allows much faster bitrates and avoids the need to encode binary data. Performance is improved, but varies considerably by task (results are for a 1000kB input):
v1.1.0 switched to USB CDC rather than serial to communicate with the host which allows much faster bitrates and avoids the need to encode binary data. Performance is improved, but varies considerably by task (results are for a 1000kB input on a RP2040):

| task | CDC<br>time(s) | CDC<br>bitrate(kbps) | serial<br>time(s) | serial<br>bitrate(kbps)| Speedup(%) |
|:--------|---------------:|---------------------:|------------------:|-----------------------:|-----------:|
Expand All @@ -86,8 +58,8 @@ The device now uses USB CDC rather than serial to communicate with the host whic

`pico-crypto-key` is a python (dev) package that provides:

- a simplified build process
- a python interface to the device.
- a simplified build process supporting multiple configurations
- a python interface to the devices.

### Dependencies/prerequisites

Expand All @@ -101,67 +73,30 @@ If this step fails, try upgrading to a more recent version of pip.

You will then need to:

- install the compiler toolchain(s) and cmake (ubuntu 22.04LTS is 10.3.1):
- install the compiler toolchain(s) and cmake:

```sh
sudo apt install gcc-arm-none-eabi cmake
```

NB 13.2.0 is recommended, but 10.3.1 and 14 seem to work too. A prebuilt RISC-V toolchain can be found [here](https://github.com/raspberrypi/pico-sdk-tools/releases/tag/v2.0.0-1).

- download [pico-sdk](https://github.com/raspberrypi/pico-sdk) >= 2, see [here](https://www.raspberrypi.org/documentation/pico/getting-started/). NB This project uses a tagged release of pico-sdk, so download and extract e.g. [2.0.0](hhttps://github.com/raspberrypi/pico-sdk/archive/refs/tags/2.0.0.tar.gz)
For RISC-V, a prebuilt toolchain can be found [here](https://github.com/raspberrypi/pico-sdk-tools/releases/tag/v2.0.0-5).

- download and extract a release of [tinyusb](https://github.com/hathach/tinyusb/releases/tag/0.16.0). Replace the empty `pico-sdk-2.0.0/lib/tinyusb` directory with a symlink to where you extracted it, e.g.
- clone [pico-sdk](https://github.com/raspberrypi/pico-sdk) see [here](https://www.raspberrypi.org/documentation/pico/getting-started/). Initialise submodules:

```sh
cd pico-sdk-2.0.0/lib
rmdir tinyusb
ln -s ../../tinyusb-0.16.0 tinyusb
git submodule update --init
```

- [**pico_w only**], repeat the above step for `cyw43-driver`, which can be found [here](https://github.com/georgerobotics/cyw43-driver)

- [**pico2 only**] tinyUSB 0.16.0 doesn't work. I used a cloned SDK with submodules (rather than a release) for pico2 builds

- download [mbedtls](https://tls.mbed.org/api/): see also their [repo](https://github.com/ARMmbed/mbedtls). Currently using the 3.6.0 release/tag. This must be kept separate from the implementation in the SDK (which still on v2) and requires a custom configuration.

create a symlink in the project root to the pico SDK and mbedtls, e.g.:
- download a release of [mbedtls](https://tls.mbed.org/api/) - the `.tar.bz` asset. Currently using the 3.6.2 release/tag. **This is a different version to the one in the SDK** (which still uses v2) so must be kept separate. It also requires a custom configuration. Create a symlink in the project root to mbedtls, e.g.:

```sh
ln -s ../mbedtls-3.6.0 mbedtls
ln -s ../mbedtls-3.6.2 mbedtls
```

You should now have a structure something like this:

```txt
.
├──mbedtls-3.6.0
├──pico-crypto-key
│ ├──config
│ │ └──boards.toml
│ ├──examples
│ ├──mbedtls -> ../mbedtls-3.6.0
│ ├──pico_crypto_key
│ │ ├──build.py
│ │ ├──device.py
│ │ └──__init__.py
│ ├──pyproject.toml
│ ├──README.md
│ ├──src
│ └──test
├──pico-sdk-2.0.0
│ └──lib
│ ├──cyw43-driver -> ../../cyw43-driver-1.0.3 *
│ └──tinyusb -> ../../tinyusb-0.16.0
└──tinyusb-0.16.0
* required for pico_w only
```
## Configure

In the `config/boards.toml` file ensure settings for `PICO_TOOLCHAIN_PATH` and `PICO_SDK_PATH` are correct.

## Configure

If using a fresh download of `mbedtls` - run the configuration script to customise the build for the Pico, e.g.:

```sh
Expand All @@ -177,7 +112,8 @@ The target board must be specified using the `--board` option when running `chec
- Pico: `--board pico`
- Pico W: `--board pico_w`
- Pimoroni Tiny2040 2MB: `--board tiny2040`
- Pico 2: `--board pico2` or `--board pico2-riscv`
- Pico2: `--board pico2` or `--board pico2-riscv`
- Pico2 W: `--board pico2_w` or `--board pico2_w-riscv`

Using the correct board will ensure (amongst other things?) the LED will work. (NB images built for one RP2040 board may work on other RP2040 boards, aside from the LED. YMMV...

Expand All @@ -189,8 +125,9 @@ Pico | Flash | - | On | - | Flashing
Pico W | Flash | - | On | - | Flashing
Tiny2040 | White flash | Green | Blue | Red | Flashing Red
Pico 2 | Flash | - | On | - | Flashing
Pico 2 W | Flash | - | On | - | Flashing

&ast; "Ready" state is only enetered after a valid pin is supplied.
&ast; "Ready" state is only entered after a valid pin is supplied.

## Build

Expand Down
18 changes: 13 additions & 5 deletions config/boards.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
[default]
PICO_PLATFORM = "rp2040"
PICO_TOOLCHAIN_PATH = "/usr"
PICO_SDK_PATH = "../../pico-sdk-2.0.0"
# use latest SDK (2.1.0) which has tinusb 0.17
PICO_SDK_PATH = "../../pico-sdk"

[pico]
PICO_BOARD = "pico"
Expand All @@ -18,12 +19,19 @@ PICO_BOARD = "pimoroni_tiny2040_2mb"
PICO_BOARD = "pico2"
PICO_PLATFORM = "rp2350-arm-s"
PICO_TOOLCHAIN_PATH = "/usr"
# TinyUSB release 0.16 doesnt work, use latest SDK which points to a random commit on main
PICO_SDK_PATH = "../../pico-sdk"

[pico2-riscv]
PICO_BOARD = "pico2"
PICO_PLATFORM = "rp2350-riscv"
PICO_TOOLCHAIN_PATH = "/opt/riscv-gcc-14"
# TinyUSB release 0.16 doesnt work, use latest SDK which points to a random commit on main
PICO_SDK_PATH = "../../pico-sdk"

[pico2_w]
PICO_BOARD = "pico2_w"
PICO_PLATFORM = "rp2350-arm-s"
PICO_TOOLCHAIN_PATH = "/usr"

[pico2_w-riscv]
PICO_BOARD = "pico2_w"
PICO_PLATFORM = "rp2350-riscv"
PICO_TOOLCHAIN_PATH = "/opt/riscv-gcc-14"

4 changes: 2 additions & 2 deletions examples/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import ecdsa

from pico_crypto_key import CryptoKey, CryptoKeyNotFoundError, CryptoKeyPinError, timestamp
from pico_crypto_key import CryptoKey, CryptoKeyConnectionError, CryptoKeyPinError, timestamp


def auth() -> None:
Expand Down Expand Up @@ -55,7 +55,7 @@ def auth() -> None:
else:
raise RuntimeError(f"{rps[i]} verified {responses[i-1]}, this should not happen")

except CryptoKeyNotFoundError:
except CryptoKeyConnectionError:
print("Key not connected")
except CryptoKeyPinError:
print("PIN error")
Expand Down
4 changes: 2 additions & 2 deletions examples/change_pin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
Example: change the device pin.
"""

from pico_crypto_key import CryptoKey, CryptoKeyNotFoundError, CryptoKeyPinError
from pico_crypto_key import CryptoKey, CryptoKeyConnectionError, CryptoKeyPinError


def change_pin() -> None:
try:
with CryptoKey() as crypto_key:
crypto_key.set_pin()
except CryptoKeyNotFoundError:
except CryptoKeyConnectionError:
print("Key not connected")
except CryptoKeyPinError:
print("PIN incorrect")
Expand Down
4 changes: 2 additions & 2 deletions examples/decrypt_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import pandas as pd # type: ignore

from pico_crypto_key import CryptoKey, CryptoKeyNotFoundError, CryptoKeyPinError
from pico_crypto_key import CryptoKey, CryptoKeyConnectionError, CryptoKeyPinError


def read_encrypted_dataframe(ciphertext: Path) -> None:
Expand All @@ -33,7 +33,7 @@ def read_encrypted_dataframe(ciphertext: Path) -> None:
df = pd.read_csv(BytesIO(crypto_key.decrypt(c.read())))
print("decryption took %.2fs" % (time() - start))
print(df)
except CryptoKeyNotFoundError:
except CryptoKeyConnectionError:
print("Key not connected")
except CryptoKeyPinError:
print("PIN incorrect")
Expand Down
4 changes: 2 additions & 2 deletions examples/hash_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import sys
from pathlib import Path

from pico_crypto_key import CryptoKey, CryptoKeyNotFoundError, CryptoKeyPinError
from pico_crypto_key import CryptoKey, CryptoKeyConnectionError, CryptoKeyPinError


def hash_file(file: Path) -> None:
Expand All @@ -15,7 +15,7 @@ def hash_file(file: Path) -> None:
print(f"PicoCryptoKey {version}")
digest = crypto_key.hash(file)
print(f"{file}: {digest.hex()}")
except CryptoKeyNotFoundError:
except CryptoKeyConnectionError:
print("Key not connected")
except CryptoKeyPinError:
print("PIN incorrect")
Expand Down
4 changes: 2 additions & 2 deletions examples/sign_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import time
from pathlib import Path

from pico_crypto_key import CryptoKey, CryptoKeyNotFoundError, CryptoKeyPinError
from pico_crypto_key import CryptoKey, CryptoKeyConnectionError, CryptoKeyPinError


def sign_data(filename: Path) -> None:
Expand All @@ -29,7 +29,7 @@ def sign_data(filename: Path) -> None:
with open("signature.json", "w") as fd:
json.dump(result, fd, indent=2)
print("signature written to signature.json")
except CryptoKeyNotFoundError:
except CryptoKeyConnectionError:
print("Key not connected")
except CryptoKeyPinError:
print("PIN incorrect")
Expand Down
4 changes: 2 additions & 2 deletions examples/verify_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pathlib import Path
from time import time

from pico_crypto_key import CryptoKey, CryptoKeyNotFoundError, CryptoKeyPinError
from pico_crypto_key import CryptoKey, CryptoKeyConnectionError, CryptoKeyPinError


def verify_data(signature_file: Path) -> None:
Expand Down Expand Up @@ -38,7 +38,7 @@ def verify_data(signature_file: Path) -> None:
else:
print("signature is valid")
print(f"verifying took {time()-start:.2f}s")
except CryptoKeyNotFoundError:
except CryptoKeyConnectionError:
print("Key not connected")
except CryptoKeyPinError:
print("PIN incorrect")
Expand Down
4 changes: 2 additions & 2 deletions examples/webauthn_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import requests

from pico_crypto_key import CryptoKey, CryptoKeyNotFoundError, CryptoKeyPinError
from pico_crypto_key import CryptoKey, CryptoKeyConnectionError, CryptoKeyPinError


def get_challenge(host: str, user: str) -> str:
Expand Down Expand Up @@ -61,7 +61,7 @@ def main() -> None:
print(f"Invalid input: {cmd}")
except requests.exceptions.HTTPError as e:
print(e)
except CryptoKeyNotFoundError:
except CryptoKeyConnectionError:
print("Key not found, is it connected?")
except CryptoKeyPinError:
print("PIN error")
Expand Down
2 changes: 1 addition & 1 deletion pico_crypto_key/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

__version__ = importlib.metadata.version("pico-crypto-key")

from .device import CryptoKey, CryptoKeyNotFoundError, CryptoKeyPinError
from .device import CryptoKey, CryptoKeyConnectionError, CryptoKeyPinError

TIMESTAMP_RESOLUTION_MS = 60_000 # 1 min

Expand Down
4 changes: 2 additions & 2 deletions pico_crypto_key/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ def check(board: str = typer.Option(help="the target board")):
"""Check the project configuration."""

_get_config(board) # load config just to check board name is valid
print(f"picobuild {__version__}")
print(f"Board: {board}")
print(f"Software version: {__version__}")
ok = True
config = _get_config(board)

Expand All @@ -70,7 +70,7 @@ def check(board: str = typer.Option(help="the target board")):

ok &= _check_symlink("./mbedtls")
ok &= _check_symlink(sdk / "lib/tinyusb")
if board == "pico_w":
if board in ["pico_w", "pico2_w"]:
ok &= _check_symlink(sdk / "lib/cyw43-driver")

if not os.getenv("PICO_CRYPTO_KEY_PIN"):
Expand Down
Loading

0 comments on commit 9a421e4

Please sign in to comment.