QA@IT

Javaで暗号化されたファイルをopensslコマンドで復号したい

5615 PV

暗号化されたファイルをopensslコマンドで復号する際のオプションに悩んでいます。

Windowsのデスクトップ向けアプリで作成した暗号化ファイルを
Linux(CentOS)の openssl コマンドで復号しようとしています。

暗号化のアルゴリズムはトリプルDESですが、
アプリは.NET版とJava版の2種類用意しています。

.NET版はKEYとIVが利用されているため、コマンドでの復号も問題なく出来たのですが、
Java版の場合、バイナリ情報のKeyインターフェースが指定されています。
openssl で復号する場合にどのようにオプションを指定してよいかが判りません。

ご存知の方がいらっしゃいましたら、ご教授いただきますようお願いいたします。

なお、下記2点に関しては対応方法として検討していません。

  1. Java版のアプリを書き換える
  2. 復号用のJavaアプリを作成し、Linux上で起動する

以下、.NETのソースコードと対応する復号コマンド、およびJavaのソースコードを紹介します。

  • .NET暗号化
    // TripleDESオブジェクトの作成
    TripleDESCryptoServiceProvider desCrypt = new TripleDESCryptoServiceProvider();

    // Key IV
    desCrypt.Key = key;
    desCrypt.IV = iv;

    // ストリーム
    FileStream fsW = new FileStream(outFile, FileMode.Create, FileAccess.Write);
    ICryptoTransform idescrypt = desCrypt.CreateEncryptor();
    CryptoStream cstream = new CryptoStream(fsW, idescrypt, CryptoStreamMode.Write);

    // ファイル読込み用
    FileStream fsR = new FileStream(inFile.FullName, FileMode.Open, FileAccess.Read);

    byte[] bs = new byte[1024];
    int readLen;

    while ((readLen = fsR.Read(bs, 0, bs.Length)) > 0)
    {
        cstream.Write(bs, 0, readLen);
    }

    // ストリーム等を閉じる
    fsR.Close();
    cstream.Close();
    desCrypt.Dispose();
    fsW.Close();
  • .NET暗号化を復号
    # /usr/bin/openssl enc -des3 -d -in {ENCFILE} -out {DECFILE} -K {KEYMESSAGE} -iv {IVMESSAGE}

    無事復号できました
  • Java暗号化
    final Cipher cipher = Cipher.getInstance("DESede");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);

    final InputStream inStream = new BufferedInputStream(
        new FileInputStream(inFile)
    );

    OutputStream outStream = new CipherOutputStream(
            new BufferedOutputStream(new FileOutputStream(outFile)),
            cipher);

    copy(inStream, outStream);

    inStream.close();
    outStream.flush();
    outStream.close();

    inStream.close();
  • Java暗号化を復号
    # /usr/bin/openssl enc -des3 -d -in {ENCFILE} -out {DECFILE} ???

    ??? secretKey に該当するものは秘密鍵?パスフレーズ?
        でもsecretKeyの値ってバイナリだぞ?

回答

まずJava SE APIのドキュメントを見てください。バージョンがわからないので、以下ではとりあえずJava SE 8とします。

Java SE API
http://docs.oracle.com/javase/jp/8/docs/api/javax/crypto/Cipher.html

上記ドキュメントからの引用

変換は、次の書式で記述されます。

    "algorithm/mode/padding"または
    "algorithm" 

後者の場合、モードおよびパディング方式には、プロバイダ固有のデフォルト値が使用されます。たとえば、次は有効な変換です。

     Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");

次に質問文によると「Java暗号化」は

final Cipher cipher = Cipher.getInstance("DESede");

となっていますが、これで問題なのは、「変換」の部分でalgorithmだけが指定されていて、modeとpaddingがないため、modeとpaddingは何が使わているかよくわからない点だと思います。これだと「プロバイダ固有のデフォルト値」としかわかりません。

標準アルゴリズム名(モードやパディングも含む)については下記を見てください。

Java暗号化アーキテクチャ標準アルゴリズム名
http://docs.oracle.com/javase/jp/8/docs/technotes/guides/security/StandardNames.html#Cipher

上記ドキュメントからの引用

  • DESede

トリプルDES暗号化(DES-EDE、3DES、またはトリプルDESとも呼ばれます)。データは、DESアルゴリズムを個別に3回使用して暗号化されます。データは、最初のサブ鍵を使用して暗号化され、次に2番目のサブ鍵を使用して復号化されたあと、3番目のサブ鍵を使用して暗号化されます。

  • ECB

FIPS PUB 81に定義されているElectronic Codebookモード(通常、このモードは複数のデータ・ブロックには使用しないでください)。

  • PKCS5Padding

「PKCS#5: Password-Based Encryption Standard」バージョン1.5 (RSA Laboratories、1993年11月)に記述されているパディング方式。

話は少し変わりますが、DESedeとは別にPBEWith<digest>And<encryption>PBEWith<prf>And<encryption>がありますが、これらがパスワードベースの暗号化になります。ですので「Java暗号化」ではパスワードベースの暗号化は使用されておらず、opensslで復号するさいにパスワード(もしくはパスフレーズ)を指定することは「ない」と思われます。復号に使うのは「秘密鍵」のほうです。

話を戻して「プロバイダ固有のデフォルト値」がどうなっているかですが、例えばOracleプロバイダの場合を見てみます。

Java暗号化アーキテクチャOracleプロバイダ
http://docs.oracle.com/javase/jp/8/docs/technotes/guides/security/SunProviders.html#ciphertrans

上記ドキュメントからの引用

javax.crypto.Cipher.getInstance(String transformation)ファクトリ・メソッドは、algorithm/mode/padding形式の変換を使用してCipherを生成します。モード/パディングを省略すると、SunJCEプロバイダとSunPKCS11プロバイダは、多くの対称暗号でECBをデフォルト・モードとして、PKCS5Paddingをデフォルト・パディングとして使用します。
デフォルトを使用するのではなく、アルゴリズム、モードおよびパディングを完全に指定した変換を使用することをお薦めします。

「多くの」という点が微妙ですが、ECB、PKCS5Paddingがデフォルトになっている可能性が高そうですね。

あとはopensslのドキュメントを見て合わせればよいと思います。

enc
https://www.openssl.org/docs/manmaster/apps/enc.html

opensslのdes3des-ede3-cbcの別名ですので、モードがECBならdes-ede3を明示的に指定する必要があります。ECBの場合はIVは使いません。

パディングも合わせる必要がありますが、たぶんデフォルトでOKのような気がします。

JavaのドキュメントにECBは複数のデータ・ブロックに使わないように指示している点にも注意してください。なぜ使っちゃいけないかの理由は調べて確認しておいてください。

編集 履歴 (2)
  • アドバイス有難うございます。
    ご紹介いただいた資料とにらめっこ中です。

    進展がありましたら報告します。
    -
  • いまだ解決には至っておりませんが、
    いつまでもズルズルと引き伸ばすのは返って問題と思い
    作業優先順位を変更することにいたしました。

    アドバイス有難うございました。
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。