#![deny(warnings, clippy::pedantic)] #![allow(clippy::missing_errors_doc)] // I'm too lazy #![cfg_attr(
not(all(feature = "client", feature = "server")),
allow(dead_code, unused_imports)
)] #[cfg(all(feature = "nss", feature = "rust-hpke"))]
compile_error!("features \"nss\" and \"rust-hpke\" are mutually incompatible");
mod config; mod crypto; mod err; pubmod hpke; #[cfg(feature = "nss")] mod nss; #[cfg(feature = "rust-hpke")] mod rand; #[cfg(feature = "rust-hpke")] mod rh; #[cfg(feature = "stream")] mod stream;
use std::{
cmp::max,
convert::TryFrom,
io::{Cursor, Read},
mem::size_of,
};
use byteorder::{NetworkEndian, WriteBytesExt}; use crypto::{Decrypt, Encrypt}; use log::trace;
/// Construct the info parameter we use to initialize an `HpkeS` instance. fn build_info(label: &[u8], key_id: KeyId, config: HpkeConfig) -> Res<Vec<u8>> { letmut info = Vec::with_capacity(label.len() + 1 + REQUEST_HEADER_LEN);
info.extend_from_slice(label);
info.push(0);
info.write_u8(key_id)?;
info.write_u16::<NetworkEndian>(u16::from(config.kem()))?;
info.write_u16::<NetworkEndian>(u16::from(config.kdf()))?;
info.write_u16::<NetworkEndian>(u16::from(config.aead()))?;
trace!("HPKE info: {}", hex::encode(&info));
Ok(info)
}
/// This is the sort of information we expect to receive from the receiver. /// This might not be necessary if we agree on a format. #[cfg(feature = "client")] pubstruct ClientRequest {
key_id: KeyId,
config: HpkeConfig,
pk: PublicKey,
}
#[cfg(feature = "client")] impl ClientRequest { /// Construct a `ClientRequest` from a specific `KeyConfig` instance. pubfn from_config(config: &mut KeyConfig) -> Res<Self> { // TODO(mt) choose the best config, not just the first. let selected = config.select(config.symmetric[0])?;
Ok(Self {
key_id: config.key_id,
config: selected,
pk: config.pk.clone(),
})
}
/// Reads an encoded configuration and constructs a single use client sender. /// See `KeyConfig::decode` for the structure details. pubfn from_encoded_config(encoded_config: &[u8]) -> Res<Self> { letmut config = KeyConfig::decode(encoded_config)?; Self::from_config(&mut config)
}
/// Reads an encoded list of configurations and constructs a single use client sender /// from the first supported configuration. /// See `KeyConfig::decode_list` for the structure details. pubfn from_encoded_config_list(encoded_config_list: &[u8]) -> Res<Self> { letmut configs = KeyConfig::decode_list(encoded_config_list)?; iflet Some(mut config) = configs.pop() { Self::from_config(&mut config)
} else {
Err(Error::Unsupported)
}
}
/// Encapsulate a request. This consumes this object. /// This produces a response handler and the bytes of an encapsulated request. pubfn encapsulate(self, request: &[u8]) -> Res<(Vec<u8>, ClientResponse)> { // Build the info, which contains the message header. let info = build_info(INFO_REQUEST, self.key_id, self.config)?; letmut hpke = HpkeS::new(self.config, &self.pk, &info)?;
let header = Vec::from(&info[INFO_REQUEST.len() + 1..]);
debug_assert_eq!(header.len(), REQUEST_HEADER_LEN);
let extra = hpke.config().kem().n_enc() + hpke.config().aead().n_t() + request.len(); let expected_len = header.len() + extra;
/// A server can handle multiple requests. /// It holds a single key pair and can generate a configuration. /// (A more complex server would have multiple key pairs. This is simple.) #[cfg(feature = "server")] #[derive(Debug, Clone)] pubstruct Server {
config: KeyConfig,
}
#[cfg(feature = "server")] impl Server { /// Create a new server configuration. /// # Panics /// If the configuration doesn't include a private key. pubfn new(config: KeyConfig) -> Res<Self> {
assert!(config.sk.is_some());
Ok(Self { config })
}
/// Get the configuration that this server uses. #[must_use] pubfn config(&self) -> &KeyConfig {
&self.config
}
fn decode_request_header(&self, r: &mutCursor<&[u8]>, label: &[u8]) -> Res<(HpkeR, Vec<u8>)> { let hpke_config = self.config.decode_hpke_config(r)?; let sym = SymmetricSuite::new(hpke_config.kdf(), hpke_config.aead()); let config = self.config.select(sym)?; let info = build_info(label, self.config.key_id, hpke_config)?;
/// Remove encapsulation on a request. /// # Panics /// Not as a consequence of this code, but Rust won't know that for sure. pubfn decapsulate(&self, enc_request: &[u8]) -> Res<(Vec<u8>, ServerResponse)> { if enc_request.len() <= REQUEST_HEADER_LEN { return Err(Error::Truncated);
} letmut r = Cursor::new(enc_request); let (mut hpke, enc) = self.decode_request_header(&mut r, INFO_REQUEST)?;
let request = hpke.open(&[], &enc_request[usize::try_from(r.position())?..])?;
Ok((request, ServerResponse::new(&hpke, &enc)?))
}
let hkdf = Hkdf::new(cfg.kdf()); let prk = hkdf.extract(&salt, secret)?;
let key = hkdf.expand_key(&prk, INFO_KEY, KeyMechanism::Aead(cfg.aead()))?; let iv = hkdf.expand_data(&prk, INFO_NONCE, cfg.aead().n_n())?; let nonce_base = <[u8; NONCE_LEN]>::try_from(iv).unwrap();
Aead::new(mode, cfg.aead(), &key, nonce_base)
}
/// An object for encapsulating responses. /// The only way to obtain one of these is through `Server::decapsulate()`. #[cfg(feature = "server")] pubstruct ServerResponse {
response_nonce: Vec<u8>,
aead: Aead,
}
/// An object for decapsulating responses. /// The only way to obtain one of these is through `ClientRequest::encapsulate()`. #[cfg(feature = "client")] pubstruct ClientResponse {
hpke: HpkeS,
enc: Vec<u8>,
}
#[cfg(feature = "client")] impl ClientResponse { /// Private method for constructing one of these. /// Doesn't do anything because we don't have the nonce yet, so /// the work that can be done is limited. fn new(hpke: HpkeS, enc: Vec<u8>) -> Self { Self { hpke, enc }
}
/// Consume this object by decapsulating a response. pubfn decapsulate(self, enc_response: &[u8]) -> Res<Vec<u8>> { let mid = entropy(self.hpke.config()); if mid >= enc_response.len() { return Err(Error::Truncated);
} let (response_nonce, ct) = enc_response.split_at(mid); letmut aead = make_aead(
Mode::Decrypt, self.hpke.config(),
&export_secret(&self.hpke, LABEL_RESPONSE, self.hpke.config())?,
&self.enc,
response_nonce,
)?;
aead.open(&[], ct) // 0 is the sequence number
}
}
#[cfg(all(test, feature = "client", feature = "server"))] mod test { use std::{fmt::Debug, io::ErrorKind};
let server_config = make_config(); let server = Server::new(server_config).unwrap(); let encoded_config = server.config().encode().unwrap();
trace!("Config: {}", hex::encode(&encoded_config));
let client = ClientRequest::from_encoded_config(&encoded_config).unwrap(); let (enc_request, client_response) = client.encapsulate(REQUEST).unwrap();
trace!("Request: {}", hex::encode(REQUEST));
trace!("Encapsulated Request: {}", hex::encode(&enc_request));
let (request, server_response) = server.decapsulate(&enc_request).unwrap();
assert_eq!(&request[..], REQUEST);
let enc_response = server_response.encapsulate(RESPONSE).unwrap();
trace!("Encapsulated Response: {}", hex::encode(&enc_response));
let response = client_response.decapsulate(&enc_response).unwrap();
assert_eq!(&response[..], RESPONSE);
trace!("Response: {}", hex::encode(RESPONSE));
}
#[test] fn two_requests() {
init();
let server_config = make_config(); let server = Server::new(server_config).unwrap(); let encoded_config = server.config().encode().unwrap();
let client1 = ClientRequest::from_encoded_config(&encoded_config).unwrap(); let (enc_request1, client_response1) = client1.encapsulate(REQUEST).unwrap(); let client2 = ClientRequest::from_encoded_config(&encoded_config).unwrap(); let (enc_request2, client_response2) = client2.encapsulate(REQUEST).unwrap();
assert_ne!(enc_request1, enc_request2);
let (request1, server_response1) = server.decapsulate(&enc_request1).unwrap();
assert_eq!(&request1[..], REQUEST); let (request2, server_response2) = server.decapsulate(&enc_request2).unwrap();
assert_eq!(&request2[..], REQUEST);
let enc_response1 = server_response1.encapsulate(RESPONSE).unwrap(); let enc_response2 = server_response2.encapsulate(RESPONSE).unwrap();
assert_ne!(enc_response1, enc_response2);
let response1 = client_response1.decapsulate(&enc_response1).unwrap();
assert_eq!(&response1[..], RESPONSE); let response2 = client_response2.decapsulate(&enc_response2).unwrap();
assert_eq!(&response2[..], RESPONSE);
}
let client = ClientRequest::from_encoded_config_list(&encoded_config_list).unwrap(); let (enc_request, client_response) = client.encapsulate(REQUEST).unwrap();
let (request, server_response) = server.decapsulate(&enc_request).unwrap();
assert_eq!(&request[..], REQUEST);
let enc_response = server_response.encapsulate(RESPONSE).unwrap();
let response = client_response.decapsulate(&enc_response).unwrap();
assert_eq!(&response[..], RESPONSE);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.