パスワードを暗号化してレジストリに保存する
開発環境: Visual Studio 2003
1.目次
2.目的
3.参考書
4.パスワードを暗号化、復号化するクラス
5.レジストリにデータをセット、ゲットする。
6.テスト用ソースコード
SMTPサーバーにメールを送信する場合に、POP Before
SMTPだとPOPのパスワードを覚えておく必要がありますよね。単純に暗号化していないパスワードをレジストリにそのまま書くのは危ないので、暗号化してしまっておく必要がありますよね。
テスト用に作ったアプリケーションはこんな感じです。
Encrypt ボタンを押すと、『今日は天気がいいですね』という入力文字列をパスワード『パスワードを入れる』で暗号化し、
暗号化されたEncrypted データをレジストリに書き込みます。
Decrypt ボタンを押すと、レジストリから、Encrypted データを読み出して、それを再度同じパスワードで復号化
するだけの簡単な動作です。
暗号化方法に関しては、参考文献(1)に書いてあるので、暗号化の中身はそちらを見てね。
System.Security.Cryptography.SymmetricAlgorithm
では、代表的な対称アルゴリズムのDES, RC2, Rijndael, TripleDESがサポートされています。
対称暗号アルゴリズムには、暗号化と復号化の両方に使用される単一の共有キーがあり、これがばれてしまうとセキュリティは確保できません。詳細は、参考文献(2)を見てください。
System.Security.Cryptography.AsymmetricAlgorithm
では、代表的な非対称アルゴリズム (公開キー アルゴリズム) のDSA,
RSAがサポートされています。非対称暗号アルゴリズムは、秘密キーと公開キー があります。初めての人は参考文献(3)がわかりやすいです。
System.Security.Cryptography.HashAlgorithmでは、代表的なMD5, SHA1, SHA256,
SHA384, SHA512がサポートされています。
くらくらきますね。こんな方法でいいのだろうかと疑問になってしまう。。。orz
-
MSDN Online = 10 行シリーズ 〜 10 行でズバリ !! 暗号化 (C#) 〜
-
MSDN SymmetricAlgorithm クラス (対称アルゴリズム)
-
サルにもわかるRSA
- まいとう情報通信研究会 (すごくわかりやすい)
まず、参考書(1)の10行シリーズをもとに、簡単なパスワードを暗号化、復号化するクラスを作成します。
このクラスには、次の2つのパブリックスタティックメソッドを用意します。
// パスワード文字列 password をキー key でTriple DES暗号化を行います。
public static byte[] Encrypt(string password, string key);
// パスワード文字列 password をキー key でTriple DES復号化を行います。
public static string Decrypt(byte [] source, string key)
参考書のコードでは、暗号化、復号化を行う TripleDESCryptoServiceProvider のKeyとIV
をローカル変数にして共通化していますので、常に復号化が可能です。しかし、普通は暗号化と復号化は別々のアプリになる可能性が高いので、
そのような場合でもKeyとIVを一致させてあげないと、復号化出来ません。
そこで、keyString からKeyとIV を生成するプライベートメソッド(GenerateKey,
GenerateIV)を用意しました。
これによりkeyStringが一致していれば、同じKeyとIVを生成するようにします。これにより、keyStringさえ忘れなければ復号化できるます。
このクラスを使って暗号化するには、エンコードする文字列と、エンコードする際のキーをEncryptメソッドに渡してあげればOKです。また、復号化する場合には、同様にDecryptに復号化するデータとエンコードしたときと同じキーを渡してあげればOKです。
クラスの呼び出し方 |
...
using System.Text;
using Microsoft.Win32;
using Uchukamen.Security;
...
private void 暗号化処理()
{ // パスワードをTriple DES 暗号化する。
byte[] encrypted = PasswordEncoder.Encrypt(エンコードする文字列, キー文字列);
レジストリに書き込む処理。
}
private void 復号化処理
{ レジストリから、Triple DESエンコードされたバイト配列を取得する処理。
// 暗号化されたパスワードを Triple DES 復号化する。
string result = PasswordEncoder.Decrypt(複合化するバイト配列, キー文字列);
}
|
レジストリにデータをセット、ゲットする簡単な方法は次のとおりです。
Applicaton.UserAppDataRegistry で、
CurrentUser\Software\CompanyName\ProductName\ProductVersion
のレジストリキーを生成してくれます。
そのために、つぎのようなメソッドを用意しておきます。
レジストリにデータをセット、ゲットする。 |
/// /// レジストリから name キーで、codeをセットする。
/// private void SetValue(string name, byte [] code)
{ RegistryKey key = Application.UserAppDataRegistry;
key.SetValue(name, code);
key.Close();
}
/// /// レジストリから name キーの値を取得する。
/// private byte[] GetValue(string name)
{ RegistryKey key = Application.UserAppDataRegistry;
byte[] result = (byte[]) key.GetValue(name);
key.Close();
return result;
}
|
レジストリには、たとえばこのように格納されます。
レジストリはそのときの環境によって違うので注意してください。
注意 |
コンパイルしてバージョンが新しくなるたびに、新しいレジストリを追加してしまいます。 これを避けるためには、インストーラによるインストールを行い、アンインストールした場合に、古いレジストリを削除するようにする必要があります。このテストをする場合もどんどん生成されているので、注意してね。 |
6.テスト用ソースコード(EncryptPassword.cs,
Form1.cs)
変更履歴 |
2004/10/24 |
初版作成 V1.0
|
EncryptPassword.cs |
using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;
namespace Uchukamen.Security
{ /// /// PasswordEncoder はパスワードをTriple DESでエンコード、デコードします。
/// public class PasswordEncoder
{
private PasswordEncoder()
{
}
/// /// keyStringから TripleDESCryptoServiceProvider のKey を生成します。
/// 注意: この生成方法を変更するとデコードできなくなります。
/// ///
///
/// private static byte[] GenerateKey(string keyString, int len)
{
byte [] key = new byte[len];
for (int i = 0; i < len; i++)
key[i] = (byte)(keyString[i % keyString.Length] + i);
return key;
}
/// /// keyStringから TripleDESCryptoServiceProvider のIV を生成します。
/// 注意: この生成方法を変更するとデコードできなくなります。
/// ///
///
/// private static byte[] GenerateIV(string keyString, int len)
{
byte [] iv = new byte[len];
for (int i = 0; i < len; i++)
iv[i] = (byte)(keyString[i % keyString.Length] - i);
return iv;
}
/// /// パスワード文字列 password をキー key でTriple DES暗号化を行います。
/// ///
///
/// public static byte[] Encrypt(string password, string key)
{
// Tripe DES のサービス プロバイダを生成します
TripleDESCryptoServiceProvider tDes = new TripleDESCryptoServiceProvider();
tDes.Key = GenerateKey(key, tDes.Key.Length);
tDes.IV = GenerateKey(key, tDes.IV.Length);
// 文字列を byte 配列に変換します
byte[] source = Encoding.Unicode.GetBytes(password);
// 入出力用のストリームを生成します
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms,
tDes.CreateEncryptor( tDes.Key, tDes.IV ), CryptoStreamMode.Write);
// ストリームに暗号化するデータを書き込みます
cs.Write(source, 0, source.Length);
cs.Close();
// 暗号化されたデータを byte 配列で取得します
byte[] destination = ms.ToArray();
ms.Close();
return destination;
}
/// /// パスワード文字列 password をキー key でTriple DES復号化を行います。
/// ///
///
/// public static string Decrypt(byte [] source, string key)
{
// Tripe DES のサービス プロバイダを生成します
TripleDESCryptoServiceProvider tDes = new TripleDESCryptoServiceProvider();
tDes.Key = GenerateKey(key, tDes.Key.Length);
tDes.IV = GenerateKey(key, tDes.IV.Length);
// 入出力用のストリームを生成します
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms,
tDes.CreateDecryptor( tDes.Key, tDes.IV ),CryptoStreamMode.Write);
// ストリームに暗号化されたデータを書き込みます
cs.Write(source, 0, source.Length);
cs.Close();
// 復号化されたデータを byte 配列で取得します
byte[] destination = ms.ToArray();
ms.Close();
// byte 配列を文字列に変換して表示します
return Encoding.Unicode.GetString(destination);
}
}
}
|
Form1.cs |
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using Microsoft.Win32;
using Uchukamen.Security;
namespace PasswordEncryption
{ /// /// Form1 の概要の説明です。
/// public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBoxInput;
private System.Windows.Forms.TextBox textBoxEncrypted;
private System.Windows.Forms.TextBox textBoxDecrypted;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox textBoxPassword;
/// /// 必要なデザイナ変数です。
/// private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();
//
// TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
//
}
/// /// 使用されているリソースに後処理を実行します。
/// protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows フォーム デザイナで生成されたコード
/// /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.textBoxInput = new System.Windows.Forms.TextBox();
this.textBoxEncrypted = new System.Windows.Forms.TextBox();
this.textBoxDecrypted = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.button2 = new System.Windows.Forms.Button();
this.textBoxPassword = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(96, 144);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(64, 24);
this.button1.TabIndex = 8;
this.button1.Text = "Encrypt";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBoxInput
//
this.textBoxInput.Location = new System.Drawing.Point(80, 16);
this.textBoxInput.Name = "textBoxInput";
this.textBoxInput.Size = new System.Drawing.Size(160, 19);
this.textBoxInput.TabIndex = 1;
this.textBoxInput.Text = "";
//
// textBoxEncrypted
//
this.textBoxEncrypted.Location = new System.Drawing.Point(80, 80);
this.textBoxEncrypted.Name = "textBoxEncrypted";
this.textBoxEncrypted.ReadOnly = true;
this.textBoxEncrypted.Size = new System.Drawing.Size(160, 19);
this.textBoxEncrypted.TabIndex = 5;
this.textBoxEncrypted.Text = "";
//
// textBoxDecrypted
//
this.textBoxDecrypted.Location = new System.Drawing.Point(80, 112);
this.textBoxDecrypted.Name = "textBoxDecrypted";
this.textBoxDecrypted.ReadOnly = true;
this.textBoxDecrypted.Size = new System.Drawing.Size(160, 19);
this.textBoxDecrypted.TabIndex = 7;
this.textBoxDecrypted.Text = "";
//
// label1
//
this.label1.Location = new System.Drawing.Point(24, 24);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(40, 16);
this.label1.TabIndex = 0;
this.label1.Text = "Input";
//
// label2
//
this.label2.Location = new System.Drawing.Point(16, 88);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(64, 24);
this.label2.TabIndex = 4;
this.label2.Text = "Encrypted";
//
// label3
//
this.label3.Location = new System.Drawing.Point(16, 120);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(64, 24);
this.label3.TabIndex = 6;
this.label3.Text = "Decrypted";
//
// button2
//
this.button2.Location = new System.Drawing.Point(176, 144);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(64, 24);
this.button2.TabIndex = 9;
this.button2.Text = "Decrypt";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// textBoxPassword
//
this.textBoxPassword.Location = new System.Drawing.Point(80, 48);
this.textBoxPassword.Name = "textBoxPassword";
this.textBoxPassword.Size = new System.Drawing.Size(160, 19);
this.textBoxPassword.TabIndex = 3;
this.textBoxPassword.Text = "";
//
// label4
//
this.label4.Location = new System.Drawing.Point(16, 56);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(56, 24);
this.label4.TabIndex = 2;
this.label4.Text = "Password";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.ClientSize = new System.Drawing.Size(264, 182);
this.Controls.Add(this.label4);
this.Controls.Add(this.textBoxPassword);
this.Controls.Add(this.button2);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBoxDecrypted);
this.Controls.Add(this.textBoxEncrypted);
this.Controls.Add(this.textBoxInput);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Triple DES";
this.ResumeLayout(false);
}
#endregion
/// /// アプリケーションのメイン エントリ ポイントです。
/// [STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
try
{
this.textBoxEncrypted.Text = this.textBoxDecrypted.Text = "";
// パスワードをTriple DES 暗号化する。
byte[] encrypted = PasswordEncoder.Encrypt(
this.textBoxInput.Text,
this.textBoxPassword.Text);
// レジストリに書き込む。
SetValue("DES", encrypted);
// byte 配列を文字列に変換して表示します
textBoxEncrypted.Text = Encoding.Unicode.GetString(encrypted);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, Application.ProductName,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void button2_Click(object sender, System.EventArgs e)
{
try
{
// レジストリから、Triple DESエンコードされた文字列を取得する。
byte [] source = GetValue("DES");
// 暗号化されたパスワードを Triple DES 復号化する。
string result = PasswordEncoder.Decrypt(
source, this.textBoxPassword.Text);
// byte 配列を文字列に変換して表示します
this.textBoxDecrypted.Text = result;
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, Application.ProductName,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// /// レジストリから name キーで、codeをセットする。
/// ///
///
private void SetValue(string name, byte [] code)
{
RegistryKey key = Application.UserAppDataRegistry;
key.SetValue(name, code);
key.Close();
}
/// /// レジストリから name キーの値を取得する。
/// ///
/// private byte[] GetValue(string name)
{
RegistryKey key = Application.UserAppDataRegistry;
byte[] result = (byte[]) key.GetValue(name);
key.Close();
return result;
}
}
}
|