0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

暗号プラグインの実装方法

Posted at

StreamRelay.NET.exe の暗号機能を呼び出しているプラグインの実装方法について説明する

StreamRelay.NET.exe/StreamRelay.NET.x86.exeには、いくつかの機能をプラグインとして実装できるようにインターフェイスを公開している。

今回は、暗号機能のためのインターフェイスを使って、プラグインを作成する方法を記述する。


既存のプラグイン

ストリームを包んでデータを暗号化/復号するストリーム。

そんな感じ。

プラグイン的には、このあたり。

  • Plugins\Plugin.Classless.Hasher.dll
  • Plugins\Plugin.BouncyCastle.Crypto.dll
  • Plugins\Plugin.CSharpCode.SharpZipLib

実装したプラグインの呼び出され方

プラグインで指定された引数を渡して、Streamを暗号で包んだりする。

という感じ。


実装するインターフェイス

以下のインターフェイスを継承したクラスを実装すればよい

  • IPlugin.dll 中の jp.dip.rocketeer.Plugins.IPluginCipherEntity インターフェイス
  • IPlugin.dll 中の jp.dip.rocketeer.Plugins.IPluginCipher インターフェイス

このクラス2つだけ実装すればよい。


jp.dip.rocketeer.Plugins.IPluginCipher インターフェイス

StreamRelay.NET.exeや、他のプラグインから、引数/オプションの解析処理中に呼び出して、引数の指定内容によって、IPluginCipherEntityを返す。

あとは、IPluginCipherEntity インターフェイスのオブジェクトが暗号化/復号を実施する。

具体的には、-(Local|Remote)Proxy の netstreamスキーム指定時の、暗号化/復号の解析で
IPluginCipherEntity CreateCipherEntity(Dictionary<String, Object> iList, Boolean IsInput,ref String errMsg)
を呼び出すので、自分の引数であれば、IPluginCipherEntityオブジェクトを返してほしい。


jp.dip.rocketeer.Plugins.IPluginCipherインターフェイスで定義しているメソッド/プロパティ

実装する必要があるのは以下

jp.dip.rocketeer.Plugins.IPluginCipherインターフェイスで定義されているのは、以下のとおり

Dictionary<String, String[]> ListDescription(out String SubDescription)
usage の文章を返す。
暗号プラグインの場合、「-ListCipher」オプションで、暗号プラグインの一覧を返すので、その説明文を返す。
SubDescription
「EncryptCipherAlgorithm」に与える引数の書式を格納してほしい。例えば私のツールだと「アルゴリズム名/モード/パディング」なので、「CipherName/CipherMode/CipherPadding」という文字列を格納している
Dictionary<String, String[]>
書式ごとのオプションを返してほしい。
私の.NET Framework標準の暗号ライブラリを呼び出すプラグインの場合、
  1. 「CipherName」という名前で「AES」「DES」「RC2」「Rijndael」「TripleDES」という文字列配列
  2. 「CipherMode」という名前で「CBC」「ECB」「OFB」「CFB」「CTS」という文字列配列
  3. 「CipherPadding」という名前で「None」「PKCS7」「Zeros」「ANSIX923」「ISO10126」という文字列配列
jp.dip.rocketeer.Plugins.IPluginCipherEntity CreateCipherEntity(Dictionary<String, Object> iList, Boolean IsInput,ref String errMsg)
オプションに基づいて暗号化/復号のオブジェクトを生成する
IsInput : 入力側か、出力側か
errMsg : エラーが発生したら、これに書き込んでください
iList : ディクショナリの配列で、名前(Key)にはオプションの名前、値にはオプションの値(Object型)が収められているので、それに応じた暗号化/復号のオブジェクトを生成してほしい。
名前には、jp.dip.rocketeer.Plugins.CipherParametersにいくつか列挙している。

現時点(2021/07/05)では、こんな感じ
Name
暗号アルゴリズム名(String)
Mode
ブロック暗号方式のモードの名前(String)
Padding
ブロック暗号方式のパディング方式の名前(String)
IV
初期値(Initial Vector)(byte[])
Password
共通鍵(SecretData(sCommonNET.dll))
PasswordHash
共通鍵を攪拌するオブジェクト(jp.dip.rocketeer.Plugins.IPluginPasswordStirringEntity)
Rounds
BouncyCastle の RC5(64Bit用)(int)
macSize
macSize(byte), Mac用
cfbSize
CFB Size(byte), Mac用
Cipher
暗号オプション
Nonce
Aeadモードの Nonce
NonceHex
Aeadモードの Nonce
AssociatedText
Aeadモードの AssociatedText
AssociatedTextHex
Aeadモードの AssociatedText
Nb
Aeadモード/KCCM の Nb
これらの名称に応じて値の型も替わっているので、それに応じて、オブジェクトを生成してほしい。

