Skip to main content

citadel_sdk/
lib.rs

1#![doc(html_logo_url = "avarok.png", html_favicon_url = "favicon.png")]
2//! Software development kit for creating high performance, extremely-secure, and post-quantum network applications. Supports p2p (NAT traversal + WebRTC) and standard client/server architectures for
3//! messaging and streaming. The underlying asynchronous runtime is [Tokio](https://tokio.rs).
4//!
5//! The Network protocol, SDK, and user libraries use 100% safe rust
6//!
7//! All peer-discovery and NAT traversal are built-in to the protocol, with the central server acting as a broker and authenticator. The central server is used for TURN-like routing when direct p2p NAT traversal fails between two nodes.
8//!
9//! Authentication to a central node is required before making peer-to-peer connections. There is both device-dependent auth as well as credentialed authentication backed by the argon2id hashing algorithm.
10//!
11//! Client/Peer information is by default synchronized to the local filesystem. If the *redis* and/or *sql* feature is enabled, a redis or SQL (MySQL, PostgreSQL, SQLite) server or cluster can be used instead.
12//!
13//! When messaging is used, perfect forward secrecy (PFS) is an optional mode on a per-session basis. Best-effort mode (BEM) is also available if the security of PFS is not needed, and instead, high throughput
14//! in messaging is required.
15//!
16//! Client-to-server connections can use TCP, TLS (default), or QUIC protocols for the underlying communication. Cryptographers recommend the use of hybrid protocols, and as such, TLS is the default to
17//! ensure implementations of post-quantum networks are at least as secure as traditional methods. Valid certificates can be specified when constructing the application, otherwise, self-signed certificates are used for the underlying protocol.
18//!
19//! Peer-to-peer connections only use QUIC. In order to establish a direct peer-to-peer connection, UDP NAT-traversal is required, and as such, the use of QUIC complements this requirement since QUIC uses UDP for ordered, reliable transport.
20//!
21//! Streaming is also available in this crate. When the use of webrtc is desired for an application, the *webrtc* feature can be enabled to allow interoperability between the [`UdpChannel`] and the [WebRTC.rs](https://webrtc.rs) ecosystem.
22//!
23//! # Feature Flags
24//! - `multi-threaded`: Uses a multi-threaded (Send) executor for the inner protocol
25//! - `redis`: Enables the use of Redis for the backend
26//! - `sql`: Enables the use of sql for the backend
27//! - `webrtc`: enables *limited* interoperability with webrtc via the [`UdpChannel`] (see: `UdpChannel::into_webrtc_compat`, available with the feature enabled)
28//!
29//!
30//! # Post-quantum key encapsulation mechanisms
31//! The user may also select a KEM family before a session to either a central server or peer begins (see: [SessionSecuritySettingsBuilder](crate::prelude::SessionSecuritySettingsBuilder)). Each KEM has variants that alter the degree of security
32//! - Kyber (default)
33//! - NTRU (Sntrup761)
34//!
35//! # Encryption Algorithms
36//! The user may also select a symmetric encryption algorithm before a session starts (see: [SessionSecuritySettingsBuilder](crate::prelude::SessionSecuritySettingsBuilder))
37//!
38//! - AES-256-GCM
39//! - Chacha20Poly-1305
40//! - Ascon-80pq
41//! - Kyber Hybrid Encryption (see below for explanation)
42//!
43//! Whereas AES-GCM and ChaCha are only quantum resistant (as opposed to post-quantum), a novel method of encryption may be used that
44//! combines the post-quantum asymmetric encryption algorithm Kyber coupled with AES. When Kyber Hybrid Encryption is used, several modifications to the protocol outlined in the whitepaper
45//! is applied. The first modification is the use of Falcon-1024 to sign each message to ensure non-repudiation. The second modification is more complex. Ciphertext is first encrypted by AES-GCM, then, randomly shifted using modular arithmetic
46//! in 32-byte blocks using a 32-byte long quasi one-time pad (OTP). The OTP is unique for each ciphertext, and, is appended at the end of the ciphertext in encrypted form (using Kyber1024 encryption). Even if the attacker uses Grover's algorithm to
47//! discover the AES key, the attacker would also have to break the lattice-based Kyber cryptography in order to properly order
48//! the ciphertext before using the AES key. Since every 32 bytes of input into the Kyber encryption scheme produces over a 1KB output ciphertext, and, each quasi-OTP is 32 bytes long,
49//! the size of each packet is increased at a minimum constant value, helping keep packet sizes minimal and security very high.
50//!
51//! # Network Architecture
52#![cfg_attr(
53    feature = "doc-images",
54    doc = ::embed_doc_image::embed_image!(
55    "network_direct_p2p",
56    "../resources/network_direct_p2p.png"
57    )
58)]
59//! ![Network Architecture w/ direct P2P][network_direct_p2p]
60//! Each network has a central node that peers may connect to. This central node helps facilitate P2P connections, and, can itself serve
61//! as a peer on a network if the program implementation on the central server so chooses.
62//!
63//! The peers Alice and Bob can only connect to each other after they use the central server to **register** to each other. Once registered, the two peers
64//! may begin attempting connecting to each other via NAT traversal. Each peer begins NAT traversal by attempting to determine what type of NAT
65//! they're each behind by communicating to 3 different STUN servers to find a predictable pattern in their internal/external socket mappings.
66//! If at least one has a predictable pattern, a direct P2P connection bypassing the central server may be facilitated.
67//!
68//! If, however, both Alice and Bob do not have predictable internal/external socket mappings (e.g., both are behind symmetric NATs), then, both will use
69//! their central server to relay their packets to each other using endpoint-to-endpoint encryption, preventing the central server from
70//! decrypting the packets.
71//!
72//! Applications never wait for NAT traversal: a peer connection is delivered, and usable, as soon as the keys are exchanged, with its
73//! traffic on the central server's relay. Hole punching runs in the background, and when a direct path is established the channel
74//! upgrades in place (and falls back to the relay if that path is later lost), with every message delivered once and in order across
75//! the switch. `PeerChannel::ensure_direct` waits for the direct path when an application needs one (e.g. for UDP), and
76//! `PeerChannel::path_changes` reports each change.
77//!
78#![cfg_attr(
79    feature = "doc-images",
80    doc = ::embed_doc_image::embed_image!(
81    "network_relay_p2p",
82    "../resources/network_relay_p2p.png"
83    )
84)]
85//! ![Network Architecture w/ relay P2P][network_relay_p2p]
86//!
87//!
88//! # Executor Architecture: The [`NetKernel`]
89#![cfg_attr(
90    feature = "doc-images",
91    doc = ::embed_doc_image::embed_image!(
92        "proto_kernel_iface",
93        "../resources/proto_kernel_iface.png"
94    )
95)]
96//! ![Protocol/Executor/NetKernel Architecture][proto_kernel_iface]
97//! Any node in the network may act as **both** a server and a client/peer (except for when [`NodeType::Peer`] or the default node type is specified). Since multiple parallel connections may exist, handling events is necessary. When the lower-level protocol produces events,
98//! they are sent to the [`NetKernel`]. The [`NetKernel`] is where your application logic must be written.
99//!
100//! ## Initialization Stage: The [`KernelExecutor`] and the [`NodeRemote`]
101//! When the node is built and awaited (as seen in the examples below), the node creates a [`NodeRemote`] which is used to communicate between the [`NetKernel`] and the lower level networking protocol. Then, the [`KernelExecutor`] passes the remote to [`NetKernel::load_remote`] (which uses a mutable reference to
102//! the kernel itself to allow mutation of the inner data, effectively ensuring that the remote may be stored without need of atomics, as well as any other config). Thereafter, the [`KernelExecutor`] calls [`NetKernel::on_start`] (uses an ``&self`` reference) where any first asynchronous calls using the remote itself may be made.
103//!
104//! ## Passive Stage
105//! As the protocol generates events, the developer may choose to add program logic to react to the events. When an event is sent from the protocol to the [`KernelExecutor`], the [`KernelExecutor`] executes [`NetKernel::on_node_event_received`], passing the new event. Importantly,
106//! every call to [`NetKernel::on_node_event_received`] is executed *concurrently* (**not** to be confused with *parallel*), allowing the developer to react to each event separately without having to await completion before handling the next event. If an error is returned from [`NetKernel::on_node_event_received`], then the [`KernelExecutor`] will attempt
107//! a graceful shutdown of the protocol and any running sessions. Errors returned from [`NetKernel::on_node_event_received`] are propagated to the initial awaited call site on the node.
108//!
109//! Important note: Since [`NetKernel::on_node_event_received`] takes self by reference and is executed concurrently, [`NetKernel`] requires that ``Self: Sync`` since by definition, if ``&T: Send``, then ``T: Sync``
110//!
111//! ## Shutdown stage
112//! Whether through an error, or, a call to [`NodeRemote::shutdown`], the [`KernelExecutor`] will call [`NetKernel::on_stop`] (which is passed an &mut). During and after the execution of [`NetKernel::on_stop`], no more calls to [`NetKernel::on_node_event_received`] will occur. Any errors returned from [`NetKernel::on_stop`] will be propagated
113//! to the initial awaited call site on the node. Execution is complete, returning the initial kernel on success
114//!
115//! # Examples
116//!
117//! ## Server
118//! When building either a client/peer or server node, a [`NetKernel`] is expected. In the case below, an EmptyKernel is used that does no additional processing of inbound connections:
119//! ```
120//! use citadel_sdk::prelude::*;
121//! use citadel_sdk::prefabs::server::empty::EmptyKernel;
122//!
123//! // this server will listen on 127.0.0.1:25021, and will use the built-in defaults. When calling 'build', a NetKernel is specified
124//! let server = DefaultNodeBuilder::default()
125//! .with_node_type(NodeType::server("127.0.0.1:25021")?)
126//! .build(EmptyKernel::default())?;
127//!
128//! // await the server to execute
129//! # async move {
130//! let result = server.await;
131//! # };
132//! # Ok::<(), Box<dyn std::error::Error>>(())
133//! ```
134//!
135//! ## Client/Peer
136//! This client will connect to the server above. It will first register (if the account is not yet registered), and thereafter, connect to the server, calling the provided future to handle the received channel
137//! ```
138//! use citadel_sdk::prefabs::client::single_connection::SingleClientServerConnectionKernel;
139//! use futures::StreamExt;
140//! use citadel_sdk::prelude::*;
141//!
142//! let server_connection_settings = DefaultServerConnectionSettingsBuilder::credentialed_registration("127.0.0.1:25021", "john.doe", "John Doe", "password").build()?;
143//!
144//! let client_kernel = SingleClientServerConnectionKernel::new(server_connection_settings, |conn| async move {
145//!     // handle program logic here
146//!     let (sink, mut stream) = conn.split();
147//!     while let Some(message) = stream.next().await {
148//!         // message received in the form of a SecBuffer (memory-protected)
149//!     }
150//!
151//!     Ok(())
152//! });
153//!
154//! let client = DefaultNodeBuilder::default().build(client_kernel)?;
155//! # async move {
156//! let result = client.await;
157//! # };
158//! # Ok::<(), Box<dyn std::error::Error>>(())
159//! ```
160//!
161//! ## Remote Encrypted Virtual Filesystem (RE-VFS)
162//! The RE-VFS allows clients, servers, and peers to treat each other as remote endpoints for encrypted file storage.
163//! Since encrypting data locally using a symmetric key poses a vulnerability if the local node is compromised, The
164//! Citadel Protocol solves this issue by using a local 1024-Kyber public key to encrypt the data (via Kyber Hybrid Encryption for
165//! keeping the data size to a minimum), then, sending the contents to the adjacent endpoint. By doing this, the private decryption
166//! key and the contents are kept separate, forcing the hacker to compromise both endpoints.
167//!
168//! In order to use the RE-VFS, both endpoints must use the Filesystem backend. Second, the endpoint serving as a storage point
169//! must accept the inbound file transfer requests, otherwise, the transfer will fail. The example below for the receiving endpoint
170//! shows how to auto-accept inbound file transfer requests
171//!
172//! # Examples
173//!
174//! ## Receiving endpoint
175//! ```
176//! use citadel_sdk::prelude::*;
177//! use citadel_sdk::prefabs::server::accept_file_transfer_kernel::AcceptFileTransferKernel;
178//!
179//! // this server will listen on 127.0.0.1:25021, and will use the built-in defaults with a kernel
180//! // that auto-accepts inbound file transfer requests
181//! let server = DefaultNodeBuilder::default()
182//! .with_node_type(NodeType::server("127.0.0.1:25021")?)
183//! .build(AcceptFileTransferKernel::default())?;
184//!
185//! // await the server to execute
186//! # async move {
187//!     let result = server.await;
188//! # };
189//! # Ok::<(), Box<dyn std::error::Error>>(())
190//! ```
191//!
192//! ## Sending endpoint
193//! ```
194//! use citadel_sdk::prefabs::client::single_connection::SingleClientServerConnectionKernel;
195//! use futures::StreamExt;
196//! use citadel_sdk::prelude::*;
197//!
198//! let server_connection_settings = DefaultServerConnectionSettingsBuilder::credentialed_registration("127.0.0.1:25021", "john.doe", "John Doe", "password").build()?;
199//!
200//! let client_kernel = SingleClientServerConnectionKernel::new(server_connection_settings, |conn| async move {
201//!     let virtual_path = "/home/virtual_user/output.pdf";
202//!     // write the contents with reinforced security.
203//!     citadel_sdk::fs::write_with_security_level(&conn.remote, "../path/to/input.pdf", SecurityLevel::Reinforced, virtual_path).await?;
204//!     // read the contents. Reading downloads the file to a local path
205//!     let stored_local_path = citadel_sdk::fs::read(&conn.remote, virtual_path).await?;
206//!  
207//!     Ok(())
208//! });
209//!
210//! let client = DefaultNodeBuilder::default().build(client_kernel)?;
211//! # async move {
212//!     let result = client.await;
213//! # };
214//! # Ok::<(), Box<dyn std::error::Error>>(())
215//! ```
216//!
217//! [`UdpChannel`]: crate::prelude::UdpChannel
218//! [`NetKernel`]: crate::prelude::NetKernel
219//! [`NetKernel::load_remote`]: crate::prelude::NetKernel::load_remote
220//! [`NetKernel::on_start`]: crate::prelude::NetKernel::on_start
221//! [`NetKernel::on_node_event_received`]: crate::prelude::NetKernel::on_node_event_received
222//! [`NetKernel::on_stop`]: crate::prelude::NetKernel::on_stop
223//! [`KernelExecutor`]: crate::prelude::KernelExecutor
224//! [`NodeRemote`]: crate::prelude::NodeRemote
225//! [`NodeRemote::shutdown`]: crate::prelude::NodeRemote::shutdown
226//! [`NodeType`]: crate::prelude::NodeType
227//! [`NodeType::Peer`]: crate::prelude::NodeType::Peer
228//! [`PeerConnectionType`]: crate::prelude::PeerConnectionType
229//! [`TargetLockedRemote`]: crate::prelude::TargetLockedRemote
230//! [`PersistenceHandler`]: crate::prelude::PersistenceHandler
231//! [`SecurityLevel`]: crate::prelude::SecurityLevel
232//! [`ObjectSource`]: crate::prelude::ObjectSource
233//! [`NetworkError`]: crate::prelude::NetworkError
234#![forbid(unsafe_code)]
235#![allow(rustdoc::invalid_html_tags)]
236#![deny(
237    clippy::cognitive_complexity,
238    trivial_numeric_casts,
239    unused_extern_crates,
240    unused_import_braces,
241    variant_size_differences,
242    unused_features,
243    unused_results
244)]
245
246/// Convenience import for building applications
247pub mod prelude {
248    pub use crate::backend_kv_store::BackendHandler;
249    pub use crate::builder::node_builder::*;
250    pub use crate::prefabs::client::peer_connection::PeerConnectionSetupAggregator;
251    pub use crate::prefabs::client::PrefabFunctions;
252    pub use crate::prefabs::client::{
253        DefaultServerConnectionSettingsBuilder, ServerConnectionSettings,
254    };
255    pub use crate::prefabs::ClientServerRemote;
256    pub use crate::remote_ext::remote_specialization::PeerRemote;
257    pub use crate::remote_ext::user_ids::*;
258    pub use crate::remote_ext::*;
259    pub use crate::responses;
260    pub use crate::sign_in::SignInManagementExt;
261    pub use citadel_proto::auth::{
262        security_key_channel, SecurityKeyChallenge, SecurityKeyPrf, SecurityKeyPurpose,
263        SecurityKeyRequest, SignInFactors,
264    };
265    pub use citadel_proto::prelude::*;
266    pub use citadel_types::auth::{
267        FactorId, FactorKind, SessionScope, SignInCredential, SignInManagementOp,
268        SignInManagementOutcome, SignInPolicy,
269    };
270    pub use citadel_types::prelude::*;
271    pub use citadel_user::auth::pq::admission::{
272        challenge_of, AdmissionChallenge, AdmissionProvider,
273    };
274}
275
276/// Store data to the backend using this library
277pub mod backend_kv_store;
278mod builder;
279/// Convenience functions for interacting with the remote encrypted virtual filesystem (RE-VFS)
280pub mod fs;
281/// Extension implementations endowed upon the [NodeRemote](crate::prelude::NodeRemote)
282mod group_create_wait;
283/// Real-time audio/video transport bound to a connection (see [`citadel_media`])
284pub mod media;
285/// The prefabs module contains pre-built kernels for common use cases.
286pub mod prefabs;
287
288pub mod remote_ext;
289/// For easy construction of replies to common message types
290pub mod responses;
291
292mod server_probe;
293/// Managing a post-quantum account's sign-in factors
294pub mod sign_in;
295#[doc(hidden)]
296pub mod test_common;
297
298/// Browser-to-browser serverless connections (WASM only).
299#[cfg(target_family = "wasm")]
300pub mod net;
301
302#[macro_use]
303pub(crate) mod macros;
304
305pub use citadel_logging as logging;
306/// Codec-agnostic media primitives used by [`media`]
307pub use citadel_media;
308/// Convenience for SDK users
309pub use citadel_proto::prelude::async_trait;
310pub use citadel_types as types;