C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[15]: 共通鍵復号化


(過去ログ 42 を表示中)

[トピック内 19 記事 (1 - 19 表示)]  << 0 >>

■21949 / inTopicNo.1)  共通鍵復号化
  
□投稿者/ adrian_beltre (21回)-(2008/07/12(Sat) 22:05:27)

分類:[C#] 

[C#]
/// <summary>
/// ファイルを復号化する
/// </summary>
/// <param name="fileName">復号化するファイル名</param>
/// <param name="key">パスワード</param>
public static void DecryptFile(string fileName, string key)
{
//DESCryptoServiceProviderオブジェクトの作成
System.Security.Cryptography.DESCryptoServiceProvider des =
new System.Security.Cryptography.DESCryptoServiceProvider();

//共有キーと初期化ベクタを決定
//パスワードをバイト配列にする
byte[] bytesKey = System.Text.Encoding.UTF8.GetBytes(key);
//共有キーと初期化ベクタを設定
des.Key = ResizeBytesArray(bytesKey, des.Key.Length);
des.IV = ResizeBytesArray(bytesKey, des.IV.Length);

//暗号化されたファイルを読み込むためのFileStream
System.IO.FileStream fsIn =
new System.IO.FileStream(fileName,
System.IO.FileMode.Open, System.IO.FileAccess.Read);
//DES復号化オブジェクトの作成
System.Security.Cryptography.ICryptoTransform desdecrypt =
des.CreateDecryptor();
//読み込むためのCryptoStreamの作成
System.Security.Cryptography.CryptoStream cryptStreem =
new System.Security.Cryptography.CryptoStream(fsIn,
desdecrypt,
System.Security.Cryptography.CryptoStreamMode.Read);

//復号化されたファイルの保存先
string outFileName;
if (fileName.ToLower().EndsWith(".enc"))
outFileName = fileName.Substring(0, fileName.Length - 4);
else
outFileName = fileName + ".dec";
//復号化されたファイルを書き出すためのFileStream
System.IO.FileStream fsOut =
new System.IO.FileStream(outFileName,
System.IO.FileMode.Create, System.IO.FileAccess.Write);

//復号化されたデータを書き出す
byte[] bs = new byte[256];
int readLen;
while ((readLen = cryptStreem.Read(bs, 0, bs.Length)) > 0)
fsOut.Write(bs, 0, readLen);

//閉じる
cryptStreem.Close();
fsIn.Close();
fsOut.Close();
}

上記のプログラムで共通化暗号化したファイルを復号することにしているのですが、誤ったパスワードを入力されたときに復号化に失敗してなおかつファイルの内容が変化してしまいます。これを解決するためにファイルを最初にコピーして失敗したら元ファイルをコピーファイルで上書きすることも考えましたがうまくいきませんでした。
そこで、誤ったパスワードを入力されたときにファイルの内容が変わらずに単なる復号化に失敗する方法はないでしょうか教えてください。
引用返信 編集キー/
■21950 / inTopicNo.2)  Re[1]: 共通鍵復号化
□投稿者/ ま (70回)-(2008/07/12(Sat) 22:38:58)

パスワードの先頭2文字をチェックサムとして、メモリストリームに Write した
結果のチェックサムと同じがどうかを判定してから、書き込み用ファイルに上書き
するってのはダメ?


引用返信 編集キー/
■21952 / inTopicNo.3)  Re[2]: 共通鍵復号化
□投稿者/ adrian_beltre (23回)-(2008/07/12(Sat) 22:44:54)
ま さん

ちょっとまさんの方法でやってみたいので具体的な方法を教えていただけますか。
引用返信 編集キー/
■21953 / inTopicNo.4)  Re[3]: 共通鍵復号化
□投稿者/ も (26回)-(2008/07/12(Sat) 22:58:03)
No21952 (adrian_beltre さん) に返信
> ま さん
>
> ちょっとまさんの方法でやってみたいので具体的な方法を教えていただけますか。
読んだ限りこの上なく具体的な方法に見えるわけですが.
チェックサムはSHA256とかで構わないので十分に実現可能だと思いますよ.
引用返信 編集キー/
■21956 / inTopicNo.5)  Re[4]: 共通鍵復号化
□投稿者/ ま (72回)-(2008/07/12(Sat) 23:40:21)
No21953 (も さん) に返信
> ■No21952 (adrian_beltre さん) に返信
>>ま さん
>>
>>ちょっとまさんの方法でやってみたいので具体的な方法を教えていただけますか。
> 読んだ限りこの上なく具体的な方法に見えるわけですが.
> チェックサムはSHA256とかで構わないので十分に実現可能だと思いますよ.

