ang [Security] surcouche C++ aux moteurs RSA et blowfish de OpenSSL

Avatar de Emmanuel Deloget
Expert Confirmé Sénior
Mise à jour le 18 janvier 2011  ·   Licence : Autre  ·   Téléchargé 72 fois   ·   276 Ko  Voir tous les téléchargements de l'auteur

CommentairesLa discussion sur le forum
Présentation
Voici une petite librairie qui effectue l'encryption / décryption de données en utilisant les algorithmes RSA (asymétrique ; avec clef publique et clef privée) et Blowfish (symétrique). Cette petite librairie se base sur une version récente de OpenSSL. Elle devrait pouvoir être compilée pour linux, Windows ou Mac OS (testée uniquement sous linux pour l'instant).

Mise à jour : version 0.4 licence explicite, améliorations du pipeline, amélioration du build sous Windows (non testé), correction d'un bug dans certaines version de la fonction sha256(), test supplémentaires sur les pipeline, ajout d'un changelog.
Mise à jour : version 0.3 changement de système de build (cmake) + pipeline + adapteurs pour les encodeurs et les cryptographes + tests unitaires
Mise à jour : version 0.2 SHA256 + encoders dans leur propre librairie
Mise à jour : version 0.1 (la précédente version n'avait pas de numéro).

Présentation
Généralement, lorsqu'on souhaite crypter des communications réseau, on instaure un protocole qui ressemble à

client : je t'envoie ma clef publique RSA
serveur : ok ; je génère une clef blowsfish et je la crypte en utilisant ta clef publique, et je te renvoie le résultat
client : je décrypte le message ; j'ai la clef blowfish. A partir de maintenant, je crypte tout avec cette clef.

On peut utiliser le cryptage privé RSA (crypter avec la clef privée, décrypter avec la clef publique) pour implémenter une mécanisme de signature des données envoyées par le serveur (ce qui nécessite que le client connaissance par avance la clef publique du serveur ; on peut mettre celle-ci dans le programme client directement). De cette façon, on peut réduire les attaques du type man in the middle, même si ce n'est pas encore parfait.

blowfish est un des algorithmes de cipher (encryption / décryption) les plus rapides, mais il est symétrique (la même clef sert aux deux opérations). Du coup, si on souhaite l'utiliser pour les communications, il faut trouver un moyen sécurisé d'envoyer la clef aux deux parties. D'où l'idée d'utiliser RSA pour le transport de la clef : l'algorithme est adapté à l'encryption de blocs de petite taille (par exemple, la taille d'une clef) mais il est lent. De plus, gérer des blocs de grande taille avec RSA est une fort mauvaise idée (il n'est pas fait pour ça).

Licence
La licence d'utilisation est une licence libre. Le texte de la licence sera ajouté à la prochaine révision. le code de encoder::base64 est basé sur celui de René Nyffenegger.

Version 0.3
Pour construire la librairie, vous devez avoir cmake installé sur votre machine. Je n'ai pas encore fait les tests de compilation avec MSVC++ (si un problème se pose, il sera corrigé dans la prochaine version).
  • cd ekogen-0.3 && mkdir build
  • cmake ..
  • make && make test


Un petit framework simple de tests unitaire a été ajouté dans cette version (test/utest.h). Vous pouvez trouver des exemples d'utilisation dans le répertoire test/. Les groupes de fonctionnalités suivants sont testés :
  • la partie sécurité (dans security.cpp), y compris sha256, avec les 40 premiers vecteurs courts ; quand j'aurais le temps, j'ajouterais l'ensemble des tests nécessaires à la validation de sha256.
  • la partie encodeurs, dans encoder.cpp
  • la partie pipeline : les pipelines permettent d'enchainer des fonctions unaires, avec une syntaxe relativement simple (voir pipeline.cpp)
  • la partie functional, de peu d'intérêt pour vous, utilisée par les pipeline

Téléchargement
Compatibilité
Linux Mac Windows  


 Poster une réponse

Avatar de gorgonite gorgonite
http://www.developpez.com
Rédacteur/Modérateur
le 29/12/2010 19:14
quid du man-in-the-middle ?

par une attaque je me fais passer pour le serveur et je reste le seul à communiquer avec le véritable serveur... tu m'envoies ta clé publique, j'initie une communication avec le véritable serveur en lui envoyant la mienne, je déchiffre la clé de communication, et te l'envoie en la chiffrant avec ta clé publique, ensuite je te transmets les paquets tout en espionnant tout au passage

tu as prévu une sorte de certificat ou autre pour vérifier que tu parles bien au bon serveur ?
Avatar de Goten Goten
http://www.developpez.com
Membre Expert
le 29/12/2010 20:29
Bah openssl quoi.. Fin, bon, faut pas être allergique à l'interface.. Je vous le laisse
Avatar de Emmanuel Deloget Emmanuel Deloget
http://www.developpez.com
Expert Confirmé Sénior
le 30/12/2010 16:54
Citation Envoyé par Goten  Voir le message
Bah openssl quoi.. Fin, bon, faut pas être allergique à l'interface.. Je vous le laisse

C'est un peu pour ça que je l'ai encapsulé

tu as prévu une sorte de certificat ou autre pour vérifier que tu parles bien au bon serveur ?

La lib n'encapsule que ce qu'elle dit encapsuler

Il reste que le protocole final doit être mis au point par l'application (c'est elle qui gère la couche réseau ; la lib ne gère que l'encryption et la génération de clef)

Par contre, tu as raison : le protocole exposé en exemple est sensibles aux attaques MIM. Je vais voir pour utiliser le code X509 de OpenSSL).

