文字列やファイルをBase64でエンコードしたい、Base64の文字列を元に戻したいときは、openssl base64を使う。

$ echo -n "hello world" | openssl base64
aGVsbG8gd29ybGQ=

デコードするには-dを付ける。

$ echo "aGVsbG8gd29ybGQ=" | openssl base64 -d
hello world

実行例はUbuntu 24.04のOpenSSL 3.0.13のもの。

ファイルをエンコード・デコードする

-inで入力ファイル、-outで出力ファイルを指定する。省略すると標準入力と標準出力を使う。

$ openssl base64 -in image.png -out image.b64
$ openssl base64 -d -in image.b64 -out image-restored.png

バイナリファイルでも元のデータに戻る。

エンコード結果を1行にする

エンコード結果は64文字ごとに改行される。たとえば100バイトのデータをエンコードすると3行になる。

$ openssl base64 -in long.txt
YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
YWFhYQ==

-Aを付けると、改行なしの1行で出力する。

$ openssl base64 -A -in long.txt
YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ==

環境変数やHTTPヘッダーなど、1行で扱いたい場所に値を渡す場合に使う。-Aなしの出力からtr -d '\n'で改行を取り除いても同じ結果になる。

1行のBase64をデコードする

-Aを付けずに1行の長いBase64をデコードすると、OpenSSL 3.0やLibreSSLではエラーにならず、何も出力されない。

$ openssl base64 -A -in long.txt | openssl base64 -d | wc -c
0

デコード時にも-Aを付ける。

$ openssl base64 -A -in long.txt | openssl base64 -d -A | wc -c
100

64文字ごとに改行された入力は、-Aなしでデコードできる。

文字列にエンコードすると改行が含まれる

echoは末尾に改行を付けるため、改行を含めた状態でエンコードされる。

$ echo "hello" | openssl base64
aGVsbG8K
$ echo -n "hello" | openssl base64
aGVsbG8=

aGVsbG8Kをデコードすると、末尾に改行を含むhelloが得られる。文字列だけをエンコードしたい場合は、echo -nかprintfを使う。

URLセーフなBase64にする

標準のBase64で使う+と/は、URLやファイル名に含めると特別な意味を持つ。openssl base64にURLセーフな出力のオプションはないため、trで置き換える。

$ printf '\xfb\xff\xfe' | openssl base64
+//+
$ printf '\xfb\xff\xfe' | openssl base64 | tr '+/' '-_' | tr -d '='
-__-

デコードするときは、逆の置き換えをしてからopenssl base64 -dに渡す。

$ echo '-__-' | tr '_-' '/+' | openssl base64 -d | od -An -tx1
 fb ff fe

=を取り除いた値は、デコード前に=を補う必要がある。補い方は次の節を参照。

デコード結果が空になる場合

openssl base64 -dは、入力が不正でもエラーメッセージを表示せず、終了コードも0のままである。デコード結果が空になる場合は、以下を疑う。

末尾に改行がない

入力の末尾に改行がないと、OpenSSL 3.0、3.5、3.6、LibreSSLのいずれでも何も出力されない。

$ printf 'aGVsbG8=' | openssl base64 -d
$ printf 'aGVsbG8=\n' | openssl base64 -d
hello

末尾に改行のない入力を渡す場合は-Aを付ける。

$ printf 'aGVsbG8=' | openssl base64 -d -A
hello

=によるパディングがない

パディングの=が取り除かれたBase64は、デコードできず何も出力されない。

$ echo 'aGVsbG8gd29ybGQ' | openssl base64 -d

4の倍数の長さになるまで=を補うと、デコードできる。

$ s='aGVsbG8gd29ybGQ'
$ while [ $(( ${#s} % 4 )) -ne 0 ]; do s="$s="; done
$ echo "$s" | openssl base64 -d
hello world

Base64以外の文字を含む

Base64に使えない文字が1つでも含まれていると、正しい行も含めて何も出力されない。

$ printf 'aGVsbG8=\n!!!\n' | openssl base64 -d

バージョンによる違い

OpenSSL 3.5では、-Aなしでも1行の長いBase64をデコードできる。OpenSSL 3.0やmacOS標準の/usr/bin/openssl(LibreSSL 3.3.6)では、前述の通り何も出力されない。デコード時に-Aを付けておけば、どのバージョンでも同じように動く。

openssl base64はopenssl enc -base64やopenssl enc -aと同じ動作である。

$ echo -n hi | openssl enc -a
aGk=

base64コマンドとの使い分け

LinuxやmacOSにはbase64コマンドもある。Base64のエンコード・デコードだけならbase64コマンドが簡単である。

$ echo -n "hello world" | base64
aGVsbG8gd29ybGQ=

GNU coreutilsのbase64は、76文字ごとに改行する。改行なしにするには-w0を付ける。

$ echo -n "hello world" | base64 -w0
aGVsbG8gd29ybGQ=

base64コマンドがない環境や、opensslを使う他の処理とまとめたいスクリプトでは、openssl base64を使う。

参考

openssl-enc - OpenSSL Documentation