use crate::key::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Hash {
Sha256,
Sha384,
Sha512,
Sha1,
}
impl Hash {
pub fn output_len(self) -> usize {
match self {
Hash::Sha256 => 32,
Hash::Sha384 => 48,
Hash::Sha512 => 64,
Hash::Sha1 => 20,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RsaSigPadding {
Pss {
salt_len: SaltLen,
},
Pkcs1v15,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum SaltLen {
DigestLength,
Max,
Fixed(usize),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RsaEncPadding {
Oaep {
hash: Hash,
mgf1: Hash,
},
Pkcs1v15,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum SigEncoding {
#[default]
Raw,
Der,
}
const F_HASH: u8 = 1 << 0;
const F_PREHASHED: u8 = 1 << 1;
const F_CONTEXT: u8 = 1 << 2;
const F_PADDING: u8 = 1 << 3;
const F_DETERMINISTIC: u8 = 1 << 4;
const F_SIG_ENCODING: u8 = 1 << 5;
const F_ENC_PADDING: u8 = 1 << 0;
const F_ENC_LABEL: u8 = 1 << 1;
#[derive(Debug, Clone, Copy)]
pub struct SignParams<'a> {
hash: Hash,
prehashed: bool,
context: &'a [u8],
padding: RsaSigPadding,
deterministic: bool,
sig_encoding: SigEncoding,
set: u8,
}
impl Default for SignParams<'_> {
fn default() -> Self {
SignParams {
hash: Hash::Sha256,
prehashed: false,
context: &[],
padding: RsaSigPadding::Pss {
salt_len: SaltLen::DigestLength,
},
deterministic: false,
sig_encoding: SigEncoding::Raw,
set: 0,
}
}
}
impl<'a> SignParams<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn hash(mut self, hash: Hash) -> Self {
self.hash = hash;
self.set |= F_HASH;
self
}
pub fn prehashed(mut self, yes: bool) -> Self {
self.prehashed = yes;
self.set |= F_PREHASHED;
self
}
pub fn context(mut self, context: &'a [u8]) -> Self {
self.context = context;
self.set |= F_CONTEXT;
self
}
pub fn sig_encoding(mut self, enc: SigEncoding) -> Self {
self.sig_encoding = enc;
self.set |= F_SIG_ENCODING;
self
}
pub fn pkcs1v15(mut self) -> Self {
self.padding = RsaSigPadding::Pkcs1v15;
self.set |= F_PADDING;
self
}
pub fn pss(mut self, salt_len: SaltLen) -> Self {
self.padding = RsaSigPadding::Pss { salt_len };
self.set |= F_PADDING;
self
}
pub fn deterministic(mut self, yes: bool) -> Self {
self.deterministic = yes;
self.set |= F_DETERMINISTIC;
self
}
pub fn reader(&self) -> SignParamsReader<'a> {
SignParamsReader {
params: *self,
used: 0,
}
}
}
#[derive(Debug)]
pub struct SignParamsReader<'a> {
params: SignParams<'a>,
used: u8,
}
impl<'a> SignParamsReader<'a> {
pub fn hash(&mut self) -> Hash {
self.used |= F_HASH;
self.params.hash
}
pub fn prehashed(&mut self) -> bool {
self.used |= F_PREHASHED;
self.params.prehashed
}
pub fn context(&mut self) -> &'a [u8] {
self.used |= F_CONTEXT;
self.params.context
}
pub fn padding(&mut self) -> RsaSigPadding {
self.used |= F_PADDING;
self.params.padding
}
pub fn deterministic(&mut self) -> bool {
self.used |= F_DETERMINISTIC;
self.params.deterministic
}
pub fn sig_encoding(&mut self) -> SigEncoding {
self.used |= F_SIG_ENCODING;
self.params.sig_encoding
}
pub fn finish(self) -> Result<(), Error> {
match first_unconsumed(self.params.set & !self.used, SIGN_PARAM_NAMES) {
Some(param) => Err(Error::UnsupportedParam { param }),
None => Ok(()),
}
}
}
const SIGN_PARAM_NAMES: &[(u8, &str)] = &[
(F_HASH, "hash"),
(F_PREHASHED, "prehashed"),
(F_CONTEXT, "context"),
(F_PADDING, "padding"),
(F_DETERMINISTIC, "deterministic"),
(F_SIG_ENCODING, "sig_encoding"),
];
const CRYPT_PARAM_NAMES: &[(u8, &str)] = &[(F_ENC_PADDING, "padding"), (F_ENC_LABEL, "label")];
fn first_unconsumed(leftover: u8, names: &[(u8, &'static str)]) -> Option<&'static str> {
if leftover == 0 {
return None;
}
for &(bit, name) in names {
if leftover & bit != 0 {
return Some(name);
}
}
Some("parameter")
}
#[derive(Debug, Clone, Copy)]
pub struct CryptParams<'a> {
padding: RsaEncPadding,
label: &'a [u8],
set: u8,
}
pub type EncryptParams<'a> = CryptParams<'a>;
pub type DecryptParams<'a> = CryptParams<'a>;
impl Default for CryptParams<'_> {
fn default() -> Self {
CryptParams {
padding: RsaEncPadding::Oaep {
hash: Hash::Sha256,
mgf1: Hash::Sha256,
},
label: &[],
set: 0,
}
}
}
impl<'a> CryptParams<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn padding(mut self, padding: RsaEncPadding) -> Self {
self.padding = padding;
self.set |= F_ENC_PADDING;
self
}
pub fn label(mut self, label: &'a [u8]) -> Self {
self.label = label;
self.set |= F_ENC_LABEL;
self
}
pub fn reader(&self) -> CryptParamsReader<'a> {
CryptParamsReader {
params: *self,
used: 0,
}
}
}
#[derive(Debug)]
pub struct CryptParamsReader<'a> {
params: CryptParams<'a>,
used: u8,
}
impl<'a> CryptParamsReader<'a> {
pub fn padding(&mut self) -> RsaEncPadding {
self.used |= F_ENC_PADDING;
self.params.padding
}
pub fn label(&mut self) -> &'a [u8] {
self.used |= F_ENC_LABEL;
self.params.label
}
pub fn finish(self) -> Result<(), Error> {
match first_unconsumed(self.params.set & !self.used, CRYPT_PARAM_NAMES) {
Some(param) => Err(Error::UnsupportedParam { param }),
None => Ok(()),
}
}
}