use std::fmt;
use std::ops::{BitAnd, BitOr};
#[cfg(test)]
use quickcheck::{Arbitrary, Gen};
use crate::types::Bitfield;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KeyFlags(Bitfield);
assert_send_and_sync!(KeyFlags);
impl fmt::Debug for KeyFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.for_certification() {
f.write_str("C")?;
}
if self.for_signing() {
f.write_str("S")?;
}
if self.for_transport_encryption() {
f.write_str("Et")?;
}
if self.for_storage_encryption() {
f.write_str("Er")?;
}
if self.for_authentication() {
f.write_str("A")?;
}
if self.is_split_key() {
f.write_str("D")?;
}
if self.is_group_key() {
f.write_str("G")?;
}
let mut need_comma = false;
for i in self.0.iter() {
match i {
KEY_FLAG_CERTIFY
| KEY_FLAG_SIGN
| KEY_FLAG_ENCRYPT_FOR_TRANSPORT
| KEY_FLAG_ENCRYPT_AT_REST
| KEY_FLAG_SPLIT_KEY
| KEY_FLAG_AUTHENTICATE
| KEY_FLAG_GROUP_KEY
=> (),
i => {
if need_comma { f.write_str(", ")?; }
write!(f, "#{}", i)?;
need_comma = true;
},
}
}
let padding = self.0.padding_len();
if padding > 0 {
if need_comma { f.write_str(", ")?; }
write!(f, "+padding({} bytes)", padding)?;
}
Ok(())
}
}
impl BitAnd for &KeyFlags {
type Output = KeyFlags;
fn bitand(self, rhs: Self) -> KeyFlags {
let l = self.as_slice();
let r = rhs.as_slice();
let mut c = Vec::with_capacity(std::cmp::min(l.len(), r.len()));
for (l, r) in l.into_iter().zip(r.into_iter()) {
c.push(l & r);
}
KeyFlags(c.into())
}
}
impl BitOr for &KeyFlags {
type Output = KeyFlags;
fn bitor(self, rhs: Self) -> KeyFlags {
let l = self.as_slice();
let r = rhs.as_slice();
let (l, r) = if l.len() > r.len() {
(l, r)
} else {
(r, l)
};
let mut l = l.to_vec();
for (i, r) in r.into_iter().enumerate() {
l[i] = l[i] | r;
}
KeyFlags(l.into())
}
}
impl AsRef<KeyFlags> for KeyFlags {
fn as_ref(&self) -> &KeyFlags {
self
}
}
impl KeyFlags {
pub fn new<B: AsRef<[u8]>>(bits: B) -> Self {
Self(bits.as_ref().to_vec().into())
}
pub fn empty() -> Self {
KeyFlags::new(&[])
}
pub(crate) fn as_slice(&self) -> &[u8] {
self.0.as_slice()
}
pub fn normalized_eq(&self, other: &Self) -> bool {
self.0.normalized_eq(&other.0)
}
pub fn get(&self, bit: usize) -> bool {
self.0.get(bit)
}
pub fn set(self, bit: usize) -> Self {
Self(self.0.set(bit))
}
pub fn clear(self, bit: usize) -> Self {
Self(self.0.clear(bit))
}
pub fn for_certification(&self) -> bool {
self.get(KEY_FLAG_CERTIFY)
}
pub fn set_certification(self) -> Self {
self.set(KEY_FLAG_CERTIFY)
}
pub fn clear_certification(self) -> Self {
self.clear(KEY_FLAG_CERTIFY)
}
pub fn for_signing(&self) -> bool {
self.get(KEY_FLAG_SIGN)
}
pub fn set_signing(self) -> Self {
self.set(KEY_FLAG_SIGN)
}
pub fn clear_signing(self) -> Self {
self.clear(KEY_FLAG_SIGN)
}
pub fn for_transport_encryption(&self) -> bool {
self.get(KEY_FLAG_ENCRYPT_FOR_TRANSPORT)
}
pub fn set_transport_encryption(self) -> Self {
self.set(KEY_FLAG_ENCRYPT_FOR_TRANSPORT)
}
pub fn clear_transport_encryption(self) -> Self {
self.clear(KEY_FLAG_ENCRYPT_FOR_TRANSPORT)
}
pub fn for_storage_encryption(&self) -> bool {
self.get(KEY_FLAG_ENCRYPT_AT_REST)
}
pub fn set_storage_encryption(self) -> Self {
self.set(KEY_FLAG_ENCRYPT_AT_REST)
}
pub fn clear_storage_encryption(self) -> Self {
self.clear(KEY_FLAG_ENCRYPT_AT_REST)
}
pub fn for_authentication(&self) -> bool {
self.get(KEY_FLAG_AUTHENTICATE)
}
pub fn set_authentication(self) -> Self {
self.set(KEY_FLAG_AUTHENTICATE)
}
pub fn clear_authentication(self) -> Self {
self.clear(KEY_FLAG_AUTHENTICATE)
}
pub fn is_split_key(&self) -> bool {
self.get(KEY_FLAG_SPLIT_KEY)
}
pub fn set_split_key(self) -> Self {
self.set(KEY_FLAG_SPLIT_KEY)
}
pub fn clear_split_key(self) -> Self {
self.clear(KEY_FLAG_SPLIT_KEY)
}
pub fn is_group_key(&self) -> bool {
self.get(KEY_FLAG_GROUP_KEY)
}
pub fn set_group_key(self) -> Self {
self.set(KEY_FLAG_GROUP_KEY)
}
pub fn is_empty(&self) -> bool {
self.as_slice().iter().all(|b| *b == 0)
}
}
const KEY_FLAG_CERTIFY: usize = 0;
const KEY_FLAG_SIGN: usize = 1;
const KEY_FLAG_ENCRYPT_FOR_TRANSPORT: usize = 2;
const KEY_FLAG_ENCRYPT_AT_REST: usize = 3;
const KEY_FLAG_SPLIT_KEY: usize = 4;
const KEY_FLAG_AUTHENTICATE: usize = 5;
const KEY_FLAG_GROUP_KEY: usize = 7;
#[cfg(test)]
impl Arbitrary for KeyFlags {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Self::new(Vec::arbitrary(g))
}
}
#[cfg(test)]
mod tests {
use super::*;
quickcheck! {
fn roundtrip(val: KeyFlags) -> bool {
let mut q = KeyFlags::new(&val.as_slice());
assert_eq!(val, q);
assert!(val.normalized_eq(&q));
q.0.raw.push(0);
assert!(val != q);
assert!(val.normalized_eq(&q));
q.0.raw.push(0);
assert!(val != q);
assert!(val.normalized_eq(&q));
true
}
}
}