Épreuve cryptographie du FCSC 2026 (ANSSI), challenge en ligne dans un cadre explicitement autorisé. Reproduction à fins pédagogiques.
Le challenge fournit un script de génération et une liste de points de courbe. Chaque caractère du flag est transformé en ord(c) * G sur la courbe française FRP256v1, et seules les coordonnées des points résultants sont publiées.
Inverser l'encodage : retrouver, pour chaque point publié, le scalaire qui l'a produit, c'est-à-dire résoudre un log discret elliptique rendu trivial par la petite taille des scalaires.
1 · Le générateur
Le script encode le flag caractère par caractère :
for f in FLAG:
pt = ord(f) * G
print(hex(pt.x), hex(pt.y))
La sécurité d'ECC repose sur la difficulté du log discret (retrouver k à partir de k·G). Ici, la faille est l'espace des scalaires : ord(f) est un octet ASCII, donc k < 128. L'espace est minuscule.
2 · Cassage par énumération
On précalcule k·G pour tout k de 1 à 127, on indexe par coordonnée x, puis on retrouve chaque caractère par simple lookup.
lookup = {}
for k in range(1, 128):
lookup[(k * G).x()] = k
flag = "".join(chr(lookup[x]) for x in cipherpoints_x)
[+] flag = FCSC{…}
Les points dupliqués dans la sortie (mêmes x) correspondent simplement à des caractères répétés du flag, un indice supplémentaire que l'encodage est déterministe et sans masque.
- Ne jamais encoder un message via
m·G: la confidentialité repose alors sur la taille dem, pas sur l'ECDLP. - Un chiffrement à courbe elliptique correct (ECIES, par exemple) combine échange de clés et chiffrement symétrique avec aléa.
- Tout schéma dont l'espace des secrets est énumérable en pratique est cassé, indépendamment de la courbe.