You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
distant/distant-core-net/src/common/key.rs

323 lines
8.4 KiB
Rust

use std::fmt;
use std::str::FromStr;
use derive_more::{Display, Error};
use rand::rngs::OsRng;
use rand::RngCore;
#[derive(Debug, Display, Error)]
pub struct SecretKeyError;
impl From<SecretKeyError> for std::io::Error {
fn from(_: SecretKeyError) -> Self {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"not valid secret key format",
)
}
}
/// Represents a 16-byte (128-bit) secret key
pub type SecretKey16 = SecretKey<16>;
/// Represents a 24-byte (192-bit) secret key
pub type SecretKey24 = SecretKey<24>;
/// Represents a 32-byte (256-bit) secret key
pub type SecretKey32 = SecretKey<32>;
/// Represents a secret key used with transport encryption and authentication
#[derive(Clone, PartialEq, Eq)]
pub struct SecretKey<const N: usize>([u8; N]);
impl<const N: usize> fmt::Debug for SecretKey<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SecretKey")
.field(&"**OMITTED**".to_string())
.finish()
}
}
impl<const N: usize> Default for SecretKey<N> {
/// Creates a new secret key of the size `N`
///
/// ### Panic
///
/// Will panic if `N` is less than 1 or greater than `isize::MAX`
fn default() -> Self {
Self::generate().unwrap()
}
}
impl<const N: usize> SecretKey<N> {
/// Returns byte slice to the key's bytes
pub fn unprotected_as_bytes(&self) -> &[u8] {
&self.0
}
/// Returns reference to array of key's bytes
pub fn unprotected_as_byte_array(&self) -> &[u8; N] {
&self.0
}
/// Consumes the secret key and returns the array of key's bytes
pub fn unprotected_into_byte_array(self) -> [u8; N] {
self.0
}
/// Consumes the secret key and returns the key's bytes as a [`HeapSecretKey`]
pub fn into_heap_secret_key(self) -> HeapSecretKey {
HeapSecretKey(self.0.to_vec())
}
/// Returns the length of the key
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
N
}
/// Generates a new secret key, returning success if key created or
/// failing if the desired key length is not between 1 and `isize::MAX`
pub fn generate() -> Result<Self, SecretKeyError> {
// Limitation described in https://github.com/orion-rs/orion/issues/130
if N < 1 || N > (isize::MAX as usize) {
return Err(SecretKeyError);
}
let mut key = [0; N];
OsRng.fill_bytes(&mut key);
Ok(Self(key))
}
/// Creates the key from the given byte slice, returning success if key created
/// or failing if the byte slice does not match the desired key length
pub fn from_slice(slice: &[u8]) -> Result<Self, SecretKeyError> {
if slice.len() != N {
return Err(SecretKeyError);
}
let mut value = [0u8; N];
value[..N].copy_from_slice(slice);
Ok(Self(value))
}
}
impl<const N: usize> From<[u8; N]> for SecretKey<N> {
fn from(arr: [u8; N]) -> Self {
Self(arr)
}
}
impl<const N: usize> FromStr for SecretKey<N> {
type Err = SecretKeyError;
/// Parse a str of hex as an N-byte secret key
fn from_str(s: &str) -> Result<Self, Self::Err> {
let bytes = hex::decode(s).map_err(|_| SecretKeyError)?;
Self::from_slice(&bytes)
}
}
impl<const N: usize> fmt::Display for SecretKey<N> {
/// Display an N-byte secret key as a hex string
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", hex::encode(self.unprotected_as_bytes()))
}
}
/// Represents a secret key used with transport encryption and authentication that is stored on the
/// heap
#[derive(Clone, PartialEq, Eq)]
pub struct HeapSecretKey(Vec<u8>);
impl fmt::Debug for HeapSecretKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("HeapSecretKey")
.field(&"**OMITTED**".to_string())
.finish()
}
}
impl HeapSecretKey {
/// Returns byte slice to the key's bytes
pub fn unprotected_as_bytes(&self) -> &[u8] {
&self.0
}
/// Consumes the secret key and returns the key's bytes
pub fn unprotected_into_bytes(self) -> Vec<u8> {
self.0.to_vec()
}
/// Returns the length of the key
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.0.len()
}
/// Generates a random key of `n` bytes in length.
///
/// ### Note
///
/// Will return an error if `n` < 1 or `n` > `isize::MAX`.
pub fn generate(n: usize) -> Result<Self, SecretKeyError> {
// Limitation described in https://github.com/orion-rs/orion/issues/130
if n < 1 || n > (isize::MAX as usize) {
return Err(SecretKeyError);
}
let mut key = Vec::new();
let mut buf = [0; 32];
// Continually generate a chunk of bytes and extend our key until we've reached
// the appropriate length
while key.len() < n {
OsRng.fill_bytes(&mut buf);
key.extend_from_slice(&buf[..std::cmp::min(n - key.len(), 32)]);
}
Ok(Self(key))
}
}
impl From<Vec<u8>> for HeapSecretKey {
fn from(bytes: Vec<u8>) -> Self {
Self(bytes)
}
}
impl<const N: usize> From<[u8; N]> for HeapSecretKey {
fn from(arr: [u8; N]) -> Self {
Self::from(arr.to_vec())
}
}
impl<const N: usize> From<SecretKey<N>> for HeapSecretKey {
fn from(key: SecretKey<N>) -> Self {
key.into_heap_secret_key()
}
}
impl FromStr for HeapSecretKey {
type Err = SecretKeyError;
/// Parse a str of hex as secret key on heap
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(hex::decode(s).map_err(|_| SecretKeyError)?))
}
}
impl fmt::Display for HeapSecretKey {
/// Display an N-byte secret key as a hex string
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", hex::encode(self.unprotected_as_bytes()))
}
}
impl<const N: usize> PartialEq<[u8; N]> for HeapSecretKey {
fn eq(&self, other: &[u8; N]) -> bool {
self.0.eq(other)
}
}
impl<const N: usize> PartialEq<HeapSecretKey> for [u8; N] {
fn eq(&self, other: &HeapSecretKey) -> bool {
other.eq(self)
}
}
impl<const N: usize> PartialEq<HeapSecretKey> for &[u8; N] {
fn eq(&self, other: &HeapSecretKey) -> bool {
other.eq(*self)
}
}
impl PartialEq<[u8]> for HeapSecretKey {
fn eq(&self, other: &[u8]) -> bool {
self.0.eq(other)
}
}
impl PartialEq<HeapSecretKey> for [u8] {
fn eq(&self, other: &HeapSecretKey) -> bool {
other.eq(self)
}
}
impl PartialEq<HeapSecretKey> for &[u8] {
fn eq(&self, other: &HeapSecretKey) -> bool {
other.eq(*self)
}
}
impl PartialEq<String> for HeapSecretKey {
fn eq(&self, other: &String) -> bool {
self.0.eq(other.as_bytes())
}
}
impl PartialEq<HeapSecretKey> for String {
fn eq(&self, other: &HeapSecretKey) -> bool {
other.eq(self)
}
}
impl PartialEq<HeapSecretKey> for &String {
fn eq(&self, other: &HeapSecretKey) -> bool {
other.eq(*self)
}
}
impl PartialEq<str> for HeapSecretKey {
fn eq(&self, other: &str) -> bool {
self.0.eq(other.as_bytes())
}
}
impl PartialEq<HeapSecretKey> for str {
fn eq(&self, other: &HeapSecretKey) -> bool {
other.eq(self)
}
}
impl PartialEq<HeapSecretKey> for &str {
fn eq(&self, other: &HeapSecretKey) -> bool {
other.eq(*self)
}
}
#[cfg(test)]
mod tests {
use test_log::test;
use super::*;
#[test]
fn secret_key_should_be_able_to_be_generated() {
SecretKey::<0>::generate().unwrap_err();
let key = SecretKey::<1>::generate().unwrap();
assert_eq!(key.len(), 1);
// NOTE: We aren't going to validate generating isize::MAX or +1 of that size because it
// takes a lot of time to do so
let key = SecretKey::<100>::generate().unwrap();
assert_eq!(key.len(), 100);
}
#[test]
fn heap_secret_key_should_be_able_to_be_generated() {
HeapSecretKey::generate(0).unwrap_err();
let key = HeapSecretKey::generate(1).unwrap();
assert_eq!(key.len(), 1);
// NOTE: We aren't going to validate generating isize::MAX or +1 of that size because it
// takes a lot of time to do so
let key = HeapSecretKey::generate(100).unwrap();
assert_eq!(key.len(), 100);
}
}