Skip to content

Commit ba1305a

Browse files
saturnericCopilot
andcommitted
feat(keys): add ed25519legacy compatibility
* Adds support for the legacy non-standard Ed25519 variant to keep pre-2024 keys usable while steering new keys toward standard Ed25519 * Prevents selecting the legacy variant for subkeys under v6 primary keys to avoid interoperability issues * Extends algorithm detection and key-length extraction to recognize the legacy variant consistently across layers Co-authored-by: Copilot <copilot@github.com>
1 parent db24cb7 commit ba1305a

4 files changed

Lines changed: 42 additions & 24 deletions

File tree

‎rust/src/types.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,14 @@ pub enum GfrKeyAlgo {
109109
DSA1024,
110110
DSA2048,
111111
DSA3072,
112-
KYBER768X25519, // Encryption-only KEM using X25519, with 768-bit security level
113-
KYBER1024X448, // Encryption-only KEM using X448, with 1024-bit security level
112+
// The original non-standard "ED25519-LEGACY" used in early versions of
113+
// GpgFrontend (pre-2024), which is actually a non-compliant variant of
114+
// Ed25519. Only kept for backward compatibility with keys generated by
115+
// those old versions. New keys should use the standard ED25519.
116+
ED25519LEGACY,
117+
// Post-quantum algorithms (non-standard, for experimental use only)
118+
KYBER768X25519,
119+
KYBER1024X448,
114120
}
115121

116122
#[repr(C)]

‎rust/src/utils.rs‎

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ pub fn resolve_key_type(algo: &GfrKeyAlgo, can_encrypt: bool) -> Result<KeyType,
242242
GfrKeyAlgo::DSA2048 => Ok(KeyType::Dsa(DsaKeySize::B2048)),
243243
GfrKeyAlgo::DSA3072 => Ok(KeyType::Dsa(DsaKeySize::B3072)),
244244

245+
GfrKeyAlgo::ED25519LEGACY => Ok(KeyType::Ed25519Legacy),
246+
245247
GfrKeyAlgo::KYBER768X25519 => Ok(KeyType::MlKem768X25519),
246248
GfrKeyAlgo::KYBER1024X448 => Ok(KeyType::MlKem1024X448),
247249

@@ -291,12 +293,34 @@ pub fn determine_algo(public_params: &PublicParams) -> GfrKeyAlgo {
291293
ECCCurve::Secp256k1 => GfrKeyAlgo::SECP256K1,
292294
_ => GfrKeyAlgo::Unknown,
293295
},
296+
PublicParams::EdDSALegacy(_) => GfrKeyAlgo::ED25519LEGACY,
294297
PublicParams::MlKem768X25519(_) => GfrKeyAlgo::KYBER768X25519,
295298
PublicParams::MlKem1024X448(_) => GfrKeyAlgo::KYBER1024X448,
296299
_ => GfrKeyAlgo::Unknown, // Fallback
297300
}
298301
}
299302

303+
pub fn extract_key_length(public_params: &PublicParams) -> Option<u32> {
304+
match public_params {
305+
PublicParams::RSA(p) => Some(p.key.n().bits() as u32),
306+
PublicParams::DSA(p) => Some(p.key.components().p().bits() as u32),
307+
308+
PublicParams::Ed25519(_) => Some(255),
309+
PublicParams::Ed448(_) => Some(448),
310+
PublicParams::X448(_) => Some(448),
311+
312+
PublicParams::ECDH(p) => Some(p.curve().nbits() as u32),
313+
PublicParams::ECDSA(p) => Some(p.curve().nbits() as u32),
314+
315+
PublicParams::EdDSALegacy(_) => Some(255),
316+
317+
PublicParams::MlKem768X25519(_) => Some(768),
318+
PublicParams::MlKem1024X448(_) => Some(1024),
319+
320+
_ => None,
321+
}
322+
}
323+
300324
pub fn check_if_quantum_hybrid_algo(algo: &GfrKeyAlgo) -> bool {
301325
matches!(algo, GfrKeyAlgo::KYBER768X25519 | GfrKeyAlgo::KYBER1024X448)
302326
}
@@ -320,26 +344,6 @@ pub fn check_if_should_use_key_ver_v6(
320344
false
321345
}
322346

323-
pub fn extract_key_length(public_params: &PublicParams) -> Option<u32> {
324-
match public_params {
325-
PublicParams::RSA(p) => Some(p.key.n().bits() as u32),
326-
PublicParams::DSA(p) => Some(p.key.components().p().bits() as u32),
327-
328-
PublicParams::Ed25519(_) => Some(255),
329-
PublicParams::Ed448(_) => Some(448),
330-
PublicParams::X448(_) => Some(448),
331-
332-
PublicParams::ECDH(p) => Some(p.curve().nbits() as u32),
333-
334-
PublicParams::ECDSA(p) => Some(p.curve().nbits() as u32),
335-
336-
PublicParams::MlKem768X25519(_) => Some(768),
337-
PublicParams::MlKem1024X448(_) => Some(1024),
338-
339-
_ => None,
340-
}
341-
}
342-
343347
pub fn is_self_signature_from_primary(sig: &Signature, primary_fpr_bytes: &[u8]) -> bool {
344348
sig.issuer_fingerprint()
345349
.iter()

‎src/core/function/rpgp/KeyGenerate.cpp‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,12 @@ auto FilterKeyAlgoByKeyRpgpImpl(OpenPGPContext& ctx, const GpgKey& key,
230230
}
231231

232232
if (key_ver == 6) {
233-
// For primary keys of version 4, any subkey algorithm is allowed.
233+
// ED25519-LEGACY is not allowed for subkeys of v6 primary keys, because
234+
// it is a non-standard variant of Ed25519 and may cause compatibility
235+
// issues. It is only kept for backward compatibility with old keys, but
236+
// should not be used for new key generation.
237+
if (algo_id == "ed25519legacy") continue;
234238
filtered_algos.append(algo);
235-
continue;
236239
}
237240

238241
if (algo_id == "ky768" || algo_id == "kyber768" || algo_id == "ky024" ||
@@ -241,6 +244,8 @@ auto FilterKeyAlgoByKeyRpgpImpl(OpenPGPContext& ctx, const GpgKey& key,
241244
continue;
242245
}
243246

247+
// For other algorithms, there is no specific limitation based on primary
248+
// key version
244249
filtered_algos.append(algo);
245250
}
246251

‎src/core/utils/RustUtils.cpp‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ auto KeyAlgoId2GfrKeyAlgo(const QString& algo_id) -> Rust::GfrKeyAlgo {
6565
if (algo_id == "dsa2048") return Rust::GfrKeyAlgo::DSA2048;
6666
if (algo_id == "dsa3072") return Rust::GfrKeyAlgo::DSA3072;
6767
if (algo_id == "dsa") return Rust::GfrKeyAlgo::DSA2048;
68+
if (algo_id == "ed25519legacy") return Rust::GfrKeyAlgo::ED25519LEGACY;
6869
if (algo_id == "kyber768_cv25519") return Rust::GfrKeyAlgo::KYBER768X25519;
6970
if (algo_id == "kyber1024_x448") return Rust::GfrKeyAlgo::KYBER1024X448;
7071
if (algo_id == "ky768_cv25519") return Rust::GfrKeyAlgo::KYBER768X25519;
@@ -110,6 +111,8 @@ auto GF_CORE_EXPORT GfrKeyAlgo2KeyAlgoName(Rust::GfrKeyAlgo algo) -> QString {
110111
return "DSA 2048";
111112
case Rust::GfrKeyAlgo::DSA3072:
112113
return "DSA 3072";
114+
case Rust::GfrKeyAlgo::ED25519LEGACY:
115+
return "ED25519";
113116
case Rust::GfrKeyAlgo::KYBER768X25519:
114117
return "Kyber768_X25519";
115118
case Rust::GfrKeyAlgo::KYBER1024X448:

0 commit comments

Comments
 (0)