mod key_v1;
use super::DataType;
use super::Error;
use super::Header;
use super::HeaderType;
use super::KeySubtype;
pub use super::KeyVersion;
use super::Result;
use key_v1::{KeyV1Private, KeyV1Public};
use std::borrow::Borrow;
use std::convert::TryFrom;
#[cfg(feature = "fuzz")]
use arbitrary::Arbitrary;
#[cfg(feature = "wbindgen")]
use wasm_bindgen::prelude::*;
#[derive(Clone)]
pub struct KeyPair {
pub private_key: PrivateKey,
pub public_key: PublicKey,
}
#[cfg_attr(feature = "wbindgen", wasm_bindgen(inspectable))]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
#[derive(Clone, Debug)]
pub struct PublicKey {
pub(crate) header: Header<PublicKey>,
payload: PublicKeyPayload,
}
#[cfg_attr(feature = "wbindgen", wasm_bindgen(inspectable))]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
#[derive(Clone, Debug)]
pub struct PrivateKey {
pub(crate) header: Header<PrivateKey>,
payload: PrivateKeyPayload,
}
impl HeaderType for PublicKey {
type Version = KeyVersion;
type Subtype = KeySubtype;
fn data_type() -> DataType {
DataType::Key
}
fn subtype() -> Self::Subtype {
KeySubtype::Public
}
}
impl HeaderType for PrivateKey {
type Version = KeyVersion;
type Subtype = KeySubtype;
fn data_type() -> DataType {
DataType::Key
}
fn subtype() -> Self::Subtype {
KeySubtype::Private
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
enum PrivateKeyPayload {
V1(KeyV1Private),
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
enum PublicKeyPayload {
V1(KeyV1Public),
}
pub fn generate_keypair(version: KeyVersion) -> KeyPair {
let (private_header, public_header) = keypair_headers(version);
let (private_key, public_key) = match version {
KeyVersion::V1 | KeyVersion::Latest => {
let keypair = key_v1::generate_keypair();
(
PrivateKeyPayload::V1(keypair.private_key),
PublicKeyPayload::V1(keypair.public_key),
)
}
};
KeyPair {
private_key: PrivateKey {
header: private_header,
payload: private_key,
},
public_key: PublicKey {
header: public_header,
payload: public_key,
},
}
}
pub fn mix_key_exchange(private_key: &PrivateKey, public_key: &PublicKey) -> Result<Vec<u8>> {
Ok(match (&private_key.payload, &public_key.payload) {
(PrivateKeyPayload::V1(private_key), PublicKeyPayload::V1(public_key)) => {
key_v1::mix_key_exchange(private_key, public_key)
} })
}
fn keypair_headers(version: KeyVersion) -> (Header<PrivateKey>, Header<PublicKey>) {
let mut private_header = Header::default();
let mut public_header = Header::default();
match version {
KeyVersion::V1 | KeyVersion::Latest => {
private_header.version = KeyVersion::V1;
public_header.version = KeyVersion::V1;
}
}
(private_header, public_header)
}
impl From<PublicKey> for Vec<u8> {
fn from(data: PublicKey) -> Self {
let mut header: Self = data.header.borrow().into();
let mut payload: Self = data.payload.into();
header.append(&mut payload);
header
}
}
impl TryFrom<&[u8]> for PublicKey {
type Error = Error;
fn try_from(data: &[u8]) -> Result<Self> {
if data.len() < Header::len() {
return Err(Error::InvalidLength);
};
let header = Header::try_from(&data[0..Header::len()])?;
if header.data_subtype != KeySubtype::Public {
return Err(Error::InvalidDataType);
}
let payload = match header.version {
KeyVersion::V1 => PublicKeyPayload::V1(KeyV1Public::try_from(&data[Header::len()..])?),
_ => return Err(Error::UnknownVersion),
};
Ok(Self { header, payload })
}
}
impl From<PrivateKey> for Vec<u8> {
fn from(data: PrivateKey) -> Self {
let mut header: Self = data.header.borrow().into();
let mut payload: Self = data.payload.into();
header.append(&mut payload);
header
}
}
impl TryFrom<&[u8]> for PrivateKey {
type Error = Error;
fn try_from(data: &[u8]) -> Result<Self> {
if data.len() < Header::len() {
return Err(Error::InvalidLength);
};
let header = Header::try_from(&data[0..Header::len()])?;
if header.data_subtype != KeySubtype::Private {
return Err(Error::InvalidDataType);
}
let payload = match header.version {
KeyVersion::V1 => {
PrivateKeyPayload::V1(KeyV1Private::try_from(&data[Header::len()..])?)
}
_ => return Err(Error::UnknownVersion),
};
Ok(Self { header, payload })
}
}
impl From<PrivateKeyPayload> for Vec<u8> {
fn from(data: PrivateKeyPayload) -> Self {
match data {
PrivateKeyPayload::V1(x) => x.into(),
}
}
}
impl From<PublicKeyPayload> for Vec<u8> {
fn from(data: PublicKeyPayload) -> Self {
match data {
PublicKeyPayload::V1(x) => x.into(),
}
}
}
impl From<&PublicKey> for x25519_dalek::PublicKey {
fn from(data: &PublicKey) -> Self {
match &data.payload {
PublicKeyPayload::V1(x) => Self::from(x),
}
}
}
impl From<&PrivateKey> for x25519_dalek::StaticSecret {
fn from(data: &PrivateKey) -> Self {
match &data.payload {
PrivateKeyPayload::V1(x) => Self::from(x),
}
}
}
#[test]
fn ecdh_test() {
let bob_keypair = generate_keypair(KeyVersion::Latest);
let alice_keypair = generate_keypair(KeyVersion::Latest);
let bob_shared = mix_key_exchange(&bob_keypair.private_key, &alice_keypair.public_key).unwrap();
let alice_shared =
mix_key_exchange(&alice_keypair.private_key, &bob_keypair.public_key).unwrap();
assert_eq!(bob_shared, alice_shared);
}