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

Bibliothèques tierces Python Discussion :

Problème de chiffrement des caractères spéciaux avec PyCrypto


Sujet :

Bibliothèques tierces Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2015
    Messages : 50
    Points : 25
    Points
    25
    Par défaut Problème de chiffrement des caractères spéciaux avec PyCrypto
    Bonjour à vous,

    j'essaye de chiffrer un fichier texte avec PyCrypto et de l'envoyer à travers un réseau depuis un serveur vers un client.
    Le chiffrement utilisé est AES 16bytes.
    Si j'ai bien compris, le nombre de caractères du texte à chiffrer doit être un multiple de 16.
    J'ai donc mis dans mon code une fonction qui rempli le fichier avec le caractère '{' pour arriver à un multiple de 16 et je les retire à la réception dans le client.

    Je parviens à chiffrer mon fichier et à l'envoyer du serveur au client et à le déchiffrer.

    MON PROBLÈME:
    le fichier peut contenir des caractères comme () {} [] sans problème mais si il contient des caractères spéciaux du style é " è ' ç etc.. une erreur apparaît sur le serveur :
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/Crypto/Cipher/blockalgo.py", line 244, in encrypt
    return self._cipher.encrypt(plaintext)
    ValueError: Input strings must be a multiple of 16 in length


    Comment puis-je chiffrer un fichier contenant des caractères spéciaux et accentués ?



    Voici le code de mon serveur

    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
     
    # -*- coding: utf-8 -*-
    from Crypto.Cipher import AES
    import socket
    import threading
     
    #configuration AES
    key = "AAAAAAAAAAAAAAAA"
    cipher = AES.new(key)
     
    def pad (s):
        return s + ((16-len(s)%16)*'{')
     
    def encrypt(plaintext):
        global cipher
        return cipher.encrypt(pad(plaintext)).encode('utf-8')
     
    class ClientThread(threading.Thread):
     
        def __init__(self, ip, port, clientsocket):
     
            threading.Thread.__init__(self)
            self.ip = ip
            self.port = port
            self.clientsocket = clientsocket
            print("[+] Nouveau thread pour %s %s" % (self.ip, self.port, ))
     
        def run(self):
            print("Connection de %s %s" % (self.ip, self.port, ))
            r = '/Users/macbookpro15/Desktop/test.conf'
            fichier = open(r, 'r')
            f = fichier.read()
            data = encrypt(f)
            fichier.close()
            self.clientsocket.send(data)
            print("Client déconnecté...")
            self.clientsocket.close()
     
    tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    tcpsock.bind(("192.168.1.2",1111))
     
    while True:
        tcpsock.listen(10)
        print( "En écoute...")
        (clientsocket, (ip, port)) = tcpsock.accept()
        newthread = ClientThread(ip, port, clientsocket)
        newthread.start()

    MERCI pour vos attentions

  2. #2
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    Et si tu fais l'encodage utf-8 avant de compléter à 16 caractères ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    >>> t = "déjà vu"
    >>> len(t)
    7
    >>> tt = t.encode('utf-8')
    >>> tt
    b'd\xc3\xa9j\xc3\xa0 vu'
    >>> len(tt)
    9

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2015
    Messages : 50
    Points : 25
    Points
    25
    Par défaut
    Bonjour VinsS,

    Merci de ta réponse rapide.
    Je n'ai que quelques minutes de libres aujourd'hui pour cela mais j'ai essayé l'encodage utf-8 avant le remplissage.

    d'abord l'encodage utf-8
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
            r = '/Users/macbookpro15/Desktop/test.conf'
            fichier = open(r, 'r')
            fich = fichier.read()
            f = fich.encode('utf-8')
            data = encrypt(f)
            fichier.close()
    puis le chiffrement (qui appelle la fonction de remplissage = pad)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    def encrypt(plaintext):
        global cipher
        return cipher.encrypt(pad(plaintext)).encode('utf-8')
    et la fonction de remplissage en question
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    def pad (s):
        return s + ((16-len(s)%16)*'{')
    Seulement j'obtiens un nouveau message d'erreur:
    File "/Users/macbookpro15/Desktop/PycharmProjects/VoIP2/PyCryptoServeur.py", line 11, in pad
    return s + ((16-len(s)%16)*'{')
    TypeError: can't concat bytes to str
    Je suis novice en python, et je ne maîtrise pas les encodages et les notion de binaire, str etc..
    et je réalise une application graphique en python pour mon stage... avec bcp d'autres travaux à effectuer sur le côté, je n'ai donc pas trop de temps pour approfondir.
    Ton aide est donc vraiment bienvenue.

    Encore un grand merci à toi.

  4. #4
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Je ne faisais qu'émettre une idée, il fallait la mettre en forme.

    Par exemple en modifiant la fonction pad()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    >>> def pad(txt):
    ...     while len(txt.encode('utf8')) < 16:
    ...             txt += '{'
    ...     return txt
    ... 
    >>> print(pad('déjà vu'))
    déjà vu{{{{{{{

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2015
    Messages : 50
    Points : 25
    Points
    25
    Par défaut
    Bonjour VinsS,
    Merci de ton suivi!!

    j'ai testé ta proposition avec toutes les variantes que j'ai pu trouver, mais cela ne fonctionne toujours pas.

    Si je teste ta mise en forme dans la fonction pad comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    def pad (s):
        while len (s.encode('utf-8')) < 16:
                s += '{'
        return s
    avec la fonction de chiffrage
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    def encrypt(plaintext):
        global cipher
        return cipher.encrypt(pad(plaintext))
    et sans encoder le contenu de mon fichier au préalable
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
            r = '/Users/macbookpro15/Desktop/test.conf'
            fichier = open(r, 'r')
            fich = fichier.read()
            data = encrypt(fich)
            fichier.close()
            self.clientsocket.send(data)
    j'obtiens tjs la même erreur
    Input strings must be a multiple of 16 in length

    Et si j'encode le contenu du fichier au préalable, comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
            r = '/Users/macbookpro15/Desktop/test.conf'
            fichier = open(r, 'r')
            fich = fichier.read()
            f = fich.encode('utf-8')
            data = encrypt(f)
            fichier.close()
            self.clientsocket.send(data)
    la fonction pad ne fonctionne plus car elle reçoit des bytes au lieu de str (si je dis pas de conneries)
    File "/Users/macbookpro15/Desktop/PycharmProjects/VoIP2/PyCryptoServeur.py", line 12, in pad
    while len (s.encode('utf-8')) < 16:
    AttributeError: 'bytes' object has no attribute 'encode'

    et je ne peux évidemment pas encoder en utf-8 après le chiffrement..
    Donc quelle solution me reste-il?

    As-tu une petite explication de la logique à avoir pour résoudre mon problème.

    Bien à toi,
    Nils.

  6. #6
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Peut-être dépasses-tu les 16 caractères.

    Que contient exactement le fichier ? N'y a-t-il pas un retour ligne ?

    De toutes façon il est bien d'ajouter une vérification et d'émettre un message d'erreur en cas de dépassement.

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2015
    Messages : 50
    Points : 25
    Points
    25
    Par défaut
    Ce sont des fichier de configuration d'un serveur Asterisk (VoIP), donc des fichier .conf qui se trouvent sur un Débian et que je télécharge sur mon macbook.
    Il y a donc un script 'serveur' sur le Debian et un script client sur mon mac, tous deux en python 3.4 et qui s'occupent du chiffrement et du transfert de fichier.

    un fichier .conf ressemble à ceci (qui n'est qu'une partie d'un des fichiers):
    ;
    ; User configuration

    [general]
    fullname = New User
    userbase = 6000
    hasvoicemail = yes
    vmsecret = 1234
    hassip = yes
    hasiax = yes
    ;hash323 = yes
    hasmanager = no
    callwaiting = yes
    threewaycalling = yes
    callwaitingcallerid = yes
    transfer = yes
    canpark = yes
    cancallforward = yes
    callreturn = yes
    callgroup = 1
    pickupgroup = 1
    ;nat = yes
    Il y a donc bien des retours à la ligne (\n)

    Le problème peut venir de là? J'arrive pourtant à chiffrer et transférer ces fichiers .conf tant qu'ils ne contiennent pas de caractères spéciaux ou accentués.
    Heu.... je ne vois pas bien comment je peux obtenir un dépassement !?

  8. #8
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Si tu passes la totalité du fichier, c'est sûr que tu dépasses les 16 caractères ...

    Si tu veux les données après le signe = tu peux faire quelque chose comme ceci:
    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
     
    >>> with open('dat.txt', 'r') as inf:
    ...     for line in inf:
    ...             try:
    ...                     print(line.split('=')[1].strip())
    ...             except:
    ...                     pass
    ... 
    New User
    6000
    yes
    1234
    yes
    yes
    yes
    no
    yes
    yes
    yes
    yes
    yes
    yes
    yes
    1
    1
    yes
    >>>
    À toi de voir ce que tu as besoin comme données.

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2015
    Messages : 50
    Points : 25
    Points
    25
    Par défaut
    Oui je dépasse les 16 caractères, le but est de crypter et transférer tout le fichier!
    C'est pour cela que j'utilisais ma fonction pad de départ:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    def pad (s):
        s = s + ((16-len(s)%16)*'{')
        print (type(s))
        print(s)
        return s
    Cette fonction de remplissage (def pad(s)) semble fonctionner vu le print() du fichier après celle-ci (on y voit des symboles '{' ).
    (le premier print() est le fichier original venant d'être lu (fichier.read), le second est ce fichier après la fonction pad(), et le troisième correspond aux données chiffrées)
    En écoute...
    [+] Nouveau thread pour 192.168.1.2 63664
    Connection de 192.168.1.2 63664
    En écoute...

    [2002]
    type=friend
    host=dynamic
    dtmfmode=rfc2833
    disallow=all
    fullname = GUYVER
    username = GUYVER9999
    secret=0107
    context = work
    allow=g729
    allow=gsm
    allow=ulaw
    allow=h263
    allow=h263p



    <class 'str'>

    [2002]
    type=friend
    host=dynamic
    dtmfmode=rfc2833
    disallow=all
    fullname = GUYVER
    username = GUYVER9999
    secret=0107
    context = work
    allow=g729
    allow=gsm
    allow=ulaw
    allow=h263
    allow=h263p


    {{{{{
    <class 'bytes'>
    b"R\xbf'@\xccy\xe42}\xea#\xfa\xc5$A\xa8#Bp\x85HD*\x88\xde^\xe3\x9dz1\x95\xfa\x96\xee\xf1\xc1\x97\x02\xab\xb8\xc5\xb1\x0e\x12\xfd6Z\xacVN\xa2\r\x17\xf5\xba\xe7P\xe7\x17\x8b,\xbe\xa2Y\xf6]r\xdd\x9bo4A\x1f\x9f\x93\\\x81&:\x00\xebD\xdf\xd9\xb1N\xac8o\x03\xd9\xde\xc9\xa79oq\xaeP\x7f\xd6\x07\x0c\x13\xcc\x90\x1a\xd6k\xd0o\xe0\x04\xd4\x9e?]\xb98\xb6l\xee\x1f\\;\xfbLT &\x80[|\xa5s\xb3#b\xfb1%U\x15\xd9ca\x14-$\xa1zr\xddzl\xb0\xa1\xc5DW\xafH\xe1\x87\x96\xfd\xe5u\x942\xc7\xf5kC\xe5Po*\x9b)t\x0f.t\x865F\xaeH7\x821"
    Client déconnecté...
    Le dernier correspond bien à un texte chiffré?

    Merci pour ton exemple, je l'utiliserai sans doute quand j'arriverai aux opérations sur les fichier!! pour l'instant j'aimerais avoir un chiffrement correct ..

  10. #10
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Oops, c'est moi qui ai mal capté, je pensais que tu cryptais par paquets de 16.

    Alors ta fonction avec modulo est bonne, suffit d'adapter à l'encodage.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    def pad(s):
        m = len(s.encode('utf8')) % 16
        if m:
            s += '{' * (16 - m)
        return s
    en procédant ainsi on évite de rajouter 16 '{' lorsque la chaîne est déjà multiple de 16.

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2015
    Messages : 50
    Points : 25
    Points
    25
    Par défaut
    Mais OUIIII!!!
    pourquoi n'y ais-je pas pensé?!

    C'est simple et efficace, cela fonctionne très bien. MERCI!


    m est donc un booléen dans ce cas !? si il est égal à zéro, il ne fait pas les instructions du if, c'est bien cela?

    Puis-je te demander ton avis, j'aimerais améliorer le chiffrement qui me parait trop minimaliste, je ne suis même pas certain qu'il chiffre réellement le message....
    un même message est à chaque fois chiffré (si il l'est) de la même façon:

    Ce message:
    [2002]
    type=friend
    host=dynamic
    dtmfmode=rfc2833
    disallow=all
    fullname = GUYVER
    username = GUYVER9999
    secret=0107
    context = work
    allow=g729
    allow=gsm
    allow=ulaw
    allow=h263
    allow=h263p
    &!çàéè

    {{{{{{{{{{{
    donne toujours ce même message chiffré:
    b"R\xbf'@\xccy\xe42}\xea#\xfa\xc5$A\xa8#Bp\x85HD*\x88\xde^\xe3\x9dz1\x95\xfa\x96\xee\xf1\xc1\x97\x02\xab\xb8\xc5\xb1\x0e\x12\xfd6Z\xacVN\xa2\r\x17\xf5\xba\xe7P\xe7\x17\x8b,\xbe\xa2Y\xf6]r\xdd\x9bo4A\x1f\x9f\x93\\\x81&:\x00\xebD\xdf\xd9\xb1N\xac8o\x03\xd9\xde\xc9\xa79oq\xaeP\x7f\xd6\x07\x0c\x13\xcc\x90\x1a\xd6k\xd0o\xe0\x04\xd4\x9e?]\xb98\xb6l\xee\x1f\\;\xfbLT &\x80[|\xa5s\xb3#b\xfb1%U\x15\xd9ca\x14-$\xa1zr\xddzl\xb0\xa1\xc5DW\xafH\xe1\x87\x96\xfd\xe5u\x942\xc7\xf5kC\xe5P\x8f7\xc5\x81\x14\xda\xfacuP\x7fV\xe6\xfc[\x89\xbc\xe4\xf9=,\xb6\x94\xe8\xa0\x9b\xdd\x0c\x93,wD"

    Je chiffre en AES mais je n'ai indiqué aucun mode (CBC, CFB etc..) et j'aimerais que le chiffrement soit aléatoire (un message pas chiffré deux fois de la même manière)
    Je peux enfin passer plus de temps à l'étude du chiffrement... As-tu des conseils de références à lire sur le sujet?

    Encore merci pour ton suivi, VinsS.

  12. #12
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Regarde ici http://www.laurentluce.com/posts/pyt...with-pycrypto/
    il propose une série d'exemples de cas d'usage différents, dont avec Crypto.Random

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2015
    Messages : 50
    Points : 25
    Points
    25
    Par défaut
    J'ai utilisé son exemple pour chiffrer en AES_CFB
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    key = "BBBBBBBBBBBBBBBB"
    iv = Random.get_random_bytes(16)
    cipher = AES.new(key, AES.MODE_CFB, iv)
    mais à la réception du fichier avec le script-client,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #configuration AES
    key = "BBBBBBBBBBBBBBBB"
    iv = Random.get_random_bytes(16)
    cipher = AES.new(key, AES.MODE_CFB, iv)
     
     
    def decrypt(ciphertext):
        global cipher
        dec = cipher.decrypt(ciphertext).decode('utf-8')
        l = dec.count('{')
        return dec[:len(dec)-l]
        return dec
    j'obtiens une erreur de décodage..
    dec = cipher.decrypt(ciphertext).decode('utf-8')
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 0: invalid start byte
    et je comprends pas trop d'où ça vient..
    est-ce le vecteur d'initialisation iv qui peut poser problème?

Discussions similaires

  1. problème d'affichage des caractères spéciaux avec la console Dos
    Par javass dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 14/05/2008, 17h58
  2. [AJAX] Affichage des caractères spéciaux
    Par mitmit dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 24/04/2007, 13h47
  3. [XPath] Problème pour rechercher des caractères spéciaux
    Par JolyLoic dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 13/12/2006, 13h41
  4. Réponses: 3
    Dernier message: 24/10/2006, 11h05
  5. traitement des caractères spéciaux avec XSLT
    Par Mirgue dans le forum XSL/XSLT/XPATH
    Réponses: 5
    Dernier message: 19/07/2004, 16h57

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