use rand::rngs::EntropyRng;
use rand::RngCore;
use {Error, ErrorKind};
impl Default for Salt {
fn default() -> Salt {
Salt::random(32)
}
}
impl From<Vec<u8>> for Salt {
fn from(bytes: Vec<u8>) -> Salt {
Salt(Kind::Deterministic(bytes))
}
}
impl From<String> for Salt {
fn from(s: String) -> Salt {
Salt(Kind::Deterministic(s.into_bytes()))
}
}
impl<'a> From<&'a [u8]> for Salt {
fn from(bytes: &[u8]) -> Salt {
Salt(Kind::Deterministic(bytes.to_vec()))
}
}
impl<'a> From<&'a str> for Salt {
fn from(s: &str) -> Salt {
Salt(Kind::Deterministic(s.as_bytes().to_vec()))
}
}
impl<'a> From<&'a Vec<u8>> for Salt {
fn from(bytes: &Vec<u8>) -> Salt {
Salt(Kind::Deterministic(bytes.clone()))
}
}
impl<'a> From<&'a String> for Salt {
fn from(s: &String) -> Salt {
Salt(Kind::Deterministic(s.clone().into_bytes()))
}
}
impl<'a> From<&'a Salt> for Salt {
fn from(salt: &Salt) -> Salt {
salt.clone()
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Salt(Kind);
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
enum Kind {
Deterministic(Vec<u8>),
Random(Vec<u8>),
}
impl Salt {
pub fn random(len: u32) -> Salt {
let bytes = vec![0u8; len as usize];
Salt(Kind::Random(bytes))
}
pub fn as_bytes(&self) -> &[u8] {
match self.0 {
Kind::Deterministic(ref bytes) => bytes.as_slice(),
Kind::Random(ref bytes) => bytes.as_slice(),
}
}
pub fn is_random(&self) -> bool {
match self.0 {
Kind::Deterministic(_) => false,
Kind::Random(_) => true,
}
}
pub fn len(&self) -> usize {
self.as_bytes().len()
}
pub fn to_str(&self) -> Result<&str, Error> {
let s = ::std::str::from_utf8(self.as_bytes()).map_err(|_| {
Error::new(ErrorKind::Utf8EncodeError)
.add_context(format!("Bytes: {:?}", self.as_bytes()))
})?;
Ok(s)
}
pub fn update(&mut self) -> Result<(), Error> {
match self.0 {
Kind::Random(ref mut bytes) => {
let mut rng = EntropyRng::new();
rng.try_fill_bytes(bytes)
.map_err(|_| Error::new(ErrorKind::OsRngError))?;
}
_ => (),
}
Ok(())
}
}
impl Salt {
pub(crate) fn validate(&self) -> Result<(), Error> {
let len = self.len();
if len < 8 {
return Err(
Error::new(ErrorKind::SaltTooShortError).add_context(format!("Length: {}", len))
);
}
if len >= ::std::u32::MAX as usize {
return Err(
Error::new(ErrorKind::SaltTooLongError).add_context(format!("Length: {}", len))
);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Salt>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Salt>();
}
#[cfg(feature = "serde")]
#[test]
fn test_serialize() {
use serde;
fn assert_serialize<T: serde::Serialize>() {}
assert_serialize::<Salt>();
}
#[cfg(feature = "serde")]
#[test]
fn test_deserialize() {
use serde;
fn assert_deserialize<'de, T: serde::Deserialize<'de>>() {}
assert_deserialize::<Salt>();
}
}