Skip to content

implement detached signature generation for pk_calc_signature #6727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 2, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions src/pgp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ use std::collections::{BTreeMap, HashSet};
use std::io::{BufRead, Cursor};

use anyhow::{Context as _, Result};
use chrono::SubsecRound;
use deltachat_contact_tools::EmailAddress;
use pgp::armor::BlockType;
use pgp::composed::{
Deserializable, KeyType as PgpKeyType, Message, MessageBuilder, SecretKeyParamsBuilder,
SignedPublicKey, SignedPublicSubKey, SignedSecretKey, StandaloneSignature, SubkeyParamsBuilder,
TheRing,
ArmorOptions, Deserializable, KeyType as PgpKeyType, Message, MessageBuilder,
SecretKeyParamsBuilder, SignedPublicKey, SignedPublicSubKey, SignedSecretKey,
StandaloneSignature, SubkeyParamsBuilder, TheRing,
};
use pgp::crypto::ecc_curve::ECCCurve;
use pgp::crypto::hash::HashAlgorithm;
use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::packet::{SignatureConfig, SignatureType, Subpacket, SubpacketData};
use pgp::types::{
CompressionAlgorithm, KeyDetails, Password, PublicKeyTrait, SignatureBytes, StringToKey,
CompressionAlgorithm, KeyDetails, KeyVersion, Password, PublicKeyTrait, SecretKeyTrait,
SignatureBytes, StringToKey,
};
use rand::thread_rng;
use tokio::runtime::Handle;
Expand Down Expand Up @@ -280,21 +283,49 @@ pub async fn pk_encrypt(
.await?
}

/// Signs `plain` text using `private_key_for_signing`.
/// Produces a detached signature for `plain` text using `private_key_for_signing`.
pub fn pk_calc_signature(
plain: Vec<u8>,
private_key_for_signing: &SignedSecretKey,
) -> Result<String> {
let mut rng = thread_rng();
let signature = MessageBuilder::from_bytes("", plain)
.sign(
&**private_key_for_signing,
Password::empty(),
HASH_ALGORITHM,
)
.to_armored_string(&mut rng, Default::default())?;
let rng = thread_rng();

let mut config = match private_key_for_signing.version() {
KeyVersion::V4 => SignatureConfig::v4(
SignatureType::Binary,
private_key_for_signing.algorithm(),
private_key_for_signing.hash_alg(),
),
KeyVersion::V6 => SignatureConfig::v6(
rng,
SignatureType::Binary,
private_key_for_signing.algorithm(),
private_key_for_signing.hash_alg(),
)?,
v => anyhow::bail!("unsupported key version {:?}", v),
};

Ok(signature)
config.hashed_subpackets = vec![
Subpacket::regular(SubpacketData::IssuerFingerprint(
private_key_for_signing.fingerprint(),
))?,
Subpacket::critical(SubpacketData::SignatureCreationTime(
chrono::Utc::now().trunc_subsecs(0),
))?,
];
config.unhashed_subpackets = vec![Subpacket::regular(SubpacketData::Issuer(
private_key_for_signing.key_id(),
))?];

let signature = config.sign(
&private_key_for_signing.primary_key,
&Password::empty(),
plain.as_slice(),
)?;

let sig = StandaloneSignature::new(signature);

Ok(sig.to_armored_string(ArmorOptions::default())?)
}

/// Decrypts the message with keys from the private key keyring.
Expand Down
Loading