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
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 ?.
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'
Maintenant on encode et on décode :
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.
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?%ù$}"'~;ï.
Partager