Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

Commit

Permalink
Publish 0.3.0
Browse files Browse the repository at this point in the history
- impl `TryFrom<&[u8]>`, `FromStr`, `AsRef<[u8]>` for every possible type
- remove duplicate functions `from_bytes`, `try_from_slice`, `from_b64`, `to_b64`, `as_slice`
- remove `FromBase64Error` and replaced it with `DecodeError::InvalidLength`
- add `Token<const S: usize>`
  • Loading branch information
soerenmeier committed Nov 26, 2021
1 parent 680ada1 commit c7dd978
Show file tree
Hide file tree
Showing 15 changed files with 832 additions and 342 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "fire-crypto"
description = "Crypto library providing encryption and signing."
version = "0.2.3"
version = "0.3.0"
authors = ["Sören Meier <info@s-me.ch>"]
repository = "https://github.com/fire-lib/fire-crypto"
homepage = "https://fire-lib.com/"
Expand All @@ -26,11 +26,11 @@ hash = ["blake2", "generic-array"]

[dependencies]
#cipher
zeroize = { version = "1.4", optional = true }
zeroize = { version = "=1.3", optional = true }
poly1305 = { version = "0.7", optional = true }
universal-hash = { version = "0.4", optional = true }
chacha20 = { version = "0.7", features = ["hchacha", "expose-core"], optional = true }
x25519-dalek = { version = "1.1", optional = true }
x25519-dalek = { version = "1.2", optional = true }