Je vais revoir une partie du design pour faire en sorte que ça soit plus simple d'utilisation.
Avatar de Emmanuel Deloget Emmanuel Deloget
http://www.developpez.com
Expert Confirmé Sénior
le 04/01/2011 19:14
J'ai fait une sévère mise à jour (en fait, une réécriture, afin d'avoir une interface clean est cohérente).

J'ai aussi rajouté le cryptage privé / décryptage public sur les cryptographes asymétriques - ce qui permet d'implémenter des mécanismes de signature.
Avatar de Emmanuel Deloget Emmanuel Deloget
http://www.developpez.com
Expert Confirmé Sénior
le 10/01/2011 13:12
Nouvelle version (0.2), avec :

* une nouvelle fonction security::sha256 ainsi que ses overload.
* les encoders (base64, hex) ont été déplacés dans leur propre librairie

Je tiens à préciser que la structure du code (les packages, librairies) est susceptible d'évoluer très fortement dans le futur.
Avatar de Emmanuel Deloget Emmanuel Deloget
http://www.developpez.com
Expert Confirmé Sénior
le 16/01/2011 22:39
Je ne l'ai pas annoncé quand je l'ai posté, donc :

nouvelle version 0.3, avec la possibilité de construire des pipeline.
Avatar de Emmanuel Deloget Emmanuel Deloget
http://www.developpez.com
Expert Confirmé Sénior
le 18/01/2011 12:37
Version 0.4

1) Contenu du ChangeLog

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
        * added LICENCE, as well as a licence header to each source code file 
         
        * added src/core/bits/stdint_types.h to import standard integer types in  
          a portable way. 
 
        * moved pipeline_stage<> from src/core/pipeline.h to  
          src/core/bits/pipeline_stage.h 
 
        * CMakeLists.txt: check for <cstdint> or <tr1/ctsdint> presence, as well 
          as for the namespace in which standard integer types are declared. 
          Added _SECURE_SCL_NO_WARNINGS define for MSVC builds. 
 
        * src/core/bits/pipeline_stage.h: added bits::concatener<> and  
          bits::extracter<> to optimize the construction of pipeline stages. 
 
        * src/core/CMakeLists.txt: added header files to the source file list; 
          added the install() commands to install the library. 
 
        * src/core/pipeline.h: stageify1/2 have been renamed stage(). They now  
          construct the pipeline_stage<> using bits::concatener<> and  
          bits::extracter<> [BREAKING CHANGE] 
 
        * src/core/security_sha_digest.h: empty collections may implement 
          iterators that cannot be dereferenced (depending on the library vendor) 
          [BUG CORRECTION] 
 
        * src/ekogen_config.h.in: added the macros to support the use of 
          src/core/bits/stdint_types.h 
 
        * test/pipeline.cpp: added tests to verify the construction of optimized 
          pipeline_stage objects.  
 
        * test/security.cpp: logging the ekogen library version in the  
          corresponding unit test.
2) Construction de pipeline

