use std::fmt;
use std::cmp::Ordering;
#[cfg(any(test, feature = "quickcheck"))]
use quickcheck::{Arbitrary, Gen};
#[cfg(any(test, feature = "quickcheck"))]
use rand::Rng;
use crate::types::{
Curve,
HashAlgorithm,
PublicKeyAlgorithm,
SymmetricAlgorithm,
};
use crate::crypto::hash::{self, Hash};
use crate::crypto::mem::{secure_cmp, Protected};
use crate::serialize::Marshal;
use crate::Error;
use crate::Result;
#[derive(Clone)]
pub struct MPI {
value: Box<[u8]>,
}
impl From<Vec<u8>> for MPI {
fn from(v: Vec<u8>) -> Self {
Self::new(&v)
}
}
impl MPI {
pub fn new(value: &[u8]) -> Self {
let mut leading_zeros = 0;
for b in value {
leading_zeros += b.leading_zeros() as usize;
if *b != 0 {
break;
}
}
let offset = leading_zeros / 8;
let value = Vec::from(&value[offset..]).into_boxed_slice();
MPI {
value,
}
}
pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self {
Self::new_point_common(x, y, field_bits).into()
}
fn new_point_common(x: &[u8], y: &[u8], field_bits: usize) -> Vec<u8> {
let field_sz = if field_bits % 8 > 0 { 1 } else { 0 } + field_bits / 8;
let mut val = vec![0x0u8; 1 + 2 * field_sz];
let x_missing = field_sz - x.len();
let y_missing = field_sz - y.len();
val[0] = 0x4;
val[1 + x_missing..1 + field_sz].copy_from_slice(x);
val[1 + field_sz + y_missing..].copy_from_slice(y);
val
}
pub fn new_compressed_point(x: &[u8]) -> Self {
Self::new_compressed_point_common(x).into()
}
fn new_compressed_point_common(x: &[u8]) -> Vec<u8> {
let mut val = vec![0; 1 + x.len()];
val[0] = 0x40;
val[1..].copy_from_slice(x);
val
}
pub fn bits(&self) -> usize {
self.value.len() * 8
- self.value.get(0).map(|&b| b.leading_zeros() as usize)
.unwrap_or(0)
}
pub fn value(&self) -> &[u8] {
&self.value
}
pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
Self::decode_point_common(self.value(), curve)
}
fn decode_point_common<'a>(value: &'a [u8], curve: &Curve)
-> Result<(&'a [u8], &'a [u8])> {
const ED25519_KEY_SIZE: usize = 32;
const CURVE25519_SIZE: usize = 32;
use self::Curve::*;
match &curve {
Ed25519 | Cv25519 => {
assert_eq!(CURVE25519_SIZE, ED25519_KEY_SIZE);
if value.len() != 1 + CURVE25519_SIZE {
return Err(Error::MalformedMPI(
format!("Bad size of Curve25519 key: {} expected: {}",
value.len(),
1 + CURVE25519_SIZE
)
).into());
}
if value.get(0).map(|&b| b != 0x40).unwrap_or(true) {
return Err(Error::MalformedMPI(
"Bad encoding of Curve25519 key".into()).into());
}
Ok((&value[1..], &[]))
},
_ => {
let coordinate_length = (curve.len()? + 7) / 8;
let expected_length =
1
+ (2
* coordinate_length);
if value.len() != expected_length {
return Err(Error::MalformedMPI(
format!("Invalid length of MPI: {} (expected {})",
value.len(), expected_length)).into());
}
if value.get(0).map(|&b| b != 0x04).unwrap_or(true) {
return Err(Error::MalformedMPI(
format!("Bad prefix: {:?} (expected Some(0x04))",
value.get(0))).into());
}
Ok((&value[1..1 + coordinate_length],
&value[1 + coordinate_length..]))
},
}
}
fn secure_memcmp(&self, other: &Self) -> Ordering {
let cmp = unsafe {
if self.value.len() == other.value.len() {
::memsec::memcmp(self.value.as_ptr(), other.value.as_ptr(),
other.value.len())
} else {
self.value.len() as i32 - other.value.len() as i32
}
};
match cmp {
0 => Ordering::Equal,
x if x < 0 => Ordering::Less,
_ => Ordering::Greater,
}
}
}
impl fmt::Debug for MPI {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!(
"{} bits: {}", self.bits(),
crate::fmt::to_hex(&*self.value, true)))
}
}
impl Hash for MPI {
fn hash(&self, hash: &mut hash::Context) {
let len = self.bits() as u16;
hash.update(&len.to_be_bytes());
hash.update(&self.value);
}
}
#[cfg(any(test, feature = "quickcheck"))]
impl Arbitrary for MPI {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
loop {
let buf = <Vec<u8>>::arbitrary(g);
if !buf.is_empty() && buf[0] != 0 {
break MPI::new(&buf);
}
}
}
}
impl PartialOrd for MPI {
fn partial_cmp(&self, other: &MPI) -> Option<Ordering> {
Some(self.secure_memcmp(other))
}
}
impl Ord for MPI {
fn cmp(&self, other: &MPI) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl PartialEq for MPI {
fn eq(&self, other: &MPI) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for MPI {}
impl std::hash::Hash for MPI {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
}
}
#[derive(Clone)]
pub struct ProtectedMPI {
value: Protected,
}
impl From<Vec<u8>> for ProtectedMPI {
fn from(m: Vec<u8>) -> Self {
MPI::from(m).into()
}
}
impl From<Protected> for ProtectedMPI {
fn from(m: Protected) -> Self {
MPI::new(&m).into()
}
}
impl From<MPI> for ProtectedMPI {
fn from(m: MPI) -> Self {
ProtectedMPI {
value: m.value.into(),
}
}
}
impl PartialOrd for ProtectedMPI {
fn partial_cmp(&self, other: &ProtectedMPI) -> Option<Ordering> {
Some(self.secure_memcmp(other))
}
}
impl Ord for ProtectedMPI {
fn cmp(&self, other: &ProtectedMPI) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl PartialEq for ProtectedMPI {
fn eq(&self, other: &ProtectedMPI) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for ProtectedMPI {}
impl std::hash::Hash for ProtectedMPI {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
}
}
impl ProtectedMPI {
pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self {
MPI::new_point_common(x, y, field_bits).into()
}
pub fn new_compressed_point(x: &[u8]) -> Self {
MPI::new_compressed_point_common(x).into()
}
pub fn bits(&self) -> usize {
self.value.len() * 8
- self.value.get(0).map(|&b| b.leading_zeros() as usize)
.unwrap_or(0)
}
pub fn value(&self) -> &[u8] {
&self.value
}
pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
MPI::decode_point_common(self.value(), curve)
}
fn secure_memcmp(&self, other: &Self) -> Ordering {
(self.value.len() as i32).cmp(&(other.value.len() as i32))
.then(
self.value.cmp(&other.value))
}
}
impl fmt::Debug for ProtectedMPI {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if cfg!(debug_assertions) {
f.write_fmt(format_args!(
"{} bits: {}", self.bits(),
crate::fmt::to_hex(&*self.value, true)))
} else {
f.write_str("<Redacted>")
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub enum PublicKey {
RSA {
e: MPI,
n: MPI,
},
DSA {
p: MPI,
q: MPI,
g: MPI,
y: MPI,
},
ElGamal {
p: MPI,
g: MPI,
y: MPI,
},
EdDSA {
curve: Curve,
q: MPI,
},
ECDSA {
curve: Curve,
q: MPI,
},
ECDH {
curve: Curve,
q: MPI,
hash: HashAlgorithm,
sym: SymmetricAlgorithm,
},
Unknown {
mpis: Box<[MPI]>,
rest: Box<[u8]>,
},
#[doc(hidden)] __Nonexhaustive,
}
impl PublicKey {
pub fn bits(&self) -> Option<usize> {
use self::PublicKey::*;
match self {
&RSA { ref n,.. } => Some(n.bits()),
&DSA { ref p,.. } => Some(p.bits()),
&ElGamal { ref p,.. } => Some(p.bits()),
&EdDSA { ref curve,.. } => curve.bits(),
&ECDSA { ref curve,.. } => curve.bits(),
&ECDH { ref curve,.. } => curve.bits(),
&Unknown { .. } => None,
__Nonexhaustive => unreachable!(),
}
}
pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
use self::PublicKey::*;
match self {
RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
DSA { .. } => Some(PublicKeyAlgorithm::DSA),
ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
Unknown { .. } => None,
__Nonexhaustive => unreachable!(),
}
}
}
impl Hash for PublicKey {
fn hash(&self, hash: &mut hash::Context) {
self.serialize(hash).expect("hashing does not fail")
}
}
#[cfg(any(test, feature = "quickcheck"))]
impl Arbitrary for PublicKey {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
use self::PublicKey::*;
match g.gen_range(0, 6) {
0 => RSA {
e: MPI::arbitrary(g),
n: MPI::arbitrary(g),
},
1 => DSA {
p: MPI::arbitrary(g),
q: MPI::arbitrary(g),
g: MPI::arbitrary(g),
y: MPI::arbitrary(g),
},
2 => ElGamal {
p: MPI::arbitrary(g),
g: MPI::arbitrary(g),
y: MPI::arbitrary(g),
},
3 => EdDSA {
curve: Curve::arbitrary(g),
q: MPI::arbitrary(g),
},
4 => ECDSA {
curve: Curve::arbitrary(g),
q: MPI::arbitrary(g),
},
5 => ECDH {
curve: Curve::arbitrary(g),
q: MPI::arbitrary(g),
hash: HashAlgorithm::arbitrary(g),
sym: SymmetricAlgorithm::arbitrary(g),
},
_ => unreachable!(),
}
}
}
#[derive(Clone, Hash)]
pub enum SecretKeyMaterial {
RSA {
d: ProtectedMPI,
p: ProtectedMPI,
q: ProtectedMPI,
u: ProtectedMPI,
},
DSA {
x: ProtectedMPI,
},
ElGamal {
x: ProtectedMPI,
},
EdDSA {
scalar: ProtectedMPI,
},
ECDSA {
scalar: ProtectedMPI,
},
ECDH {
scalar: ProtectedMPI,
},
Unknown {
mpis: Box<[ProtectedMPI]>,
rest: Protected,
},
#[doc(hidden)] __Nonexhaustive,
}
impl fmt::Debug for SecretKeyMaterial {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if cfg!(debug_assertions) {
match self {
&SecretKeyMaterial::RSA{ ref d, ref p, ref q, ref u } =>
write!(f, "RSA {{ d: {:?}, p: {:?}, q: {:?}, u: {:?} }}", d, p, q, u),
&SecretKeyMaterial::DSA{ ref x } =>
write!(f, "DSA {{ x: {:?} }}", x),
&SecretKeyMaterial::ElGamal{ ref x } =>
write!(f, "ElGamal {{ x: {:?} }}", x),
&SecretKeyMaterial::EdDSA{ ref scalar } =>
write!(f, "EdDSA {{ scalar: {:?} }}", scalar),
&SecretKeyMaterial::ECDSA{ ref scalar } =>
write!(f, "ECDSA {{ scalar: {:?} }}", scalar),
&SecretKeyMaterial::ECDH{ ref scalar } =>
write!(f, "ECDH {{ scalar: {:?} }}", scalar),
&SecretKeyMaterial::Unknown{ ref mpis, ref rest } =>
write!(f, "Unknown {{ mips: {:?}, rest: {:?} }}", mpis, rest),
SecretKeyMaterial::__Nonexhaustive => unreachable!(),
}
} else {
match self {
&SecretKeyMaterial::RSA{ .. } =>
f.write_str("RSA { <Redacted> }"),
&SecretKeyMaterial::DSA{ .. } =>
f.write_str("DSA { <Redacted> }"),
&SecretKeyMaterial::ElGamal{ .. } =>
f.write_str("ElGamal { <Redacted> }"),
&SecretKeyMaterial::EdDSA{ .. } =>
f.write_str("EdDSA { <Redacted> }"),
&SecretKeyMaterial::ECDSA{ .. } =>
f.write_str("ECDSA { <Redacted> }"),
&SecretKeyMaterial::ECDH{ .. } =>
f.write_str("ECDH { <Redacted> }"),
&SecretKeyMaterial::Unknown{ .. } =>
f.write_str("Unknown { <Redacted> }"),
SecretKeyMaterial::__Nonexhaustive => unreachable!(),
}
}
}
}
impl PartialOrd for SecretKeyMaterial {
fn partial_cmp(&self, other: &SecretKeyMaterial) -> Option<Ordering> {
use std::iter;
fn discriminant(sk: &SecretKeyMaterial) -> usize {
match sk {
&SecretKeyMaterial::RSA{ .. } => 0,
&SecretKeyMaterial::DSA{ .. } => 1,
&SecretKeyMaterial::ElGamal{ .. } => 2,
&SecretKeyMaterial::EdDSA{ .. } => 3,
&SecretKeyMaterial::ECDSA{ .. } => 4,
&SecretKeyMaterial::ECDH{ .. } => 5,
&SecretKeyMaterial::Unknown{ .. } => 6,
SecretKeyMaterial::__Nonexhaustive => unreachable!(),
}
}
let ret = match (self, other) {
(&SecretKeyMaterial::RSA{ d: ref d1, p: ref p1, q: ref q1, u: ref u1 }
,&SecretKeyMaterial::RSA{ d: ref d2, p: ref p2, q: ref q2, u: ref u2 }) => {
let o1 = d1.cmp(d2);
let o2 = p1.cmp(p2);
let o3 = q1.cmp(q2);
let o4 = u1.cmp(u2);
if o1 != Ordering::Equal { return Some(o1); }
if o2 != Ordering::Equal { return Some(o2); }
if o3 != Ordering::Equal { return Some(o3); }
o4
}
(&SecretKeyMaterial::DSA{ x: ref x1 }
,&SecretKeyMaterial::DSA{ x: ref x2 }) => {
x1.cmp(x2)
}
(&SecretKeyMaterial::ElGamal{ x: ref x1 }
,&SecretKeyMaterial::ElGamal{ x: ref x2 }) => {
x1.cmp(x2)
}
(&SecretKeyMaterial::EdDSA{ scalar: ref scalar1 }
,&SecretKeyMaterial::EdDSA{ scalar: ref scalar2 }) => {
scalar1.cmp(scalar2)
}
(&SecretKeyMaterial::ECDSA{ scalar: ref scalar1 }
,&SecretKeyMaterial::ECDSA{ scalar: ref scalar2 }) => {
scalar1.cmp(scalar2)
}
(&SecretKeyMaterial::ECDH{ scalar: ref scalar1 }
,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => {
scalar1.cmp(scalar2)
}
(&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 }
,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
let o1 = secure_cmp(rest1, rest2);
let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
a.cmp(b)
}).collect::<Vec<_>>();
iter::once(o1)
.chain(on.iter().cloned())
.fold(Ordering::Equal, |acc, x| acc.then(x))
}
(a, b) => {
let ret = discriminant(a).cmp(&discriminant(b));
assert!(ret != Ordering::Equal);
ret
}
};
Some(ret)
}
}
impl Ord for SecretKeyMaterial {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl PartialEq for SecretKeyMaterial {
fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
}
impl Eq for SecretKeyMaterial {}
impl SecretKeyMaterial {
pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
use self::SecretKeyMaterial::*;
match self {
RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
DSA { .. } => Some(PublicKeyAlgorithm::DSA),
ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
Unknown { .. } => None,
__Nonexhaustive => unreachable!(),
}
}
}
impl Hash for SecretKeyMaterial {
fn hash(&self, hash: &mut hash::Context) {
self.serialize(hash).expect("hashing does not fail")
}
}
#[cfg(any(test, feature = "quickcheck"))]
impl Arbitrary for SecretKeyMaterial {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
match g.gen_range(0, 6) {
0 => SecretKeyMaterial::RSA {
d: MPI::arbitrary(g).into(),
p: MPI::arbitrary(g).into(),
q: MPI::arbitrary(g).into(),
u: MPI::arbitrary(g).into(),
},
1 => SecretKeyMaterial::DSA {
x: MPI::arbitrary(g).into(),
},
2 => SecretKeyMaterial::ElGamal {
x: MPI::arbitrary(g).into(),
},
3 => SecretKeyMaterial::EdDSA {
scalar: MPI::arbitrary(g).into(),
},
4 => SecretKeyMaterial::ECDSA {
scalar: MPI::arbitrary(g).into(),
},
5 => SecretKeyMaterial::ECDH {
scalar: MPI::arbitrary(g).into(),
},
_ => unreachable!(),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub enum Ciphertext {
RSA {
c: MPI,
},
ElGamal {
e: MPI,
c: MPI,
},
ECDH {
e: MPI,
key: Box<[u8]>,
},
Unknown {
mpis: Box<[MPI]>,
rest: Box<[u8]>,
},
#[doc(hidden)] __Nonexhaustive,
}
impl Ciphertext {
pub fn pk_algo(&self) -> Option<PublicKeyAlgorithm> {
use self::Ciphertext::*;
match self {
&RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
&ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
&ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
&Unknown { .. } => None,
__Nonexhaustive => unreachable!(),
}
}
}
impl Hash for Ciphertext {
fn hash(&self, hash: &mut hash::Context) {
self.serialize(hash).expect("hashing does not fail")
}
}
#[cfg(any(test, feature = "quickcheck"))]
impl Arbitrary for Ciphertext {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
match g.gen_range(0, 3) {
0 => Ciphertext::RSA {
c: MPI::arbitrary(g),
},
1 => Ciphertext::ElGamal {
e: MPI::arbitrary(g),
c: MPI::arbitrary(g)
},
2 => Ciphertext::ECDH {
e: MPI::arbitrary(g),
key: {
let mut k = <Vec<u8>>::arbitrary(g);
k.truncate(255);
k.into_boxed_slice()
},
},
_ => unreachable!(),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub enum Signature {
RSA {
s: MPI,
},
DSA {
r: MPI,
s: MPI,
},
ElGamal {
r: MPI,
s: MPI,
},
EdDSA {
r: MPI,
s: MPI,
},
ECDSA {
r: MPI,
s: MPI,
},
Unknown {
mpis: Box<[MPI]>,
rest: Box<[u8]>,
},
#[doc(hidden)] __Nonexhaustive,
}
impl Hash for Signature {
fn hash(&self, hash: &mut hash::Context) {
self.serialize(hash).expect("hashing does not fail")
}
}
#[cfg(any(test, feature = "quickcheck"))]
impl Arbitrary for Signature {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
match g.gen_range(0, 4) {
0 => Signature::RSA {
s: MPI::arbitrary(g),
},
1 => Signature::DSA {
r: MPI::arbitrary(g),
s: MPI::arbitrary(g),
},
2 => Signature::EdDSA {
r: MPI::arbitrary(g),
s: MPI::arbitrary(g),
},
3 => Signature::ECDSA {
r: MPI::arbitrary(g),
s: MPI::arbitrary(g),
},
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse::Parse;
quickcheck! {
fn mpi_roundtrip(mpi: MPI) -> bool {
let mut buf = Vec::new();
mpi.serialize(&mut buf).unwrap();
MPI::from_bytes(&buf).unwrap() == mpi
}
}
quickcheck! {
fn pk_roundtrip(pk: PublicKey) -> bool {
use std::io::Cursor;
use crate::PublicKeyAlgorithm::*;
let buf = Vec::<u8>::default();
let mut cur = Cursor::new(buf);
pk.serialize(&mut cur).unwrap();
#[allow(deprecated)]
let pk_ = match &pk {
PublicKey::RSA { .. } =>
PublicKey::parse(
RSAEncryptSign, cur.into_inner()).unwrap(),
PublicKey::DSA { .. } =>
PublicKey::parse(
DSA, cur.into_inner()).unwrap(),
PublicKey::ElGamal { .. } =>
PublicKey::parse(
ElGamalEncrypt, cur.into_inner()).unwrap(),
PublicKey::EdDSA { .. } =>
PublicKey::parse(
EdDSA, cur.into_inner()).unwrap(),
PublicKey::ECDSA { .. } =>
PublicKey::parse(
ECDSA, cur.into_inner()).unwrap(),
PublicKey::ECDH { .. } =>
PublicKey::parse(
ECDH, cur.into_inner()).unwrap(),
PublicKey::Unknown { .. } => unreachable!(),
PublicKey::__Nonexhaustive => unreachable!(),
};
pk == pk_
}
}
#[test]
fn pk_bits() {
for (name, key_no, bits) in &[
("testy.pgp", 0, 2048),
("testy-new.pgp", 1, 256),
("dennis-simon-anton.pgp", 0, 2048),
("dsa2048-elgamal3072.pgp", 1, 3072),
("emmelie-dorothea-dina-samantha-awina-ed25519.pgp", 0, 256),
("erika-corinna-daniela-simone-antonia-nistp256.pgp", 0, 256),
("erika-corinna-daniela-simone-antonia-nistp384.pgp", 0, 384),
("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521),
] {
let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap();
let ka = cert.keys().nth(*key_no).unwrap();
assert_eq!(ka.key().mpis().bits().unwrap(), *bits,
"Cert {}, key no {}", name, *key_no);
}
}
quickcheck! {
fn sk_roundtrip(sk: SecretKeyMaterial) -> bool {
use std::io::Cursor;
use crate::PublicKeyAlgorithm::*;
let buf = Vec::<u8>::default();
let mut cur = Cursor::new(buf);
sk.serialize(&mut cur).unwrap();
#[allow(deprecated)]
let sk_ = match &sk {
SecretKeyMaterial::RSA { .. } =>
SecretKeyMaterial::parse(
RSAEncryptSign, cur.into_inner()).unwrap(),
SecretKeyMaterial::DSA { .. } =>
SecretKeyMaterial::parse(
DSA, cur.into_inner()).unwrap(),
SecretKeyMaterial::EdDSA { .. } =>
SecretKeyMaterial::parse(
EdDSA, cur.into_inner()).unwrap(),
SecretKeyMaterial::ECDSA { .. } =>
SecretKeyMaterial::parse(
ECDSA, cur.into_inner()).unwrap(),
SecretKeyMaterial::ECDH { .. } =>
SecretKeyMaterial::parse(
ECDH, cur.into_inner()).unwrap(),
SecretKeyMaterial::ElGamal { .. } =>
SecretKeyMaterial::parse(
ElGamalEncrypt, cur.into_inner()).unwrap(),
SecretKeyMaterial::Unknown { .. } => unreachable!(),
SecretKeyMaterial::__Nonexhaustive => unreachable!(),
};
sk == sk_
}
}
quickcheck! {
fn ct_roundtrip(ct: Ciphertext) -> bool {
use std::io::Cursor;
use crate::PublicKeyAlgorithm::*;
let buf = Vec::<u8>::default();
let mut cur = Cursor::new(buf);
ct.serialize(&mut cur).unwrap();
#[allow(deprecated)]
let ct_ = match &ct {
Ciphertext::RSA { .. } =>
Ciphertext::parse(
RSAEncryptSign, cur.into_inner()).unwrap(),
Ciphertext::ElGamal { .. } =>
Ciphertext::parse(
ElGamalEncrypt, cur.into_inner()).unwrap(),
Ciphertext::ECDH { .. } =>
Ciphertext::parse(
ECDH, cur.into_inner()).unwrap(),
Ciphertext::Unknown { .. } => unreachable!(),
Ciphertext::__Nonexhaustive => unreachable!(),
};
ct == ct_
}
}
quickcheck! {
fn signature_roundtrip(sig: Signature) -> bool {
use std::io::Cursor;
use crate::PublicKeyAlgorithm::*;
let buf = Vec::<u8>::default();
let mut cur = Cursor::new(buf);
sig.serialize(&mut cur).unwrap();
#[allow(deprecated)]
let sig_ = match &sig {
Signature::RSA { .. } =>
Signature::parse(
RSAEncryptSign, cur.into_inner()).unwrap(),
Signature::DSA { .. } =>
Signature::parse(
DSA, cur.into_inner()).unwrap(),
Signature::ElGamal { .. } =>
Signature::parse(
ElGamalEncryptSign, cur.into_inner()).unwrap(),
Signature::EdDSA { .. } =>
Signature::parse(
EdDSA, cur.into_inner()).unwrap(),
Signature::ECDSA { .. } =>
Signature::parse(
ECDSA, cur.into_inner()).unwrap(),
Signature::Unknown { .. } => unreachable!(),
Signature::__Nonexhaustive => unreachable!(),
};
sig == sig_
}
}
}