Comme mentionné, l'authentification de Postcard se base sur une procédure de signature simplifiée par moyen d’algorithme cryptographique RSA. Lors de l’émission de la carte, les données en clair de la carte sont signées (composé entre autres du numéro de carte et la période de validité) avec la clé privée de l'éditeur (PostFinance). Le cryptogramme reçu est enregistré ensemble avec les données de la carte dans le secteur ROM de celle-ci..
L’algorithme RSA permet théoriquement de calculée la clé privée à partir de la clé publique; la sécurité de la procédure est fonder sur l'impossibilité en pratique de la calculer et dépend directement de la longueur de la clé utilisée ainsi que les procédures mathématiques disponibles pour la factorisation de nombre premier des nombres très grands. Aujourd'hui, une clef RSA avec une longueur d'au moins 1024 bits sont considérés comme sûr.
Une paire de clés, de l’algorithme RSA, se compose de trois paramètres: modulo m, l'exposant public e et l'exposant privé d. La clé publique est alors définie par {e, m}, la clé privée, en conséquence, par {d, m}.
Le (dé)chiffrement des données en clair k et de cryptogramme c est mis en équation comme suivant:
Chiffrement: c = k^d mod m
Déchiffrement: k = c^e mod m
Tous les trois paramètres de paire de clés sont liés par des relations mathématiques suivant: modulo m est le produit de deux grands nombres premiers p et q, c.-à-d. que m = p · q. Comme variable auxiliaire on utilise le plus petit commun multiple de p-1 et de q-1. Il on résulte: r = PPCM (p-1, q-1) . Pour les exposants e et d tant e · d ? 1 mod r, et tant l'exposant public e qui est choisi librement, doit être un diviseur de r.
Si on réussit, à diviser modulo m dans ses deux produits de facteurs de nombres premiers p et q, on peut, avec la connaissance de l'exposant public e au moyen de l’équation ci-dessus, calculée l’exposant privé d et alors la clé privée.
Normalement on peut déduire modulo directement de la clé publique. Dans notre cas, la clé publique « n'est toutefois pas publiée ». Pour déterminer modulo de la paire de clés, il y a deux approches:
Si on est en possession d'un terminal de Postcard, on peut essayer extraire la clé de l’équipement. Cette procédure est toutefois très longue et exige les connaissances de l’équipement utilisé.
Modulo rechercher peut être calculé aussi directement à partir des données de deux Postcards; cette procédure est nettement plus simple, puisqu’elle ne requit aucun équipement spécial.
Pour trouver modulo, nous choisissons la procédure 2 qui est plus simple. Nous nécessitons les données de deux Postcards, dont nous devons déterminer à jaque fois la valeur pour le texte en clair k ainsi bien que pour le cryptogramme c.
Pour recevoir la valeur modulo m, nous ne servons de la réflexion mathématique ci-dessous. Nous présumons que la valeur pour l'exposant public est 3 (comme pour la carte bancaire française).
Les équations suivantes sont en vigueur:
k1 = c1³ mod m ∧ k2 = c2³ mod m → c1³ - k1 = n1 · m ∧ c2³ - k2 = n2 · m → m = ggT (c1³ - k1, c2³ - k2) |
Puisque nous pouvons utiliser deux Postcards quelconque, nous ne connaissons éventuellement pas le préfix de chaque carte. Par conséquent, nous calculons seulement kx (k'sans préfix) pour chaque carte. Le programme suivant calcule ainsi modulo avec les données des cartes:
import java.math.BigInteger; public class ComputeMod2 { public static void main (String[] argv) { String c1Str = "0EC6DA0D247A69CD093B6D852118CA4346B44EEECE4A3394F872C1356A8070BFEBB54669F375A63F2"; String kx1Str = "0050162300000234208157701030503"; String c2Str = "09BA94341F1DD339766F71DF4BA1CC807C565AA0FC3BE835570104F5A0DF636D4F4F4AC7BFA481257"; String kx2Str = "0050162300000234208157706021002"; BigInteger c13 = new BigInteger (c1Str, 16).pow(3); BigInteger c23 = new BigInteger (c2Str, 16).pow(3); for (int n1 = 0; n1 < 16; n1++) { String tmp = "00004" + hex.charAt(n1) + "000" + kx1Str; BigInteger k1 = new BigInteger (tmp + tmp, 16); BigInteger a = c13.add(k1.negate()); for (int n2 = 0; n2 < 16; n2++) { tmp = "00004" + hex.charAt(n2) + "000" + kx2Str; BigInteger k2 = new BigInteger (tmp + tmp, 16); BigInteger b = c23.add(k2.negate()); BigInteger m = a.gcd(b); if (m.bitLength() > 318) { System.out.println ("Modulus: 0x" + m.toString(16)); System.out.println (" " + m.toString()); return; } } } System.out.println ("Kein Modulus gefunden !?"); } private static String hex = "0123456789ABCDEF"; } |
Si on exécute ce calcul pour deux Postcard, on reçoit la valeur suivante pour modulo:
m = 100000000000000000000D62C6F32CD0EBF84B9339E3997B46570D236179E4675433DAA5FF513A6CF
|
Maintenant, on peut diviser modulo m par ses facteurs de nombres premiers p et q. En utilisant un programme comme qsieve qui permet en même temps de factoriser avec plusieurs ordinateurs, on reçoit le résultat souhaité après quelques heures:
p = 39D6E856F2DF3C90B6C973BF29DFB66E8E73DEA7 |
Pour déterminer l'exposant privé nous pouvons utiliser l’équation e · d ? 1 mod r. La variable auxiliaire r a la valeur:
r = 800000000000000000006B16379966875FC25C977BA8C96bC7D5DC1767667EFDAC9973F6E3803248
|
Avec les valeurs calculées pour e et r, on obtient:
d = 2AAAAAAAAAAAAAAAAAAACE5CBD33222d1FEB74327E8D9879429C9EB277CCD4FF39887BFCF68010C3
|
Avec le petit programme en Java, ci-dessous, nous pouvons examiner si tous nos résultats sont corrects. Tout essai devrait livrer « true » comme résultat. Celui qui possède une Postcard soi-même et un lecteur de cartes à puce, peut lire ses propres données et remplacer les valeurs c et k par les valeurs qu’il a déterminé lui-même:
import java.math.BigInteger; public class Test { public static void main (String[] argv) { BigInteger c = new BigInteger ("0EC6DA0D247A69CD093B6D852118CA4346B44EEECE4A3394F872C1356A8070BFEBB54669F375A63F2", 16); BigInteger k = new BigInteger ("04400000501623000002342081577010305030000440000050162300000234208157701030503", 16); BigInteger m = new BigInteger ("100000000000000000000D62C6F32CD0EBF84B9339E3997B46570D236179E4675433DAA5FF513A6CF", 16); BigInteger p = new BigInteger ("39D6E856F2DF3C90B6C973BF29DFB66E8E73DEA7", 16); BigInteger q = new BigInteger ("46D111C85E2E5DD769207D4BAC02B0C039F9F6399", 16); BigInteger d = new BigInteger ("2AAAAAAAAAAAAAAAAAAACE5CBD33222d1FEB74327E8D9879429C9EB277CCD4FF39887BFCF68010C3", 16); BigInteger e = BigInteger.valueOf (3); check ("p * q == m", p.multiply (q), m); check ("c^d mod m == k", c.modPow (e, m), k); check ("k^d mod m == c", k.modPow (d, m), c); } private static void check (String msg, BigInteger a, BigInteger b) { boolean ok = a.equals(b); if (ok) System.out.println (msg + ": SUCCESS"); else { System.out.println (msg + ": FAILED!"); System.out.println (" " + a.toString(16)); System.out.println (" <> " + b.toString(16)); } } } |