トップ回答者
TripleDESCryptoServiceProviderでバイト列を暗号化する

質問
-
TripleDESCryptoServiceProviderのサンプル、たとえば
http://msdn.microsoft.com/ja-jp/library/system.security.cryptography.tripledescryptoserviceprovider.aspx
では文字列を暗号化することは出来ますが、バイト列を暗号化出来ません。
StreamWriterとStreamReaderを別のものに置き換えれば良いように思うのですが、どうすれば良いか分かりません。
文字列ではなくバイト列を暗号化するにはどうすれば良いのでしょうか。
回答
-
暗号化されたバイト列は、任意のバイトで終了します。つまり、末尾のバイトは 0x00 ~ 0xFF まで全てをとります。
このため、復号時にパディングの除去作業として、
- 復号化されたバイト列の最後のオクテット T を取得する。
- 復号化されたバイト列の末尾から、連続する T を削除する。
という操作を行うことを想定すると、暗号化されたバイト列は必ずパディング文字で終わる必要があります。具体例をあげると、
- ABC を暗号化した場合、パディング文字は C 以外の任意が使用できます。たとえば、B を使用して ABCBBBBB とできます。
- 同様に、ABCABCA をパディング B を含めて ABCABCAB で暗号化できます。
- ABCABCAB を暗号化した場合、パディング文字を埋めないと ABCABCAB になります。
- ABCABCAB をパディング文字を含める場合、末尾が B なので B 以外の何か...たとえば A を使用して ABCABCABAAAAAAAA になります。
パディング文字がない場合、復号化できないという問題が発生することがわかりますでしょうか?
- 編集済み K. Takaoka 2010年12月14日 6:30 若干、言い回しや助詞を変更
- 回答としてマーク 山本春海 2010年12月20日 2:24
-
サンプルの EncryptTextToFile で使用されている StreamWriter は、cStream に対して文字列を書き込むために使用されています。
バイト列を書き込みたい場合には、StreamWriter を作成しないで cStream の Write メソッドを直接呼べばよいと思います。int 等のデータを書きこむ場合には、StreamWriter のかわりに BinaryWriter を作成するとよいかと思います。
具体的な方法がわかりにくい場合、CryptoStream は一般的な Stream として扱うことができるので、暗号化関連に限らずに「ファイルに xxx を書きこむ方法」などの FileStream を対象にしたサンプルコード類を検索されるとよいかもしれません。
- 回答としてマーク 山本春海 2010年12月20日 2:24
-
だから仕様ですって。
PKCS#7 は RFC2315 で定義されています。パディングのサイズに関する記述を抜き出すと、
the method shall be to pad the input at the trailing end with k - (l mod k) octets all having value k - (l mod k), where l is the length of the input.
となっています。この式から、パディングのサイズは、入力データの長さ l がブロックサイズ k で割り切れる場合、ブロックサイズ k と一致します(ただし単位はオクテット = 8bit = 普通のPCの 1 byte)。
ブロックサイズが 64bit = 8 byte で、入力が 16 byte の場合、8 - (16 mod 8) となり、16 ÷ 8 の余りは 0 で、8 - 0 = 8 byte がパディングになります。
- 回答としてマーク 山本春海 2010年12月20日 2:24
すべての返信
-
サンプルの EncryptTextToFile で使用されている StreamWriter は、cStream に対して文字列を書き込むために使用されています。
バイト列を書き込みたい場合には、StreamWriter を作成しないで cStream の Write メソッドを直接呼べばよいと思います。int 等のデータを書きこむ場合には、StreamWriter のかわりに BinaryWriter を作成するとよいかと思います。
具体的な方法がわかりにくい場合、CryptoStream は一般的な Stream として扱うことができるので、暗号化関連に限らずに「ファイルに xxx を書きこむ方法」などの FileStream を対象にしたサンプルコード類を検索されるとよいかもしれません。
- 回答としてマーク 山本春海 2010年12月20日 2:24
-
ありがとうございます。
CryptoStream に対して直接 Read Write する方法と、BinaryWriter BinaryReader を使う方法を両方ためしてみました。
まず、CryptoStream に対して直接 Read Write する方法はデータのバイト数が8の倍数で無ければ Read 時にエラーになります。
BinaryWriter BinaryReader を使う方法はデータのバイト数が8の倍数でなくても、エンコード デコード可能です。
ただし、どちらの方法にも共通の問題があり悩んでいます。
元のデータが7バイト以下のときは暗号化した結果は8バイトになります。
しかし、8バイトのデータを暗号化すると、結果は16バイトになってしまいます。データの長さは変わらないと言うことなので、8バイトのデータを暗号化すると8バイト、9バイトのデータを暗号化すると16バイト、
なら分かるのですが、なぜ8バイトのデータを暗号化すると16バイトになってしまうのか、悩んでいます。 -
だから仕様ですって。
PKCS#7 は RFC2315 で定義されています。パディングのサイズに関する記述を抜き出すと、
the method shall be to pad the input at the trailing end with k - (l mod k) octets all having value k - (l mod k), where l is the length of the input.
となっています。この式から、パディングのサイズは、入力データの長さ l がブロックサイズ k で割り切れる場合、ブロックサイズ k と一致します(ただし単位はオクテット = 8bit = 普通のPCの 1 byte)。
ブロックサイズが 64bit = 8 byte で、入力が 16 byte の場合、8 - (16 mod 8) となり、16 ÷ 8 の余りは 0 で、8 - 0 = 8 byte がパディングになります。
- 回答としてマーク 山本春海 2010年12月20日 2:24
-
暗号化されたバイト列は、任意のバイトで終了します。つまり、末尾のバイトは 0x00 ~ 0xFF まで全てをとります。
このため、復号時にパディングの除去作業として、
- 復号化されたバイト列の最後のオクテット T を取得する。
- 復号化されたバイト列の末尾から、連続する T を削除する。
という操作を行うことを想定すると、暗号化されたバイト列は必ずパディング文字で終わる必要があります。具体例をあげると、
- ABC を暗号化した場合、パディング文字は C 以外の任意が使用できます。たとえば、B を使用して ABCBBBBB とできます。
- 同様に、ABCABCA をパディング B を含めて ABCABCAB で暗号化できます。
- ABCABCAB を暗号化した場合、パディング文字を埋めないと ABCABCAB になります。
- ABCABCAB をパディング文字を含める場合、末尾が B なので B 以外の何か...たとえば A を使用して ABCABCABAAAAAAAA になります。
パディング文字がない場合、復号化できないという問題が発生することがわかりますでしょうか?
- 編集済み K. Takaoka 2010年12月14日 6:30 若干、言い回しや助詞を変更
- 回答としてマーク 山本春海 2010年12月20日 2:24