LoginSignup
1
1

More than 1 year has passed since last update.

[OutSystems]パスワード付きZipを作成する

Posted at

以前書いたOutSystemsでzipファイルを扱うでは、OutSystemsにプリインストールされているZip Extensionを使ってZipファイルを作成する方法を確認した。

ただ、この方法だと作成するZipファイルにパスワードをつけることができないように見える。
よって、ちょっと手を入れて、パスワードを付けるI/Fを追加してみる。

環境

Personal Environment(Version 11.15.0 (Build 34858))
Service Studio(Version 11.14.16)
Zip Extension(For version 11.15.0)

Zip Extension

基本と使い方

このExtensionはSystem Componentの1つで、OutSystemsをインストールした環境にはデフォルトで入っているはず。
使い方は、以前書いたOutSystemsでzipファイルを扱うを参照。

Zipファイルの操作を実現している方法

私のPEに入っているZip Extensionは、内部でMITライセンスのSharpZipLibを使っている。バージョンはファイルのプロパティを見る限り、1.1.0.145。

SharpZipLibのドキュメントを見ると、暗号化周りの情報があるので、これを流用すれば、暗号化してパスワードを付与したzipを作れそう。

修正方針の検討

パスワードを付与する

Zip Extensionは、Zipファイルを作成する際に、SharpZipLibのZipOutputStreamクラスを使っている。
このクラスのPasswordプロパティを設定すれば、作成したZipファイルにパスワードをかけられそう。

When set to null or if the password is empty no encryption is performed

とのことなので、このプロパティを設定しないと、暗号化が行われない(そしてもちろんパスワードもかからない?)ようだ。
ZipOutputStreamの初期化時に、同時にPasswordも指定するように改修する。

暗号化アルゴリズム

Zipの場合、初期に使用していた暗号化アルゴリズムに、現代では問題が見つかっているらしい。
そこで、この方法で作成したZipファイルに使われる暗号化アルゴリズムを確認しておきたい。

Stack OverflowにUsing SharpZipLib How do I set the encryption algorithm?という質問があり、その回答が参考になる。

As I understand from reading the code and forum posts, EncryptionAlgorithm exists to document the values available in the Zip standard and not as an option for the end user.

各種暗号化アルゴリズムを列挙したenum EncryptionAlgorithmがあるが、これはZipの標準で定められたアルゴリズムを列挙するためのもので、このライブラリで使えるアルゴリズムを示したものではない。

The encryption algorithms that are actually available to you are AES128 and AES256. You apply the algorithm on each entry by assigning the AESKeySize property.

実際には、AES128かAES256のみが選択可能で、使用するビット数はZipEntry.AESKeySizeで指定する。
わざわざ低いビット数を選ぶ理由もないので、ZipEntryをインスタンス化した後にAESKeySizeに256を設定しておくとする。

修正

Extensionを用意

まずは、Integration StudioでZip Extensionを開く。
開いたら、Fileメニュー → Cloneを選択、今回は動作確認するだけなので、名前はデフォルトの「CloneOfZip」としておく。
私のPEで試したところ、Publish時にエラーが発生した。

  • 「現在ターゲットされているフレームワークで解決できなかったフレームワーク アセンブリ "System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" に間接的に依存するため、解決できませんでした。".NETFramework,Version=v4.6.1"。」のようなメッセージが出る:Visual Studioでプロジェクトを選択 → プロパティ → 開いたダイアログで、Target Framework 4.6.1だったのを4.7.2にしてみる
  • 「型または名前空間名 'ICSharpCode' が見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足しています。 」のようなメッセージが出る:nugetから復元したSharpZipLibの参照解決ができていない。Copy Local->nugetできる場所がプロパティに見当たらなかったので、nuget参照を消してbinフォルダのdllを参照させるように変更

CreateZip Actionのコピーを作る

Input Parameter 「Password」を追加したCreateZip2 Actionを、CreateZip Actionをコピーして作成。
image.png

Actionの実装。

public void MssCreateZip2(out object ssZipHandle, int ssCompressionLevel, string ssPassword) {
    ssZipHandle = new ZipHandle(ssCompressionLevel, ssPassword);
} // MssCreateZip2

ZipHandleクラスのコンストラクタに第2引数Passwordを追加したものを作成する。なお、ZipHandleクラスはExtension内で、SharpZipLibを操作するための処理をまとめたクラス。メンバ変数のpasswordに渡した値を保存しておく。

public ZipHandle(int level, string password = "") {
    this.level = level;
    this.password = password;
}

以下は、作成するZipファイルに個別のファイルを登録していくAddFile Actionから呼び出されるWriteStream。このメソッドは保存しておいたZipOutputStreamオブジェクトを返す。最初の呼び出し時にZipOutputStreamをインスタンス化しているので、このとき同時にPasswordを設定する処理を追加しておく(outputStream.Password = this.password;とその前のif文)。

public ZipOutputStream WriteStream {
    get {
        if (null == outputStream) {
            if (outputMemoryStream != null) {
                outputMemoryStream.Dispose();
            }
            outputMemoryStream = new MemoryStream();
            outputStream = new ZipOutputStream(outputMemoryStream);
            outputStream.UseZip64 = UseZip64.Off;
            if (!string.IsNullOrEmpty(this.password))
                outputStream.Password = this.password;
            outputStream.SetLevel(this.level);
        }
        return outputStream;
    }
}

次に、AESのビット指定について。
AddFile Actionの実体にentry.AESKeySize = 256;を追加する。これで、パスワードを指定したとき、AES256で暗号化してくれるようになるはず。

public void MssAddFile(object ssZipHandle, string ssFileName, DateTime ssDateTime, byte[] ssFileContent) {
    Crc32 crc = new Crc32();
    ZipOutputStream stream = ((ZipHandle)ssZipHandle).WriteStream;
    ZipEntry entry = new ZipEntry(ssFileName);

    crc.Reset();
    crc.Update(ssFileContent);

    entry.Crc = crc.Value;
    entry.DateTime = ssDateTime;
    entry.IsUnicodeText = true;
    entry.AESKeySize = 256;     // AES暗号化に使うビット数

    stream.PutNextEntry(entry);
    stream.Write(ssFileContent, 0, ssFileContent.Length);
}

動作確認

上記修正を入れたCloneOfZipをPublishし、Zipの代わりに暗号化処理を行ってみる。
以下の通り処理の流れは、以前の記事で説明したZip Extensionの場合と同じで、違いは今回追加したCreateZip2を使っている点だけ。

image.png

7-Zipで暗号化が適用されていることを確認

7-ZipでZipファイルを開くと、各ファイルに適用されている暗号化アルゴリズムを確認できる。

image.png

ちなみに、AESKeySizeを指定せずにPasswordだけを指定した場合のZipファイルは以下の通り、ZipCryptoで圧縮されているらしい。この方法は危ないかもしれない。
image.png

ライセンスの検討

パスワード付きZipを作成する方法の調査として色々書いてきたが、System Component(Zip Extension)のソースコード流用がOKかどうかは不明。
OutSystemsに確認するか、もしくは内部で使っているSharpZipLibがMITライセンスなので、同等のものを自分で作るかかな。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1