Tweets by TwitterDev " />

Découverte du Format Preserving Encryption (FPE)

Dans le cadre de la veille continue nécessaire dans nos métiers, j'ai eu l'opportunité d'avoir une présentation de Microfocus sur leurs “Solutions de cryptage pour la sécurité et la confidentialité des données”.

 J'ai été particulièrement intéressé par la partie Voltage Securedata qui, en schématiquement, est une suite très complète d'outils de chiffrement qui permettent d'intégrer de manière sûre du chiffrement de bout en bout dans une application.

 J'arrête la partie marketing 😉, et j'en profite pour préciser que je n'ai aucun intérêt particulier avec Microfocus.

Exemple chiffrement FF3

Lors de cette présentation, ma curiosité a été titillée par la technologie "Format Preserving Encryption", ou FPE pour les intimes.

Sa promesse est de chiffrer les données tout en préservant le format et la longueur de donnée initiale.

J'ai tout de suite imaginé les applications d'une telle technologie comme la modernisation d’applications en introduisant un chiffrement peu impactant ou la génération de données de test.

Au premier abord, ne connaissant pas FPE, j'ai cru qu'il s'agissait de tokenisation, ou on remplace le contenu par un autre contenu non lié mais qui peut préserver le format.

La conséquence est qu'il faut maintenir des dictionnaires de données qui enregistrent les correspondances. Dictionnaires qui selon la nature des données doivent eux même être chiffrés.

Mais ce n'était pas le cas et j'ai donc commencé mes recherches sur le sujet.

Suivons le lapin blanc

Après un premier passage par Wikipédia https://en.wikipedia.org/wiki/Format-preserving_encryption, je me suis rendu compte que le sujet était plus touffu que je ne le pensais.

Il existe différents algorithmes FF1, FF2, FF3, FF3-1 pour les plus connus, dont certains comme le FF2  n'ont pas été reconnus par le NIST, le FF3 est déprécié par le FF3-1 qui reste en "Draft".

Le NIST est le National Institute of Standards and Technology, ils maintiennent des standards et des guides dans le domaine de la sécurité et de la protection des données personnelles.

Leurs recommandations, sont suivies, par exemple, dans des normes telles que PCI-DSS ou HIPAA.

Le document du NIST qui traite du sujet est : Recommendation for Block Cipher Modes of Operation: Methods for Format-Preserving Encryption