この”シャァニゴロ”ってのは、XORってこと?
自分は手抜きでXORを多用するんですが。
エスエィッチエーニヒャクゴジュウロクって読むんですかね。
エスエィッチエーワンじゃなくて、しゃーいち。

#頭文字の通称を皆なんて脳内変換しているのか気になります。


元データから暗号キーを作成するときに、キー作成後、元データを 例えば
FF で XORを取る。その結果を16進数文字列にしてキーの前にくっつける。

デコードするときは、先頭2文字を16進数に変換して、先頭から3文字目以降
をキーとして、復号する。復号結果を 先頭2文字で XORすると、元のFFに戻る。
戻れば、改変無しの可能性90%くらい、戻らなければ改変あり。
90%の根拠はまったくないけど、ちゃんと複合化できたかどうかの判断を自分
でどこに持ってくるかだけだと思いますね。それには、XORなんぞ使わず
にもっとこじゃれたチェックサムを採用すればOK。

XORは簡単だから。
全部足して、素数で割った余りを先頭にくっつけるとか、方法は色々あるかな。




引用返信 編集キー/
■21957 / inTopicNo.6)  Re[5]: 共通鍵復号化
□投稿者/ も (27回)-(2008/07/13(Sun) 00:05:33)
No21956 (ま さん) に返信
> ■No21953 (も さん) に返信
>>■No21952 (adrian_beltre さん) に返信
> >>ま さん
> >>
> >>ちょっとまさんの方法でやってみたいので具体的な方法を教えていただけますか。
>>読んだ限りこの上なく具体的な方法に見えるわけですが.
>>チェックサムはSHA256とかで構わないので十分に実現可能だと思いますよ.
>
> この”シャァニゴロ”ってのは、XORってこと?
> 自分は手抜きでXORを多用するんですが。
> エスエィッチエーニヒャクゴジュウロクって読むんですかね。
> エスエィッチエーワンじゃなくて、しゃーいち。
>
> #頭文字の通称を皆なんて脳内変換しているのか気になります。
http://msdn.microsoft.com/ja-jp/library/system.security.cryptography.sha256(VS.80).aspx

べつにCRC32でも何でもいいですけど,そんなに面倒じゃない方法ということでハッシュ関数を薦めますた
引用返信 編集キー/
■21958 / inTopicNo.7)  Re[6]: 共通鍵復号化
□投稿者/ ま (73回)-(2008/07/13(Sun) 01:38:28)
CRC32
http://blog.goo.ne.jp/masaki_goo_2006/e/4abe49f891bf03b22354f0283dfd2806

なにやってるのかよくわからんけど、勉強になります。

SHA256
http://www.f13g.com/%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0/C_C%2B%2B/SHA256/

これも同じく。

ということで、スレ主さんも既存アルゴリズムが難解で嫌うなら自分で工夫してみる
といいですよ。検査なんで別にどれでもいいんだけど。


引用返信 編集キー/
■21961 / inTopicNo.8)  Re[5]: 共通鍵復号化
□投稿者/ れい (697回)-(2008/07/14(Mon) 05:46:13)
No21956 (ま さん) に返信
> 90%の根拠はまったくないけど、ちゃんと複合化できたかどうかの判断を自分
> でどこに持ってくるかだけだと思いますね。それには、XORなんぞ使わず
> にもっとこじゃれたチェックサムを採用すればOK。

「根拠はまったくない」とか言ってしまうと他人が説得できません。
誤り検出は重要な概念の一つですので、
基本を抑えておくと良いと思います。

XORはハッシュとしてまぁまぁ良好で、
復号失敗やファイル改竄などがあった場合は十分に分散すると考えられます。

XORを1バイト単位でXORを取るなら255/256=99.6%以上の確率で正しいと判断してOKです。
普通は32bit以上のバス幅ですから4バイト毎にXORを取れば(1-1/2^32)となりますので
間違う確率は10^-10程度になります。

No21949 (adrian_beltre さん) に返信
> そこで、誤ったパスワードを入力されたときにファイルの内容が変わらずに単なる復号化に失敗する方法はないでしょうか教えてください。

DESは64ビットのブロック暗号です。(64ビット毎に暗号化を行っている。)
最低64ビットのデータがあれば複合化できることになります。

なので、最初の64ビット=8バイトに、復号検証用の64ビットのマジックナンバーを入れておけば検証できます。
64ビット程度であればローカル変数に保存しても問題になりません。
ソフトウェア名やバージョンなどをいれることが多いようです。

具体的には…

最初に64ビット読み込み、それを復号してマジックナンバーと一致しないなら「鍵が違う」といって停止。
一致したならその時点で書き込み用ストリームを開き、
マジックナンバーを書き込む。
その後今までどおり復号ストリームから読み取って書き込み用ストリームに書き込めば良いでしょう。

DESは時代遅れとはいえ暗号化アルゴリズムなので、
「鍵が違っていたのに復号したらたまたまマジックナンバーが一致してしまった」
というのは考慮する必要はありません。
違う鍵で同じ平分に復号できてしまう確率は2^-64の確率になります。

もしそれ以上の確率でマジックナンバーが一致してしまうことがあるなら、
暗号化アルゴリズムの欠陥を発見したことになります。
#その場合「ファイルの復号がうまくいかない」とか言ってる場合ではありません。

引用返信 編集キー/
■21964 / inTopicNo.9)  Re[6]: 共通鍵復号化
□投稿者/ なちゃ (147回)-(2008/07/14(Mon) 08:39:54)
念のため、たまたまのミスあるいはビット誤りのようなものを防ぐ目的と、改ざんなどの検出は別レベルで考えたほうが良いでしょう。

ちなみに件のコードのDES方式では、実質鍵サイズはおそらく40ビット程度です。
※パスワードを8文字しっかり使った場合で

引用返信 編集キー/
■22137 / inTopicNo.10)  Re[7]: 共通鍵復号化
□投稿者/ adrian_beltre (24回)-(2008/07/15(Tue) 23:37:12)
れいさん

マジックナンバーはどのように作ればよろしいのでしょうか?
引用返信 編集キー/
■22140 / inTopicNo.11)  Re[8]: 共通鍵復号化
□投稿者/ adrian_beltre (25回)-(2008/07/15(Tue) 23:53:18)
一応、暗号化のプログラムも載せておきます。

/// <summary>
/// ファイルを暗号化する
/// </summary>
/// <remarks>
/// 暗号化されたファイルは"(ファイル名).enc"として保存される
/// </remarks>
/// <param name="fileName">暗号化するファイル名</param>
/// <param name="key">パスワード</param>
public static void EncryptFile(string fileName, string key)
{
//暗号化するファイルを読み込む
System.IO.FileStream fsIn =
new System.IO.FileStream(fileName,
System.IO.FileMode.Open, System.IO.FileAccess.Read);
//すべて読み込む
byte[] bytesIn = new byte[fsIn.Length];
fsIn.Read(bytesIn, 0, bytesIn.Length);
//閉じる
fsIn.Close();

//DESCryptoServiceProviderオブジェクトの作成
System.Security.Cryptography.DESCryptoServiceProvider des =
new System.Security.Cryptography.DESCryptoServiceProvider();

//共有キーと初期化ベクタを決定
//パスワードをバイト配列にする
byte[] bytesKey = System.Text.Encoding.UTF8.GetBytes(key);
//共有キーと初期化ベクタを設定
des.Key = ResizeBytesArray(bytesKey, des.Key.Length);
des.IV = ResizeBytesArray(bytesKey, des.IV.Length);

//暗号化されたファイルの保存先
string outFileName = fileName + ".enc";
//暗号化されたファイルを書き出すためのFileStream
System.IO.FileStream fsOut =
new System.IO.FileStream(outFileName,
System.IO.FileMode.Create, System.IO.FileAccess.Write);
//DES暗号化オブジェクトの作成
System.Security.Cryptography.ICryptoTransform desdecrypt =
des.CreateEncryptor();
//書き込むためのCryptoStreamの作成
System.Security.Cryptography.CryptoStream cryptStreem =
new System.Security.Cryptography.CryptoStream(fsOut,
desdecrypt,
System.Security.Cryptography.CryptoStreamMode.Write);
//書き込む
cryptStreem.Write(bytesIn, 0, bytesIn.Length);
//閉じる
cryptStreem.Close();
fsOut.Close();
}

/// <summary>
/// ファイルを復号化する
/// </summary>
/// <param name="fileName">復号化するファイル名</param>
/// <param name="key">パスワード</param>
public static void DecryptFile(string fileName, string key)
{
//DESCryptoServiceProviderオブジェクトの作成
System.Security.Cryptography.DESCryptoServiceProvider des =
new System.Security.Cryptography.DESCryptoServiceProvider();

//共有キーと初期化ベクタを決定
//パスワードをバイト配列にする
byte[] bytesKey = System.Text.Encoding.UTF8.GetBytes(key);
//共有キーと初期化ベクタを設定
des.Key = ResizeBytesArray(bytesKey, des.Key.Length);
des.IV = ResizeBytesArray(bytesKey, des.IV.Length);

//暗号化されたファイルを読み込むためのFileStream
System.IO.FileStream fsIn =
new System.IO.FileStream(fileName,
System.IO.FileMode.Open, System.IO.FileAccess.Read);
//DES復号化オブジェクトの作成
System.Security.Cryptography.ICryptoTransform desdecrypt =
des.CreateDecryptor();
//読み込むためのCryptoStreamの作成
System.Security.Cryptography.CryptoStream cryptStreem =
new System.Security.Cryptography.CryptoStream(fsIn,
desdecrypt,
System.Security.Cryptography.CryptoStreamMode.Read);

//復号化されたファイルの保存先
string outFileName;
if (fileName.ToLower().EndsWith(".enc"))
outFileName = fileName.Substring(0, fileName.Length - 4);
else
outFileName = fileName + ".dec";

//復号化されたデータを書き出すためのStreamWriter
System.IO.StreamWriter sw =
new System.IO.StreamWriter(outFileName, false,
System.Text.Encoding.GetEncoding("sjis"));
//復号化されたデータを読み込む
System.IO.StreamReader sr =
new System.IO.StreamReader(cryptStreem,
System.Text.Encoding.GetEncoding("sjis"));
//復号化されたデータを書き出す
sw.Write(sr.ReadToEnd());
sw.Flush();

//閉じる
sr.Close();
sw.Close();
cryptStreem.Close();
fsIn.Close();
}

/// <summary>
/// 共有キー用に、バイト配列のサイズを変更する
/// </summary>
/// <param name="bytes">サイズを変更するバイト配列</param>
/// <param name="newSize">バイト配列の新しい大きさ</param>
/// <returns>サイズが変更されたバイト配列</returns>
private static byte[] ResizeBytesArray(byte[] bytes, int newSize)
{
byte[] newBytes = new byte[newSize];
if (bytes.Length <= newSize)
{
for (int i = 0; i < bytes.Length; i++)
newBytes[i] = bytes[i];
}
else
{
int pos = 0;
for (int i = 0; i < bytes.Length; i++)
{
newBytes[pos++] ^= bytes[i];
if (pos >= newBytes.Length)
pos = 0;
}
}
return newBytes;
}

引用返信 編集キー/
■22161 / inTopicNo.12)  Re[8]: 共通鍵復号化
□投稿者/ れい (703回)-(2008/07/16(Wed) 12:23:34)
No22137 (adrian_beltre さん) に返信
> れいさん
>
> マジックナンバーはどのように作ればよろしいのでしょうか?

0とか-1は避けたほうがいいでしょうが、
それ以外だったらなんでも。
引用返信 編集キー/
■22237 / inTopicNo.13)  Re[9]: 共通鍵復号化
□投稿者/ adrian_beltre (26回)-(2008/07/17(Thu) 12:02:07)
れいさん

ちょっと申し訳ないのですが、暗号化プログラムのどこを変更すれば実現できるのでしょうか。教えてください。
引用返信 編集キー/
■22248 / inTopicNo.14)  Re[10]: 共通鍵復号化
□投稿者/ れい (706回)-(2008/07/17(Thu) 15:38:54)
No22237 (adrian_beltre さん) に返信
> れいさん
>
> ちょっと申し訳ないのですが、暗号化プログラムのどこを変更すれば実現できるのでしょうか。教えてください。

この辺と

>//書き込む
>cryptStreem.Write(bytesIn, 0, bytesIn.Length);

この辺ですね。

>//復号化されたデータを読み込む
>System.IO.StreamReader sr =
>new System.IO.StreamReader(cryptStreem,
>System.Text.Encoding.GetEncoding("sjis"));
>//復号化されたデータを書き出す
>sw.Write(sr.ReadToEnd());

引用返信 編集キー/
■22251 / inTopicNo.15)  Re[11]: 共通鍵復号化
□投稿者/ adrian_beltre (27回)-(2008/07/17(Thu) 16:12:39)
No22248 (れい さん) に返信
れいさん
>
> >//書き込む
> >cryptStreem.Write(bytesIn, 0, bytesIn.Length);
>
を確認します。

byte[] magicNumber = 78; //マジックナンバーを78とする。
//書き込む
cryptStreem.Write(magicNumber, 0, magicNumber.Length);
cryptStreem.Write(bytesIn, magicNumber.Length, magicNumber.Length + bytesIn.Length);