jp.dip.rocketeer.Plugins.IPluginBaseインターフェイスで定義されている分については、インターフェイス IPluginBase についてを参照


jp.dip.rocketeer.Plugins.IPluginCipher#CreateCipherEntity メソッドの Dictionary<String, Object> 型について

例えば、
netstream://EncryptCipherAlgorithm=AES/CBC/PKCS7&EncryptCipherPassword=password&EncryptCipherPasswordHashAlgorithm=SHA512&EncryptCipherIV=IVIVIVIV
コマンドライン上だと**「&」**をエスケープして、
netstream://EncryptCipherAlgorithm=AES/cbc/PKCS7^&EncryptCipherPassword=password^&EncryptCipherPasswordHashAlgorithm=SHA512^&EncryptCipherIV=IVIVIVIV
だけど・・・

↑は

  • .NET Framework標準のAESのオブジェクトを使って
  • モードは「CBC」で、パディングは「PKCS7」
  • IVは「IVIVIVIV」
  • 暗号鍵は「password」で
  • 暗号鍵はSHA512で攪拌する

という設定となるのだけど・・・

さて、、、
↑の場合、jp.dip.rocketeer.Plugins.IPluginCipher#CreateCipherEntityメソッドに渡されるDictionary<String, Object>型には

  1. 「Name」という名前で文字列「AES」
  2. 「Mode」という名前で文字列「CBC」
  3. 「Padding」という名前で文字列「PKCS7」
  4. 「IV」という名前で文字列「IVIVIVIV」のバイト配列
  5. 「Password」という名前でjp.dip.rocketeer.Common.SecretData型に「password」が格納
  6. 「PasswordHash」という名前でjp.dip.rocketeer.Common.Cipher.DefaultHashMac型でSHA512を実行するオブジェクト

という6つのディクショナリを持つ。

そして、暗号鍵は、

(list をDictionary<String, Object>型の引数だとして・・・)

Byte[] hako = ((jp.dip.rocketeer.Common.SecretData)list[jp.dip.rocketeer.Plugins.CipherParameters.Password.ToString()]).GetSecret();

でバイト配列として取得できる(「password」のバイト配列)

これを SHA512で攪拌するには、

jp.dip.rocketeer.Plugins.IPluginPasswordStirringEntity tempObj =(jp.dip.rocketeer.Plugins.IPluginPasswordStirringEntity)list[jp.dip.rocketeer.Plugins.CipherParameters.PasswordHash.ToString()]; hako = tempObj.GetHash(hako);

で、攪拌してくれるので、これを適当なサイズに切り取って(※)、暗号化/復号オブジェクトの暗号鍵として使えばよいだろう。

(※) : 暗号アルゴリズムによって、暗号鍵のサイズは厳密に定義されているので、それを意味している。


jp.dip.rocketeer.Common.SecretData 型について

暗号鍵(パスワード)はsCommonNET.dllで実装しているjp.dip.rocketeer.Common.SecretData型で渡されるので、sCommonNET.dllもインポートする必要があるだろう。


jp.dip.rocketeer.Plugins.IPluginCipherEntity インターフェイスで定義しているメソッド/プロパティ

実装する必要があるのは以下

jp.dip.rocketeer.Plugins.IPluginCipherEntityインターフェイスで定義されているのは、以下のとおり

Boolean IsInput { get; set; }
InputStream or OutputStream
Boolean IsTest()
指定されたオプションで暗号オブジェクトを生成できるかのテストをする
パスワードは、後から渡される場合もあるので、NULL のままこの関数が呼ばれる場合もある
InOutStream CreateStream(Stream baseStream)
Cipherストリームを返す
String ArgorithmName()
Cipher アルゴリズム名を返す
IPluginCipherEntity Copy()
マルチスレッドを考慮して自分自身のディープコピーを返す

jp.dip.rocketeer.Plugins.InOutStream について

この入力と出力のどちらか(または両方)のストリームのクラスは、フィルタストリームのプラグインのところで説明したので、省略。


目次へ戻る

目次というか最初の一歩

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?