#[macro_use] extern crate quick_error;
extern crate ssb_crypto;
use ssb_crypto::{
PublicKey,
SecretKey,
Signature,
NetworkKey,
NonceGen,
secretbox,
};
use ssb_crypto::handshake::{
EphPublicKey,
EphSecretKey,
derive_shared_secret,
derive_shared_secret_pk,
derive_shared_secret_sk,
SharedSecret,
generate_ephemeral_keypair,
};
use ssb_crypto::hash::{hash, Digest};
use std::mem::size_of;
use std::slice;
mod error;
pub use error::HandshakeError;
pub mod messages;
#[derive(Clone)]
pub struct ClientPublicKey(pub PublicKey);
impl ClientPublicKey {
pub fn from_slice(b: &[u8]) -> Option<ClientPublicKey> {
Some(ClientPublicKey(PublicKey::from_slice(b)?))
}
}
pub struct ClientSecretKey(pub SecretKey);
impl ClientSecretKey {
pub fn from_slice(b: &[u8]) -> Option<ClientSecretKey> {
Some(ClientSecretKey(SecretKey::from_slice(b)?))
}
}
#[derive(Clone)]
pub struct ServerPublicKey(pub PublicKey);
impl ServerPublicKey {
pub fn from_slice(b: &[u8]) -> Option<ServerPublicKey> {
Some(ServerPublicKey(PublicKey::from_slice(b)?))
}
pub fn as_slice(&self) -> &[u8] {
&self.0[..]
}
}
pub struct ServerSecretKey(pub SecretKey);
impl ServerSecretKey {
pub fn from_slice(b: &[u8]) -> Option<ServerSecretKey> {
Some(ServerSecretKey(SecretKey::from_slice(b)?))
}
}
#[derive(Clone)]
pub struct ClientSignature(Signature);
struct ServerSignature(Signature);
#[derive(Clone)]
pub struct ClientEphPublicKey(pub EphPublicKey);
pub struct ClientEphSecretKey(pub EphSecretKey);
#[derive(Clone)]
pub struct ServerEphPublicKey(pub EphPublicKey);
pub struct ServerEphSecretKey(pub EphSecretKey);
pub mod client {
use super::*;
pub fn generate_eph_keypair() -> (ClientEphPublicKey, ClientEphSecretKey) {
let (pk, sk) = generate_ephemeral_keypair();
(ClientEphPublicKey(pk), ClientEphSecretKey(sk))
}
}
pub mod server {
use super::*;
pub fn generate_eph_keypair() -> (ServerEphPublicKey, ServerEphSecretKey) {
let (pk, sk) = generate_ephemeral_keypair();
(ServerEphPublicKey(pk), ServerEphSecretKey(sk))
}
}
#[derive(Clone)]
pub struct SharedA(SharedSecret);
impl SharedA {
pub fn client_side(
sk: &ClientEphSecretKey,
pk: &ServerEphPublicKey,
) -> Result<SharedA, HandshakeError> {
derive_shared_secret(&sk.0, &pk.0)
.map(SharedA)
.ok_or(HandshakeError::SharedAInvalid)
}
pub fn server_side(
sk: &ServerEphSecretKey,
pk: &ClientEphPublicKey,
) -> Result<SharedA, HandshakeError> {
derive_shared_secret(&sk.0, &pk.0)
.map(SharedA)
.ok_or(HandshakeError::SharedAInvalid)
}
fn hash(&self) -> SharedAHash {
SharedAHash(hash(&self.0[..]))
}
}
struct SharedAHash(Digest);
#[derive(Clone)]
pub struct SharedB(SharedSecret);
impl SharedB {
pub fn client_side(
sk: &ClientEphSecretKey,
pk: &ServerPublicKey,
) -> Result<SharedB, HandshakeError> {
derive_shared_secret_pk(&sk.0, &pk.0)
.map(SharedB)
.ok_or(HandshakeError::SharedBInvalid)
}
pub fn server_side(
sk: &ServerSecretKey,
pk: &ClientEphPublicKey,
) -> Result<SharedB, HandshakeError> {
derive_shared_secret_sk(&sk.0, &pk.0)
.map(SharedB)
.ok_or(HandshakeError::SharedBInvalid)
}
}
#[derive(Clone)]
pub struct SharedC(SharedSecret);
impl SharedC {
pub fn client_side(
sk: &ClientSecretKey,
pk: &ServerEphPublicKey,
) -> Result<SharedC, HandshakeError> {
derive_shared_secret_sk(&sk.0, &pk.0)
.map(SharedC)
.ok_or(HandshakeError::SharedCInvalid)
}
pub fn server_side(
sk: &ServerEphSecretKey,
pk: &ClientPublicKey,
) -> Result<SharedC, HandshakeError> {
derive_shared_secret_pk(&sk.0, &pk.0)
.map(SharedC)
.ok_or(HandshakeError::SharedCInvalid)
}
}
struct SharedKeyHash(Digest);
#[repr(C, packed)]
struct SharedKeyHashData {
net_key: NetworkKey,
shared_a: SharedA,
shared_b: SharedB,
shared_c: SharedC,
}
impl SharedKeyHashData {
fn into_hash(self) -> SharedKeyHash {
let h1 = unsafe { hash(bytes(&self)) };
SharedKeyHash(hash(&h1[..]))
}
}
#[repr(C, packed)]
struct SharedKeyData {
double_hash: SharedKeyHash,
pk: PublicKey,
}
impl SharedKeyData {
fn into_key(self) -> secretbox::Key {
let digest = unsafe { hash(bytes(&self)) };
secretbox::Key::from_slice(&digest[..]).unwrap()
}
}
fn build_shared_key(
pk: &PublicKey,
net_key: &NetworkKey,
shared_a: &SharedA,
shared_b: &SharedB,
shared_c: &SharedC,
) -> secretbox::Key {
let double_hash = SharedKeyHashData {
net_key: net_key.clone(),
shared_a: shared_a.clone(),
shared_b: shared_b.clone(),
shared_c: shared_c.clone(),
}
.into_hash();
SharedKeyData {
double_hash,
pk: pk.clone(),
}
.into_key()
}
pub fn client_to_server_key(
server_pk: &ServerPublicKey,
net_key: &NetworkKey,
shared_a: &SharedA,
shared_b: &SharedB,
shared_c: &SharedC,
) -> secretbox::Key {
build_shared_key(
&server_pk.0,
net_key,
shared_a,
shared_b,
shared_c,
)
}
pub fn server_to_client_key(
server_pk: &ClientPublicKey,
net_key: &NetworkKey,
shared_a: &SharedA,
shared_b: &SharedB,
shared_c: &SharedC,
) -> secretbox::Key {
build_shared_key(
&server_pk.0,
net_key,
shared_a,
shared_b,
shared_c,
)
}
pub struct HandshakeOutcome {
pub read_key: secretbox::Key,
pub read_noncegen: NonceGen,
pub write_key: secretbox::Key,
pub write_noncegen: NonceGen,
}
fn zero_nonce() -> secretbox::Nonce {
secretbox::Nonce([0u8; size_of::<secretbox::Nonce>()])
}
pub(crate) unsafe fn bytes<T>(t: &T) -> &[u8] {
let p = t as *const T as *const u8;
slice::from_raw_parts(p, size_of::<T>())
}