#signature
ed25519-dalek = { version = "1.0", optional = true }
Expand Down
40 changes: 33 additions & 7 deletions src/cipher/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ pub struct Key {
impl Key {
/// Creates a new key.
/// And modifying the shared_secret to be a uniformly random key.
pub(crate) fn new(shared_secret: [u8; 32], initial_nonce: [u8; 24]) -> Self {
pub(crate) fn new(
shared_secret: [u8; 32],
initial_nonce: [u8; 24]
) -> Self {
// is this really necessary See: https://github.com/RustCrypto/AEADs/pull/295
let shared_secret = hchacha::<chacha20::R20>(
shared_secret.as_ref().into(),
Expand All @@ -50,7 +53,11 @@ impl Key {

/// Decrypts data, returning an Error if the Mac's do not
/// match.
pub fn decrypt(&mut self, msg: &mut [u8], recv_mac: &Mac) -> Result<(), MacNotEqual> {
pub fn decrypt(
&mut self,
msg: &mut [u8],
recv_mac: &Mac
) -> Result<(), MacNotEqual> {
self.new_cipher().decrypt(msg, recv_mac)
}

Expand Down Expand Up @@ -102,7 +109,11 @@ pub struct SyncKey {
impl SyncKey {
/// Creates a new key.
/// And modifying the shared_secret to be a uniformly random key.
fn new(shared_secret: [u8; 32], initial_nonce: [u8; 24], count: u64) -> Self {
fn new(
shared_secret: [u8; 32],
initial_nonce: [u8; 24],
count: u64
) -> Self {
Self {
shared_secret,
initial_nonce,
Expand All @@ -118,7 +129,11 @@ impl SyncKey {

/// Decrypts data, returning an Error if the Mac's do not
/// match.
pub fn decrypt(&self, msg: &mut [u8], recv_mac: &Mac) -> Result<(), MacNotEqual> {
pub fn decrypt(
&self,
msg: &mut [u8],
recv_mac: &Mac
) -> Result<(), MacNotEqual> {
self.new_cipher().decrypt(msg, recv_mac)
}

Expand Down Expand Up @@ -173,12 +188,19 @@ struct Cipher {
}

impl Cipher {
fn new(shared_secret: &[u8; 32], initial_nonce: &[u8; 24], count: u64) -> Self {
fn new(
shared_secret: &[u8; 32],
initial_nonce: &[u8; 24],
count: u64
) -> Self {
// new chacha
let mut iv = initial_nonce.clone();
xor_nonce_with_u64(&mut iv, count);

let mut cipher = XChaCha20::new(shared_secret.into(), iv.as_ref().into());
let mut cipher = XChaCha20::new(
shared_secret.into(),
iv.as_ref().into()
);

// Derive Poly1305 key from the first 32-bytes of the ChaCha20 keystream
let mut mac_key = [0u8; 32];
Expand All @@ -201,7 +223,11 @@ impl Cipher {
self.poly.to_mac(msg.len())
}

fn decrypt(mut self, msg: &mut [u8], recv_mac: &Mac) -> Result<(), MacNotEqual> {
fn decrypt(
mut self,
msg: &mut [u8],
recv_mac: &Mac
) -> Result<(), MacNotEqual> {
self.poly.update_padded(msg);
let mac = self.poly.to_mac(msg.len());

Expand Down
103 changes: 69 additions & 34 deletions src/cipher/keypair.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use super::{PublicKey, SharedSecret};
use crate::error::TryFromError;
#[cfg(feature = "b64")]
use crate::FromBase64Error;
use crate::error::DecodeError;

use std::fmt;
use std::convert::TryInto;
use std::convert::{TryFrom, TryInto};

use rand::rngs::OsRng;

Expand Down Expand Up @@ -68,21 +69,10 @@ impl Keypair {
)
}

pub fn from_bytes(bytes: [u8; 32]) -> Self {
Self::from_static_secret(
x::StaticSecret::from(bytes)
)
}

/// ## Panics
/// if the slice is not 32 bytes long.
pub fn from_slice(slice: &[u8]) -> Self {
Self::from_bytes(slice.try_into().unwrap())
}

pub fn try_from_slice(slice: &[u8]) -> Option<Self> {
slice.try_into().ok()
.map(Self::from_bytes)
slice.try_into().unwrap()
}

pub fn to_bytes(&self) -> [u8; 32] {
Expand All @@ -93,18 +83,6 @@ impl Keypair {
// self.secret.as_ref()
// }

#[cfg(feature = "b64")]
pub fn from_b64<T: AsRef<[u8]>>(input: T) -> Result<Self, FromBase64Error> {
let b = base64::decode_config(input, base64::URL_SAFE_NO_PAD)?;
Self::try_from_slice(&b)
.ok_or(FromBase64Error::LengthNot32Bytes)
}

#[cfg(feature = "b64")]
pub fn to_b64(&self) -> String {
base64::encode_config(self.to_bytes().as_ref(), base64::URL_SAFE_NO_PAD)
}

pub fn public(&self) -> &PublicKey {
&self.public
}
Expand All @@ -115,21 +93,21 @@ impl Keypair {
}
}

#[cfg(feature = "b64")]
#[cfg(not(feature = "b64"))]
impl fmt::Debug for Keypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Keypair")
.field("secret", &self.to_b64())
.field("secret", &self.to_bytes())
.field("public", &self.public)
.finish()
}
}

#[cfg(not(feature = "b64"))]
#[cfg(feature = "b64")]
impl fmt::Debug for Keypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Keypair")
.field("secret", &self.to_bytes())
.field("secret", &self.to_string())
.field("public", &self.public)
.finish()
}
Expand All @@ -139,15 +117,72 @@ impl fmt::Debug for Keypair {
#[cfg(feature = "b64")]
impl fmt::Display for Keypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_b64())
base64::display::Base64Display::with_config(
&self.to_bytes(),
base64::URL_SAFE_NO_PAD
).fmt(f)
}
}

impl From<[u8; 32]> for Keypair {
fn from(bytes: [u8; 32]) -> Self {
Self::from_bytes(bytes)
Self::from_static_secret(
x::StaticSecret::from(bytes)
)
}
}

impl TryFrom<&[u8]> for Keypair {
type Error = TryFromError;

fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
<[u8; 32]>::try_from(v)
.map(Self::from)
.map_err(TryFromError::from_any)
}
}

#[cfg(all(feature = "serde", feature = "b64"))]
impl_serde!(Keypair, 43);
#[cfg(feature = "b64")]
impl crate::FromStr for Keypair {
type Err = DecodeError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() != crate::calculate_b64_len(Self::LEN) {
return Err(DecodeError::InvalidLength)
}

let mut bytes = [0u8; Self::LEN];
base64::decode_config_slice(s, base64::URL_SAFE_NO_PAD, &mut bytes)
.map(|_| Self::from(bytes))
.map_err(DecodeError::inv_bytes)
}
}

#[cfg(all(feature = "b64", feature = "serde"))]
mod impl_serde {

use super::*;

use std::borrow::Cow;
use std::str::FromStr;

use _serde::{Serialize, Serializer, Deserialize, Deserializer};
use _serde::de::Error;

impl Serialize for Keypair {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
serializer.collect_str(&self)
}
}

impl<'de> Deserialize<'de> for Keypair {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
let s: Cow<'_, str> = Deserialize::deserialize(deserializer)?;
Self::from_str(s.as_ref())
.map_err(D::Error::custom)
}
}

}
35 changes: 19 additions & 16 deletions src/cipher/mac.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::error::TryFromError;

use std::fmt;
use std::convert::TryInto;
use std::convert::{TryFrom, TryInto};

use generic_array::{GenericArray, typenum};
use typenum::{U16};
Expand All @@ -24,23 +26,10 @@ impl Mac {
Self { tag }
}

/// This function should only be used with bytes that
/// were received with a message.
pub fn from_bytes(bytes: [u8; 16]) -> Self {
let gen: GenericArray<u8, U16> = bytes.into();

Self { tag: Tag::new(gen) }
}

/// ## Panics
/// if the slice is not 16 bytes long.
pub fn from_slice(slice: &[u8]) -> Self {
Self::from_bytes(slice.try_into().unwrap())
}

pub fn try_from_slice(slice: &[u8]) -> Option<Self> {
slice.try_into().ok()
.map(Self::from_bytes)
slice.try_into().unwrap()
}

pub fn into_bytes(self) -> [u8; 16] {
Expand All @@ -55,7 +44,21 @@ impl fmt::Debug for Mac {
}

impl From<[u8; 16]> for Mac {
/// This function should only be used with bytes that
/// were received with a message.
fn from(bytes: [u8; 16]) -> Self {
Self::from_bytes(bytes)
let gen: GenericArray<u8, U16> = bytes.into();

Self { tag: Tag::new(gen) }
}
}

impl TryFrom<&[u8]> for Mac {
type Error = TryFromError;

fn try_from(s: &[u8]) -> Result<Self, Self::Error> {
<[u8; 16]>::try_from(s)
.map_err(TryFromError::from_any)
.map(Mac::from)
}
}
13 changes: 8 additions & 5 deletions src/cipher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ mod tests {

use super::*;

#[cfg(feature = "b64")]
use std::str::FromStr;

#[test]
pub fn diffie_keypair() {
let alice = Keypair::new();
Expand Down Expand Up @@ -98,10 +101,10 @@ mod tests {
pub fn b64() {
let alice = Keypair::new();

let b64 = alice.to_b64();
let alice_2 = Keypair::from_b64(&b64).unwrap();
let b64 = alice.to_string();
let alice_2 = Keypair::from_str(&b64).unwrap();

assert_eq!(b64, alice_2.to_b64());
assert_eq!(b64, alice_2.to_string());
}

#[test]
Expand Down Expand Up @@ -154,8 +157,8 @@ mod tests {
#[cfg(feature = "b64")]
#[test]
pub fn static_encrypt_decrypt() {
let alice = Keypair::from_b64("4KbU6aVELDln5wCADIA53wBrldKuaoRFA4Pw0WB73XQ").unwrap();
let bob = Keypair::from_b64("WG1CTI9LGEtUZbLFI1glU-8jIsfh3VkzrUKrmUqeqU8").unwrap();
let alice = Keypair::from_str("4KbU6aVELDln5wCADIA53wBrldKuaoRFA4Pw0WB73XQ").unwrap();
let bob = Keypair::from_str("WG1CTI9LGEtUZbLFI1glU-8jIsfh3VkzrUKrmUqeqU8").unwrap();

let alice_ssk = alice.diffie_hellman(bob.public());
let bob_ssk = bob.diffie_hellman(alice.public());
Expand Down
Loading

0 comments on commit c7dd978

Please sign in to comment.