Skip to content

Commit

Permalink
Merge pull request #43 from stakwork/feat/chacha20poly1305
Browse files Browse the repository at this point in the history
Feat/chacha20poly1305
  • Loading branch information
Evanfeenstra authored Jul 5, 2022
2 parents 3def3a2 + 0c9b947 commit d9b7ddb
Show file tree
Hide file tree
Showing 20 changed files with 460 additions and 103 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Cargo.lock
.DS_Store
sphinx-key/Cargo.lock
notes.md
test-flash
test-flash
.env
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ members = [

exclude = [
"sphinx-key",
"crypter"
]

[patch.crates-io]
# updates the "rand" create to use esp RNG
getrandom = { version = "0.2", git = "https://github.com/esp-rs-compat/getrandom.git" }
secp256k1 = { git = "https://github.com/Evanfeenstra/rust-secp256k1", branch = "v0.22.0-new-rand" }
lightning = { git = "https://github.com/Evanfeenstra/rust-lightning", branch = "v0.0.108-branch" }
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ Find the path to your `riscv32-esp-elf-gcc` binary within the `.embuild` dir:

### flash release

`espflash target/riscv32imc-esp-espidf/release/sphinx-key --monitor`
`esptool.py --chip esp32c3 elf2image target/riscv32imc-esp-espidf/release/sphinx-key`

`esptool.py --chip esp32c3 -p /dev/tty.usbserial-1420 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x10000 target/riscv32imc-esp-espidf/release/sphinx-key.bin`

### monitor

Expand All @@ -32,6 +34,26 @@ ls /dev/cu.*
espmonitor /dev/tty.usbserial-1420
```

### configure the hardware

make a seed: `./sphinx-key/newseed.sh`

make a `.env` file like:

```
SSID=my_ssid
PASS=my_wifi_password
BROKER=my_ip:1883
SEED=my_seed
NETWORK=regtest
```

connect to the `sphinxkey` network on your computer

`cargo run --bin config`

This will encrypt your seed and send to the hardware, along with your home wifi information and broker address

# dependencies

`cd sphinx-key`
Expand Down Expand Up @@ -98,3 +120,11 @@ esptool.py --chip esp32c3 elf2image target/riscv32imc-esp-espidf/release/sphinx-
esptool.py --chip esp32c3 -p /dev/tty.usbserial-1420 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x10000 target/riscv32imc-esp-espidf/release/sphinx-key.bin

espmonitor /dev/tty.usbserial-1420

### config

./sphinx-key/rando.sh

make your .env

cargo run --bin config
21 changes: 0 additions & 21 deletions broker/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ mod util;
use crate::chain_tracker::MqttSignerPort;
use crate::mqtt::start_broker;
use crate::unix_fd::SignerLoop;
use bitcoin::Network;
use clap::{arg, App, AppSettings, Arg};
use std::env;
use std::sync::Arc;
Expand Down Expand Up @@ -54,26 +53,9 @@ fn main() -> anyhow::Result<()> {
.arg(arg!(--"log-io" "ignored dev flag"))
.arg(arg!(--version "show a dummy version"))
.arg(arg!(--test "run a test against the embedded device"))
.arg(
Arg::new("network")
.help("bitcoin network")
.long("network")
.value_parser(["regtest", "signet", "testnet", "mainnet", "bitcoin"])
.default_value("regtest"),
);

let matches = app.get_matches();

let network_string: &String = matches.get_one("network").expect("expected a network");
let network: Network = match network_string.as_str() {
"bitcoin" => Network::Bitcoin,
"mainnet" => Network::Bitcoin,
"testnet" => Network::Testnet,
"signet" => Network::Signet,
"regtest" => Network::Regtest,
_ => Network::Regtest,
};

if matches.is_present("version") {
// Pretend to be the right version, given to us by an env var
let version =
Expand All @@ -82,7 +64,6 @@ fn main() -> anyhow::Result<()> {
return Ok(());
}

log::info!("NETWORK: {}", network.to_string());
if matches.is_present("test") {
run_test::run_test();
return Ok(());
Expand All @@ -98,8 +79,6 @@ fn main() -> anyhow::Result<()> {
log::info!("=> connection status: {}", status);
assert_eq!(status, true, "expected connected = true");
// runtime.block_on(async {
init::blocking_connect(tx.clone(), network);
log::info!("=====> sent seed!");

if let Ok(btc_url) = env::var("BITCOIND_RPC_URL") {
let signer_port = MqttSignerPort::new(tx.clone());
Expand Down
23 changes: 23 additions & 0 deletions crypter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "sphinx-key-crypter"
version = "0.1.0"
authors = ["Evan Feenstra <[email protected]>"]
edition = "2018"

[dependencies]
rand = "0.8"
anyhow = {version = "1", features = ["backtrace"]}
log = "0.4"
base64 = { version = "0.13.0" }
secp256k1 = { version = "0.22.0", features = ["std", "rand-std"] }

[dependencies.lightning]
version = "0.0.108"
default-features = false
features = ["std", "grind_signatures"]

[patch.crates-io]
getrandom = { version = "0.2", git = "https://github.com/esp-rs-compat/getrandom.git" }
secp256k1 = { git = "https://github.com/Evanfeenstra/rust-secp256k1", branch = "v0.22.0-new-rand" }
lightning = { git = "https://github.com/Evanfeenstra/rust-lightning", branch = "v0.0.108-branch" }

59 changes: 59 additions & 0 deletions crypter/src/chacha.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use anyhow::anyhow;
use lightning::util::chacha20poly1305rfc::ChaCha20Poly1305RFC;

pub const MSG_LEN: usize = 32;
pub const KEY_LEN: usize = 32;
pub const NONCE_END_LEN: usize = 8;
pub const TAG_LEN: usize = 16;
pub const CIPHER_LEN: usize = MSG_LEN + NONCE_END_LEN + TAG_LEN;

pub fn encrypt(
plaintext: [u8; MSG_LEN],
key: [u8; KEY_LEN],
nonce_end: [u8; NONCE_END_LEN],
) -> anyhow::Result<[u8; CIPHER_LEN]> {
let mut nonce = [0; 4 + NONCE_END_LEN];
nonce[4..].copy_from_slice(&nonce_end);
let mut chacha = ChaCha20Poly1305RFC::new(&key, &nonce, &[0; 0]);
let mut res = [0; MSG_LEN];
let mut tag = [0; TAG_LEN];
chacha.encrypt(&plaintext[..], &mut res[0..plaintext.len()], &mut tag);
let mut ret = [0; CIPHER_LEN];
ret[..MSG_LEN].copy_from_slice(&res);
ret[MSG_LEN..MSG_LEN + NONCE_END_LEN].copy_from_slice(&nonce_end);
ret[MSG_LEN + NONCE_END_LEN..].copy_from_slice(&tag);
Ok(ret)
}

pub fn decrypt(ciphertext: [u8; CIPHER_LEN], key: [u8; KEY_LEN]) -> anyhow::Result<[u8; MSG_LEN]> {
let mut nonce = [0; 4 + NONCE_END_LEN];
nonce[4..].copy_from_slice(&ciphertext[MSG_LEN..MSG_LEN + NONCE_END_LEN]);
let mut tag = [0; TAG_LEN];
tag.copy_from_slice(&ciphertext[MSG_LEN + NONCE_END_LEN..]);
let mut chacha2 = ChaCha20Poly1305RFC::new(&key, &nonce, &[0; 0]);
let mut dec = [0; MSG_LEN];
let ok = chacha2.decrypt(&ciphertext[..MSG_LEN], &mut dec, &tag);
if ok {
Ok(dec)
} else {
Err(anyhow!("failed chacha authentication"))
}
}

#[cfg(test)]
mod tests {
use crate::chacha::{decrypt, encrypt, KEY_LEN, MSG_LEN, NONCE_END_LEN};
use rand::{rngs::OsRng, RngCore};

#[test]
fn test_chacha() -> anyhow::Result<()> {
let key = [9; KEY_LEN];
let plaintext = [1; MSG_LEN];
let mut nonce_end = [0; NONCE_END_LEN];
OsRng.fill_bytes(&mut nonce_end);
let cipher = encrypt(plaintext, key, nonce_end)?;
let plain = decrypt(cipher, key)?;
assert_eq!(plaintext, plain);
Ok(())
}
}
47 changes: 47 additions & 0 deletions crypter/src/ecdh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use secp256k1::ecdh::SharedSecret;
use secp256k1::{SecretKey, PublicKey};
use anyhow::Result;

pub const PUBLIC_KEY_LEN: usize = 33;
pub const PRIVATE_KEY_LEN: usize = 32;
pub const SECRET_LEN: usize = 32;

pub fn derive_shared_secret_from_slice(their_public_key: [u8; PUBLIC_KEY_LEN], my_private_key: [u8; PRIVATE_KEY_LEN]) -> Result<[u8; SECRET_LEN]> {
let public_key = PublicKey::from_slice(&their_public_key[..])?;
let private_key = SecretKey::from_slice(&my_private_key[..])?;
Ok(derive_shared_secret(&public_key, &private_key).secret_bytes())
}

pub fn derive_shared_secret(their_public_key: &PublicKey, my_private_key: &SecretKey) -> SharedSecret {
SharedSecret::new(their_public_key, my_private_key)
}

#[cfg(test)]
mod tests {
use crate::ecdh::{derive_shared_secret, derive_shared_secret_from_slice};
use rand::thread_rng;
use secp256k1::Secp256k1;

#[test]
fn test_ecdh() -> anyhow::Result<()> {
let s = Secp256k1::new();
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
let sec1 = derive_shared_secret(&pk2, &sk1);
let sec2 = derive_shared_secret(&pk1, &sk2);
assert_eq!(sec1, sec2);
Ok(())
}

#[test]
fn test_ecdh_from_slice() -> anyhow::Result<()> {
let s = Secp256k1::new();
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
let sec1 = derive_shared_secret_from_slice(pk2.serialize(), sk1.secret_bytes())?;
let sec2 = derive_shared_secret_from_slice(pk1.serialize(), sk2.secret_bytes())?;
assert_eq!(sec1, sec2);
Ok(())
}

}
38 changes: 38 additions & 0 deletions crypter/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
pub mod chacha;
pub mod ecdh;

pub use secp256k1;

#[cfg(test)]
mod tests {
use crate::chacha::{decrypt, encrypt, MSG_LEN, NONCE_END_LEN};
use crate::ecdh::derive_shared_secret_from_slice;
use secp256k1::rand::{rngs::OsRng, thread_rng, RngCore};
use secp256k1::Secp256k1;

#[test]
fn test_crypter() -> anyhow::Result<()> {
// two keypairs
let s = Secp256k1::new();
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());

// derive shared secrets
let sec1 = derive_shared_secret_from_slice(pk2.serialize(), sk1.secret_bytes())?;
let sec2 = derive_shared_secret_from_slice(pk1.serialize(), sk2.secret_bytes())?;
assert_eq!(sec1, sec2);

// encrypt plaintext with sec1
let plaintext = [1; MSG_LEN];
let mut nonce_end = [0; NONCE_END_LEN];
OsRng.fill_bytes(&mut nonce_end);
let cipher = encrypt(plaintext, sec1, nonce_end)?;

// decrypt with sec2
let plain = decrypt(cipher, sec2)?;
assert_eq!(plaintext, plain);

println!("PLAINTEXT MATCHES!");
Ok(())
}
}
3 changes: 2 additions & 1 deletion signer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use lightning_signer::persist::{DummyPersister, Persist};
// use lightning_signer::Arc;
use sphinx_key_parser::MsgDriver;
use std::sync::Arc;
use vls_protocol::model::PubKey;
use vls_protocol::msgs::{self, read_serial_request_header, write_serial_response_header, Message};
use vls_protocol::serde_bolt::WireString;
use vls_protocol_signer::handler::{Handler, RootHandler};

pub use vls_protocol_signer::lightning_signer;
pub use vls_protocol_signer::lightning_signer::bitcoin::Network;
pub use vls_protocol_signer::vls_protocol;
pub use sphinx_key_parser::MsgDriver;

pub struct InitResponse {
pub root_handler: RootHandler,
Expand Down
3 changes: 3 additions & 0 deletions sphinx-key/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pingpong = []
[dependencies]
esp-idf-sys = { version = "0.31.5", features = ["binstart"] }
sphinx-key-signer = { path = "../signer", optional = true }
sphinx-key-crypter = { path = "../crypter" }
embedded-svc = { version = "0.21.2" }
esp-idf-svc = "0.41"
esp-idf-hal = "0.37"
Expand All @@ -31,11 +32,13 @@ url = "2"
serde_urlencoded = "0.7.1"
serde = { version = "1.0.137", default-features = false }
serde_json = { version = "1.0.81", default-features = false }
hex = "0.4.3"

[patch.crates-io]
# updates the "rand" create to use esp RNG
getrandom = { version = "0.2", git = "https://github.com/esp-rs-compat/getrandom.git" }
secp256k1 = { git = "https://github.com/Evanfeenstra/rust-secp256k1", branch = "v0.22.0-new-rand" }
lightning = { git = "https://github.com/Evanfeenstra/rust-lightning", branch = "v0.0.108-branch" }

[build-dependencies]
embuild = "0.29"
Expand Down
5 changes: 5 additions & 0 deletions sphinx-key/newseed.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

n=32

hexdump -vn "$n" -e ' /1 "%02x"' /dev/urandom ; echo
7 changes: 7 additions & 0 deletions sphinx-key/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cargo +nightly build --release

esptool.py --chip esp32c3 elf2image target/riscv32imc-esp-espidf/release/sphinx-key

esptool.py --chip esp32c3 -p /dev/tty.usbserial-1420 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x10000 target/riscv32imc-esp-espidf/release/sphinx-key.bin

espmonitor /dev/tty.usbserial-1420
Loading

0 comments on commit d9b7ddb

Please sign in to comment.