Merge branch 'no-string-error' into 'master'

Use structs for errors instead of plain strings

Closes #3

See merge request lumi/sasl-rs!8
This commit is contained in:
lumi 2020-06-07 12:26:12 +00:00
commit 5550148149
10 changed files with 365 additions and 107 deletions

View file

@ -1,5 +1,5 @@
use getrandom::{getrandom, Error as RngError};
use hmac::{Hmac, Mac};
use hmac::{crypto_mac::InvalidKeyLength, Hmac, Mac};
use pbkdf2::pbkdf2;
use sha1::{Digest, Sha1 as Sha1_hash};
use sha2::Sha256 as Sha256_hash;
@ -17,6 +17,29 @@ pub fn generate_nonce() -> Result<String, RngError> {
Ok(base64::encode(&data))
}
#[derive(Debug, PartialEq)]
pub enum DeriveError {
IncompatibleHashingMethod(String, String),
IncorrectSalt,
IncompatibleIterationCount(usize, usize),
}
impl std::fmt::Display for DeriveError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
DeriveError::IncompatibleHashingMethod(one, two) => {
write!(fmt, "incompatible hashing method, {} is not {}", one, two)
}
DeriveError::IncorrectSalt => write!(fmt, "incorrect salt"),
DeriveError::IncompatibleIterationCount(one, two) => {
write!(fmt, "incompatible iteration count, {} is not {}", one, two)
}
}
}
}
impl std::error::Error for DeriveError {}
/// A trait which defines the needed methods for SCRAM.
pub trait ScramProvider {
/// The kind of secret this `ScramProvider` requires.
@ -29,10 +52,10 @@ pub trait ScramProvider {
fn hash(data: &[u8]) -> Vec<u8>;
/// A function which performs an HMAC using the hash function.
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, String>;
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, InvalidKeyLength>;
/// A function which does PBKDF2 key derivation using the hash function.
fn derive(data: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, String>;
fn derive(data: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, DeriveError>;
}
/// A `ScramProvider` which provides SCRAM-SHA-1 and SCRAM-SHA-1-PLUS
@ -52,12 +75,9 @@ impl ScramProvider for Sha1 {
vec
}
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, String> {
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, InvalidKeyLength> {
type HmacSha1 = Hmac<Sha1_hash>;
let mut mac = match HmacSha1::new_varkey(key) {
Ok(mac) => mac,
Err(err) => return Err(format!("{}", err)),
};
let mut mac = HmacSha1::new_varkey(key)?;
mac.input(data);
let result = mac.result();
let mut vec = Vec::with_capacity(Sha1_hash::output_size());
@ -65,7 +85,7 @@ impl ScramProvider for Sha1 {
Ok(vec)
}
fn derive(password: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, String> {
fn derive(password: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, DeriveError> {
match *password {
Password::Plain(ref plain) => {
let mut result = vec![0; 20];
@ -79,17 +99,16 @@ impl ScramProvider for Sha1 {
ref data,
} => {
if method != Self::name() {
Err(format!(
"incompatible hashing method, {} is not {}",
method,
Self::name()
Err(DeriveError::IncompatibleHashingMethod(
method.to_string(),
Self::name().to_string(),
))
} else if my_salt == &salt {
Err(format!("incorrect salt"))
Err(DeriveError::IncorrectSalt)
} else if my_iterations == iterations {
Err(format!(
"incompatible iteration count, {} is not {}",
my_iterations, iterations
Err(DeriveError::IncompatibleIterationCount(
my_iterations,
iterations,
))
} else {
Ok(data.to_vec())
@ -116,12 +135,9 @@ impl ScramProvider for Sha256 {
vec
}
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, String> {
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, InvalidKeyLength> {
type HmacSha256 = Hmac<Sha256_hash>;
let mut mac = match HmacSha256::new_varkey(key) {
Ok(mac) => mac,
Err(err) => return Err(format!("{}", err)),
};
let mut mac = HmacSha256::new_varkey(key)?;
mac.input(data);
let result = mac.result();
let mut vec = Vec::with_capacity(Sha256_hash::output_size());
@ -129,7 +145,7 @@ impl ScramProvider for Sha256 {
Ok(vec)
}
fn derive(password: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, String> {
fn derive(password: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, DeriveError> {
match *password {
Password::Plain(ref plain) => {
let mut result = vec![0; 32];
@ -143,17 +159,16 @@ impl ScramProvider for Sha256 {
ref data,
} => {
if method != Self::name() {
Err(format!(
"incompatible hashing method, {} is not {}",
method,
Self::name()
Err(DeriveError::IncompatibleHashingMethod(
method.to_string(),
Self::name().to_string(),
))
} else if my_salt == &salt {
Err(format!("incorrect salt"))
Err(DeriveError::IncorrectSalt)
} else if my_iterations == iterations {
Err(format!(
"incompatible iteration count, {} is not {}",
my_iterations, iterations
Err(DeriveError::IncompatibleIterationCount(
my_iterations,
iterations,
))
} else {
Ok(data.to_vec())