Article technique
Comment déchiffrer les données de carte de crédit, Partie II
Les clients nous demandent souvent : Comment puis-je déchiffrer les données provenant de mon lecteur de carte de crédit ID TECH ?
La réponse : vous devez connaître l'algorithme utilisé pour chiffrer les données, ainsi que la clé employée. Vous pourrez alors déchiffrer les données à l'aide de cette clé.
De nos jours, pratiquement toutes les données de carte de crédit sont chiffrées à l'aide d'une clé à usage unique, obtenue via un système de gestion des clés spécial appelé DUKPT (acronyme de Derived Unique Key Per Transaction, soit « clé unique dérivée par transaction »). Il est important de comprendre que dans l'univers DUKPT, chaque transaction dispose de sa propre clé. Cette clé ne peut être réutilisée pour aucune autre transaction ; les attaques par rejeu sont donc impossibles.
La question est la suivante : comment dériver une clé DUKPT permettant de déverrouiller une transaction donnée ? La réponse est : en règle générale, vous avez besoin du numéro de série de clé (KSN) associé à la transaction, ainsi que d'une valeur spéciale appelée IPEK, soit la clé initiale injectée dans le lecteur de carte de crédit. L'IPEK est elle-même dérivée d'une clé ultra-secrète — qui n'est jamais injectée dans un lecteur de carte — appelée BDK (Base Derivation Key). Contrairement à la BDK, l'IPEK est propre à un appareil physique donné. (Une seule BDK peut être à l'origine de nombreuses IPEK uniques.) Si vous ne connaissez pas l'IPEK de votre appareil — ce qui est tout à fait normal, puisque l'IPEK n'est jamais consignée nulle part —, vous pouvez la dériver à partir d'un KSN et d'une Base Derivation Key, en utilisant la technique décrite dans la Partie I de cet article.
La dérivation d'une clé de session (parfois appelée clé de travail, ou simplement « clé de données ») se conçoit mieux comme un processus en 3 étapes, à savoir :
1. Utiliser la BDK et le KSN pour dériver l'IPEK. (Voir la Partie I de cet article pour plus de détails sur la procédure à suivre.)
2. Utilisez l'algorithme de dérivation de clé ANSI X9.24 (DUKPT) pour dériver une clé de base, ou « clé dérivée » initiale, à partir du KSN et de l'IPEK.
3. Convertissez la clé dérivée obtenue à l'étape 2 en Data Key, PIN Key ou MAC Key, selon votre choix. (À noter que si la plupart des lecteurs de cartes de crédit sont configurés pour utiliser la variante Data comme clé de session de transaction, certains utilisent en réalité la variante PIN.)
Voyons maintenant ce qu'implique l'obtention de la « clé dérivée » (étape 2), car il s'agit de loin de la partie la plus fastidieuse du processus en 3 étapes. Une fois la clé dérivée obtenue, nous verrons comment la transformer en variante Data, PIN ou MAC, ce qui est relativement simple.
Nous utiliserons ci-dessous un certain nombre de pseudocodes, mais rassurez-vous, vous trouverez un code source complet et fonctionnel (en JavaScript) pour toutes les étapes suivantes dans notre populaire Outil de chiffrement/déchiffrement. (Essayez-le dès maintenant, si ce n'est pas encore fait. Il s'agit d'une page web autonome qui fonctionne dans tout navigateur moderne.)
Dérivation d'une clé
Pour dériver la clé de base à partir de laquelle une variante Data, PIN ou MAC peut être créée, vous devez disposer d'un KSN de transaction et d'un IPEK. Une fois ces éléments en main (encore une fois : consultez Partie I de cette série), procédez comme suit :
1. Extrayez les 8 octets inférieurs (les plus à droite) de votre KSN de 10 octets. Ignorez les deux octets supérieurs.
2. Créez une variable BaseKSN pour stocker une version masquée de votre KSN de 8 octets. Obtenez cette version masquée en appliquant un ET logique (AND) entre le KSN de 8 octets de l'étape 1 et la valeur hexadécimale 0xFFFFFFFFFFE00000.
3. Extrayez les bits de compteur de votre KSN d'origine de 10 octets (non masqué !) en appliquant un ET logique (AND) entre ses trois octets inférieurs et la valeur 0x1FFFFF. (Rappelons que les 21 bits inférieurs d'un KSN constituent le compteur de transaction.) Nous placerons cette valeur dans une variable appelée (quoi d'autre ?) counter.
4. Copiez votre IPEK de 16 octets dans une variable appelée curKey.
5. Nous devons maintenant mettre en place une boucle. À chaque itération, nous allons examiner les bits du counter (en commençant par le bit le plus haut, soit le 21e bit ; au deuxième passage, nous vérifierons le 20e bit ; puis le 19e ; et ainsi de suite). Chaque fois que nous trouvons un bit activé, nous l'appliquons par OR au BaseKSN, puis nous appelons generateKey() pour mettre à jour curKey. Le BaseKSN accumule des bits à chaque passage dans la boucle, et la valeur de curKey se met à jour à chaque bit du counter activé que nous trouvons.
Que fait generateKey() ? Bonne question ! Si votre langage de programmation prend en charge les calculs en grands entiers (BigInteger), le code ressemblera à quelque chose comme ceci :
Bien. Vous pouvez constater que la clé de 16 octets est masquée, puis utilisée pour chiffrer la valeur ksn de 8 octets, afin d'obtenir la moitié gauche (les 8 octets de gauche) d'une nouvelle clé. La moitié droite de cette nouvelle clé est un chiffré produit à partir du même ksn, mais en utilisant une clé non masquée.
Enfin, vous devez savoir à quoi ressemble encryptRegister() . Voici ce que c'est :
Notez que le chiffrement par enchaînement de blocs (Cipher Block Chaining) n'a ici aucune signification concrète, car nous chiffrons une valeur de 8 octets (un seul bloc de données). Il n'y a rien à « enchaîner ». Il est inclus dans le code uniquement parce que la routine de chiffrement requiert un paramètre indiquant si l'enchaînement est activé ou non.
Notez également que nous utilisons une clé de 8 octets pour effectuer le chiffrement. TDES bascule par défaut vers le DES simple lorsque la clé ne fait que 8 octets. En effet, une clé de 8 octets produirait (en triple DES) un cycle chiffrement/déchiffrement/chiffrement équivalent à un simple chiffrement.
En termes simples, la routine utilise les 8 premiers octets d'une clé de 16 octets pour chiffrer une valeur spéciale obtenue par opération XOR entre les 8 derniers octets de la clé et le ksn (de 8 octets). Le résultat est un hachage unidirectionnel du ksn.
En combinant l'ensemble, la boucle de l'étape 5 ci-dessus produit une valeur curKey qui constitue une clé de base à partir de laquelle nous pouvons dériver des variantes Data, PIN ou MAC. (La boucle de l'étape 5 est, ou devrait être, intégrée dans une fonction qui retourne finalement curKey, soit la clé de base.)
Il est maintenant temps d'examiner plus en détail ces trois options de « variantes de clé ».
Création des variantes de clés Data, PIN et MAC
La norme ANSI X9.24 permet à une clé DUKPT de prendre l'une des trois formes finales, appelées variantes : MAC, PIN et Data. Laissons de côté pour l'instant la question de l'utilisation de ces différents types de clés afin de nous concentrer sur la manière dont ils sont créés.
Le point de départ pour chacune des variantes est une clé de base DUKPT (la clé dérivée que nous avons appelée curKey à l'étape 5 ci-dessus). Pour obtenir la variante MAC, il suffit d'appliquer un XOR entre la clé de base (la « clé dérivée ») et une constante spéciale :
La variante PIN est créée de manière similaire, mais en utilisant une constante différente :
La variante Data nécessite encore une autre constante :
Pour les variantes MAC et PIN, l'opération XOR constitue l'étape finale de création de la clé de session correspondante. Pour la variante Data, il est d'usage d'effectuer une étape supplémentaire faisant intervenir un hachage à sens unique (afin d'éviter toute possibilité qu'une clé Data soit rétro-transformée en clé MAC). En pseudocode :
En clair : commencez par obtenir une version sur 24 octets de votre clé dérivée en appliquant la méthode d'expansion EDE3. (Cela consiste simplement à copier les 8 premiers octets d'une clé de 16 octets à la fin de cette clé, créant ainsi une clé de 24 octets dont les 8 premiers et les 8 derniers octets sont identiques.) Utilisez cette clé pour chiffrer par TDES les 8 premiers octets de votre clé dérivée de 16 octets, générant ainsi un bloc chiffré de 8 octets. Celui-ci constitue la moitié gauche de la clé de données finale. Pour créer la moitié droite, utilisez la même clé de 24 octets pour chiffrer les 8 derniers octets de la clé dérivée. Combinez les deux blocs chiffrés de 8 octets (parties gauche et droite) : la clé est alors complète.
Valeurs de référence
Si vous souhaitez reproduire ces opérations par vous-même, vous pouvez vérifier vos résultats en les comparant à des valeurs de référence connues. Pour ce faire, utilisez une BDK de 16 octets égale à 0123456789ABCDEFFEDCBA9876543210 (en hexadécimal), qui est la valeur de clé de test couramment utilisée. Essayez ensuite une valeur KSN de test égale à 629949012C0000000003. Ces deux valeurs doivent vous permettre de dériver un IPEK égal à D2943CCF80F42E88E23C12D1162FD547. (Référez-vous à la Partie I de cet article si vous souhaitez voir comment dériver l'IPEK.)
En partant de l'IPEK mentionné ci-dessus, vous devriez obtenir les valeurs suivantes lors de la dérivation d'une « clé dérivée » (ou clé de base DUKPT) :
Au premier passage dans le « if » de la boucle du compteur KSN, votre BaseKSN sera 49012C0000000002 et curKey deviendra B58CDA5C7A1E9FF5E7335B988626D01A après generateKey().
Au deuxième passage dans le « if » de la boucle du compteur, vous aurez traité les deux bits « ON » du compteur, et par conséquent votre BaseKSN sera 49012C0000000003 et la curKey résultante sera 841AB7B94ED086EBC2B8A8385DA7DFCA. (Rappel : vous effectuez un OR des bits du compteur, du MSB au LSB, dans le BaseKSN. Si le compteur se termine par 0x0F, le BaseKSN passera successivement de 49012C0000000008 à 49012C000000000C, puis à 49012C000000000E, puis à 49012C000000000F à mesure que vous appliquez les bits par OR.)
Votre « clé dérivée » sera donc 841AB7B94ED086EBC2B8A8385DA7DFCA.
Après application d'un XOR avec la constante de variante de données, la clé dérivée sera modifiée en 841AB7B94E2F86EBC2B8A8385D58DFCA.
Après chiffrement des moitiés supérieure et inférieure de cette valeur, à l'aide d'une clé d'expansion EDE3 de 841AB7B94E2F86EBC2B8A8385D58DFCA841AB7B94E2F86EB, vous devriez obtenir une clé de données finale de F739AEF595D3877F731782D28BB6AC4F. Autrement dit : en utilisant la clé EDE3 de 24 octets pour chiffrer 841AB7B94E2F86EB, vous devriez obtenir un chiffré de F739AEF595D3877F, et en utilisant la même clé pour chiffrer C2B8A8385D58DFCA, vous devriez obtenir un chiffré de 731782D28BB6AC4F. Concaténez les deux chiffrés, et le tour est joué. Vous disposez désormais d'une clé de 16 octets permettant de déchiffrer les données de la transaction dont le KSN était 629949012C0000000003.
Exemple de code : l'outil de chiffrement/déchiffrement ID TECH
Pour accéder au code source complet de toutes les routines de dérivation de clés DUKPT présentées ici, n'oubliez pas de télécharger (et d'examiner le code source de) notre outil Outil de chiffrement/déchiffrementbasé sur HTML et JavaScript, qui permet de calculer des IPEK, de dériver les 3 variantes de clés DUKPT, de chiffrer ou déchiffrer des données via TDES ou AES, et bien plus encore. Vous pouvez utiliser l'excellente console de développement de Chrome pour parcourir le code de l'outil en temps réel, inspecter les valeurs des variables au fil de leurs modifications, poser des points d'arrêt, etc. C'est un outil d'apprentissage extrêmement précieux. Et il est gratuit ! Téléchargez donc l'outil Outil de chiffrement/déchiffrement, explorez-le et parlez-en autour de vous. À ma connaissance, il s'agit de la seule implémentation DUKPT entièrement en JavaScript disponible sur le Web.
