use crate::common::{concat, i2osp};
use crate::oprf::{CurveHashSuite, OprfCipherSuite};
pub struct OpaqueCipherSuite {
oprf_suite: OprfCipherSuite,
curve_hash_suite: CurveHashSuite,
}
pub struct AkeKeyPair {
pub private_key: Vec<u8>,
pub public_key: Vec<u8>,
}
impl OpaqueCipherSuite {
pub fn p256_sha256() -> Self {
Self {
oprf_suite: OprfCipherSuite::new(CurveHashSuite::P256Sha256),
curve_hash_suite: CurveHashSuite::P256Sha256,
}
}
pub fn p384_sha384() -> Self {
Self {
oprf_suite: OprfCipherSuite::new(CurveHashSuite::P384Sha384),
curve_hash_suite: CurveHashSuite::P384Sha384,
}
}
pub fn p521_sha512() -> Self {
Self {
oprf_suite: OprfCipherSuite::new(CurveHashSuite::P521Sha512),
curve_hash_suite: CurveHashSuite::P521Sha512,
}
}
pub fn ristretto255_sha512() -> Self {
Self {
oprf_suite: OprfCipherSuite::new(CurveHashSuite::Ristretto255Sha512),
curve_hash_suite: CurveHashSuite::Ristretto255Sha512,
}
}
pub fn from_name(name: &str) -> Self {
match name {
"P256_SHA256" => Self::p256_sha256(),
"P384_SHA384" => Self::p384_sha384(),
"P521_SHA512" => Self::p521_sha512(),
"RISTRETTO255_SHA512" => Self::ristretto255_sha512(),
_ => panic!("Unknown OPAQUE cipher suite: {}", name),
}
}
pub fn name(&self) -> &'static str {
self.curve_hash_suite.name()
}
pub fn oprf_suite(&self) -> &OprfCipherSuite {
&self.oprf_suite
}
pub fn npk(&self) -> usize {
self.oprf_suite.element_size()
}
pub fn nsk(&self) -> usize {
self.oprf_suite.group_spec().scalar_size()
}
pub fn nh(&self) -> usize {
self.oprf_suite.hash_output_length()
}
pub fn nm(&self) -> usize {
self.nh()
}
pub fn nx(&self) -> usize {
self.nh()
}
pub fn noe(&self) -> usize {
self.npk()
}
pub fn nok(&self) -> usize {
self.nsk()
}
pub fn nn(&self) -> usize {
32
}
pub fn envelope_size(&self) -> usize {
self.nn() + self.nm()
}
pub fn masked_response_size(&self) -> usize {
self.npk() + self.envelope_size()
}
pub fn hkdf_extract(&self, salt: &[u8], ikm: &[u8]) -> Vec<u8> {
let actual_salt = if salt.is_empty() {
vec![0u8; self.nh()]
} else {
salt.to_vec()
};
self.oprf_suite.hmac(&actual_salt, ikm)
}
pub fn hkdf_expand(&self, prk: &[u8], info: &[u8], len: usize) -> Vec<u8> {
let hash_len = self.nh();
let mut result = Vec::with_capacity(len);
let mut t: Vec<u8> = Vec::new();
let mut counter: u8 = 1;
while result.len() < len {
let input = concat(&[&t, info, &[counter]]);
t = self.oprf_suite.hmac(prk, &input);
let to_copy = std::cmp::min(len - result.len(), hash_len);
result.extend_from_slice(&t[..to_copy]);
counter += 1;
}
result
}
pub fn hkdf_expand_label(
&self,
secret: &[u8],
label: &[u8],
context: &[u8],
length: usize,
) -> Vec<u8> {
let full_label = concat(&[b"OPAQUE-", label]);
let info = concat(&[
&i2osp(length as u32, 2),
&i2osp(full_label.len() as u32, 1),
&full_label,
&i2osp(context.len() as u32, 1),
context,
]);
self.hkdf_expand(secret, &info, length)
}
pub fn hmac(&self, key: &[u8], data: &[u8]) -> Vec<u8> {
self.oprf_suite.hmac(key, data)
}
pub fn hash(&self, data: &[u8]) -> Vec<u8> {
self.oprf_suite.hash(data)
}
pub fn derive_ake_key_pair(&self, seed: &[u8]) -> AkeKeyPair {
let sk = self
.oprf_suite
.derive_key_pair(seed, b"OPAQUE-DeriveDiffieHellmanKeyPair");
let pk = self.oprf_suite.group_spec().scalar_multiply_generator(&sk);
AkeKeyPair {
private_key: sk,
public_key: pk,
}
}
}