openssl で AES 暗号化したファイルを java で復号

 2018/09/20 -  moriya -  ~3 Minutes

android で暗号化したファイルを復号しようと思ったが、どのようにするか。

暗号化は、わざわざツールを作るのも面倒なので、openssl でよいかと考えた。

openssl java で検索すると以下のような記事が見つかる。

openssl enc -e -aes-128-cbc で暗号化したファイルの先頭には、Salted__ソルトが入るようだ。
これは、openssl の仕様で、Java の Cipher クラスには、そのようなインタフェースはない。
上記の記事ではそれらを実装しているのだと思うが、面倒だし、openssl 依存というのもなあ、と思った。

とりあえず、man enc してみた。たぶん、そうこうしている間に実装できただろうが。

興味深いオプションとしては、-P オプション、-S オプション、-nosalt オプション、-K、-iv オプションだろうか。

オプション 機能
-P オプション salt、key、iv を表示して終了する。
-S オプション salt を指定して暗号化する。
-nosalt salt を使わない。
-K、-iv -K で指定したキーと -iv で指定した initial vector を使う。

暗号化する時に、Key / iv を表示させて、それを Java の Cipher クラスに渡せばよい。

使用例:

$ openssl enc -aes-128-cbc -P 
enter aes-128-cbc encryption password:
Verifying - enter aes-128-cbc encryption password:
salt=E89360B042EFDBE0
key=35E38573AB84F2054BB8BCD8E5CD56EE
iv =382EA02910F2C2B5E2990846A30C169D

パスワードは hogehoge を入れてみた。実行毎に salt は変わるので、key/iv は変わる。もし、同じ salt を指定したければ、次のとおり。

$ openssl enc -aes-128-cbc -P -S E89360B042EFDBE0
enter aes-128-cbc encryption password:
Verifying - enter aes-128-cbc encryption password:
salt=E89360B042EFDBE0
key=35E38573AB84F2054BB8BCD8E5CD56EE
iv =382EA02910F2C2B5E2990846A30C169D

試しに salt を指定して暗号化したファイルの hexdump。

$ openssl enc -aes-128-cbc -S E89360B042EFDBE0 -in hoge.txt -out hoge.txt.enc
$ hexdump -C hoge.txt.enc 
00000000  53 61 6c 74 65 64 5f 5f  e8 93 60 b0 42 ef db e0  |Salted__..`.B...|
00000010  65 f6 60 7a 8f f7 e3 21  a3 b2 dd a1 5c a7 dd be  |e.`z...!....\...|
00000020

(-nosalt を使えば、Salted__ソルト、は出力されない。)

もらったファイルから key / iv を表示する場合

$ openssl enc -d -aes-128-cbc -in hoge.txt.enc -P
enter aes-128-cbc decryption password:
salt=E89360B042EFDBE0
key=35E38573AB84F2054BB8BCD8E5CD56EE
iv =382EA02910F2C2B5E2990846A30C169D

ソルトの部分を削れば復号できるのか。

$ dd if=hoge.txt.enc of=hoge.txt.enc.nosalt bs=1 skip=16
16+0 records in
16+0 records out
16 bytes transferred in 0.000732 secs (21860 bytes/sec)
$ hexdump -C hoge.txt.enc.nosalt 
00000000  65 f6 60 7a 8f f7 e3 21  a3 b2 dd a1 5c a7 dd be  |e.`z...!....\...|
00000010
$ openssl enc -d -aes-128-cbc -in hoge.txt.enc.nosalt -K 35E38573AB84F2054BB8BCD8E5CD56EE -iv 382EA02910F2C2B5E2990846A30C169D
$ openssl enc -d -aes-128-cbc -in hoge.txt.enc.nosalt -K 35E38573AB84F2054BB8BCD8E5CD56EE -iv 382EA02910F2C2B5E2990846A30C169D
hogehoge

Java Cipher を使って復号する場合

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); // openssl は PKCS5Padding で暗号化する
Key k = new SecretKeySpec(key, "AES"); // key は byte 配列
IvParameterSpec p = new IvParameterSpec(iv); // iv は byte 配列
c.init(Cipher.DECRYPT_MODE, k, p);
byte[] ret = c.doFinal(buf); // buf は byte 配列 (Salted__ソルトは削るか-nosaltで出力させない)

[PR]

私は、「Java チュートリアル」という本でざっくりと使い方を習得しました。内容も古くなっているため、Amazon おすすめの本を購入するのが良いと思います。 Java を習得する必要があるのに、間違って JavaScript の本を買わないように。