This commit is contained in:
Cilly Leang 2026-06-23 01:35:22 +10:00
commit 41042ecbb0
Signed by: cilly
GPG key ID: 6500251E087653C9
7 changed files with 1576 additions and 0 deletions

158
src/main.rs Normal file
View file

@ -0,0 +1,158 @@
use std::collections::HashMap;
use std::fs;
use std::io::stdin;
use ctap_hid_fido2::fidokey::{GetAssertionArgsBuilder, MakeCredentialArgsBuilder};
use ctap_hid_fido2::public_key::PublicKey;
use ctap_hid_fido2::public_key_credential_user_entity::PublicKeyCredentialUserEntity;
use ctap_hid_fido2::util::to_hex_str;
use ctap_hid_fido2::{Cfg, FidoKeyHidFactory, verifier};
use serde::{Serialize, Deserialize};
use sha2::Digest;
const RPID: &str = "thistle.lava.moe";
const RPID_HASH: [u8; 32] = sha2_const::Sha256::new()
.update(RPID.as_bytes())
.finalize();
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct Directory {
nonresidents: HashMap<String, String>,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
enum DirectoryFormat {
Version1(Directory)
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct VaultBlock {
salt: [u8; 8],
keys: Vec<[u8; 32]>,
data: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct Vault {
id: u128,
salt: [u8; 32],
blocks: Vec<VaultBlock>,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
enum VaultFormat {
Version1(Vault)
}
fn prompt(msg: &str) -> anyhow::Result<String> {
print!("{}", msg);
let mut res = String::new();
stdin().read_line(&mut res)?;
Ok(res.trim().to_string())
}
fn cmd_auth() -> anyhow::Result<()> {
// let f = format!("{:x}",
let device = FidoKeyHidFactory::create(&Cfg::init())?;
let challenge = verifier::create_challenge();
let pin = rpassword::prompt_password("Input PIN: ")?;
let get_assertion_args = GetAssertionArgsBuilder::new(RPID, &challenge)
.pin(&pin)
// .without_pin_and_uv()
.without_up()
.build();
let assertions = device.get_assertion_with_args(&get_assertion_args)?;
println!("-- Authenticate Success");
println!("-- Assertion Num = {:?}", assertions.len());
for assertion in &assertions {
println!("- assertion = {}", assertion);
println!("- user = {}", assertion.user);
}
let enu = device.credential_management_enumerate_credentials(Some(&pin), &RPID_HASH)?;
println!("-- Cred Num = {:?}", enu.len());
for enume in &enu {
println!("{}", enume);
}
Ok(())
}
fn cmd_create() -> anyhow::Result<()> {
let device = FidoKeyHidFactory::create(&Cfg::init())?;
let pin = rpassword::prompt_password("Input PIN: ")?;
let file_id: u128 = rand::random();
let ent = PublicKeyCredentialUserEntity::new(
Some(&file_id.to_le_bytes()),
None, None,
);
let challenge = verifier::create_challenge();
let make_credential_args = MakeCredentialArgsBuilder::new(RPID, &challenge)
.user_entity(&ent)
.resident_key()
.pin(&pin)
.build();
let attestation = device.make_credential_with_args(&make_credential_args)?;
println!("{}", attestation);
println!("Registered");
let verify_result = verifier::verify_attestation(RPID, &challenge, &attestation);
if !verify_result.is_success {
println!("! Verification failed, faulty key?");
return Ok(());
}
println!("Verified");
let vault = Vault {
id: file_id,
salt: rand::random(),
blocks: vec![],
};
fs::write(format!("./data/{}.vault", to_hex_str(&file_id.to_le_bytes())), postcard::to_stdvec(&vault)?)?;
Ok(())
}
fn cmd_decrypt(name: &str) -> anyhow::Result<()> {
Ok(())
}
fn cmd_encrypt(name: &str) -> anyhow::Result<()> {
Ok(())
}
fn cmd_info() -> anyhow::Result<()> {
let device = FidoKeyHidFactory::create(&Cfg::init())?;
println!("{}", device.get_info()?);
Ok(())
}
fn main() -> anyhow::Result<()> {
println!("Hello, world!");
let args = std::env::args().collect::<Vec<_>>();
let Some(cmd) = args.get(1) else {
eprintln!("Missing args");
return Ok(())
};
let fname = args.get(2);
match cmd.as_str() {
"auth" => cmd_auth()?,
"create" => cmd_create()?,
"decrypt" => cmd_create()?,
"encrypt" => cmd_create()?,
"info" => cmd_info()?,
_ => {
eprintln!("Unknown command");
}
}
Ok(())
}