À quoi sert le remplissage dans l'encodage base64. Ce qui suit est l'extrait de wikipedia:
"Un caractère de remplissage supplémentaire est alloué qui peut être utilisé pour forcer la sortie codée en un multiple entier de 4 caractères (ou de manière équivalente lorsque le texte binaire non codé n'est pas un multiple de 3 octets); ces caractères de remplissage doivent ensuite être supprimés lors du décodage mais permet toujours le calcul de la longueur effective du texte non codé, lorsque sa longueur binaire en entrée ne serait pas un multiple de 3 octets (le dernier caractère non-pad est normalement codé de sorte que le dernier bloc de 6 bits qu'il représente sera zéro -rempli sur ses bits les moins significatifs, au plus deux caractères de remplissage peuvent apparaître à la fin du flux codé). "
J'ai écrit un programme qui pourrait encoder en base64 n'importe quelle chaîne et décoder n'importe quelle chaîne encodée en base64. Quel problème le rembourrage résout-il?
Votre conclusion selon laquelle le rembourrage n'est pas nécessaire est juste. Il est toujours possible de déterminer la longueur de l'entrée sans ambiguïté à partir de la longueur de la séquence codée.
Cependant, le remplissage est utile dans les situations où les chaînes codées en base64 sont concaténées de telle manière que les longueurs des séquences individuelles sont perdues, comme cela peut arriver, par exemple, dans un protocole réseau très simple.
Si non rembourré les chaînes sont concaténées, il est impossible de récupérer les données d'origine car les informations sur le nombre d'octets impairs à la fin de chaque séquence individuelle sont perdues. Cependant, si des séquences remplies sont utilisées, il n'y a aucune ambiguïté et la séquence dans son ensemble peut être décodée correctement.
Supposons que nous ayons un programme qui code en base64 les mots, les concatène et les envoie sur un réseau. Il code "I", "AM" et "TJM", prend en sandwich les résultats sans remplissage et les transmet.
I
code en SQ
(SQ==
avec rembourrage)AM
code pour QU0
(QU0=
avec rembourrage)TJM
code en VEpN
(VEpN
avec un rembourrage)Les données transmises sont donc SQQU0VEpN
. Le récepteur base64 décode ceci comme I\x04\x14\xd1Q)
au lieu du IAMTJM
prévu. Le résultat est un non-sens car l'expéditeur a détruit les informations sur la fin de chaque mot dans la séquence codée. Si l'expéditeur a envoyé SQ==QU0=VEpN
à la place, le récepteur aurait pu décoder cela en trois séquences base64 distinctes qui se concaténeraient pour donner IAMTJM
.
Pourquoi ne pas simplement concevoir le protocole pour préfixer chaque mot avec une longueur entière? Le récepteur pourrait alors décoder le flux correctement et il n'y aurait pas besoin de remplissage.
C'est une excellente idée, tant que nous savons la longueur des données que nous encodons avant de commencer à les encoder. Mais que se passerait-il si, au lieu de mots, nous encodions des morceaux de vidéo à partir d'une caméra en direct? Nous ne connaissons peut-être pas la longueur de chaque morceau à l'avance.
Si le protocole utilisait un remplissage, il ne serait pas nécessaire de transmettre une longueur du tout. Les données pouvaient être encodées à mesure qu'elles provenaient de la caméra, chaque bloc se terminant par un rembourrage, et le récepteur serait en mesure de décoder le flux correctement.
Évidemment, c'est un exemple très artificiel, mais il illustre peut-être pourquoi le rembourrage peut éventuellement être utile dans certaines situations.
Les caractères de remplissage aident à satisfaire les exigences de longueur et n'ont aucune signification.
Exemple décimal de remplissage: Étant donné l'exigence arbitraire, toutes les chaînes doivent avoir 8 caractères, le nombre 640 peut répondre à cette exigence en utilisant les 0 précédents comme caractères de remplissage car ils n'ont aucune signification, "00000640".
Le paradigme des octets: L'octet est l'unité de mesure standard de facto et tout schéma de codage doit se rapporter aux octets.
Base256 correspond exactement à ce paradigme. Un octet est égal à un caractère en base256.
Base16 , hexadécimal ou hex, utilise 4 bits pour chaque caractère. Un octet peut représenter deux caractères base16.
Base64 ne rentre pas uniformément dans le paradigme des octets, contrairement à base256 et base16. Tous les caractères base64 peuvent être représentés sur 6 bits, à moins de 2 bits d'un octet complet.
Nous pouvons représenter le codage base64 par rapport au paradigme d'octets comme une fraction: 6 bits par caractère sur 8 bits par octet. Cette fraction réduite est de 3 octets sur 4 caractères.
Ce ratio, 3 octets pour 4 caractères base64, est la règle que nous voulons suivre lors de l'encodage base64. L'encodage Base64 ne peut promettre que la mesure même avec des paquets de 3 octets, contrairement à base16 et base256 où chaque octet peut se suffire à lui-même.
Donc pourquoi le remplissage est-il encouragé même si l'encodage pourrait très bien fonctionner sans les caractères de remplissage? Les caractères de remplissage communiquent explicitement que ces taches supplémentaires doivent être vides et excluent toute ambiguïté ou bugs potentiellement désagréables. Le rembourrage nous permet de décoder l'encodage base64 avec la promesse de ne pas perdre de bits. Sans remplissage, il n'y a plus de reconnaissance explicite de la mesure dans des paquets de trois octets et nous ne pouvons plus garantir la reproduction exacte de l'encodage d'origine sans informations supplémentaires.
Voici l'exemple de formulaire RFC 4648 ( http://tools.ietf.org/html/rfc4648#section-8 )
Chaque caractère à l'intérieur de la fonction "BASE64" utilise un octet (base256). Nous traduisons ensuite cela en base64.
BASE64("") = "" (No bytes used. 0%3=0.)
BASE64("f") = "Zg==" (One byte used. 1%3=1.)
BASE64("fo") = "Zm8=" (Two bytes. 2%3=2.)
BASE64("foo") = "Zm9v" (Three bytes. 3%3=0.)
BASE64("foob") = "Zm9vYg==" (Four bytes. 4%3=1.)
BASE64("fooba") = "Zm9vYmE=" (Five bytes. 5%3=2.)
BASE64("foobar") = "Zm9vYmFy" (Six bytes. 6%3=0.)
Voici un encodeur avec lequel vous pouvez jouer: http://www.motobit.com/util/base64-decoder-encoder.asp
Ce n'est qu'une théorie à moi, et je ne peux fournir aucune source, mais je pense que le ou les caractères de remplissage ne servent qu'à faire quelques implémentations du algorithme de décodage un plus petit bit plus simple. En particulier, si l'algorithme place la chaîne encodée dans quelque chose comme int[]
alors la valeur finale sera parfois trop longue.
Si le remplissage est déjà présent dans l'entrée, rien d'autre ne doit être fait - l'algorithme peut simplement lire et décoder l'entrée.
Si l'algorithme n'est pas autorisé à supposer que le remplissage est présent, cependant et il utilise int[]
- comme la structure de données, puis il doit remplir manuellement l'entier final avant le décodage, ou effectuer une comptabilité supplémentaire sur la longueur d'origine de l'entrée.
Personnellement, je ne pense plus que le rembourrage serve à quelque chose que ce soit, mais à l'époque où le processeur et RAM n'étaient pas aussi abondants que maintenant, cette légère optimisation aurait pu avoir de l'importance. Je doute que cela ait autant d'importance que ... une bonne implémentation aurait encore besoin de faire quelque chose de raisonnable lorsqu'elle est alimentée en entrée qui a été tronquée de manière aléatoire, et cela, l'OMI, permettrait de traiter les entrées non remplies sans frais supplémentaires.