Skip to content

Crypto v0.0.4 - #799

Open
janiejestemja wants to merge 18 commits into
release/0.0.13from
feat/pqc-r0.0.13
Open

Crypto v0.0.4#799
janiejestemja wants to merge 18 commits into
release/0.0.13from
feat/pqc-r0.0.13

Conversation

@janiejestemja

@janiejestemja janiejestemja commented Jul 20, 2026

Copy link
Copy Markdown
Member

This draft contains:

  • static crypto keys for (own) com hub
  • static crypto keys for each (peers) socket (setup via HelloBlock)
  • per msg random symmetric key
    • msg keys are wrapped using key encryption key, derived from shared secret (using pri keys from own com hub and pub keys from peers socket properties)

Additional changes:

  • fixes surrounding stackoverflows within the com hub on esp (moved code around, removed some clones, lightened stack with heap allocations)

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (datex_macros)

10 tests  ±0   10 ✅ ±0   0s ⏱️ ±0s
 2 suites ±0    0 💤 ±0 
 1 files   ±0    0 ❌ ±0 

Results for commit 425a1cf. ± Comparison against base commit aca6e0c.

@janiejestemja janiejestemja left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you're ok with the changes in general, i'll go ahead and replace all the .unwrap()'s with more proper error handling. @benStre @jonasstrehle

sadly i failed at my first attempt to implement pqc across the board, i'll try more thoroughly for crypto v0.0.5 i suppose. luckily this means, i didn't had to introduce the HalloBack block type for now.

in general next things i'd approach are these two

  • wire up rng behind nonce for aes, and salt for hkdf (current version leaks a little 🥹)
  • add ephemeral x25519 keys (current implementation is not forward secure 😭 )

what i can't wrap my mind around is

  • add static keys via config file and implement some sort of whitelisting within the interface-section as well? is there really a need for this?

}
}

pub trait CryptoSync: Send + Sync {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the idea here is to circumvent the async restrictions given by web crypto api, for now...

since only web crypto is async, i copied the crypto implementation from embedded there. it's kind of a cheat, and i feel like this can be done differently by doing some refactoring around it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good solution to separate the async and sync implementations - we did something similar for the ComInterfaceFactories. But since crypto is just included via the facade, we need a uniform interface for every implementation. So I think you could implement CryptoSync e.g. for native like it is right now, and then auto derive the Crypto trait for every T that implements CryptoSync.
We could then later actually support sync execution with crypto, but for now, only the async Crypto trait will actually be used.

/// * the block signature is validated because the block is for own endpoint and signature is set
/// * the block needs to be relayed to other endpoints or is a trace block, which requires async handling for the relay/trace logic
/// The MaybeAsync returns the own received block if the block is for own endpoint and signature is valid, otherwise None
// FIXME #732: this seams to generate a very big future which causes heap allocation to fail on embedded targets (!?)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not entirely certain if i fixed this, by fixing a FIXME no-clone, reordering the code, and using pinned boxes for trace blocks.

if is_for_own && block_type != BlockType::Hello {
info!("Block is for this endpoint ({})", self.endpoint);

Some(block) // FIXME #733: no clone

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixme comment can be removed, left it there as a reference for review....

}

/// Updates the sender and timestamp of the block
fn update_sender_and_timestamp(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm uncertain why this method was nested into the one beneath (prapare_own_block()), as far as i understand nested function in general lead to issues, although i don't know if this would be here the case.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was just an arbitrary decision because this function was only used inside prepare_own_block, and is also just a standalone utitlity function, not a method that needs self. I don't think theres really a downside in this case, but I also think its cleaner to have it as a separate method.

.flags_and_timestamp
.set_block_type(BlockType::Hello);
// TODO #182 include fingerprint of the own public key into body
// -> done in prepare_own_block (for now?)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually the prepare body function currently clones own public keys into the body of hello-blocks, not just a fingerprint. without a working certificate authority, where the fingerprint can be used to retrieve a verified key a fingerprint seems rather useless for now.

although if the long term plan is to setup a server acting as certificate authority in this context, it would be unnecessary to implement per-interface-whitelisting of any sorts.

@benStre benStre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you - looks good.
I added a view comments - overall, I think you can continue with this approach.
Loading the endpoint keys from the config would be very cool to have, but you can also add this at the end once everything else works.

}
}

pub trait CryptoSync: Send + Sync {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good solution to separate the async and sync implementations - we did something similar for the ComInterfaceFactories. But since crypto is just included via the facade, we need a uniform interface for every implementation. So I think you could implement CryptoSync e.g. for native like it is right now, and then auto derive the Crypto trait for every T that implements CryptoSync.
We could then later actually support sync execution with crypto, but for now, only the async Crypto trait will actually be used.


fn gen_ed25519<'a>()
-> AsyncCryptoResult<'a, (Vec<u8>, Vec<u8>), Self::Ed25519GenError>
-> AsyncCryptoResult<'a, ([u8; 32], [u8; 32]), Self::Ed25519GenError>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend to define a type alias for the [u8; 32] and others that are used in multiple locations, e.g.

type PrivKey = [u8; 32]

It might even be better to put them into actual newtype wrapper structs, to ensure a private and public key or whatever don't get accidently mixed up.

}

/// Updates the sender and timestamp of the block
fn update_sender_and_timestamp(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was just an arbitrary decision because this function was only used inside prepare_own_block, and is also just a standalone utitlity function, not a method that needs self. I don't think theres really a downside in this case, but I also think its cleaner to have it as a separate method.

pub direct_endpoint: Option<Endpoint>,
pub connection_timestamp: u64,
uuid: ComInterfaceSocketUUID,
pub pub_sig_key: Option<[u8; 32]>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keys should always be associated directly with an Endpoint, not with a socket. An endpoint might be connected via multiple sockets, and multiple endpoints might be connected via a single socket. It's also necessary to keep the keys in memory when a socket disconnects.
The most simple solution would be something like a HashMap<Endpointt,Keys> stored in the ComHub.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants