none
TripleDESCryptoServiceProviderでバイト列を暗号化する RRS feed

回答

  • 暗号化されたバイト列は、任意のバイトで終了します。つまり、末尾のバイトは 0x00 ~ 0xFF まで全てをとります。

    このため、復号時にパディングの除去作業として、

    1. 復号化されたバイト列の最後のオクテット T を取得する。
    2. 復号化されたバイト列の末尾から、連続する 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
    2010年12月14日 5:02
  • サンプルの EncryptTextToFile で使用されている StreamWriter は、cStream に対して文字列を書き込むために使用されています。

    バイト列を書き込みたい場合には、StreamWriter を作成しないで cStream の Write メソッドを直接呼べばよいと思います。int 等のデータを書きこむ場合には、StreamWriter のかわりに BinaryWriter を作成するとよいかと思います。

    具体的な方法がわかりにくい場合、CryptoStream は一般的な Stream として扱うことができるので、暗号化関連に限らずに「ファイルに xxx を書きこむ方法」などの FileStream を対象にしたサンプルコード類を検索されるとよいかもしれません。

    • 回答としてマーク 山本春海 2010年12月20日 2:24
    2010年12月8日 3:24
  • 既定のパディングモードである PKCS#7 の仕様です(パディングについては、「ブロック暗号 パディング」辺りで検索してください)。

    .NET では、各対称アルゴリズムの実装の基底クラスである SymmetricAlgorithm の、Padding プロパティで指定できますが、既定値である PKCS7 が推奨されています。

    • 回答としてマーク 山本春海 2010年12月20日 2:24
    2010年12月8日 8:29
  • だから仕様ですって。

    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
    2010年12月9日 2:23

すべての返信

  • リンク先のサンプルの二つ目、特に文字列に限った内容でも無いですけど。StreamWriter/StreamReader 使ってませんし。

    2010年12月8日 2:23
  • サンプルの EncryptTextToFile で使用されている StreamWriter は、cStream に対して文字列を書き込むために使用されています。

    バイト列を書き込みたい場合には、StreamWriter を作成しないで cStream の Write メソッドを直接呼べばよいと思います。int 等のデータを書きこむ場合には、StreamWriter のかわりに BinaryWriter を作成するとよいかと思います。

    具体的な方法がわかりにくい場合、CryptoStream は一般的な Stream として扱うことができるので、暗号化関連に限らずに「ファイルに xxx を書きこむ方法」などの FileStream を対象にしたサンプルコード類を検索されるとよいかもしれません。

    • 回答としてマーク 山本春海 2010年12月20日 2:24
    2010年12月8日 3:24
  • ありがとうございます。

    CryptoStream に対して直接 Read Write する方法と、BinaryWriter BinaryReader を使う方法を両方ためしてみました。

    まず、CryptoStream に対して直接 Read Write する方法はデータのバイト数が8の倍数で無ければ Read 時にエラーになります。

    BinaryWriter BinaryReader を使う方法はデータのバイト数が8の倍数でなくても、エンコード デコード可能です。

    ただし、どちらの方法にも共通の問題があり悩んでいます。

    元のデータが7バイト以下のときは暗号化した結果は8バイトになります。
    しかし、8バイトのデータを暗号化すると、結果は16バイトになってしまいます。

    データの長さは変わらないと言うことなので、8バイトのデータを暗号化すると8バイト、9バイトのデータを暗号化すると16バイト、
    なら分かるのですが、なぜ8バイトのデータを暗号化すると16バイトになってしまうのか、悩んでいます。

    2010年12月8日 7:03
  • 既定のパディングモードである PKCS#7 の仕様です(パディングについては、「ブロック暗号 パディング」辺りで検索してください)。

    .NET では、各対称アルゴリズムの実装の基底クラスである SymmetricAlgorithm の、Padding プロパティで指定できますが、既定値である PKCS7 が推奨されています。

    • 回答としてマーク 山本春海 2010年12月20日 2:24
    2010年12月8日 8:29
  • Padding を PaddingMode.None にすると8バイトのデータを暗号化すれば結果も8バイトになりました。

    しかし、ぴったりブロックサイズなのに勝手にパディングを追加して1ブロック増やしてしまうというのは、どう考えてもおかしいと思います。
    .NET のバグでしょうか。

    2010年12月9日 1:27
  • だから仕様ですって。

    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
    2010年12月9日 2:23
  • 仕様だと言うこと、了解しました。
    しかし、なぜぴったりブロックサイズの時に1ブロック追加してしまうのでしょうか。
    1ブロック追加することで何か利点があるのでしょうか。

    2010年12月14日 2:44
  • 暗号化されたバイト列は、任意のバイトで終了します。つまり、末尾のバイトは 0x00 ~ 0xFF まで全てをとります。

    このため、復号時にパディングの除去作業として、

    1. 復号化されたバイト列の最後のオクテット T を取得する。
    2. 復号化されたバイト列の末尾から、連続する 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
    2010年12月14日 5:02