L'encodage Base64

base64 est un système d'encodage qui convertit des données binaires en texte.

L'objectif est de pouvoir transmettre du binaire via des protocoles textuels (plaintext protocols).

Le format est défini dans le RFC 4648.

Un sous-ensemble de 65 caractères ASCII est utilisé (A-Z, a-z, 0-9, +, / et =) :

  • des séquences de 6 bits sont converties en un des 64 caractères possibles
  • le 65è caractère (signe =) est utilisé comme caractère de rembourrage (padding)

Pourquoi des séquences de 6 bits ?

Parce qu'on a voulu utiliser ASCII qui est universellement accepté et dont chacun des caractères n'occupe qu'un seul octet en UTF-8.

Pour comprendre, il faut visualiser les données en entrée comme un flux de bits plutôt que comme une séquence d'octets.

Par exemple, la chaîne Hello! donne le flux binaire suivant (echo -n "Hello!" | xxd -b) :

010010000110010101101100011011000110111100100001

Si des séquences de 4 bits étaient utilisées pour représenter les données en sortie, on aurait besoin d'un alphabet de 16 valeurs (24) et on pourrait utiliser l'hexadécimal :

0100 1000 0110 0101 0110 1100 0110 1100 0110 1111 0010 0001
4    8    6    5    6    c    6    c    6    f    2    1

On se retrouverait alors avec deux octets de texte ASCII en sortie pour chaque octet en entrée, soit un surcoût de 100 %.

Des séquences de 7 bits nécessiteraient un alphabet de 128 valeurs (27).

Or 128 valeurs représentent la totalité des 128 caractères ASCII, parmi lesquels 95 seulement sont imprimables.

Donc le meilleur compromis pour pouvoir utiliser un jeu ASCII de caractères imprimables est d'utiliser des séquences de 6 bits qui nécessitent un alphabet de 64 caractères (26) :

010010 000110 010101 101100 011011 000110 111100 100001
S      G      V      s      b      G      8      h

On se retrouve alors avec 4 octets de texte ASCII en sortie pour 3 octets en entrée, soit un surcoût de 33 % (un tiers).

Mécanisme d'encodage base64

Mécanisme :

  • 3 octets de données binaires en entrée (24 bits)
  • divisés en 4 séquences binaires de 6 bits (24 bits)
  • convertis en 4 octets de texte ASCII (32 bits)
+------------------------------------------------------------------------+
| Bits           |         8        |         8       |         8        |
| Input ASCII    |         A        |         A       |         A        |
+------------------------------------------------------------------------+
| Binary         | 0 1 0 0 0 0 | 0 1 0 1 0 0 | 0 0 0 1 0 1 | 0 0 0 0 0 1 |
| Bits           |      6      |      6      |      6      |      6      |
+------------------------------------------------------------------------+
| Decimal (0-64) |     16      |     20      |      5      |      1      |
+------------------------------------------------------------------------+
| Output Base64  |      Q      |      U      |      F      |      B      |
| Bits           |      8      |      8      |      8      |      8      |
+------------------------------------------------------------------------+

L'encodage opère sur des groupes successifs de 24 bits car c'est le plus petit commun multiple entre des segments de 8 bits et de 6 bits.

Rembourrage et caractère =

Si une séquence binaire en entrée est plus petite que 24 bits, des 0 lui sont ajoutés pour la rembourrer (padding).

Si un groupe de 6 bits est entièrement rembourré de 0, il est représenté par le caractère = en sortie :

+------------------------------------------------------+
| ASCII          |         A        |        A         |
+------------------------------------------------------+-------------------+
| Binary         | 0 1 0 0 0 0 | 0 1 0 1 0 0 | 0 0 0 1   0 0 | 0 0 0 0 0 0 |
+------------------------------------------------------+-------------------+
| Decimal (0-64) |     16      |      6      |    4    |
+------------------------------------------------------+-------------------+
| Base64         |      Q      |      U      |    E          |      =      |
+------------------------------------------------------+-------------------+

C'est pourquoi la sortie ASCII de base64 contient toujours des suites de 4 caractères :

$ echo -n "A" | base64
QQ==

$ echo -n "AA" | base64
QUE=

$ echo -n "AAA" | base64
QUFB

$ echo -n "AAAA" | base64
QUFBQQ==

Erreur Incorrect padding en Python

Une chaîne en base64 correctement rembourrée a donc une longueur qui doit être un multiple de 4.

Si ça n'est pas le cas, Python vous le fera savoir :

>>> import base64

>>> base64_str = "V2VzaCBsZXMgcGluZ291aW5zIQ"
>>> base64.b64decode(base64_str).decode()

binascii.Error: Incorrect padding

On peut y remédier en rembourrant manuellement :

>>> base64_str += "=="
>>> base64.b64decode(base64_str).decode()

'Wesh les pingouins!'

Avant Gestion ennuyeuse des dépendances Python

Tag Kemar Joint