use hmac::{Hmac, Mac};
use crate::algorithms::Algorithm;
use crate::decoding::DecodingKey;
use crate::encoding::EncodingKey;
use crate::errors::{new_error, ErrorKind, Result};
use crate::serialization::{b64_decode, b64_encode};
use sha2::{Sha256, Sha384, Sha512};
pub(crate) mod rsa;
type HmacSha256 = Hmac<Sha256>;
type HmacSha384 = Hmac<Sha384>;
type HmacSha512 = Hmac<Sha512>;
pub(crate) fn sign_hmac(alg: Algorithm, key: &[u8], message: &str) -> Result<String> {
let digest = match alg {
Algorithm::HS256 => {
let mut mac = HmacSha256::new_from_slice(key).unwrap();
mac.update(message.as_bytes());
b64_encode(mac.finalize().into_bytes().as_slice())
}
Algorithm::HS384 => {
let mut mac = HmacSha384::new_from_slice(key).unwrap();
mac.update(message.as_bytes());
b64_encode(mac.finalize().into_bytes().as_slice())
}
Algorithm::HS512 => {
let mut mac = HmacSha512::new_from_slice(key).unwrap();
mac.update(message.as_bytes());
b64_encode(mac.finalize().into_bytes().as_slice())
}
_ => unreachable!(),
};
Ok(digest)
}
pub fn validate_matching_key(key: &EncodingKey, algorithm: Algorithm) -> Result<()> {
match key {
EncodingKey::Hmac(_) => match algorithm {
Algorithm::HS256 => Ok(()),
Algorithm::HS384 => Ok(()),
Algorithm::HS512 => Ok(()),
_ => Err(ErrorKind::InvalidAlgorithm.into()),
},
EncodingKey::Rsa(_) => match algorithm {
Algorithm::RS256
| Algorithm::PS256
| Algorithm::PS384
| Algorithm::PS512
| Algorithm::RS384
| Algorithm::RS512 => Ok(()),
_ => Err(ErrorKind::InvalidAlgorithm.into()),
},
}
}
pub fn sign(message: &str, key: &EncodingKey, algorithm: Algorithm) -> Result<String> {
match key {
EncodingKey::Hmac(s) => match algorithm {
Algorithm::HS256 => sign_hmac(Algorithm::HS256, s, message),
Algorithm::HS384 => sign_hmac(Algorithm::HS384, s, message),
Algorithm::HS512 => sign_hmac(Algorithm::HS512, s, message),
_ => Err(ErrorKind::InvalidAlgorithm.into()),
},
EncodingKey::Rsa(k) => match algorithm {
Algorithm::RS256
| Algorithm::RS384
| Algorithm::RS512
| Algorithm::PS256
| Algorithm::PS384
| Algorithm::PS512 => rsa::sign(algorithm, k, message),
_ => Err(ErrorKind::InvalidAlgorithm.into()),
},
}
}
pub fn verify(
signature: &str,
message: &str,
key: &DecodingKey,
algorithm: Algorithm,
) -> Result<bool> {
match key {
DecodingKey::Hmac(s) => match algorithm {
Algorithm::HS256 => {
let mut mac = HmacSha256::new_from_slice(s).unwrap();
mac.update(message.as_bytes());
Ok(mac.finalize().into_bytes().as_slice()
== b64_decode(signature)
.map_err(|_e| new_error(ErrorKind::InvalidSignature))?)
}
Algorithm::HS384 => {
let mut mac = HmacSha384::new_from_slice(s).unwrap();
mac.update(message.as_bytes());
Ok(mac.finalize().into_bytes().as_slice()
== b64_decode(signature)
.map_err(|_e| new_error(ErrorKind::InvalidSignature))?)
}
Algorithm::HS512 => {
let mut mac = HmacSha512::new_from_slice(s).unwrap();
mac.update(message.as_bytes());
Ok(mac.finalize().into_bytes().as_slice()
== b64_decode(signature)
.map_err(|_e| new_error(ErrorKind::InvalidSignature))?)
}
_ => Err(ErrorKind::InvalidAlgorithm.into()),
},
DecodingKey::Rsa(k) => match algorithm {
Algorithm::RS256
| Algorithm::RS384
| Algorithm::RS512
| Algorithm::PS256
| Algorithm::PS384
| Algorithm::PS512 => rsa::verify(algorithm, signature, message, k),
_ => Err(ErrorKind::InvalidAlgorithm.into()),
},
}
}