Les fonctions ekogen::stageify1() et ekogen::stageify2() ont été renommées en ekogen::stage() (deux overload) afin de simplifier le code client.

La construction des pipelines a été améliorée. ekogen::stage() renvoie une instance de ekogen::bits::pipeline_stage<F1,F2>(), ou F1 et F2 sont des callables ; une version spécialisée ou F2 = ekogen::bits::nulltype existe, pour générer des pipeline à un élément. Les pipelines sont ensuite composés avec des appels successifs à la fonction stage(), ou via un opérateur | surchargé.

Ainsi, dans la version 0.3, (stage(f1) | stage(f2)) renvoie un pipeline_stage<pipeline_stage<F1,nulltype>,pipeline_stage<F2,nulltype> >. La nouvelle version va plus loin - elle est capable de détecter les "trous" (nulltype) dans les pipeline_stage<> considérés, et adapte le fonctionnement de stage() et de l'opérateur | en conséquence. Du coup, l'expression (stage(f1) | stage(f2)) renvoie maintenant une instance de pipeline_stage<F1,F2>.

Dans le cas ou un "trou" doit être rempli, l'instance construite peut "bouger" les fonctions, tout en respectant l'ordre dans lequel elles sont ajoutées. Les règles suivantes ont été implémentées (entre crochet, la version naîve, implémentée dans la version 0.3 de la librairie):

* operator|(ps<F1,F2>, F3) est équivalent à stage(ps<F1,F2>, F3)
* stage(F1) ==> ps<F1,null> [ ps<F1,null> ]
* stage(F1,F2) ==> ps<F1,F2> [ ps<F1,F2> ]
* stage(ps<F1,F2>) ==> ps<F1,F2> [ ps<ps<F1,F2>,null> ]
* stage(F1) | stage(F2) ==> ps<F1,F2> [ ps<ps<F1,null>,ps<F2,null>> ]
* stage(F1) | F2 ==> ps<F1,F2> [ ps<ps<F1,null>,F2> ]
* stage(F1) | F2 | F3 ==> ps<ps<F1,F2>,F3> [ ps<ps<ps<F1,null>,F2>,F3> ]
* stage(F1) | F2 | stage(F3) ==> ps<ps<F1,F2>,F3> [ ps<ps<ps<F1,null>,F2>,ps<F3,null>> ]
* stage(F1,F2) | stage(F3) ==> ps<ps<F1,F2>,F3> [ ps<ps<F1,F2>,ps<F3,null>> ]
* stage(F1) | stage(F2,F3) ==> ps<ps<F1,F2>,F3> [ ps<ps<F1,null>, ps<F2,F3> ]

On voit clairement l'amélioration sur la profondeur du code généré (non pas que ça posait des problèmes au runtime ; tout ou presque est inliné ; mais c'est quand même beaucoup plus propre et plus logique).

pipeline_stage<> n'est pas censé être utilisé tel quel. Il est bien évidemment possible d'évaluer l'expression définie (l'instance créée est une fonction unaire), voire d'écrire un code ressemblant à :

Code :
1
2
 
std::transform(in.begin(), in.end(), out.begin(), (stage(F1) | F2 | F3 | F4));
La classe ekogen::pipeline<> a été créée pour manipuler le pipeline résultant. Elle s'utilise ainsi :

Code :
ekogen::pipeline<R(A)> p(stage(F1) | F2 | ... | Fn);
* R est bits::callable_traits<Fn>::result_type
* A est bits::callable_traits<F1>::argument_type

Fi peut être un foncteur (qui doit alors hériter de std::unary_function<>) ou un pointeur sur fonction (j'ai oublié de traiter le cas des fonctions membres ; oups).

Il y a bien évidemment des améliorations à faire, mais l'interface ne devrait plus évoluer de manière significative. ekogen::pipeline<> pourrait être étendu (un opérateur () prenant en paramètres trois itérateurs (infirst, inlast, outfirst) pourrait avoir un intérêt), et la construction d'un pipeline pourrait être simplifiée encore, de manière à pouvoir écrire

Code :
ekogen::pipeline<R(A)> p = stage(F1) | ... | Fn;
Plutôt que de passer systématiquement par le constructeur.
Developpez.com décline toute responsabilité quant à l'utilisation des différents éléments téléchargés.
 
 
 
 
Partenaires

PlanetHoster
Ikoula