use std::io::stdout;
use minipgp6_armor::{DataType, write::Armorer};
use minipgp6_packet::{
Serialize,
body::{
secret_key::{SecretKey, SecretKeyMaterial},
signature::{
SignatureType,
Subpacket,
subpacket_data::{
Features,
IssuerFingerprint,
KeyExpirationTime,
KeyFlags,
PreferredAeadCiphersuites,
SignatureCreationTime,
},
},
},
transferable::{SignedComponent, Tsk},
types::{
KeyRole,
algorithm::PublicKeyAlgorithm,
time::{Duration, Timestamp},
},
unlocked::UnlockedSoftwareKey,
};
use minipgp6_sign::component::{sign_direct_key, sign_key_binding};
use rand::thread_rng;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = thread_rng();
let create = Timestamp(1722466800);
let primary = minipgp6_sign::generate_key(
&mut rng,
PublicKeyAlgorithm::Ed25519,
KeyRole::Primary,
create,
)?;
let hashed_area = vec![
Subpacket::regular(SignatureCreationTime(create))?,
Subpacket::regular(KeyExpirationTime(Duration(365 * 24 * 60 * 60)))?,
Subpacket::regular(IssuerFingerprint(primary.public().fingerprint()))?,
Subpacket::regular(KeyFlags(Box::new([0x03])))?,
Subpacket::regular(Features(Box::new([0x08])))?,
Subpacket::regular(PreferredAeadCiphersuites(Box::new([0x07, 0x02])))?,
];
let config = minipgp6_sign::new_signature(
&mut rng,
SignatureType::DirectKey,
PublicKeyAlgorithm::Ed25519,
PublicKeyAlgorithm::Ed25519.hash_algorithm()?,
hashed_area,
Vec::new(),
)?;
let SecretKeyMaterial::Unprotected(plain) = &primary.secret_key_material else {
unreachable!();
};
let signer = UnlockedSoftwareKey::new(plain.clone(), primary.public());
let dks = sign_direct_key(config, &signer, primary.public())?;
let subkey = minipgp6_encrypt::generate_key(
&mut rng,
PublicKeyAlgorithm::X25519,
create,
KeyRole::Subkey,
)?;
let hashed_area = vec![
Subpacket::regular(SignatureCreationTime(create))?,
Subpacket::regular(KeyExpirationTime(Duration(365 * 24 * 60 * 60)))?,
Subpacket::regular(IssuerFingerprint(primary.public().fingerprint()))?,
Subpacket::regular(KeyFlags(Box::new([0x04 | 0x08])))?, ];
let primary_pk = primary.public().public_key_algorithm();
let config = minipgp6_sign::new_signature(
&mut rng,
SignatureType::SubkeyBinding,
primary_pk,
primary_pk.hash_algorithm()?,
hashed_area,
Vec::new(),
)?;
let binding = sign_key_binding(config, &signer, primary.public(), subkey.public())?;
let sk = SignedComponent::<SecretKey> {
component: subkey,
revocations: Vec::new(),
signatures: vec![binding],
};
let tsk = Tsk {
primary: SignedComponent::<SecretKey> {
component: primary,
revocations: Vec::new(),
signatures: vec![dks],
},
subkeys: vec![sk],
user_ids: Vec::new(),
};
let mut out = Armorer::new(stdout(), DataType::Private)?;
tsk.to_writer(&mut out)?;
out.finalize()?;
Ok(())
}