mirror of
https://github.com/stakwork/sphinx-key.git
synced 2025-12-18 07:44:21 +01:00
encrypted seed to hardware, configDTO, tested config bin that takes params from .env
This commit is contained in:
27
README.md
27
README.md
@@ -32,6 +32,25 @@ 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
|
||||
```
|
||||
|
||||
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`
|
||||
@@ -98,3 +117,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
|
||||
@@ -1,13 +1,17 @@
|
||||
use lightning::util::chacha20poly1305rfc::ChaCha20Poly1305RFC;
|
||||
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;
|
||||
const TAG_LEN: usize = 16;
|
||||
const CIPHER_LEN: usize = MSG_LEN + NONCE_END_LEN + TAG_LEN;
|
||||
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]> {
|
||||
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]);
|
||||
@@ -38,7 +42,7 @@ pub fn decrypt(ciphertext: [u8; CIPHER_LEN], key: [u8; KEY_LEN]) -> anyhow::Resu
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::chacha::{decrypt, encrypt, MSG_LEN, KEY_LEN, NONCE_END_LEN};
|
||||
use crate::chacha::{decrypt, encrypt, KEY_LEN, MSG_LEN, NONCE_END_LEN};
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
|
||||
#[test]
|
||||
@@ -52,5 +56,4 @@ mod tests {
|
||||
assert_eq!(plaintext, plain);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ pub use secp256k1;
|
||||
mod tests {
|
||||
use crate::chacha::{decrypt, encrypt, MSG_LEN, NONCE_END_LEN};
|
||||
use crate::ecdh::derive_shared_secret_from_slice;
|
||||
use rand::{rngs::OsRng, thread_rng, RngCore};
|
||||
use secp256k1::rand::{rngs::OsRng, thread_rng, RngCore};
|
||||
use secp256k1::Secp256k1;
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -32,6 +32,7 @@ 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
|
||||
|
||||
5
sphinx-key/newseed.sh
Executable file
5
sphinx-key/newseed.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
n=32
|
||||
|
||||
hexdump -vn "$n" -e ' /1 "%02x"' /dev/urandom ; echo
|
||||
7
sphinx-key/run.sh
Executable file
7
sphinx-key/run.sh
Executable file
@@ -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
|
||||
@@ -1,32 +1,64 @@
|
||||
use crate::conn::html;
|
||||
use crate::core::config::Config;
|
||||
use crate::core::config::{Config, ConfigDTO};
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
|
||||
use embedded_svc::httpd::registry::Registry;
|
||||
use embedded_svc::httpd::*;
|
||||
use esp_idf_svc::httpd as idf;
|
||||
use std::sync::{Condvar, Mutex, Arc};
|
||||
use embedded_svc::httpd::registry::Registry;
|
||||
use serde::Deserialize;
|
||||
|
||||
use sphinx_key_crypter::chacha::{decrypt, CIPHER_LEN};
|
||||
use sphinx_key_crypter::ecdh::{derive_shared_secret_from_slice, PUBLIC_KEY_LEN};
|
||||
use sphinx_key_crypter::secp256k1::rand::thread_rng;
|
||||
use sphinx_key_crypter::secp256k1::Secp256k1;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Ecdh {
|
||||
pub pubkey: String,
|
||||
}
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Params {
|
||||
pub config: String
|
||||
pub config: String,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn config_server(mutex: Arc<(Mutex<Option<Config>>, Condvar)>) -> Result<idf::Server> {
|
||||
let s = Secp256k1::new();
|
||||
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
||||
let pk_hex = hex::encode(pk1.serialize());
|
||||
|
||||
let server = idf::ServerRegistry::new()
|
||||
.at("/")
|
||||
.get(|_| Ok(html::HTML.into()))?
|
||||
.at("/ecdh")
|
||||
.get(move |_| Ok(format!("{{\"pubkey\":\"{}\"}}", pk_hex).to_owned().into()))?
|
||||
.at("/config")
|
||||
.post(move |request| {
|
||||
let bod = &request.query_string()
|
||||
let bod = &request
|
||||
.query_string()
|
||||
.ok_or(anyhow::anyhow!("failed to parse query string"))?;
|
||||
println!("bod {:?}", bod);
|
||||
let params = serde_urlencoded::from_str::<Params>(bod)?;
|
||||
|
||||
let conf = serde_json::from_str::<Config>(¶ms.config)?;
|
||||
let dto = serde_json::from_str::<ConfigDTO>(¶ms.config)?;
|
||||
|
||||
let their_pk = hex::decode(dto.pubkey)?;
|
||||
let their_pk_bytes: [u8; PUBLIC_KEY_LEN] = their_pk[..PUBLIC_KEY_LEN].try_into()?;
|
||||
let shared_secret =
|
||||
derive_shared_secret_from_slice(their_pk_bytes, sk1.secret_bytes())?;
|
||||
// decrypt seed
|
||||
let cipher_seed = hex::decode(dto.seed)?;
|
||||
let cipher: [u8; CIPHER_LEN] = cipher_seed[..CIPHER_LEN].try_into()?;
|
||||
let seed = decrypt(cipher, shared_secret)?;
|
||||
|
||||
let conf = Config {
|
||||
broker: dto.broker,
|
||||
ssid: dto.ssid,
|
||||
pass: dto.pass,
|
||||
seed: seed,
|
||||
};
|
||||
let mut wait = mutex.0.lock().unwrap();
|
||||
*wait = Some(conf);
|
||||
mutex.1.notify_one();
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
use crate::conn;
|
||||
|
||||
use anyhow::Result;
|
||||
use std::sync::{Condvar, Mutex, Arc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
use std::time::Duration;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use embedded_svc::wifi::*;
|
||||
use esp_idf_svc::nvs::*;
|
||||
use esp_idf_svc::wifi::*;
|
||||
use embedded_svc::wifi::*;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
pub broker: String,
|
||||
pub ssid: String,
|
||||
pub pass: String,
|
||||
pub seed: [u8; 32],
|
||||
}
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct ConfigDTO {
|
||||
pub broker: String,
|
||||
pub ssid: String,
|
||||
pub pass: String,
|
||||
pub pubkey: String,
|
||||
pub seed: String, // encrypted (56 bytes)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -28,26 +37,21 @@ http://192.168.71.1/?broker=192.168.86.222%3A1883
|
||||
*/
|
||||
|
||||
pub fn start_wifi_client(default_nvs: Arc<EspDefaultNvs>, config: &Config) -> Result<Box<EspWifi>> {
|
||||
let wifi = conn::wifi::start_client(
|
||||
default_nvs,
|
||||
config
|
||||
)?;
|
||||
let wifi = conn::wifi::start_client(default_nvs, config)?;
|
||||
println!("CLIENT CONNECTED!!!!!! {:?}", wifi.get_status());
|
||||
Ok(wifi)
|
||||
}
|
||||
|
||||
pub fn start_config_server_and_wait(default_nvs: Arc<EspDefaultNvs>) -> Result<(Box<EspWifi>, Config)> {
|
||||
|
||||
pub fn start_config_server_and_wait(
|
||||
default_nvs: Arc<EspDefaultNvs>,
|
||||
) -> Result<(Box<EspWifi>, Config)> {
|
||||
let mutex = Arc::new((Mutex::new(None), Condvar::new()));
|
||||
|
||||
#[allow(clippy::redundant_clone)]
|
||||
#[allow(unused_mut)]
|
||||
let mut wifi = conn::wifi::start_access_point(
|
||||
default_nvs.clone(),
|
||||
)?;
|
||||
let mut wifi = conn::wifi::start_access_point(default_nvs.clone())?;
|
||||
|
||||
let httpd = conn::http::config_server(mutex.clone());
|
||||
|
||||
let mut wait = mutex.0.lock().unwrap();
|
||||
|
||||
let config: &Config = loop {
|
||||
|
||||
@@ -21,6 +21,7 @@ pub struct ConfigBody {
|
||||
pub ssid: String,
|
||||
pub pass: String,
|
||||
pub broker: String,
|
||||
pub pubkey: String, // for ecdh
|
||||
}
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ConfigResponse {
|
||||
@@ -34,6 +35,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
let ssid: String = env::var("SSID").expect("no ssid");
|
||||
let pass: String = env::var("PASS").expect("no pass");
|
||||
let broker: String = env::var("BROKER").expect("no broker");
|
||||
let seed_string: String = env::var("SEED").expect("no seed");
|
||||
let seed: [u8; MSG_LEN] = hex::decode(seed_string)?[..MSG_LEN].try_into()?;
|
||||
println!("seed {:?}", seed);
|
||||
|
||||
let s = Secp256k1::new();
|
||||
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
||||
@@ -43,12 +47,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
.build()
|
||||
.expect("couldnt build reqwest client");
|
||||
|
||||
let body = EcdhBody {
|
||||
pubkey: hex::encode(pk1.serialize()),
|
||||
};
|
||||
let res = client
|
||||
.post(format!("{}{}", URL, "ecdh"))
|
||||
.json(&body)
|
||||
.get(format!("{}{}", URL, "ecdh"))
|
||||
.header("Content-Type", "application/json")
|
||||
.send()
|
||||
.await?;
|
||||
@@ -58,22 +58,22 @@ async fn main() -> anyhow::Result<()> {
|
||||
let their_pk_bytes: [u8; PUBLIC_KEY_LEN] = their_pk[..PUBLIC_KEY_LEN].try_into()?;
|
||||
let shared_secret = derive_shared_secret_from_slice(their_pk_bytes, sk1.secret_bytes())?;
|
||||
|
||||
let plaintext = [1; MSG_LEN];
|
||||
let mut nonce_end = [0; NONCE_END_LEN];
|
||||
OsRng.fill_bytes(&mut nonce_end);
|
||||
let cipher = encrypt(plaintext, shared_secret, nonce_end)?;
|
||||
let cipher = encrypt(seed, shared_secret, nonce_end)?;
|
||||
|
||||
let cipher_seed = hex::encode(cipher);
|
||||
let config = ConfigBody {
|
||||
seed: cipher_seed,
|
||||
ssid, pass, broker,
|
||||
pubkey: hex::encode(pk1.serialize()),
|
||||
};
|
||||
|
||||
let conf_string = serde_json::to_string(&config)?;
|
||||
let conf_encoded = urlencoding::encode(&conf_string).to_owned();
|
||||
|
||||
let res2 = client
|
||||
.post(format!("{}{}{}", URL, "/config?config=", conf_encoded))
|
||||
.post(format!("{}{}{}", URL, "config?config=", conf_encoded))
|
||||
.send()
|
||||
.await?;
|
||||
let conf_res: ConfigResponse = res2.json().await?;
|
||||
|
||||
Reference in New Issue
Block a user