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
|
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
|
# dependencies
|
||||||
|
|
||||||
`cd sphinx-key`
|
`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
|
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
|
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 anyhow::anyhow;
|
||||||
|
use lightning::util::chacha20poly1305rfc::ChaCha20Poly1305RFC;
|
||||||
|
|
||||||
pub const MSG_LEN: usize = 32;
|
pub const MSG_LEN: usize = 32;
|
||||||
pub const KEY_LEN: usize = 32;
|
pub const KEY_LEN: usize = 32;
|
||||||
pub const NONCE_END_LEN: usize = 8;
|
pub const NONCE_END_LEN: usize = 8;
|
||||||
const TAG_LEN: usize = 16;
|
pub const TAG_LEN: usize = 16;
|
||||||
const CIPHER_LEN: usize = MSG_LEN + NONCE_END_LEN + TAG_LEN;
|
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];
|
let mut nonce = [0; 4 + NONCE_END_LEN];
|
||||||
nonce[4..].copy_from_slice(&nonce_end);
|
nonce[4..].copy_from_slice(&nonce_end);
|
||||||
let mut chacha = ChaCha20Poly1305RFC::new(&key, &nonce, &[0; 0]);
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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};
|
use rand::{rngs::OsRng, RngCore};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -52,5 +56,4 @@ mod tests {
|
|||||||
assert_eq!(plaintext, plain);
|
assert_eq!(plaintext, plain);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub use secp256k1;
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::chacha::{decrypt, encrypt, MSG_LEN, NONCE_END_LEN};
|
use crate::chacha::{decrypt, encrypt, MSG_LEN, NONCE_END_LEN};
|
||||||
use crate::ecdh::derive_shared_secret_from_slice;
|
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;
|
use secp256k1::Secp256k1;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ url = "2"
|
|||||||
serde_urlencoded = "0.7.1"
|
serde_urlencoded = "0.7.1"
|
||||||
serde = { version = "1.0.137", default-features = false }
|
serde = { version = "1.0.137", default-features = false }
|
||||||
serde_json = { version = "1.0.81", default-features = false }
|
serde_json = { version = "1.0.81", default-features = false }
|
||||||
|
hex = "0.4.3"
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
# updates the "rand" create to use esp RNG
|
# 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::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 embedded_svc::httpd::*;
|
||||||
use esp_idf_svc::httpd as idf;
|
use esp_idf_svc::httpd as idf;
|
||||||
use std::sync::{Condvar, Mutex, Arc};
|
|
||||||
use embedded_svc::httpd::registry::Registry;
|
use sphinx_key_crypter::chacha::{decrypt, CIPHER_LEN};
|
||||||
use serde::Deserialize;
|
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)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub config: String
|
pub config: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn config_server(mutex: Arc<(Mutex<Option<Config>>, Condvar)>) -> Result<idf::Server> {
|
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()
|
let server = idf::ServerRegistry::new()
|
||||||
.at("/")
|
.at("/")
|
||||||
.get(|_| Ok(html::HTML.into()))?
|
.get(|_| Ok(html::HTML.into()))?
|
||||||
|
.at("/ecdh")
|
||||||
|
.get(move |_| Ok(format!("{{\"pubkey\":\"{}\"}}", pk_hex).to_owned().into()))?
|
||||||
.at("/config")
|
.at("/config")
|
||||||
.post(move |request| {
|
.post(move |request| {
|
||||||
let bod = &request.query_string()
|
let bod = &request
|
||||||
|
.query_string()
|
||||||
.ok_or(anyhow::anyhow!("failed to parse query string"))?;
|
.ok_or(anyhow::anyhow!("failed to parse query string"))?;
|
||||||
println!("bod {:?}", bod);
|
println!("bod {:?}", bod);
|
||||||
let params = serde_urlencoded::from_str::<Params>(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();
|
let mut wait = mutex.0.lock().unwrap();
|
||||||
*wait = Some(conf);
|
*wait = Some(conf);
|
||||||
mutex.1.notify_one();
|
mutex.1.notify_one();
|
||||||
@@ -34,4 +66,4 @@ pub fn config_server(mutex: Arc<(Mutex<Option<Config>>, Condvar)>) -> Result<idf
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
server.start(&Default::default())
|
server.start(&Default::default())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,28 @@
|
|||||||
use crate::conn;
|
use crate::conn;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::sync::{Condvar, Mutex, Arc};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
|
use embedded_svc::wifi::*;
|
||||||
use esp_idf_svc::nvs::*;
|
use esp_idf_svc::nvs::*;
|
||||||
use esp_idf_svc::wifi::*;
|
use esp_idf_svc::wifi::*;
|
||||||
use embedded_svc::wifi::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub broker: String,
|
pub broker: String,
|
||||||
pub ssid: String,
|
pub ssid: String,
|
||||||
pub pass: 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -27,27 +36,22 @@ 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>> {
|
pub fn start_wifi_client(default_nvs: Arc<EspDefaultNvs>, config: &Config) -> Result<Box<EspWifi>> {
|
||||||
let wifi = conn::wifi::start_client(
|
let wifi = conn::wifi::start_client(default_nvs, config)?;
|
||||||
default_nvs,
|
|
||||||
config
|
|
||||||
)?;
|
|
||||||
println!("CLIENT CONNECTED!!!!!! {:?}", wifi.get_status());
|
println!("CLIENT CONNECTED!!!!!! {:?}", wifi.get_status());
|
||||||
Ok(wifi)
|
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()));
|
let mutex = Arc::new((Mutex::new(None), Condvar::new()));
|
||||||
|
|
||||||
#[allow(clippy::redundant_clone)]
|
#[allow(clippy::redundant_clone)]
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut wifi = conn::wifi::start_access_point(
|
let mut wifi = conn::wifi::start_access_point(default_nvs.clone())?;
|
||||||
default_nvs.clone(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let httpd = conn::http::config_server(mutex.clone());
|
let httpd = conn::http::config_server(mutex.clone());
|
||||||
|
|
||||||
let mut wait = mutex.0.lock().unwrap();
|
let mut wait = mutex.0.lock().unwrap();
|
||||||
|
|
||||||
let config: &Config = loop {
|
let config: &Config = loop {
|
||||||
@@ -67,4 +71,4 @@ pub fn start_config_server_and_wait(default_nvs: Arc<EspDefaultNvs>) -> Result<(
|
|||||||
// thread::sleep(Duration::from_secs(1));
|
// thread::sleep(Duration::from_secs(1));
|
||||||
println!("===> config! {:?}", config);
|
println!("===> config! {:?}", config);
|
||||||
Ok((wifi, config.clone()))
|
Ok((wifi, config.clone()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ pub struct ConfigBody {
|
|||||||
pub ssid: String,
|
pub ssid: String,
|
||||||
pub pass: String,
|
pub pass: String,
|
||||||
pub broker: String,
|
pub broker: String,
|
||||||
|
pub pubkey: String, // for ecdh
|
||||||
}
|
}
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct ConfigResponse {
|
pub struct ConfigResponse {
|
||||||
@@ -34,6 +35,9 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let ssid: String = env::var("SSID").expect("no ssid");
|
let ssid: String = env::var("SSID").expect("no ssid");
|
||||||
let pass: String = env::var("PASS").expect("no pass");
|
let pass: String = env::var("PASS").expect("no pass");
|
||||||
let broker: String = env::var("BROKER").expect("no broker");
|
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 s = Secp256k1::new();
|
||||||
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
||||||
@@ -43,12 +47,8 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
.build()
|
.build()
|
||||||
.expect("couldnt build reqwest client");
|
.expect("couldnt build reqwest client");
|
||||||
|
|
||||||
let body = EcdhBody {
|
|
||||||
pubkey: hex::encode(pk1.serialize()),
|
|
||||||
};
|
|
||||||
let res = client
|
let res = client
|
||||||
.post(format!("{}{}", URL, "ecdh"))
|
.get(format!("{}{}", URL, "ecdh"))
|
||||||
.json(&body)
|
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.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 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 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];
|
let mut nonce_end = [0; NONCE_END_LEN];
|
||||||
OsRng.fill_bytes(&mut nonce_end);
|
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 cipher_seed = hex::encode(cipher);
|
||||||
let config = ConfigBody {
|
let config = ConfigBody {
|
||||||
seed: cipher_seed,
|
seed: cipher_seed,
|
||||||
ssid, pass, broker,
|
ssid, pass, broker,
|
||||||
|
pubkey: hex::encode(pk1.serialize()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let conf_string = serde_json::to_string(&config)?;
|
let conf_string = serde_json::to_string(&config)?;
|
||||||
let conf_encoded = urlencoding::encode(&conf_string).to_owned();
|
let conf_encoded = urlencoding::encode(&conf_string).to_owned();
|
||||||
|
|
||||||
let res2 = client
|
let res2 = client
|
||||||
.post(format!("{}{}{}", URL, "/config?config=", conf_encoded))
|
.post(format!("{}{}{}", URL, "config?config=", conf_encoded))
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
let conf_res: ConfigResponse = res2.json().await?;
|
let conf_res: ConfigResponse = res2.json().await?;
|
||||||
|
|||||||
Reference in New Issue
Block a user