IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Python 3.2 - Cryptage symétrique AES en mode CBC


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Juillet 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2013
    Messages : 16
    Par défaut Python 3.2 - Cryptage symétrique AES en mode CBC
    Bonjour,

    Mon but est la prise en main du cryptage avec python 3, j'ai donc parcouru le web ce week-end pour glaner des informations sur RSA / AES etc ... enfin ce qui pouvait ressembler à une possibilité d'encrypter des données texte pour les transmettre d'une manière la plus sécurisée possible .. sans parano non plus, juste faire en sorte que le truc soit bien chiant à lire quoi !

    Honnêtemment je n'y connais pas grand chose en cryptographie. Après plusieurs heures de recherche et collecte de code et d'infos, mes tentatives échouaient à cause de problème de longueur de blocs invalides ou autres erreurs de conversion dues aux exemples fournis en Python 2.7. Je n'ai trouvé que très peu d'exemples en python 3 et les méthodes de cryptage employées me paraissaient bancales par rapport à ce que j'avais pu lire sur AES / RSA ou autres hiéroglyphes du genre.

    J'ai enfin pu faire fonctionner le code ci-dessous qui accepte les caractères accentués style ISO 8859-1. En fait j'ai tout encapsuler en UTF-8 pour limiter les problèmes .. enfin je crois.

    Je souhaiterais savoir si je suis sur la bonne piste et surtout si la sécurisation des données est raisonnable, encore une fois je ne cherche par une solution théoriquement inviolable. N'hésitez pas à me remonter commentaires ou suggestions et surtout les anneries que j'aurais pu faire !

    merci d'avance.

    note : pour la suite je souhaite transmettre au destinataire, le mot de passe de décryptage codé toujours en session sécuriseé (TLS). Le mot de passe sera différent pour chaque message d'où le besoin qu'il ait d'être automatiquement décrypté sur le client. Il sera transmis sous cryptage asymétrique RSA avec une clé la plus solide possible sans toutefois pénaliser les performances. L'objectif est de transmettre des messages ou des volumes de données importants dans des délais raisonnables.

    @+ j'espère.

    Pour exécuter le code ci-dessous l'installation de PyCrypto (python 3) est nécessaire.

    Class Aes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
     
    import os, base64, hashlib
    from Crypto.Cipher import AES
     
    class Aes(object):
        '''
        Crypte / décrypte un texte donné en AES mode CBC. Accepte l'encodage base64.
        Encrypts input text string & decrypts bytes encoded string with or without base64 encoding
        
        Author: emmanuel.brunet@live.fr - 12/2013
        ''' 
     
        SALT_LENGTH = 64
        DERIVATION_ROUNDS=10000
        BLOCK_SIZE = 16
        KEY_SIZE = 256
        MODE = AES.MODE_CBC
     
        def encrypt(self, source, aes_key, outfile=None, base64_encode=False):
            '''
            Crypte l'entrée source en AES mode CBC avec sortie encodage base64 / fichier facultative
            
            
            @param bytes password: password in byte
            @param str plaintext: text to encode or text file path
            @parm str outfile: disk file to write encoded text to. defaults to None
            @param bool base64_encode: returns base64 encoded string if True (for emails) or bytes if False
            
            @return bytes ciphertext: the bytes encoded string.
            '''
     
     
            '''
            ----------------------------
            Traitement des entrées
            ----------------------------
            '''
            if os.path.exists(source):
     
                fp = open(source, 'rb')
                input_text = fp.read()
                fp.close()
     
            else:
     
                input_text = bytes(source, 'UTF-8')
     
            if input_text == b'':
                print('No data to encrypt')
                return
     
            padding_len = 16 - (len(input_text) % 16)         
            padded_text = str(input_text, 'UTF-8') + chr(padding_len) * padding_len
     
            '''
            ---------------------------------------------------------
            Calcul de la clé dérivée (derived_key). 
            ---------------------------------------------------------
            Elle permet d'utiliser la clé initiale (aes_key) plusieurs 
            fois, une pour chaque bloc à encrypter.
            ---------------------------------------------------------
            '''
     
            salt = os.urandom(self.SALT_LENGTH)
     
            derived_key = bytes(aes_key, 'UTF-8')     
     
            for unused in range(0,self.DERIVATION_ROUNDS):
     
                derived_key = hashlib.sha256(derived_key + salt).digest()
     
            derived_key = derived_key[:self.KEY_SIZE]
     
            '''
            ----------------
            Encryptage
            ----------------
            '''      
            # le vecteur d'initialisation doit être aléatoire
            iv = os.urandom(self.BLOCK_SIZE)
     
            cipherSpec = AES.new(derived_key, self.MODE, iv)
            cipher_text = cipherSpec.encrypt(padded_text)
            cipher_text = cipher_text + iv + salt
     
            '''
            -------------------------
            Traitement sortie
            -------------------------
            '''
            if outfile is None:
                '''
                Returns cipher in base64 encoding. Useful for email management for instance
                '''
                if base64_encode:
                    return(base64.b64encode(cipher_text))
                else:
                    return(cipher_text)
     
            else:
                '''
                Writes result to disk
                '''
     
                fp = open(outfile, 'w')
     
                if base64_encode:
                    fp.write(base64.b64encode(cipher_text))
                else:
                    fp.write(cipher_text)
     
                fp.close()
     
                print('Cipher text saved in', outfile)
     
     
        def decrypt(self, source, aes_key, outfile=None, base64_encode=False):
            '''
            @param bytes or str source: encrypted bytes string to decode or file path        
            @param bytes aes_key: password
            @parm str outfile: disk file to write encoded text to. defaults to None        
            @param bool base64_encode: cipher text is given base64 encoded (for mails content for examples)
            
            @returns str secret_text: the decoding text string or None if invalid key given
            '''
     
            '''
            ---------------------------
            Traitement des entrées
            ---------------------------
            '''
     
            if type(source) == str and os.path.exists(source):
     
                fp = open(source, 'rb')
                ciphertext = fp.read()
                fp.close()
     
            elif type(source) == bytes:
                ciphertext = source
     
            else:
                print('Invalid data source')
                return
     
            if base64_encode:
                encoded_text = base64.b64decode(ciphertext)
            else:
                # decodedCiphertext = ciphertext.decode("hex")
                encoded_text = ciphertext
     
            '''
            -------------------------
            Calcul de la clé dérivée
            -------------------------
            '''
     
            iv_start = len(encoded_text) - self.BLOCK_SIZE - self.SALT_LENGTH
            salt_start = len(encoded_text) - self.SALT_LENGTH
            data, iv, salt = encoded_text[:iv_start], encoded_text[iv_start:salt_start], encoded_text[salt_start:]
     
            derived_key = bytes(aes_key, 'utf-8')
     
            for unused in range(0, self.DERIVATION_ROUNDS):
                derived_key = hashlib.sha256(derived_key + salt).digest()
     
            derived_key = derived_key[:self.KEY_SIZE]
     
     
            '''
            -------------------------
            Décryptage
            -------------------------
            '''
            Cipher = AES.new(derived_key, self.MODE, iv)
            padded_text = Cipher.decrypt(data)
     
            padding_length = padded_text[-1]
            secret_text = padded_text[:-padding_length]
     
            '''
            Si le flux n'est pas décodé (mot de passe invalide),  la conversion UTF-8 plante ou au mieux on obtient un texte illisible
            '''
            try:
                secret_text = str(secret_text, 'utf-8')
            except:
                return
     
            if outfile is None:
     
                return(secret_text)
     
            else:
                '''
                Writes result to disk
                '''
                fp = open(outfile, 'w')
                fp.write(secret_text)
                fp.close()

    Exemple

    Fichier d'entrée : msg.txt
    Ce texte ne peut être lu qu'après déverouillage du contenu avec la clé appropriée dy style #12?%ù$}"'~;ï.

    sous python 3.2 (pas testé sous d'autres versions), placez vous dans le répertoire contenant le module developpez_crypto.py
    fourni en pièce jointe. Créez le fichier msg.txt dans ce même répertoire avec un éditeur de texte

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
    Python 3.2.3 (default, Sep 25 2013, 18:22:43) 
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from developpez_crypto import Aes
    >>> A = Aes()
    >>> A.encrypt('msg.txt', 'mdp#@%')
    b'\x87Mf#\xe0gd\xa8\x83\xbelo\x83p>\x1c\xeay\xb5w#\x1d\xcc\xf7\xb69\x95\xc8\xda\xbf\xc6~\x160\xa1}\x18\xa2%=\xb9\x12\x81\xa5\xcf\xc1\xf3\xabu\x10\xf2\xf8?\xe1\x93\xcdS\x1f\xb8\xec\xd1\x96{:qH\xbfO*]\x9e\xa1\x9c\xb2>=\x8e\xba\xef\x1d\xb9\x9c\xb8\xe0\xfc\xb2\xfa\x1b\x1c\xf7\x98.Rr=sz\x86\xe4g\xe1\x06 \xfa\xe5\xbaZ\xca\xe3\xf2q0h`^\xd8U\xdc\xde\xb84 x\x10\x19N\x14\xf0\xb8\xd3\xa3\xae\x0e\x0f\x8db\xd1\xde\x01\x94\xa66\xc9\x10\xb1\'+B\x88#\xb2\xf9\x92\xf8\xd7\xedT\xae\xfe\x93w\x15;W\x8fb\x1d\xdb\xc0\x97>4;\xb0"(\xf7u\xbfY\xedU}\xe3\x9bq\xe27\xa5\x7f\xae\xdds\xa1\xc8\x95\xc8sG\xdb\n\xdb\xa2Q\xe2\xfe4\xfa'
    >>> A.encrypt('msg.txt', 'mdp#@%')
    b'g\xe7~\xce\x15\x16\xf1,u\x91\xb3j\x81\x8b\x8e\xc2<\x9bj5\xa3\xb4\xf8w\xc4\x83\xac\x89\xd5\xc89[\xc3@2^LlV\xef\xdf\xc5Je\xb9y\x0c\xfb\xd7\x1fs\xef\x88\xff\x7f\xe4\x8f\xb5R\x067\x10\xd6$\xee/<\xf5\x0c\xa2\xad7\xe3f\xb8\x15\x83v\x94\xd5 \xbf\x9f\xa7\x0bqL\xca\xb9\x9d\x89"\x0b\xd8\x13\x87\xbf!\x0e#\xb6\xee\x1d\xa4%*\xc2]\xdfO\x1c\x05\x99\x15\xea\xa5\xe9y!F%\x1aI*y\x9e=i\xe2\xaeb\xa5\xc7\xe4\xadsY\xdc\xeen\x8c\xa3\xfd\xef2\xa2V\xaa\xb24\x06+\xff\xe6\xdd\x8d\xdc\x07\xc9\x11,\xb4\x91\xb0\x1et\x06\xa7\xb5Lg\xeex\xb2\x83\r\x10]\x90c\x98\x04w\xa2s72\xbb\xbc)j\x931-\xdbw\xf0\x1aS\x80\xa9W\x19\x0c\xf7\x9f\xc6\xa2'
    Comme vous le voyez le résultat est différent à chaque exécution. C'est l'intérêt de la clé dérivée ... génial non ?.

    Maintenant on encode et on décode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    >>> cipher = A.encrypt('msg.txt')
    >>> cipher
    b"\xc4\xc6p\xf9\xc0Pk8\xed\xec\x1a\x0eF\xc2n\xd0\x17m\xb1)i\x17y\xb4\x8a\xf9\xee\xc7\xb1y;\x90\x84A6\xc1n\x16\xe9\x8cf\xe8\x0cjG\x89\xc0\x9ay\x96\xb5\xf24\xb4n\xb0.\xce/\xec\x00\x83r/Bs\x95P\xe7\xfdL\xe5V}$\x93\x98\xbb\xabu\x97\x91!\xfd\xf6\x97\xc7q\x97\xd2\xcf:)<\xa1F\xacp\xf5hp\x1e\xe9\xd9\xf8\x12xp\xab\x8fh\x93\xf0c\x9e8-\x1d\x1b\xa2\xadC\xdd\x1f\xbf\xa4\xd2\x16\x9e\xbfm\xb4\xdd\x8f\xab\xd8\x80q\xd9A\xb7\x1b\xcej\x1f~3eH\x82Q\x81}\x0c\x0b\xeeo\xd3*\xc5\xcc\xa2k{\xefG\x8c\xa1\xb3\xfb?\xb61D\xe7\x9d\x99n\xe9\x1bq'i$\xfcP\xa7s[\x19\xcal\x0cD\xbb\x7f\x98I\xb8\xd2\xf6.\xec\x89\xab\xdf(\x1e"
     
    >>> print(A.decrypt(cipher, 'mdp#@%'))
    Ce texte ne peut être lu qu'après déverouillage du contenu avec la clé appropriée dy style #12?%ù$}"'~;ï.
    En fait le plus galère ça a été la gestion de l'encodage, et je ne sais pas si c'est vraiment nikel .... donc encore une fois merci de votre retour.
    Fichiers attachés Fichiers attachés

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Salut,
    Je souhaiterais savoir si je suis sur la bonne piste et surtout si la sécurisation des données est raisonnable, encore une fois je ne cherche par une solution théoriquement inviolable.
    Pourquoi ne pas utiliser une solution qui fonctionne plutôt qu'en coder une qui sera douteuse?

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre averti
    Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Juillet 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2013
    Messages : 16
    Par défaut
    merci de ta réponse.
    Certainement, je suis en phase avec toi c'est beaucoup plus efficace et sûre. Mais c''est justement ce que je n'ai pas trouvé .

    Peut être ai-je mal cherché.
    Je précise aussi que je souhaite pouvoir intégrer ces fonctions dans mes programmes python existants , pas simplement envoyer un fichier texte encodé en pièce jointe via un mail, mais pouvoir encoder dynamiquement des données inter-programmes.

    Et merci je vais regarder plus en profondeur ou sont les failles de sécurité

  4. #4
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    Citation Envoyé par jeby6372 Voir le message
    merci de ta réponse.
    Certainement, je suis en phase avec toi c'est beaucoup plus efficace et sûre. Mais c''est justement ce que je n'ai pas trouvé .
    openssl fait ca de de base (cf enc command): http://www.openssl.org/docs/apps/enc.html

    Citation Envoyé par jeby6372 Voir le message
    Et merci je vais regarder plus en profondeur ou sont les failles de sécurité
    J'ai survole rapidement la source et j'ai rien vu d'evident (je suis loin d'etre un expert non plus). L'iv et salt sont correctement generes, et ton pbkdf2 du pauvre a l'air ok a premiere vue. J'imagine egalement que la fonction Cipher.decrypt() s'execute en temps constant fonction de la longueur du message.

    Apres question performance tu peux sans doute reduire SALT_LENGTH, car la taille recommendee est 64 bits et non bytes. Pareil pour ton nombre d'iterations sur le calcul de ta cle intermediaire. Apres si tu t'en fous des perfs (ce qui a l'air d'etre le cas, vu l'application), plus c'es toujours mieux

    T'as resolu la partie facile, maintenant reste a partager la cle... Tu as l'air de vouloir utiliser RSA. J'espere que la ou tu veux utiliser ca, t'as une PKI .

  5. #5
    Membre averti
    Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Juillet 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2013
    Messages : 16
    Par défaut
    T'as resolu la partie facile, maintenant reste a partager la cle... Tu as l'air de vouloir utiliser RSA. J'espere que la ou tu veux utiliser ca, t'as une PKI .
    pour ça je vais regarder du côté des DH key exchange, merci pour ton retour

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Citation Envoyé par jeby6372 Voir le message
    Je précise aussi que je souhaite pouvoir intégrer ces fonctions dans mes programmes python existants , pas simplement envoyer un fichier texte encodé en pièce jointe via un mail, mais pouvoir encoder dynamiquement des données inter-programmes
    Chiffrer dynamiquement les données inter programme, encrypter des messages qui devront être "stockes" s'approchent différemment: les attaques n'ont pas le même profil.

    Peut être ai-je mal cherché.
    Pour ces deux cas, TLS et PGP sont un bon point de départ.
    Ils sont relativement faciles a mettre en œuvre depuis Python.

    On peut coder ses propres algo. mais arriver a prouver qu'ils sont robustes est un exercice a plusieurs passes: pas la peine de coder un algo. qui ne tient déjà pas la route sur le papier.
    Si vous débutez en sécurité, vous n'imaginez pas le travail de fou furieux que ça représente. Et quelle sera l’utilité de construire et utiliser des codes dans lesquels vous même n'aurez pas confiance?
    N'est-il pas plus profitable d’améliorer les fonctionnalités "metiers" de l'application plutôt que de le passe a coder cela?

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre averti
    Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Juillet 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2013
    Messages : 16
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Pour ces deux cas, TLS et PGP sont un bon point de départ.
    Ils sont relativement faciles a mettre en œuvre depuis Python.
    Je ne connaissais pas PGP. je vais regarder de cé côté, merci beaucoup pour le coup de main

  8. #8
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    Citation Envoyé par jeby6372 Voir le message
    pour ça je vais regarder du côté des DH key exchange, merci pour ton retour
    DH est compromissible par MITM. En effet si tu vois l'echange DH, rien ne t'empeche d'envoyer des premiers que tu choisis au 2 cotes de la transaction. Sauf si tu ajoutes une surcouche d'authentification, mais retour a la case PKI.
    Mais ca resouds partiellement le probleme de l'echange de cles, surtout si le MITM n'est pas un probleme pour toi.

    Citation Envoyé par jeby6372 Voir le message
    Je ne connaissais pas PGP. je vais regarder de cé côté, merci beaucoup pour le coup de main
    PGP ne resouds pas le probleme de gestion des cles, c'est une forme de PKI decentralisee.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Cryptage symétrique - longueur clé invalide
    Par mikado10 dans le forum Sécurité
    Réponses: 1
    Dernier message: 27/12/2012, 12h55
  2. cryptage/décryptage AES / open SSL avec VB6 ?
    Par Popaul22 dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 24/01/2010, 16h04
  3. Système de cryptage symétrique
    Par epeichette dans le forum Langage
    Réponses: 5
    Dernier message: 23/11/2008, 02h49
  4. Triple DES Mode CBC décryptage
    Par nathieb dans le forum Sécurité
    Réponses: 2
    Dernier message: 05/11/2008, 17h12
  5. Cryptage symétrique en C++
    Par demonia dans le forum C++
    Réponses: 5
    Dernier message: 12/12/2007, 19h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo