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

Mode arborescent

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

+ 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