web-dev-qa-db-ja.com

base64エンコード時に末尾の「=」を削除

文字列をbase64でエンコードするたびに、末尾に「=」が追加されることに気付きました。この文字を削除し、後で追加して確実にデコードできますか、またはこれは危険ですか?言い換えると、「= always」が追加されますか、それとも特定の場合にのみ追加されますか?

エンコードされた文字列をできるだけ短くしたいので、常に「=」文字を削除して、デコードする前に追加できるかどうかを知りたいのです。

42
Steve N

=はパディングです。

ウィキペディア 言う

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

反対側を制御する場合は、トランスポート中に削除し、デコードする前に(文字列の長さをチェックすることで)挿入し直すことができます。
データはトランスポートでは有効なBase64ではないことに注意してください。

59
SLaks

Apacheのcommons-codec-1.4.jar Base64デコーダーの一部を書きましたが、そのロジックではパディング文字がなくても問題ありません。ファイルの終わりとストリームの終わりは、任意の数の「=」文字と同様にBase64メッセージが終了したことを示す良い指標です!

Commons-codec-1.4で導入したURLセーフバリアントは、物事を小さく保つために意図的にパディング文字を省略します!

http://commons.Apache.org/codec/apidocs/src-html/org/Apache/commons/codec/binary/Base64.html#line.478

より安全な答えは「デコーダの実装に依存する」と思いますが、論理的には、パディングを必要としないデコーダを書くことは難しくありません。

23
Julius Musseau

JavaScriptでは、次のようなことができます。

// if this is your Base64 encoded string
var str = 'VGhpcyBpcyBhbiBhd2Vzb21lIHNjcmlwdA=='; 

// make URL friendly:
str = str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');

// reverse to original encoding
if (str.length % 4 != 0){
  str += ('===').slice(0, 4 - (str.length % 4));
}
str = str.replace(/-/g, '+').replace(/_/g, '/');

このフィドルもご覧ください: http://jsfiddle.net/7bjaT/66/

22
magikMaker

=がパディング用に追加されます。 base64文字列の長さは4の倍数である必要があるため、1または2 =が必要に応じて追加されます。

読む:いいえ、削除しないでください。

9

オンAndroid私はこれを使用しています:

グローバル

String CHARSET_NAME ="UTF-8";

エンコード

String base64 = new String(
            Base64.encode(byteArray, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_CLOSE | Base64.NO_WRAP),
            CHARSET_NAME);
return base64.trim();

デコード

byte[] bytes = Base64.decode(base64String,
            Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_CLOSE | Base64.NO_WRAP);

javaではこれと同じです。

エンコード

private static String base64UrlEncode(byte[] input)
{
    Base64 encoder = new Base64(true);
    byte[] encodedBytes = encoder.encode(input);
    return StringUtils.newStringUtf8(encodedBytes).trim();
}

デコード

private static byte[] base64UrlDecode(String input) {
    byte[] originalValue = StringUtils.getBytesUtf8(input);
    Base64 decoder = new Base64(true);
    return decoder.decode(originalValue);
}

末尾の「=」に問題はなかったし、Bouncycastleも使用しています

3
Spektakulatius

PHPを使用している場合、次の関数は削除された文字列を適切なパディングで元の形式に戻します。

<?php

$str = 'base64 encoded string without equal signs stripped';
$str = str_pad($str, strlen($str) + (4 - ((strlen($str) % 4) ?: 4)), '=');

echo $str, "\n";
1
supersan

バイトを固定ビット長でエンコードしている場合、パディングは冗長です。これはほとんどの人に当てはまります。

Base64は一度に6ビットを消費し、6ビットの組み合わせのみを使用する8ビットのバイトを生成します。

文字列が1バイト(8ビット)の場合、8が収まる最小の6の倍数として12ビットの出力があり、さらに4ビットが追加されます。文字列が2バイトの場合、18ビットを出力する必要があり、2ビット余分になります。 8の倍数に対して6の倍数の場合、0、2、または4ビットの残りを使用できます。

パディングは、これらの余分な4(==)または2(=)ビットを無視するように指示します。パディングはそこにあり、デコーダにパディングを伝えます。

バイトをエンコードする場合、パディングは実際には必要ありません。 base64エンコーダーは、合計8ビット未満の残りのビットを単に無視できます。この場合、削除するのが最善です。

パディングは、2の倍数である限り、ストリーミングおよび任意の長さのビットシーケンスに使用できます。残りのビットがすべてゼロの場合、残りのビットが残っているときに最後の4ビットのみを送信したい場合にも使用できます。不完全なシーケンスを検出するためにそれを使用したい人もいるかもしれませんが、それはほとんど信頼できません。実際にこの最適化を見たことはありません。これらの状況はめったにありません。ほとんどの人は、個別のバイトシーケンスにbase64を使用しています。

そのままにしておくことを提案する回答が表示された場合、単にバイトをエンコードしているだけではあまりお勧めできません。これは、一連の状況に対して機能を有効にすることです。その場合にそれをオンにする唯一の理由は、パディングなしでは機能しないデコーダに耐性を追加するためかもしれません。両端を制御する場合、それは無関心です。

1
jgmjgm

For Android Android.util.base64クラスを使用する場合、トラブルが発生する可能性があります。これは、統合テストを行うUnitTestを実行できないためです。Adnroid環境を使用します。

一方、Java.util.base64を使用する場合、コンパイラは、使用するためにsdkを低く(26未満に)する必要があることを警告します。

だからAndroid開発者が使用することをお勧めします

implementation "commons-codec:commons-codec:1.13"

エンコードオブジェクト

fun encodeObjectToBase64(objectToEncode: Any): String{
    val objectJson = Gson().toJson(objectToEncode).toString()
    return encodeStringToBase64(objectJson.toByteArray(Charsets.UTF_8))
}

fun encodeStringToBase64(byteArray: ByteArray): String{
    return Base64.encodeBase64URLSafeString(byteArray).toString() // encode with no padding
}

オブジェクトへのデコード

fun <T> decodeBase64Object(encodedMessage: String, encodeToClass: Class<T>): T{
    val decodedBytes = Base64.decodeBase64(encodedMessage)
    val messageString = String(decodedBytes, StandardCharsets.UTF_8)
    return Gson().fromJson(messageString, encodeToClass)
}

もちろん、Gsonの解析を省略して、メソッドをStringArrayに変換したString

0
murt

Pythonを使用すると、base64パディングを削除して、次のように追加し直すことができます。

from math import ceil

stripped = original.rstrip('=')

original = stripped.ljust(ceil(len(stripped) / 4) * 4, '=')
0
sirex