N’étant pas un amoureux des algorithmes de chiffrement, j’ajoute à mon vocabulaire les Réseaux de Feistel qui sont à la base de FF1 et FF3 et de quelques autres algorithmes de chiffrement connus comme DES,Blowfish ou RC5 (https://fr.wikipedia.org/wiki/R%C3%A9seau_de_Feistel). Je passe rapidement cette partie plus théorique pour m’intéresser à deux autres points:

  • la notion de taille du domaine

  • des revendications au niveau des brevets.

La question du brevet

Je ne rentrerais pas en détail dans la partie brevets, mais il faut retenir que l’utilisation des algorithmes FF1 et FF3 est soumise à une autorisation du propriétaire du brevet qui est, tiens donc, Microfocus qui l’a obtenu dans une de ses acquisitions. La boucle est bouclée 😉

En cas d'intérêt je conseille ce document comme point de départ : https://csrc.nist.gov/csrc/media/projects/block-cipher-techniques/documents/bcm/proposed-modes/ffx/ffx-voltage-ip.pdf.

La taille de domaine

 J’ai plus approfondi la taille de domaine car elle a un impact direct sur les scénarios possibles.

En premier, il est important de comprendre ce qu’est une taille de domaine. Elle représente tous les états que peuvent prendre un champ.  Elle se construit à partir de la taille de l’alphabet utilisé et du nombre de position dans le champ.

Exemple :

Pin code a 4 chiffres, alphabet 0,1,2,3,4,5,6,7,8,9 soit une taille d’alphabet de 10. Le domaine a donc une taille de 10000 (10x10x10x10 ou 10^4)

Initialement la taille de domaine minimum conseillée était de 100 mais a été remontée à 1 million (10^6) lorsque que des faiblesses ont été trouvées (en cas d'intérêt Message-Recovery Attacks on Feistel-Based Format Preserving Encryption, The curse of Small Domains).

Donc vouloir utiliser cette solution pour des chiffres de moins de 6 positions n'est pas forcément une bonne idée. A titre d'exemple, notre pin code n’est pas un bon candidat, mais la taille du domaine pour un numéro de carte de crédit est de 10^16. Là on est bon.

Fort de ces recherches, je me suis dit qu'une petite mise en pratique serait amusante.

Un peu d’expérimentation

Heureusement des librairies open source existent (open source et algorithme breveté, quel mélange 😉)

Aidé par wikipédia j'ai jeté mon dévolu sur une librairie en C (plus par nostalgie que par réflexion je dois dire ):  https://github.com/mysto/clang-fpe

Un petit git clone https://github.com/mysto/clang-fpe.git et quelques problèmes de dépendances avec openssl résolus (ahh le développement avec Brew sur MAC) et me voilà prêt.

Un tour rapide dans le readme pour constater que le programme a besoin de la taille du domaine, d'une clef et d'un tweak (qui agit un peu comme le salt dans les hashs), ce qui n'est pas une surprise si on a bien lu le Wiki et le document du NIST.

Je lance le make, dé-commente les affichages dans le programme de test python et je lance le test qui est censé vérifier les vecteurs de test du NIST  (en résumé des entrée sorties d’algorithme validées).

Bon ça a l'air de marcher…

Comme chiffrer c’est bien mais déchiffrer c’est mieux je tente donc  de chiffrer et de  déchiffrer une chaîne de type carte de crédit, et la oh surprise le déchiffrement FF3 ne marche pas.

./example EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C D8E7920AFA330A73 10 890121234567890000
plaintext: 890121234567890000
FF1 ciphertext: 171733553004398814
FF1 text: 890121234567890000
FF3 ciphertext: 922011205562777495
FF3 text: 922011205562777495

Je parcours un peu le code, en dehors d’une limite de tableau forcée à 100 qui me fait dire que le code n’est pas prêt pour de la production, je ne vois rien d’évident.

void FPE_ff3_decrypt(char *ciphertext, char *plaintext, FPE_KEY *key)
{
 int txtlen = strlen(ciphertext);
 unsigned int x[100],
 y[txtlen];
 map_chars(ciphertext, x);
 FF3_decrypt(x, y, key, key->tweak, txtlen);
 inverse_map_chars(y, plaintext, txtlen);
}


Je reprends le code du fork initial https://github.com/0NG/Format-Preserving-Encryption.git

Et après quelques ajustements sur le makefile, je refais le test et la ça marche.

Test de déchiffrement FPE Ok

Par manque de temps et de cas concret, je n’irai pas plus loin avec les expérimentations…

Mes enseignements

La première morale est qu’il ne faut pas faire confiance aveuglément à du code pris sur internet… Dans le cas présent le code est imparfait et a des limites (taille de tableau, alphabet géré au minimum) qui en font plus un proof of concept même s’il passe les vecteurs de test du NIST.

En plus, le choix du langage C ne serait pas forcément le plus évident en cas de vrai projet...

Avec les différentes contraintes énumérées, je me verrai bien utiliser ce type de chiffrement pour neutraliser des informations sensibles entre un environnement de production et un environnement de développement.

Pour d’autres usages comme la neutralisation de colonnes dans des bases de données sur site ou dans le cloud il faut se poser la question de la gestion et l’utilisation sécurisée des clés. C’est un aspect à ne jamais négliger…

Il reste que le chiffrement FPE à surement un rôle à jouer dans la « rénovation sécuritaire» d’applications (anciennes ou nouvelles) qui supportent assez mal le changement de nature de leur champs.

Au final, entre la question des brevets et la complexité potentielle de la tâche, il est peut-être plus efficace de reposer sur une solution du marché qui intègre un chiffrement validé et une bonne gestion des clefs.

Bon, assez de veille pour aujourd'hui, back to business 😊

Elric Osmont