Contexte: j'essaie un programme qui capture certains messages MQTT puis les enregistre. En faisant cela, je rencontre un problème étrange et j'ai besoin d'aide.

Dans les messages entrants, j'obtiens une chaîne codée en base64. Mon programme essaie de décoder et d'analyser les données binaires pour comprendre certains en-têtes du paquet. Le code que j'ai ressemble à ceci:

result = base64.standard_b64decode("AO/Nq4lnRSMBZXMnLHcKXhSObYxiFvY=")

La sortie du résultat ressemble à ceci:

b"\x00\xef\xcd\xab\x89gE#\x01es',w\n^\x14\x8em\x8cb\x16\xf6"

Si la même opération est effectuée à l'aide d'une implémentation nodeJS, la sortie est assez différente:

<Buffer 00 ef cd ab 89 67 45 23 01 65 73 27 2c 77 0a 5e 14 8e 6d 8c 62 16 f6>

J'ai lu quelques autres liens dans le débordement de la pile et je ne pouvais pas comprendre pourquoi la différence existe. Le lien NodeJS base64 Vs Python base64 contient des points valides par rapport au l'encodage qui a été fait, donc ce que Python fait ici n'est pas faux.

En lisant plus loin, j'ai trouvé une autre astuce où une fonction binascii a été utilisée. Donc, si j'applique cette logique, ma sortie ressemble exactement à la sortie NodeJS!

import binascii
binascii.hexlify(result)
b'00efcdab89674523016573272c770a5e148e6d8c6216f6'

Maintenant, ma sortie ressemble à ce que je veux. Cependant, il y a un autre nouveau problème. La sortie du décodage base64 était au format b '\ x00' tandis que la sortie de hexlify est b'0 '. En raison de cette différence, je ne peux pas exécuter l'autre partie de mon code qui divise cet octet de sortie octet pour faire struct.unpack dans différents formats en fonction de l'en-tête du paquet.

Puis-je obtenir de l'aide pour continuer?

1
Sharath Chandra 19 mars 2019 à 16:36

2 réponses

Meilleure réponse

Si je comprends bien, vous êtes confus par le formatage Python des octets.

Fondamentalement, lors de l'affichage d'un octet en Python, si cet octet correspond à un caractère ASCII, le caractère est utilisé à la place de la valeur numérique. Les résultats sont en fait les mêmes en Python et NodeJS, seule la représentation diffère.

Vous pouvez le vérifier en alignant les deux représentations:

b"    \x00\xef\xcd\xab\x89  g  E  #\x01  e  s  '  ,  w \n  ^\x14\x8e  m\x8c  b\x16\xf6"
<Buffer 00  ef  cd  ab  89 67 45 23  01 65 73 27 2c 77 0a 5e  14  8e 6d  8c 62  16  f6>

Comme vous pouvez le voir, les valeurs sont identiques à l'exception de:

67 -> g
45 -> E
23 -> #
65 -> e
73 -> s
27 -> '
2c -> ,
0a -> \n
5e -> ^
6d -> m

Le fait est que chaque valeur hexadécimale affichée ci-dessus correspond à un caractère de la table ASCII.

Vous pouvez le vérifier facilement dans un interpréteur Python (ord donne le code ascii du caractère donné et hex le convertit en représentation hexadécimale):

>>> hex(ord('g'))
'0x67'
>>> hex(ord('E'))
'0x45'
>>> hex(ord('#'))
'0x23'

Enfin, vous pouvez même obtenir exactement la même représentation que NodeJS dans quelques lignes de Python:

>>> bytes = b"\x00\xef\xcd\xab\x89gE#\x01es',w\n^\x14\x8em\x8cb\x16\xf6"
>>> print('<Buffer {}>'.format(' '.join([format(c, '02x') for c in bytes])))
<Buffer 00 ef cd ab 89 67 45 23 01 65 73 27 2c 77 0a 5e 14 8e 6d 8c 62 16 f6>
1
Tryph 19 mars 2019 à 14:56

base64.standard_b64decode renvoie un bytes object, qui est une séquence immuable d'octets uniques. Ceci est indiqué par la lettre b avant le ".

À partir de la docs :

Les littéraux d'octets sont toujours préfixés par 'b' ou 'B' ; ils produisent une instance du type bytes au lieu du type str. Ils ne peuvent contenir que des caractères ASCII ; les octets avec une valeur numérique de 128 ou plus doivent être exprimés avec des échappements.

Ce que vous voyez ici est la représentation ASCII de l'objet bytes, pas une chaîne.

Afin de convertir un objet bytes en une chaîne similaire au résultat que vous obtenez de nodeJS, vous pouvez utiliser la méthode objet bytes hex :

import base64

result = base64.b64decode(b"AO/Nq4lnRSMBZXMnLHcKXhSObYxiFvY=")

print(result.hex())

>>> 00efcdab89674523016573272c770a5e148e6d8c6216f6
0
Jacques Gaudin 20 mars 2019 à 10:00