Adding support for "internal mode" and fake credential response + test vectors (#155)
* Adding support for internal and external mode
This commit is contained in:
+160
-208
@@ -4,10 +4,13 @@
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
use crate::{
|
||||
ciphersuite::CipherSuite,
|
||||
errors::{utils::check_slice_size, InternalPakeError, PakeError, ProtocolError},
|
||||
group::Group,
|
||||
hash::Hash,
|
||||
keypair::PublicKey,
|
||||
serialization::serialize,
|
||||
keypair::{KeyPair, PrivateKey, PublicKey},
|
||||
map_to_curve::GroupWithMapToCurve,
|
||||
opaque::{bytestrings_from_identifiers, Identifiers},
|
||||
};
|
||||
use digest::Digest;
|
||||
use generic_array::{typenum::Unsigned, GenericArray};
|
||||
@@ -19,81 +22,62 @@ use std::convert::TryFrom;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
// Constant string used as salt for HKDF computation
|
||||
const STR_PAD: &[u8] = b"Pad";
|
||||
const STR_AUTH_KEY: &[u8] = b"AuthKey";
|
||||
const STR_EXPORT_KEY: &[u8] = b"ExportKey";
|
||||
const STR_PRIVATE_KEY: &[u8] = b"PrivateKey";
|
||||
const STR_OPAQUE_HASH_TO_SCALAR: &[u8] = b"OPAQUE-HashToScalar";
|
||||
|
||||
const NONCE_LEN: usize = 32;
|
||||
|
||||
fn build_inner_envelope_internal<CS: CipherSuite>(
|
||||
random_pwd: &[u8],
|
||||
nonce: &[u8],
|
||||
) -> Result<PublicKey, InternalPakeError> {
|
||||
let h = Hkdf::<CS::Hash>::new(None, random_pwd);
|
||||
let mut keypair_seed = vec![0u8; <PrivateKey as SizedBytes>::Len::to_usize()];
|
||||
h.expand(&[nonce, STR_PRIVATE_KEY].concat(), &mut keypair_seed)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
let client_static_keypair =
|
||||
KeyPair::<CS::Group>::from_private_key_slice(CS::Group::scalar_as_bytes(
|
||||
&CS::Group::hash_to_scalar::<CS::Hash>(&keypair_seed[..], STR_OPAQUE_HASH_TO_SCALAR)?,
|
||||
))?;
|
||||
|
||||
Ok(client_static_keypair.public().clone())
|
||||
}
|
||||
|
||||
fn recover_keys_internal<CS: CipherSuite>(
|
||||
random_pwd: &[u8],
|
||||
nonce: &[u8],
|
||||
) -> Result<KeyPair<CS::Group>, InternalPakeError> {
|
||||
let h = Hkdf::<CS::Hash>::new(None, random_pwd);
|
||||
let mut keypair_seed = vec![0u8; <PrivateKey as SizedBytes>::Len::to_usize()];
|
||||
h.expand(&[nonce, STR_PRIVATE_KEY].concat(), &mut keypair_seed)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
let client_static_keypair =
|
||||
KeyPair::<CS::Group>::from_private_key_slice(CS::Group::scalar_as_bytes(
|
||||
&CS::Group::hash_to_scalar::<CS::Hash>(&keypair_seed[..], STR_OPAQUE_HASH_TO_SCALAR)?,
|
||||
))?;
|
||||
|
||||
Ok(client_static_keypair)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Zeroize)]
|
||||
#[zeroize(drop)]
|
||||
pub(crate) enum InnerEnvelopeMode {
|
||||
Unused = 0,
|
||||
Base = 1,
|
||||
CustomIdentifier = 2,
|
||||
Zero = 0,
|
||||
Internal = 1,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for InnerEnvelopeMode {
|
||||
type Error = PakeError;
|
||||
fn try_from(x: u8) -> Result<Self, Self::Error> {
|
||||
match x {
|
||||
1 => Ok(InnerEnvelopeMode::Base),
|
||||
2 => Ok(InnerEnvelopeMode::CustomIdentifier),
|
||||
1 => Ok(InnerEnvelopeMode::Internal),
|
||||
_ => Err(PakeError::SerializationError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Zeroize)]
|
||||
#[zeroize(drop)]
|
||||
pub(crate) struct InnerEnvelope {
|
||||
mode: InnerEnvelopeMode,
|
||||
nonce: Vec<u8>,
|
||||
ciphertext: Vec<u8>,
|
||||
}
|
||||
|
||||
impl InnerEnvelope {
|
||||
pub(crate) fn serialize(&self) -> Vec<u8> {
|
||||
[&[self.mode as u8], &self.nonce[..], &self.ciphertext[..]].concat()
|
||||
}
|
||||
|
||||
pub(crate) fn deserialize(input: &[u8]) -> Result<(Self, Vec<u8>), ProtocolError> {
|
||||
if input.is_empty() {
|
||||
return Err(ProtocolError::VerificationError(
|
||||
PakeError::SerializationError,
|
||||
));
|
||||
}
|
||||
let mode = InnerEnvelopeMode::try_from(input[0])?;
|
||||
|
||||
let key_len = <PublicKey as SizedBytes>::Len::to_usize();
|
||||
|
||||
let bytes = &input[1..];
|
||||
if bytes.len() < NONCE_LEN + key_len {
|
||||
return Err(ProtocolError::VerificationError(
|
||||
PakeError::SerializationError,
|
||||
));
|
||||
}
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
mode,
|
||||
nonce: bytes[..NONCE_LEN].to_vec(),
|
||||
ciphertext: bytes[NONCE_LEN..NONCE_LEN + key_len].to_vec(),
|
||||
},
|
||||
bytes[NONCE_LEN + key_len..].to_vec(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn as_byte_ptrs(&self) -> Vec<(*const u8, usize)> {
|
||||
vec![
|
||||
/* Cannot easily get raw pointer of enum value, otherwise would do self.mode.as_ptr() */
|
||||
(self.nonce.as_ptr(), self.nonce.len()),
|
||||
(self.ciphertext.as_ptr(), self.ciphertext.len()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct is an instantiation of the envelope as described in
|
||||
/// https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-06#section-4
|
||||
///
|
||||
@@ -104,128 +88,151 @@ impl InnerEnvelope {
|
||||
/// The specification update has simplified this assumption by taking
|
||||
/// an XOR-based approach without compromising on security, and to avoid
|
||||
/// the confusion around the implementation of an RKR-secure encryption.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Envelope<D: Hash> {
|
||||
inner_envelope: InnerEnvelope,
|
||||
hmac: GenericArray<u8, <D as Digest>::OutputSize>,
|
||||
pub(crate) struct Envelope<CS: CipherSuite> {
|
||||
mode: InnerEnvelopeMode,
|
||||
nonce: Vec<u8>,
|
||||
hmac: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
|
||||
}
|
||||
|
||||
// Cannot be derived because it would require for CS to be Clone.
|
||||
impl<CS: CipherSuite> Clone for Envelope<CS> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
mode: self.mode,
|
||||
nonce: self.nonce.clone(),
|
||||
hmac: self.hmac.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this struct represents an envelope that has been "opened" with the asssociated
|
||||
// key. This key is also used to derive the export_key parameter, which is technically
|
||||
// unrelated to the envelope's encrypted and authenticated contents.
|
||||
pub(crate) struct OpenedEnvelope<D: Hash> {
|
||||
pub(crate) client_s_sk: Vec<u8>,
|
||||
pub(crate) export_key: GenericArray<u8, <D as Digest>::OutputSize>,
|
||||
pub(crate) struct OpenedEnvelope<CS: CipherSuite> {
|
||||
pub(crate) client_static_keypair: KeyPair<CS::Group>,
|
||||
pub(crate) export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
|
||||
pub(crate) id_u: Vec<u8>,
|
||||
pub(crate) id_s: Vec<u8>,
|
||||
}
|
||||
|
||||
pub(crate) struct OpenedInnerEnvelope<D: Hash> {
|
||||
pub(crate) plaintext: Vec<u8>,
|
||||
pub(crate) export_key: GenericArray<u8, <D as Digest>::OutputSize>,
|
||||
}
|
||||
|
||||
impl<D: Hash> Envelope<D> {
|
||||
impl<CS: CipherSuite> Envelope<CS> {
|
||||
fn hmac_key_size() -> usize {
|
||||
<D as Digest>::OutputSize::to_usize()
|
||||
<CS::Hash as Digest>::OutputSize::to_usize()
|
||||
}
|
||||
|
||||
fn export_key_size() -> usize {
|
||||
<D as Digest>::OutputSize::to_usize()
|
||||
<CS::Hash as Digest>::OutputSize::to_usize()
|
||||
}
|
||||
|
||||
pub(crate) fn len() -> usize {
|
||||
1 + <PublicKey as SizedBytes>::Len::to_usize() + <D as Digest>::OutputSize::to_usize() + NONCE_LEN
|
||||
}
|
||||
|
||||
pub(crate) fn get_mode(&self) -> InnerEnvelopeMode {
|
||||
self.inner_envelope.mode
|
||||
<CS::Hash as Digest>::OutputSize::to_usize() + NONCE_LEN
|
||||
}
|
||||
|
||||
pub(crate) fn serialize(&self) -> Vec<u8> {
|
||||
[&self.inner_envelope.serialize(), &self.hmac[..]].concat()
|
||||
[&self.nonce[..], &self.hmac[..]].concat()
|
||||
}
|
||||
pub(crate) fn deserialize(bytes: &[u8]) -> Result<Self, ProtocolError> {
|
||||
let mode = InnerEnvelopeMode::Internal; // Better way to hard-code this?
|
||||
|
||||
pub(crate) fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
||||
let (inner_envelope, remainder) = InnerEnvelope::deserialize(input)
|
||||
.map_err(|_| ProtocolError::InvalidInnerEnvelopeError)?;
|
||||
if bytes.len() < NONCE_LEN {
|
||||
return Err(ProtocolError::VerificationError(
|
||||
PakeError::SerializationError,
|
||||
));
|
||||
}
|
||||
let nonce = bytes[..NONCE_LEN].to_vec();
|
||||
|
||||
let remainder = match mode {
|
||||
InnerEnvelopeMode::Zero => {
|
||||
return Err(InternalPakeError::IncompatibleEnvelopeModeError.into())
|
||||
}
|
||||
InnerEnvelopeMode::Internal => bytes[NONCE_LEN..].to_vec(),
|
||||
};
|
||||
|
||||
let hmac_key_size = Self::hmac_key_size();
|
||||
let hmac = check_slice_size(&remainder, hmac_key_size, "hmac_key_size")?;
|
||||
|
||||
Ok(Self {
|
||||
inner_envelope,
|
||||
hmac: GenericArray::clone_from_slice(&hmac),
|
||||
mode,
|
||||
nonce,
|
||||
hmac: GenericArray::clone_from_slice(hmac),
|
||||
})
|
||||
}
|
||||
|
||||
// Creates a dummy envelope object that serializes to the all-zeros byte string
|
||||
pub(crate) fn dummy() -> Self {
|
||||
Self {
|
||||
inner_envelope: InnerEnvelope {
|
||||
mode: InnerEnvelopeMode::Unused,
|
||||
nonce: vec![0u8; NONCE_LEN],
|
||||
ciphertext: vec![0u8; <PublicKey as SizedBytes>::Len::to_usize()],
|
||||
},
|
||||
hmac: GenericArray::clone_from_slice(&vec![0u8; <D as Digest>::OutputSize::to_usize()]),
|
||||
mode: InnerEnvelopeMode::Zero,
|
||||
nonce: vec![0u8; NONCE_LEN],
|
||||
hmac: GenericArray::clone_from_slice(&vec![
|
||||
0u8;
|
||||
<CS::Hash as Digest>::OutputSize::to_usize()
|
||||
]),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn seal<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
key: &[u8],
|
||||
client_s_sk: &[u8],
|
||||
server_s_pk: &[u8],
|
||||
optional_ids: Option<(Vec<u8>, Vec<u8>)>,
|
||||
) -> Result<(Self, GenericArray<u8, <D as Digest>::OutputSize>), InternalPakeError> {
|
||||
let aad = construct_aad(server_s_pk, &optional_ids);
|
||||
Self::seal_raw(rng, key, client_s_sk, &aad, mode_from_ids(&optional_ids))
|
||||
optional_ids: Option<Identifiers>,
|
||||
) -> Result<
|
||||
(
|
||||
Self,
|
||||
PublicKey,
|
||||
GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
|
||||
),
|
||||
InternalPakeError,
|
||||
> {
|
||||
let mut nonce = vec![0u8; NONCE_LEN];
|
||||
rng.fill_bytes(&mut nonce);
|
||||
|
||||
let (mode, client_s_pk) = (
|
||||
InnerEnvelopeMode::Internal,
|
||||
build_inner_envelope_internal::<CS>(key, &nonce)?,
|
||||
);
|
||||
|
||||
let (id_u, id_s) =
|
||||
bytestrings_from_identifiers(&optional_ids, &client_s_pk.to_arr(), server_s_pk);
|
||||
let aad = construct_aad(&id_u, &id_s, server_s_pk);
|
||||
|
||||
let (envelope, export_key) = Self::seal_raw(key, &nonce, &aad, mode)?;
|
||||
Ok((envelope, client_s_pk, export_key))
|
||||
}
|
||||
|
||||
/// Uses a key to convert the plaintext into an envelope, authenticated by the aad field.
|
||||
/// Note that a new nonce is sampled for each call to seal.
|
||||
pub(crate) fn seal_raw<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn seal_raw(
|
||||
key: &[u8],
|
||||
plaintext: &[u8],
|
||||
nonce: &[u8],
|
||||
aad: &[u8],
|
||||
mode: InnerEnvelopeMode,
|
||||
) -> Result<(Self, GenericArray<u8, <D as Digest>::OutputSize>), InternalPakeError> {
|
||||
let mut nonce = vec![0u8; NONCE_LEN];
|
||||
rng.fill_bytes(&mut nonce);
|
||||
|
||||
let h = Hkdf::<D>::new(None, key);
|
||||
let mut xor_key = vec![0u8; plaintext.len()];
|
||||
) -> Result<(Self, GenericArray<u8, <CS::Hash as Digest>::OutputSize>), InternalPakeError> {
|
||||
let h = Hkdf::<CS::Hash>::new(None, key);
|
||||
let mut hmac_key = vec![0u8; Self::hmac_key_size()];
|
||||
let mut export_key = vec![0u8; Self::export_key_size()];
|
||||
|
||||
h.expand(&[&nonce, STR_PAD].concat(), &mut xor_key)
|
||||
h.expand(&[nonce, STR_AUTH_KEY].concat(), &mut hmac_key)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
h.expand(&[&nonce, STR_AUTH_KEY].concat(), &mut hmac_key)
|
||||
h.expand(&[nonce, STR_EXPORT_KEY].concat(), &mut export_key)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
h.expand(&[&nonce, STR_EXPORT_KEY].concat(), &mut export_key)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
|
||||
let ciphertext: Vec<u8> = xor_key
|
||||
.iter()
|
||||
.zip(plaintext.iter())
|
||||
.map(|(&x1, &x2)| x1 ^ x2)
|
||||
.collect();
|
||||
|
||||
let inner_envelope = InnerEnvelope {
|
||||
mode,
|
||||
nonce,
|
||||
ciphertext,
|
||||
};
|
||||
|
||||
let mut hmac =
|
||||
Hmac::<D>::new_varkey(&hmac_key).map_err(|_| InternalPakeError::HmacError)?;
|
||||
hmac.update(&inner_envelope.serialize());
|
||||
Hmac::<CS::Hash>::new_varkey(&hmac_key).map_err(|_| InternalPakeError::HmacError)?;
|
||||
hmac.update(nonce);
|
||||
hmac.update(aad);
|
||||
|
||||
let hmac_bytes = hmac.finalize().into_bytes();
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
inner_envelope,
|
||||
mode,
|
||||
nonce: nonce.to_vec(),
|
||||
hmac: hmac_bytes,
|
||||
},
|
||||
GenericArray::clone_from_slice(&export_key),
|
||||
@@ -236,24 +243,29 @@ impl<D: Hash> Envelope<D> {
|
||||
&self,
|
||||
key: &[u8],
|
||||
server_s_pk: &[u8],
|
||||
optional_ids: &Option<(Vec<u8>, Vec<u8>)>,
|
||||
) -> Result<OpenedEnvelope<D>, InternalPakeError> {
|
||||
// First, check that mode matches
|
||||
if self.inner_envelope.mode != mode_from_ids(optional_ids) {
|
||||
return Err(InternalPakeError::IncompatibleEnvelopeModeError);
|
||||
}
|
||||
optional_ids: &Option<Identifiers>,
|
||||
) -> Result<OpenedEnvelope<CS>, InternalPakeError> {
|
||||
let client_static_keypair = match self.mode {
|
||||
InnerEnvelopeMode::Zero => {
|
||||
return Err(InternalPakeError::IncompatibleEnvelopeModeError)
|
||||
}
|
||||
InnerEnvelopeMode::Internal => recover_keys_internal::<CS>(key, &self.nonce)?,
|
||||
};
|
||||
|
||||
let (id_u, id_s) = bytestrings_from_identifiers(
|
||||
optional_ids,
|
||||
&client_static_keypair.public().to_arr(),
|
||||
server_s_pk,
|
||||
);
|
||||
let aad = construct_aad(&id_u, &id_s, server_s_pk);
|
||||
|
||||
let aad = construct_aad(server_s_pk, optional_ids);
|
||||
let opened = self.open_raw(key, &aad)?;
|
||||
|
||||
if opened.plaintext.len() != <PublicKey as SizedBytes>::Len::to_usize() {
|
||||
// Plaintext should consist of a single key
|
||||
return Err(InternalPakeError::UnexpectedEnvelopeContentsError);
|
||||
}
|
||||
|
||||
Ok(OpenedEnvelope {
|
||||
client_s_sk: opened.plaintext,
|
||||
client_static_keypair,
|
||||
export_key: opened.export_key,
|
||||
id_u,
|
||||
id_s,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -263,44 +275,26 @@ impl<D: Hash> Envelope<D> {
|
||||
&self,
|
||||
key: &[u8],
|
||||
aad: &[u8],
|
||||
) -> Result<OpenedInnerEnvelope<D>, InternalPakeError> {
|
||||
let h = Hkdf::<D>::new(None, key);
|
||||
let mut xor_key = vec![0u8; self.inner_envelope.ciphertext.len()];
|
||||
) -> Result<OpenedInnerEnvelope<CS::Hash>, InternalPakeError> {
|
||||
let h = Hkdf::<CS::Hash>::new(None, key);
|
||||
let mut hmac_key = vec![0u8; Self::hmac_key_size()];
|
||||
let mut export_key = vec![0u8; Self::export_key_size()];
|
||||
|
||||
h.expand(
|
||||
&[&self.inner_envelope.nonce, STR_PAD].concat(),
|
||||
&mut xor_key,
|
||||
)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
h.expand(
|
||||
&[&self.inner_envelope.nonce, STR_AUTH_KEY].concat(),
|
||||
&mut hmac_key,
|
||||
)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
h.expand(
|
||||
&[&self.inner_envelope.nonce, STR_EXPORT_KEY].concat(),
|
||||
&mut export_key,
|
||||
)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
h.expand(&[&self.nonce, STR_AUTH_KEY].concat(), &mut hmac_key)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
h.expand(&[&self.nonce, STR_EXPORT_KEY].concat(), &mut export_key)
|
||||
.map_err(|_| InternalPakeError::HkdfError)?;
|
||||
|
||||
let mut hmac =
|
||||
Hmac::<D>::new_varkey(&hmac_key).map_err(|_| InternalPakeError::HmacError)?;
|
||||
hmac.update(&self.inner_envelope.serialize());
|
||||
Hmac::<CS::Hash>::new_varkey(&hmac_key).map_err(|_| InternalPakeError::HmacError)?;
|
||||
hmac.update(&self.nonce);
|
||||
hmac.update(aad);
|
||||
if hmac.verify(&self.hmac).is_err() {
|
||||
return Err(InternalPakeError::SealOpenHmacError);
|
||||
}
|
||||
|
||||
let plaintext: Vec<u8> = xor_key
|
||||
.iter()
|
||||
.zip(self.inner_envelope.ciphertext.iter())
|
||||
.map(|(&x1, &x2)| x1 ^ x2)
|
||||
.collect();
|
||||
Ok(OpenedInnerEnvelope {
|
||||
plaintext,
|
||||
export_key: GenericArray::<u8, <D as Digest>::OutputSize>::clone_from_slice(
|
||||
export_key: GenericArray::<u8, <CS::Hash as Digest>::OutputSize>::clone_from_slice(
|
||||
&export_key,
|
||||
),
|
||||
})
|
||||
@@ -308,23 +302,20 @@ impl<D: Hash> Envelope<D> {
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn as_byte_ptrs(&self) -> Vec<(*const u8, usize)> {
|
||||
[
|
||||
self.inner_envelope.as_byte_ptrs(),
|
||||
vec![(self.hmac.as_ptr(), self.hmac.len())],
|
||||
]
|
||||
.concat()
|
||||
vec![(self.hmac.as_ptr(), self.hmac.len())]
|
||||
}
|
||||
}
|
||||
|
||||
// This can't be derived because of the use of a phantom parameter
|
||||
impl<D: Hash> Zeroize for Envelope<D> {
|
||||
impl<CS: CipherSuite> Zeroize for Envelope<CS> {
|
||||
fn zeroize(&mut self) {
|
||||
self.inner_envelope.zeroize();
|
||||
self.mode.zeroize();
|
||||
self.nonce.zeroize();
|
||||
self.hmac.zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Hash> Drop for Envelope<D> {
|
||||
impl<CS: CipherSuite> Drop for Envelope<CS> {
|
||||
fn drop(&mut self) {
|
||||
self.zeroize();
|
||||
}
|
||||
@@ -332,45 +323,6 @@ impl<D: Hash> Drop for Envelope<D> {
|
||||
|
||||
// Helper functions
|
||||
|
||||
fn construct_aad(server_s_pk: &[u8], optional_ids: &Option<(Vec<u8>, Vec<u8>)>) -> Vec<u8> {
|
||||
let ids = optional_ids
|
||||
.iter()
|
||||
.flat_map(|(l, r)| [serialize(l, 2), serialize(r, 2)].concat())
|
||||
.collect();
|
||||
[server_s_pk.to_vec(), ids].concat()
|
||||
}
|
||||
|
||||
pub(crate) fn mode_from_ids(optional_ids: &Option<(Vec<u8>, Vec<u8>)>) -> InnerEnvelopeMode {
|
||||
match optional_ids {
|
||||
Some(_) => InnerEnvelopeMode::CustomIdentifier,
|
||||
None => InnerEnvelopeMode::Base,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
#[test]
|
||||
fn seal_and_open() {
|
||||
let mut rng = OsRng;
|
||||
let mut key = [0u8; 32];
|
||||
rng.fill_bytes(&mut key);
|
||||
|
||||
let mut msg = [0u8; 100];
|
||||
rng.fill_bytes(&mut msg);
|
||||
|
||||
let (envelope, export_key) = Envelope::<sha2::Sha256>::seal_raw(
|
||||
&mut rng,
|
||||
&key,
|
||||
&msg,
|
||||
b"aad",
|
||||
InnerEnvelopeMode::Base,
|
||||
)
|
||||
.unwrap();
|
||||
let opened_envelope = envelope.open_raw(&key, b"aad").unwrap();
|
||||
assert_eq!(&msg.to_vec(), &opened_envelope.plaintext);
|
||||
assert_eq!(&export_key.to_vec(), &opened_envelope.export_key.to_vec());
|
||||
}
|
||||
fn construct_aad(id_u: &[u8], id_s: &[u8], server_s_pk: &[u8]) -> Vec<u8> {
|
||||
[server_s_pk, id_s, id_u].concat()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user