というように書き換えればよろしいのでしょうか?
引用返信 編集キー/
■22260 / inTopicNo.16)  Re[12]: 共通鍵復号化
□投稿者/ れい (707回)-(2008/07/17(Thu) 16:42:54)
No22251 (adrian_beltre さん) に返信
> ■No22248 (れい さん) に返信
> れいさん
>>
>>>//書き込む
>>>cryptStreem.Write(bytesIn, 0, bytesIn.Length);
>>
> を確認します。
>
> byte[] magicNumber = 78; //マジックナンバーを78とする。
> //書き込む
> cryptStreem.Write(magicNumber, 0, magicNumber.Length);
> cryptStreem.Write(bytesIn, magicNumber.Length, magicNumber.Length + bytesIn.Length);
>
> というように書き換えればよろしいのでしょうか?

よいかどうか、やってみたらよいと思います。
とりあえず、配列の初期化が間違っています。

引用返信 編集キー/
■22297 / inTopicNo.17)  Re[13]: 共通鍵復号化
□投稿者/ adrian_beltre (28回)-(2008/07/18(Fri) 00:08:09)
No22260 (れい さん) に返信
class EncryptFile
{
/// ファイルを暗号化する
public EncryptFile(string fileName, string key)
{
try
{
//---------------------------------------
int x = InDateTime.count(fileName);
byte[] bytesIn = new byte[x + 10240];
bytesIn = InDateTime.In(fileName);
//RijndaelManagedオブジェクトの作成
System.Security.Cryptography.RijndaelManaged aes =
new System.Security.Cryptography.RijndaelManaged();

//共有キーと初期化ベクタを決定
//パスワードをバイト配列にする
byte[] bytesKey = System.Text.Encoding.UTF8.GetBytes(key);
//共有キーと初期化ベクタを設定
aes.Key = ResizeBytesArray(bytesKey, aes.Key.Length);
aes.IV = ResizeBytesArray(bytesKey, aes.IV.Length);

//desktop
string Ap = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string ApDa = XmlIn.In(Ap + @"\TEST\\filepass.xml");
string stFileName = System.IO.Path.GetFileName(fileName);
//暗号化されたファイルの保存先
string outFileName;
outFileName = FilePlace(stFileName);
//暗号化されたファイルを書き出すためのFileStream
System.IO.FileStream fsOut =
new System.IO.FileStream(outFileName,
System.IO.FileMode.Create, System.IO.FileAccess.Write);
//AES暗号化オブジェクトの作成
System.Security.Cryptography.ICryptoTransform desdecrypt =
aes.CreateEncryptor();
//書き込むためのCryptoStreamの作成
System.Security.Cryptography.CryptoStream cryptStreem =
new System.Security.Cryptography.CryptoStream(fsOut,
desdecrypt,
System.Security.Cryptography.CryptoStreamMode.Write);

//書き込む
byte[] hash = PasswordByte(key); //Sha-1のハッシュ値
cryptStreem.Write(hash, 0, hash.Length);
cryptStreem.Write(bytesIn, hash.Length, bytesIn.Length + hash.Length);
//閉じる
cryptStreem.Close();
fsOut.Close();
}

catch (Exception ex)
{
MessageBox.Show(ex.Message);
}


}

これだとマジックナンバーの変わりにパスワードのSHA-1ハッシュ値を入れることになります。しかし
「配列オフセットおよび長さが範囲を超えているか、カウンタがソースコレクションのインデックスから最後までの要素数より大きい値です」というエラーが発生します。どうしてこのようなことになるのでしょうか? 回答よろしくお願いします。
引用返信 編集キー/
■22306 / inTopicNo.18)  Re[14]: 共通鍵復号化
□投稿者/ れい (708回)-(2008/07/18(Fri) 04:17:36)
No22297 (adrian_beltre さん) に返信
> これだとマジックナンバーの変わりにパスワードのSHA-1ハッシュ値を入れることになります。しかし
> 「配列オフセットおよび長さが範囲を超えているか、カウンタがソースコレクションのインデックスから最後までの要素数より大きい値です」というエラーが発生します。どうしてこのようなことになるのでしょうか? 回答よろしくお願いします。

メッセージそのまんまですね。
配列の範囲外を指定しているので例外となっています。

適当にみただけですが
> cryptStreem.Write(bytesIn, hash.Length, bytesIn.Length + hash.Length);
ここが問題なんですよね?
MSDNのStream.Writeを参照すれば分かるかと思います。


引用返信 編集キー/
■22326 / inTopicNo.19)  Re[15]: 共通鍵復号化
□投稿者/ adrian_beltre (29回)-(2008/07/18(Fri) 12:02:11)
No22306 (れい さん) に返信
直したらきちんと目的したことが行えるようになりました。ご協力ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -