Skip to content

Commit 7a06690

Browse files
committed
feat(gpg): add post-quantum and hybrid key algos
* Adds SLH-DSA and additional EdDSA options for key generation where supported by the active engine * Introduces hybrid primary signing algorithms and exposes them in the supported-algorithm list when version checks pass * Keeps hybrid subkey behavior aligned by relaxing the comment to match the shared support-gating logic
1 parent 2d8dacc commit 7a06690

2 files changed

Lines changed: 144 additions & 1 deletion

File tree

src/core/model/GpgKeyGenerateInfo.cpp

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,62 @@ const QContainer<KeyAlgo> KeyGenerateInfo::kPrimaryKeyAlgos = {
180180
kSIGN | kAUTH | kCERT,
181181
{{OpenPGPEngine::kGNUPG, "2.3.0"}, {OpenPGPEngine::kRPGP, "0.1.0"}},
182182
},
183+
184+
{
185+
"slhdsashake128s",
186+
"SLH-DSA-SHAKE-128S",
187+
"SLH-DSA",
188+
128,
189+
kSIGN | kAUTH,
190+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
191+
},
192+
{
193+
"slhdsashake128f",
194+
"SLH-DSA-SHAKE-128F",
195+
"SLH-DSA",
196+
128,
197+
kSIGN | kAUTH,
198+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
199+
},
200+
{
201+
"slhdsashake256s",
202+
"SLH-DSA-SHAKE-256S",
203+
"SLH-DSA",
204+
256,
205+
kSIGN | kAUTH,
206+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
207+
},
208+
};
209+
210+
const QContainer<KeyAlgo> KeyGenerateInfo::kHybridPrimaryKeyAlgo = {
211+
{"mldsa65",
212+
"MLD-DSA-65",
213+
"HYBRID-SIGN",
214+
65,
215+
kSIGN | kAUTH,
216+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
217+
{
218+
{
219+
kPrimaryKeyAlgos[8], // ed25519
220+
{
221+
{OpenPGPEngine::kRPGP, "0.1.2"},
222+
},
223+
},
224+
}},
225+
{"mldsa87",
226+
"MLD-DSA-87",
227+
"HYBRID-SIGN",
228+
87,
229+
kSIGN | kAUTH,
230+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
231+
{
232+
{
233+
kPrimaryKeyAlgos[15], // ed448
234+
{
235+
{OpenPGPEngine::kRPGP, "0.1.2"},
236+
},
237+
},
238+
}},
183239
};
184240

185241
const QContainer<KeyAlgo> KeyGenerateInfo::kSubKeyAlgos = {
@@ -358,6 +414,41 @@ const QContainer<KeyAlgo> KeyGenerateInfo::kSubKeyAlgos = {
358414
kENCRYPT,
359415
{{OpenPGPEngine::kGNUPG, "2.2.0"}},
360416
},
417+
418+
{
419+
"ed448",
420+
"ED448",
421+
"EdDSA",
422+
448,
423+
kSIGN | kAUTH,
424+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
425+
},
426+
427+
{
428+
"slhdsashake128s",
429+
"SLH-DSA-SHAKE-128S",
430+
"SLH-DSA",
431+
128,
432+
kSIGN | kAUTH,
433+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
434+
},
435+
{
436+
"slhdsashake128f",
437+
"SLH-DSA-SHAKE-128F",
438+
"SLH-DSA",
439+
128,
440+
kSIGN | kAUTH,
441+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
442+
},
443+
{
444+
"slhdsashake256s",
445+
"SLH-DSA-SHAKE-256S",
446+
"SLH-DSA",
447+
256,
448+
kSIGN | kAUTH,
449+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
450+
},
451+
361452
};
362453

363454
// Refer: https://lists.gnupg.org/pipermail/gnupg-devel/2024-May/035537.html
@@ -474,6 +565,34 @@ const QContainer<KeyAlgo> KeyGenerateInfo::kHybridSubKeyAlgos = {
474565
},
475566
},
476567
}},
568+
{"mldsa65",
569+
"MLD-DSA-65",
570+
"HYBRID-SIGN",
571+
65,
572+
kSIGN | kAUTH,
573+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
574+
{
575+
{
576+
kSubKeyAlgos[8], // ed25519
577+
{
578+
{OpenPGPEngine::kRPGP, "0.1.2"},
579+
},
580+
},
581+
}},
582+
{"mldsa87",
583+
"MLD-DSA-87",
584+
"HYBRID-SIGN",
585+
87,
586+
kSIGN | kAUTH,
587+
{{OpenPGPEngine::kRPGP, "0.1.2"}},
588+
{
589+
{
590+
kSubKeyAlgos[22], // ed448
591+
{
592+
{OpenPGPEngine::kRPGP, "0.1.2"},
593+
},
594+
},
595+
}},
477596
};
478597

479598
auto KeyGenerateInfo::GetSupportedKeyAlgo(int channel) -> QContainer<KeyAlgo> {
@@ -485,6 +604,29 @@ auto KeyGenerateInfo::GetSupportedKeyAlgo(int channel) -> QContainer<KeyAlgo> {
485604
algos.append(algo);
486605
}
487606

607+
// Add hybrid primary key algos if supported since we only have few hybrid
608+
// primary key algos, we can directly add them as a normal algo temperately.
609+
for (const auto &algo : kHybridPrimaryKeyAlgo) {
610+
if (!GpgContextSupportIf(channel, algo.SupportedVersion())) continue;
611+
612+
for (const auto &hybrid_algo : algo.SubAlgos(channel)) {
613+
auto cap_opera = 0;
614+
if (hybrid_algo.CanCert()) cap_opera |= kCERT;
615+
if (hybrid_algo.CanEncrypt()) cap_opera |= kENCRYPT;
616+
if (hybrid_algo.CanSign()) cap_opera |= kSIGN;
617+
if (hybrid_algo.CanAuth()) cap_opera |= kAUTH;
618+
619+
algos.append(KeyAlgo{
620+
algo.Id() + "_" + hybrid_algo.Id(),
621+
algo.Name() + "_" + hybrid_algo.Name(),
622+
"HYBRID",
623+
algo.KeyLength(),
624+
cap_opera,
625+
algo.SupportedVersion(),
626+
});
627+
}
628+
}
629+
488630
std::sort(algos.begin(), algos.end(), [](const KeyAlgo &a, const KeyAlgo &b) {
489631
return a.Name() < b.Name() && a.KeyLength() < b.KeyLength();
490632
});
@@ -502,7 +644,7 @@ auto KeyGenerateInfo::GetSupportedSubkeyAlgo(int channel)
502644
algos.append(algo);
503645
}
504646

505-
// Add hybrid subkey algos if supported by current GPG version
647+
// Add hybrid subkey algos if supported
506648
for (const auto &algo : kHybridSubKeyAlgos) {
507649
if (!GpgContextSupportIf(channel, algo.SupportedVersion())) continue;
508650

src/core/model/GpgKeyGenerateInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class GF_CORE_EXPORT KeyGenerateInfo : public QObject {
8686
public:
8787
static const KeyAlgo kNoneAlgo;
8888
static const QContainer<KeyAlgo> kPrimaryKeyAlgos;
89+
static const QContainer<KeyAlgo> kHybridPrimaryKeyAlgo;
8990
static const QContainer<KeyAlgo> kSubKeyAlgos;
9091
static const QContainer<KeyAlgo> kHybridSubKeyAlgos;
9192

0 commit comments

Comments
 (0)