Choisir un algorithme de signature pour vos clés de licence : Ed25519, ECDSA et RSA comparés
Une clé de licence est une charge utile signée, et l'algorithme de signature que vous choisissez n'est pas un détail interchangeable — il décide de la longueur de la clé que votre client doit taper, de la vitesse à laquelle chaque lancement la vérifie, et du risque qu'une seule erreur dans votre code d'émission fasse fuiter la clé privée. Les signatures RSA-2048 font 256 octets, ce qui transforme une clé tapable en un mur de base32 ; ECDSA P-256 en fait le tiers mais porte un nonce qui, réutilisé, livre votre clé à un attaquant ; Ed25519 fait 64 octets, est déterministe et n'a aucun nonce à rater. Cet article pèse les trois sur les axes qui comptent vraiment pour une licence hors ligne — taille de la signature et de la clé publique, coût de vérification au démarrage à froid, déterminisme et modes de défaillance, et à quoi ressemble chacun dans System.Security.Cryptography — et explique pourquoi Keyright signe avec Ed25519 par défaut.
Une clé de licence Keyright n’est ni un mot de passe ni un jeton aléatoire. C’est un court document — le client, le niveau, le nombre de sièges, l’expiration — enveloppé dans une signature numérique que votre application vérifie hors ligne contre une clé publique qu’elle embarque. La signature est toute l’histoire de la sécurité : c’est pour cela qu’un client ne peut pas remplacer « Standard » par « Pro » dans une clé et la faire valider quand même, et que personne ne peut fabriquer une clé que vous n’avez pas émise.
Ce qui soulève une question qui ressemble à un détail d’implémentation et n’en est pas un : quel algorithme de signature ? La réponse honnête est que ce choix se propage à trois choses que vos clients et votre équipe de support ressentent directement — la longueur de la clé, la vitesse à laquelle chaque lancement la vérifie, et la gravité des dégâts qu’un seul bug dans votre code d’émission peut causer. Cet article pèse les trois options réalistes — RSA, ECDSA et Ed25519 — exactement sur ces axes, et explique pourquoi Keyright signe avec Ed25519 par défaut.
Ce qui finit réellement dans la clé
Partez de la forme de la clé, car c’est là que l’argument de taille atterrit. Une clé de licence est la charge utile canonique plus une signature sur celle-ci, encodée en caractères qu’un humain peut taper :
key = base32( canonical_payload_bytes || signature_bytes )
La charge utile est petite et à peu près fixe — quelques dizaines d’octets de revendications. La signature est la variable, et pour la plupart des algorithmes c’est le plus gros élément de la clé. Donc, en première approximation, la longueur brute en octets d’une signature est la longueur de votre clé. C’est la lentille à travers laquelle lire la section suivante : chaque octet de signature devient environ 1,6 caractère base32 que votre client doit taper ou coller sans faute de frappe.
RSA : ça marche, et c’est la mauvaise forme pour une clé
RSA est l’algorithme vers lequel tout le monde se tourne d’abord, parce que c’est celui qu’on a appris. Pour signer des licences, il est défendable et c’est aussi le moins bien adapté des trois.
Le problème de taille est immédiat. Une signature RSA-2048 fait exactement 256 octets — la taille du modulus — quelle que soit la petitesse de votre charge utile. Encodez cela en base32 et vous avez ajouté environ 410 caractères à la clé avant les revendications. Une clé aussi longue n’est pas quelque chose qu’un client tape ; c’est quelque chose qu’il colle, et si elle doit un jour être lue à voix haute, imprimée sur une carte ou saisie sur un appareil sans presse-papiers, vous avez déjà perdu. Pousser RSA jusqu’au niveau de sécurité de 128 bits qu’atteignent les options à courbe elliptique signifie RSA-3072, dont la signature fait 384 octets, ce qui ne fait qu’empirer la clé.
RSA a bien une vraie force qu’il faut nommer honnêtement : la vérification est rapide, parce qu’elle utilise un minuscule exposant public (65537), donc la vérification côté client — l’opération qui se produit à chaque lancement — est bon marché. Mais ECDSA et Ed25519 vérifient aussi bien en dessous de la milliseconde, donc cet avantage ne vous achète rien qu’un utilisateur puisse percevoir, et il vient attaché à une signature quatre fois plus grosse.
En .NET, le côté vérification ressemble à ceci :
using var rsa = RSA.Create();
rsa.ImportSubjectPublicKeyInfo(publicKeyDer, out _);
bool ok = rsa.VerifyData(
payload, signature,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
Rien n’est faux dans ce code. Le problème, ce sont les 256 octets assis dans signature, et aucune astuce d’encodage ne les rend plus petits.
ECDSA : la bonne taille, avec un nonce qu’on peut rater
L’ECDSA sur la courbe NIST P-256 vous donne 128 bits de sécurité — comparable à RSA-3072 — avec une signature brute de seulement 64 octets (deux entiers de 32 octets, r et s). C’est un quart de la taille de RSA-2048 pour une clé plus forte, et il est intégré directement dans System.Security.Cryptography sur toutes les versions supportées de .NET, ce qui en fait le choix évident si votre contrainte est « uniquement des algorithmes intégrés » :
using var ecdsa = ECDsa.Create();
ecdsa.ImportSubjectPublicKeyInfo(publicKeyDer, out _);
// Keyright stores the raw r‖s form to keep the key short; .NET verifies it directly.
bool ok = ecdsa.VerifyData(
payload, signature,
HashAlgorithmName.SHA256,
DSASignatureFormat.IeeeP1363FixedFieldConcatenation);
Notez ce dernier argument. Les signatures ECDSA ont deux encodages : la concaténation compacte IEEE P1363 de r et s sur 64 octets, et la forme ASN.1 DER, qui les enveloppe dans une SEQUENCE de deux INTEGER et fait 70 à 72 octets de longueur variable (les règles de zéro initial font que les signatures DER diffèrent en taille d’une signature à l’autre). Pour une clé de licence, vous voulez la forme fixe de 64 octets ; une signature DER de longueur variable fait vaciller la longueur de votre clé et complique l’analyse à largeur fixe. Se tromper ici est un bug d’interopérabilité courant — un signataire qui émet du DER et un vérificateur qui attend du P1363 rejettera chaque signature valide.
Le problème plus profond avec ECDSA n’est pas la taille, c’est le nonce. Chaque signature ECDSA consomme une valeur secrète par signature k. Si k est un jour réutilisé entre deux messages différents, ou est même légèrement prévisible, la clé privée tombe des deux signatures avec quelques lignes d’algèbre. Ce n’est pas une hypothèse — c’est exactement le mécanisme derrière plusieurs extractions de clés célèbres. L’ECDsa de .NET génère k correctement et le garde en interne, donc la signature dans le framework est sûre. Mais dès que votre chemin d’émission implique du code personnalisé, un autre langage ou un RNG emprunté — et un backend de licences grandit souvent exactement ainsi — ECDSA n’est qu’à une mauvaise source d’aléa de faire fuiter la clé qui protège tout votre produit. L’algorithme vous tend un pistolet chargé et vous fait confiance pour le garder pointé ailleurs.
Ed25519 : petit, rapide, et rien à rater
Ed25519 — EdDSA sur la courbe d’Edwards dérivée de Curve25519 — a été conçu avec les leçons de RSA et d’ECDSA intégrées, et pour des clés de licence, il gagne sur chaque axe qui compte.
Les tailles sont les meilleures des trois : une signature de 64 octets et une clé publique de 32 octets, avec 128 bits de sécurité. La clé publique compte aussi, car c’est la valeur que votre application embarque et (si vous la durcissez) épingle ; une ancre de 32 octets est bien plus facile à empreinter et à protéger que le SubjectPublicKeyInfo d’environ 294 octets de RSA. Sa clé publique DER commence par le préfixe fixe MCowBQYDK2Vw en base64, un signe révélateur que vous regardez une clé Ed25519.
Point crucial, Ed25519 est déterministe. Le nonce par signature est dérivé en hachant la clé privée avec le message, donc il est unique par message sans avoir besoin du moindre aléa au moment de signer. Il n’y a pas de k à réutiliser, pas de RNG à mal configurer, pas de biais de nonce pour faire fuiter la clé — l’arête la plus tranchante d’ECDSA est tout simplement absente. Signer deux fois la même charge utile produit une sortie identique octet pour octet, ce qui rend aussi l’émission idempotente et les fixtures de test stables. La vérification est en temps constant par construction, évitant une classe de problèmes de timing sur lesquels vous devriez autrement raisonner.
Le seul piège pratique sur .NET : Ed25519 n’est pas exposé par la surface intégrée de System.Security.Cryptography comme le sont RSA et ECDsa, donc la vérification passe par une implémentation embarquée plutôt que par la BCL. Du point de vue d’un intégrateur, c’est invisible — le SDK Keyright vérifie pour vous :
var verifier = new LicenseVerifier(new LicenseVerifierOptions
{
// 32-byte Ed25519 public key, base64 SubjectPublicKeyInfo — safe to ship, worth pinning.
PublicKeyBase64 = "MCowBQYDK2VwAyEA9mF3rQ2pxK8vN1cWbYh6Zt0uQ4sJ7eD3rL5nX8kH2A=",
});
LicenseResult result = verifier.Verify(licenseKey);
if (result.IsValid && result.Claims.Tier == "Pro")
{
// honor the entitlements
}
La signature de 64 octets garde la clé courte, la conception déterministe tient votre côté émission à l’écart du champ de mines du nonce, et l’appel de vérification est une opération sous la milliseconde que vous pouvez exécuter à chaque lancement sans serveur sur le chemin.
Comment les trois se placent sur les axes qui comptent
Lisez le tableau comme un système de licences le vit. La ligne qui décide si votre clé est utilisable tout court est la longueur de clé, et elle élimine RSA pour tout ce qu’un humain touche. La ligne qui décide si une seule mauvaise journée dans votre code d’émission vous coûte tout le produit est le danger du nonce, et elle sépare Ed25519 d’ECDSA. Sur les deux lignes où RSA est compétitif — déterminisme et vitesse de vérification — les options à courbe elliptique l’égalent ou le battent de toute façon. Il n’y a aucun axe sur lequel RSA-2048 est la bonne réponse pour des clés de licence, et le seul axe sur lequel ECDSA bat Ed25519 est « déjà intégré sur toutes les vieilles cibles ».
Ce que cela signifie en pratique
Si vous partez de zéro, signez avec Ed25519. Il produit les clés les plus courtes, atteint un niveau de sécurité de 128 bits, vérifie assez vite pour tourner à chaque lancement et — la partie qui compte le plus quand votre chemin de signature grandit au-delà d’une fonction bien rangée — il n’a aucun nonce par signature pour faire fuiter la clé privée. C’est pourquoi c’est le défaut de Keyright : le SDK embarque une clé publique de 32 octets que vous pouvez épingler, vérifie la signature de 64 octets hors ligne et ne demande jamais à votre côté émission de fournir un aléa qu’il pourrait rater.
Ne vous tournez vers ECDSA P-256 que lorsqu’une contrainte dure vous impose des algorithmes intégrés sur une cible où Ed25519 n’est pas disponible — et si vous le faites, fixez l’encodage IEEE P1363 de 64 octets, laissez le framework générer le nonce et ne laissez jamais un signataire personnalisé s’approcher de k. Ne vous tournez vers RSA que lorsque vous interopérez avec un système qui l’impose déjà, et acceptez que vos clés ne pourront qu’être collées.
L’algorithme de signature est la fondation sur laquelle repose tout le schéma de licence. Choisissez celui qui est assez petit pour être tapé, assez fort pour durer, et façonné de telle sorte que le chemin le plus facile dans votre propre code soit aussi le chemin sûr.
Essayez Nebula.NET
Renforcez votre code .NET en quelques minutes — commencez avec l'édition gratuite.