ファイルをパスワードで暗号化して保管したい、暗号化したファイルを元に戻したいときは、openssl encを使う。
$ openssl enc -aes-256-cbc -pbkdf2 -in plain.txt -out plain.txt.enc
enter AES-256-CBC encryption password:
Verifying - enter AES-256-CBC encryption password:
復号するときは-dを付ける。
$ openssl enc -d -aes-256-cbc -pbkdf2 -in plain.txt.enc -out plain.txt
enter AES-256-CBC decryption password:
パスワードは対話的に入力する。-pbkdf2は必ず付ける。理由は後述する。暗号化と復号でアルゴリズムと-pbkdf2などのオプションを揃える必要がある。
実行例はUbuntu 24.04のOpenSSL 3.0.13のもの。
パスワードの渡し方を選ぶ
スクリプトから実行する場合は、対話入力の代わりに-passでパスワードの取得元を指定する。
| 指定 | パスワードの取得元 |
|---|---|
-pass pass:[パスワード] | コマンドラインに直接書く |
-pass env:[環境変数名] | 環境変数から読む |
-pass file:[ファイル] | ファイルの1行目から読む |
$ export PW=secret
$ openssl enc -aes-256-cbc -pbkdf2 -in plain.txt -out plain.txt.enc -pass env:PW
$ echo 'secret' > pw.txt
$ openssl enc -aes-256-cbc -pbkdf2 -in plain.txt -out plain.txt.enc -pass file:pw.txt
pass:はコマンドラインに書くため、psの出力やシェルの履歴にパスワードが残る。共有環境ではenv:かfile:を使う。file:を使う場合は、パスワードのファイルのパーミッションを600にする。
標準入力が端末でない環境で-passを指定しないと、パスワードを読み込めずに失敗する。
$ openssl enc -aes-256-cbc -pbkdf2 -in plain.txt -out x.enc </dev/null
enter AES-256-CBC encryption password:
bad password read
パスワードに使う文字列は、openssl randで生成できる。
参考: 【openssl】ランダムな文字列を生成する (rand)
-pbkdf2を付ける理由
パスワードから暗号鍵を作る処理を鍵導出と呼ぶ。-pbkdf2を付けないと、OpenSSLは古い鍵導出(ソルト付きパスワードのハッシュを1回だけ計算する方式)を使う。総当たりでパスワードを試されやすいため、警告が表示される。
$ openssl enc -aes-256-cbc -in plain.txt -out plain.txt.enc -pass pass:pw
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
-pbkdf2を付けると、パスワードを何千回も繰り返してハッシュ化する鍵導出(PBKDF2)を使う。警告も表示されなくなる。
暗号化したときと異なる鍵導出で復号すると、復号に失敗する。
$ openssl enc -d -aes-256-cbc -in plain.txt.enc -pass pass:pw
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
bad decrypt
-pbkdf2を付けて暗号化したファイルは、-pbkdf2を付けて復号する。
繰り返し回数を増やす
-iterでPBKDF2の繰り返し回数を指定できる。デフォルトは10000回である。回数を増やすほど、総当たりに時間がかかる。
$ openssl enc -aes-256-cbc -pbkdf2 -iter 600000 -in plain.txt -out plain.txt.enc -pass env:PW
-iterの値は保存されない。復号時にも同じ値を指定する。
$ openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 -in plain.txt.enc -pass env:PW
secret-data
$ openssl enc -d -aes-256-cbc -pbkdf2 -in plain.txt.enc -pass env:PW
bad decrypt
暗号化したファイルの中身
暗号化したファイルは、先頭8バイトがSalted__、続く8バイトがソルト(ランダムな値)である。
$ head -c 8 plain.txt.enc | od -c | head -1
0000000 S a l t e d _ _
ソルトは暗号化ごとにランダムな値が選ばれる。入力とパスワードが同じでも、出力は毎回異なる。
$ openssl enc -aes-256-cbc -pbkdf2 -in plain.txt -pass pass:pw | md5sum
e0c3bcba638cd9d28dc35ef590befab4 -
$ openssl enc -aes-256-cbc -pbkdf2 -in plain.txt -pass pass:pw | md5sum
b67f226b2a2cbd46d1ae7f61ee0d03ed -
ソルトを付けたくない場合は-nosaltを指定する。同じ入力から同じ出力が得られるため、ソルトなしで運用するのは避ける。
暗号化結果をテキストで扱う
-aを付けると、暗号化結果をBase64で出力する。メールやチャットへ貼り付ける場合に使う。復号時も-aを付ける。
$ openssl enc -aes-256-cbc -pbkdf2 -a -in plain.txt -pass env:PW
U2FsdGVkX18PwgUW9Ogx00Qu/SRs1VkgVIgaNXaCWAI=
$ openssl enc -d -aes-256-cbc -pbkdf2 -a -in plain.b64 -pass env:PW
secret-data
ディレクトリを暗号化する
encはファイル単位の処理である。ディレクトリはtarでまとめてからパイプで渡す。
$ tar czf - [ディレクトリ] | openssl enc -aes-256-cbc -pbkdf2 -pass env:PW -out dir.tgz.enc
$ openssl enc -d -aes-256-cbc -pbkdf2 -pass env:PW -in dir.tgz.enc | tar tzf -
d/
d/a
復号に失敗する場合
パスワードが違う場合や、暗号化時と異なるアルゴリズム・オプションを指定した場合は、bad decryptで失敗する。
$ openssl enc -d -aes-256-cbc -pbkdf2 -in plain.txt.enc -pass pass:bad
bad decrypt
誤ったパスワードでも、偶然パディングの形式が正しくなると、エラーなしで壊れたデータが出力される。復号結果が正しいかどうかは、ハッシュ値の比較など別の手段で確認する。
参考: 【openssl】ファイルのハッシュ値を計算する (dgst)
使えるアルゴリズム
openssl enc -listで、使えるアルゴリズムを一覧表示できる。-aes-256-cbc以外に、-aes-128-cbcや-aes-256-ctrなどがある。
-aes-256-gcmのような認証付き暗号(AEAD)は、encでは使えない。
$ openssl enc -aes-256-gcm -pbkdf2 -in plain.txt -pass pass:pw
enc: AEAD ciphers not supported
encで使うCBCは、データが改ざんされても検知できない。改ざんの検知が必要な用途では、GnuPGなどほかのツールを検討する。
バージョンによる違い
警告の有無はバージョンで異なる。OpenSSL 3.0、3.5、3.6では、-pbkdf2なしで警告が表示される。macOS標準の/usr/bin/openssl(LibreSSL 3.3.6)では、警告は表示されない。
-pbkdf2を付けて暗号化したファイルは、OpenSSL 3.0、3.6、LibreSSLの間で相互に復号できる。
