use std::time;
use crate::packet;
use crate::packet::{
key,
Key,
key::Key4,
};
use crate::Result;
use crate::packet::Signature;
use crate::packet::signature;
use crate::Cert;
use crate::cert::CertRevocationBuilder;
use crate::Error;
use crate::crypto::Password;
use crate::autocrypt::Autocrypt;
use crate::types::{
Features,
HashAlgorithm,
KeyFlags,
SignatureType,
SymmetricAlgorithm,
};
/// Groups symmetric and asymmetric algorithms
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)]
pub enum CipherSuite {
/// EdDSA and ECDH over Curve25519 with SHA512 and AES256
Cv25519,
/// 3072 bit RSA with SHA512 and AES256
RSA3k,
/// EdDSA and ECDH over NIST P-256 with SHA256 and AES256
P256,
/// EdDSA and ECDH over NIST P-384 with SHA384 and AES256
P384,
/// EdDSA and ECDH over NIST P-521 with SHA512 and AES256
P521,
/// 2048 bit RSA with SHA512 and AES256
RSA2k,
/// 4096 bit RSA with SHA512 and AES256
RSA4k,
}
impl Default for CipherSuite {
fn default() -> Self {
CipherSuite::Cv25519
}
}
impl CipherSuite {
fn generate_key<R>(self, flags: &KeyFlags)
-> Result<Key<key::SecretParts, R>>
where R: key::KeyRole
{
use crate::types::Curve;
match self {
CipherSuite::RSA2k =>
Key4::generate_rsa(2048),
CipherSuite::RSA3k =>
Key4::generate_rsa(3072),
CipherSuite::RSA4k =>
Key4::generate_rsa(4096),
CipherSuite::Cv25519 | CipherSuite::P256 |
CipherSuite::P384 | CipherSuite::P521 => {
let sign = flags.for_certification() || flags.for_signing()
|| flags.for_authentication();
let encrypt = flags.for_transport_encryption()
|| flags.for_storage_encryption();
let curve = match self {
CipherSuite::Cv25519 if sign => Curve::Ed25519,
CipherSuite::Cv25519 if encrypt => Curve::Cv25519,
CipherSuite::Cv25519 => {
return Err(Error::InvalidOperation(
"No key flags set".into())
.into());
}
CipherSuite::P256 => Curve::NistP256,
CipherSuite::P384 => Curve::NistP384,
CipherSuite::P521 => Curve::NistP521,
_ => unreachable!(),
};
match (sign, encrypt) {
(true, false) => Key4::generate_ecc(true, curve),
(false, true) => Key4::generate_ecc(false, curve),
(true, true) =>
Err(Error::InvalidOperation(
"Can't use key for encryption and signing".into())
.into()),
(false, false) =>
Err(Error::InvalidOperation(
"No key flags set".into())
.into()),
}
},
}.map(|key| key.into())
}
}
#[derive(Clone, Debug)]
pub struct KeyBlueprint {
flags: KeyFlags,
expiration: Option<time::Duration>,
}
/// Simplifies generation of Keys.
///
/// Builder to generate complex Cert hierarchies with multiple user IDs.
#[derive(Clone, Debug)]
pub struct CertBuilder {
creation_time: Option<std::time::SystemTime>,
ciphersuite: CipherSuite,
primary: KeyBlueprint,
subkeys: Vec<KeyBlueprint>,
userids: Vec<packet::UserID>,
user_attributes: Vec<packet::UserAttribute>,
password: Option<Password>,
}
impl CertBuilder {
/// Returns a new CertBuilder.
///
/// The returned CertBuilder is setup to only create a
/// certification-capable primary key using the default cipher
/// suite. You'll almost certainly want to add subkeys (using
/// `CertBuilder::add_signing_subkey`, or
/// `CertBuilder::add_transport_encryption_subkey`, for instance), and user
/// ids (using `CertBuilder::add_userid`).
pub fn new() -> Self {
CertBuilder{
creation_time: None,
ciphersuite: CipherSuite::default(),
primary: KeyBlueprint{
flags: KeyFlags::default().set_certification(true),
expiration: None