web-dev-qa-db-ja.com

入力長が3で割り切れない場合、base64エンコードではパディングが必要なのはなぜですか?

Base64エンコーディングのパディングの目的は何ですか。以下はウィキペディアからの抜粋です。

「エンコードされた出力を強制的に4文字の整数倍にする(またはエンコードされていないバイナリテキストが3バイトの倍数でない場合)ために使用できる追加のパッド文字が割り当てられます。入力バイナリの長さが3バイトの倍数ではない場合、エンコードされていないテキストの有効な長さの計算を引き続き許可します(通常、最後の非パッド文字はエンコードされるため、それが表す最後の6ビットブロックはゼロになります-最下位ビットにパディングされ、エンコードされたストリームの最後に最大2つのパディング文字が発生する場合があります。」

文字列をbase64でエンコードし、base64でエンコードされた文字列をデコードできるプログラムを作成しました。パディングはどのような問題を解決しますか?

67
Anand Patel

パディングが不要であるというあなたの結論は正しいです。エンコードされたシーケンスの長さから入力の長さを明確に決定することは常に可能です。

ただし、パディングは、たとえば非常に単純なネットワークプロトコルで発生する可能性のある、個々のシーケンスの長さが失われるような方法でbase64エンコード文字列が連結される状況で役立ちます。

npadded文字列が連結されている場合、各シーケンスの最後の奇数バイト数に関する情報が失われるため、元のデータを復元することはできません。ただし、パディングシーケンスを使用する場合、あいまいさはなく、シーケンス全体を正しくデコードできます。

編集:イラスト

単語をbase64でエンコードし、それらを連結してネットワーク経由で送信するプログラムがあるとします。 「I」、「AM」、および「TJM」をエンコードし、パディングなしで結果をサンドイッチして送信します。

  • ISQにエンコードします(SQ==パディング付き)
  • AMQU0にエンコードします(QU0=パディング付き)
  • TJMVEpNにエンコードします(パディング付きのVEpN

したがって、送信されるデータはSQQU0VEpNです。受信側は、これを意図したIAMTJMではなくI\x04\x14\xd1Q)としてbase64デコードします。送信者がエンコードされたシーケンスで各Wordの終了位置に関する破壊された情報を持っているため、結果はナンセンスです。送信者がSQ==QU0=VEpNを代わりに送信した場合、受信者はこれを連結してIAMTJMを与える3つの個別のbase64シーケンスとしてデコードできます。

パディングに煩わ​​される理由

各Wordの前に整数の長さを付加するプロトコルを設計しないのはなぜですか?その後、受信者はストリームを正しくデコードでき、パディングの必要はありません。

knowエンコードを開始する前にエンコードするデータの長さである限り、これは素晴らしいアイデアです。しかし、言葉の代わりに、ライブカメラからのビデオのチャンクをエンコードしていた場合はどうでしょうか。各チャンクの長さが事前にわからない場合があります。

プロトコルがパディングを使用した場合、長さを送信する必要はまったくありません。データはカメラから入ってくるときにエンコードされ、各チャンクはパディングで終了し、受信機はストリームを正しくデコードできます。

明らかにそれは非常に不自然な例ですが、おそらく、いくつかの状況でパディングが役立つと考えられる理由を示している可能性があります。

154
TJM

パディングキャラクターとは

パディング文字は長さの要件を満たすのに役立ち、意味を持ちません。

パディングの10進数の例:任意の要件ですべての文字列の長さは8文字であるため、数字640は、先行する0をパディング文字として使用してこの要件を満たすことができます「00000640」という意味はありません。

バイナリエンコーディング

バイトパラダイム:バイトは事実上の標準測定単位であり、エンコードスキームはバイトに関連する必要があります。

Base256は、このパラダイムに正確に適合します。 1バイトは、base256の1文字に相当します。

Base16、16進数または16進数は、各文字に4ビットを使用します。 1バイトは2つのbase16文字を表すことができます。

Base64は、base256やbase16とは異なり、バイトパラダイムに均等に適合しません。すべてのbase64文字は6ビットで表現でき、2バイトは完全なバイトより短くなります。

Base64エンコーディングとバイトパラダイムを分数として表すことができます:バイトあたり8ビット以上の文字あたり6ビット。この割合を減らすと、4文字で3バイトになります。

この比率は、4つのbase64文字ごとに3バイトであり、base64をエンコードするときに従うルールです。 Base64エンコーディングは、すべてのバイトが独立しているbase16およびbase256とは異なり、3バイトバンドルでの測定でさえも約束できます

whyは、パディング文字がなくてもエンコードがうまく機能する場合でも、パディングが推奨されますか?パディング文字は、これらの余分なスポットを空にする必要があることを明確に伝え、曖昧さや潜在的に厄介なバグを排除します。パディングにより、失われたビットがないことを約束して、base64エンコードをデコードできます。パディングなしでは、3バイトバンドルで測定することの明示的な確認はなくなり、追加情報なしで元のエンコードの正確な再現を保証できなくなりました。

RFC 4648の形式の例を次に示します( http://tools.ietf.org/html/rfc4648#section-8

「BASE64」関数内の各文字は、1バイト(base256)を使用します。次に、それを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.)

試してみることができるエンコーダは次のとおりです。 http://www.motobit.com/util/base64-decoder-encoder.asp

30
Zamicol

これは私の理論であり、ソースを提供することはできませんが、パディング文字は、デコードアルゴリズムの一部の実装を作成するのに役立つと思いますtiniest少しシンプル。特に、アルゴリズムがエンコードされた文字列をint[]のようなものにすると、最終値が長すぎる場合があります。

入力にパディングがすでに存在する場合、他に何もする必要はありません-アルゴリズムは入力を読み取ってデコードするだけです。

ただし、アルゴリズムがパディングの存在を想定できない場合、andint[]- likeデータ構造を使用し、thenは最後に手動でパディングする必要がありますデコードする前の整数、または入力の元の長さで追加のブックキーピングを行います。

私は個人的にパディングがもう何の目的にも役立つとは思いませんが、CPUとRAMが今はこのわずかな最適化が重要であるほど豊富ではなかったときに戻ってきました。 ...優れた実装では、ランダムに切り捨てられた入力をフィードするときに賢明なことを行う必要があり、IMOは追加費用なしでパッドなしの入力を処理できるようになります。

2
Roman Starkov