use {
pgp::{
crypto::{hash::HashAlgorithm, sym::SymmetricKeyAlgorithm},
types::{CompressionAlgorithm, SecretKeyTrait},
Deserializable, KeyType, SecretKeyParams, SecretKeyParamsBuilder, SignedPublicKey,
SignedSecretKey,
},
smallvec::smallvec,
std::io::Cursor,
strum::EnumIter,
};
pub const DEBIAN_8_RELEASE_KEY: &str = include_str!("keys/debian-8-release.asc");
pub const DEBIAN_8_ARCHIVE_KEY: &str = include_str!("keys/debian-8-archive.asc");
pub const DEBIAN_8_SECURITY_ARCHIVE_KEY: &str = include_str!("keys/debian-8-security.asc");
pub const DEBIAN_9_RELEASE_KEY: &str = include_str!("keys/debian-9-release.asc");
pub const DEBIAN_9_ARCHIVE_KEY: &str = include_str!("keys/debian-9-archive.asc");
pub const DEBIAN_9_SECURITY_ARCHIVE_KEY: &str = include_str!("keys/debian-9-security.asc");
pub const DEBIAN_10_RELEASE_KEY: &str = include_str!("keys/debian-10-release.asc");
pub const DEBIAN_10_ARCHIVE_KEY: &str = include_str!("keys/debian-10-archive.asc");
pub const DEBIAN_10_SECURITY_ARCHIVE_KEY: &str = include_str!("keys/debian-10-security.asc");
pub const DEBIAN_11_RELEASE_KEY: &str = include_str!("keys/debian-11-release.asc");
pub const DEBIAN_11_ARCHIVE_KEY: &str = include_str!("keys/debian-11-archive.asc");
pub const DEBIAN_11_SECURITY_ARCHIVE_KEY: &str = include_str!("keys/debian-11-security.asc");
#[derive(Clone, Copy, Debug, EnumIter)]
pub enum DistroSigningKey {
Debian8Release,
Debian8Archive,
Debian8SecurityArchive,
Debian9Release,
Debian9Archive,
Debian9SecurityArchive,
Debian10Release,
Debian10Archive,
Debian10SecurityArchive,
Debian11Release,
Debian11Archive,
Debian11SecurityArchive,
}
impl DistroSigningKey {
pub fn armored_public_key(&self) -> &'static str {
match self {
Self::Debian8Release => DEBIAN_8_RELEASE_KEY,
Self::Debian8Archive => DEBIAN_8_ARCHIVE_KEY,
Self::Debian8SecurityArchive => DEBIAN_8_SECURITY_ARCHIVE_KEY,
Self::Debian9Release => DEBIAN_9_RELEASE_KEY,
Self::Debian9Archive => DEBIAN_9_ARCHIVE_KEY,
Self::Debian9SecurityArchive => DEBIAN_9_SECURITY_ARCHIVE_KEY,
Self::Debian10Release => DEBIAN_10_RELEASE_KEY,
Self::Debian10Archive => DEBIAN_10_ARCHIVE_KEY,
Self::Debian10SecurityArchive => DEBIAN_10_SECURITY_ARCHIVE_KEY,
Self::Debian11Release => DEBIAN_11_RELEASE_KEY,
Self::Debian11Archive => DEBIAN_11_ARCHIVE_KEY,
Self::Debian11SecurityArchive => DEBIAN_11_SECURITY_ARCHIVE_KEY,
}
}
pub fn public_key(&self) -> SignedPublicKey {
SignedPublicKey::from_armor_single(Cursor::new(self.armored_public_key().as_bytes()))
.expect("built-in signing keys should parse")
.0
}
}
pub fn signing_secret_key_params_builder(primary_user_id: impl ToString) -> SecretKeyParamsBuilder {
let mut key_params = SecretKeyParamsBuilder::default();
key_params
.key_type(KeyType::Rsa(2048))
.preferred_symmetric_algorithms(smallvec![SymmetricKeyAlgorithm::AES256])
.preferred_hash_algorithms(smallvec![
HashAlgorithm::SHA2_256,
HashAlgorithm::SHA2_384,
HashAlgorithm::SHA2_512
])
.preferred_compression_algorithms(smallvec![CompressionAlgorithm::ZLIB])
.can_sign(true)
.primary_user_id(primary_user_id.to_string());
key_params
}
pub fn create_self_signed_key<PW>(
params: SecretKeyParams,
key_passphrase: PW,
) -> pgp::errors::Result<(SignedSecretKey, SignedPublicKey)>
where
PW: (FnOnce() -> String) + Clone,
{
let mut rng = rand::thread_rng();
let secret_key = params.generate(&mut rng)?;
let secret_key_signed = secret_key.sign(&mut rng, key_passphrase.clone())?;
let public_key = secret_key_signed.public_key();
let public_key_signed = public_key.sign(&mut rng, &secret_key_signed, key_passphrase)?;
Ok((secret_key_signed, public_key_signed))
}
#[cfg(test)]
mod test {
use {super::*, strum::IntoEnumIterator};
#[test]
fn all_distro_signing_keys() {
for key in DistroSigningKey::iter() {
key.public_key();
}
}
#[test]
fn key_creation() -> pgp::errors::Result<()> {
let builder = signing_secret_key_params_builder("Me <someone@example.com>");
let params = builder.build().unwrap();
let (private, public) = create_self_signed_key(params, || "passphrase".to_string())?;
assert!(private
.to_armored_string(Default::default())?
.starts_with("-----BEGIN PGP PRIVATE KEY BLOCK-----"));
assert!(public
.to_armored_string(Default::default())?
.starts_with("-----BEGIN PGP PUBLIC KEY BLOCK-----"));
Ok(())
}
}