.NETプログラミング研究 第18号 †
.NET質問箱 †
公開鍵暗号による暗号化 †
前回は「秘密鍵暗号方式による暗号化」について説明しましたが、今回は公開鍵暗号(非対称暗号化方式、公開キー暗号方式)により暗号化、復号化する方法を紹介します。
公開鍵暗号とは、公開鍵と秘密鍵(個人鍵)の2つの鍵を使って暗号化、復号化する方法です。公開鍵方式に関して「アスキーデジタル用語辞典」では次のように説明されています。
「暗号化専用の鍵(公開鍵)と解読専用の鍵(個人鍵)を使って、暗号化と解読を行なう形式。受信側で事前に公開鍵と個人鍵のペアを用意し、暗号文の送信側に公開鍵のほうを配布する。送信側は平文を公開鍵で暗号文に変換できるが、解読はできない。受信側は、個人鍵で平文に復元可能。公開鍵だけでは解読できないという利点がある。」
.NETでは公開キー暗号化アルゴリズムを実装するクラスとして、DSACryptoServiceProvider(DSA)とRSACryptoServiceProvider(RSA)の2つが用意されていますが、ここではRSACryptoServiceProviderを使った例のみを示します。なおDSA、RSAとは何かということ関しては次のURLが参考になります。
次に示すサンプルは、公開鍵暗号により文字列を暗号化、復号化するため3つの静的メソッドからなります。まずCreateKeysメソッドで公開鍵と秘密鍵のペアを作成し、その公開鍵を使ってEncryptメソッドにより暗号化します。復号化は秘密鍵を指定してDecryptメソッドにより行います。
暗号化にはRSACryptoServiceProvider.Encryptメソッドを使用しますが、この時渡す暗号化されるデータにはサイズの制限があります。OAEPパディング、Direct Encryption、ともにサポートなしのそれぞれのケースで暗号化されるデータの最大長の計算法が異なり、このことはヘルプ(「RSACryptoServiceProvider.Encrypt メソッド」)で説明されています。
例えばDirect Encryption(高度暗号化パックがインストールされている Microsoft Windows 2000 以降)の場合、RSACryptoServiceProvider.KeySize プロパティから取得できるキーサイズが1024ビットだとすると、暗号化されるデータの最大長は、 1024/8-11=117バイト となります。
下のコードでは暗号化されるデータの最大長のチェックは全く行っていませんので、ご注意ください。
なお下の例の「RSACryptoServiceProviderオブジェクトの作成」の部分についてですが、詳しくは「マイクロソフト サポート技術情報 - 322371」をご覧ください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
| | public static void CreateKeys(out string publicKey, out string privateKey)
{
System.Security.Cryptography.CspParameters CSPParam =
new System.Security.Cryptography.CspParameters();
CSPParam.Flags =
System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore;
System.Security.Cryptography.RSACryptoServiceProvider rsa =
new System.Security.Cryptography.RSACryptoServiceProvider(CSPParam);
publicKey = rsa.ToXmlString(false);
privateKey = rsa.ToXmlString(true);
}
public static string Encrypt(string str, string publicKey)
{
System.Security.Cryptography.CspParameters CSPParam =
new System.Security.Cryptography.CspParameters();
CSPParam.Flags =
System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore;
System.Security.Cryptography.RSACryptoServiceProvider rsa =
new System.Security.Cryptography.RSACryptoServiceProvider(CSPParam);
rsa.FromXmlString(publicKey);
byte[] data = System.Text.Encoding.UTF8.GetBytes(str);
byte[] encryptedData = rsa.Encrypt(data, false);
return System.Convert.ToBase64String(encryptedData);
}
public static string Decrypt(string str, string privateKey)
{
System.Security.Cryptography.CspParameters CSPParam =
new System.Security.Cryptography.CspParameters();
CSPParam.Flags =
System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore;
System.Security.Cryptography.RSACryptoServiceProvider rsa =
new System.Security.Cryptography.RSACryptoServiceProvider(CSPParam);
rsa.FromXmlString(privateKey);
byte[] data = System.Convert.FromBase64String(str);
byte[] decryptedData = rsa.Decrypt(data, false);
return System.Text.Encoding.UTF8.GetString(decryptedData);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
| | Public Shared Sub CreateKeys(ByRef publicKey As String, _
ByRef privateKey As String)
Dim CSPParam As New System.Security.Cryptography.CspParameters
CSPParam.Flags = _
System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore
Dim rsa As New _
System.Security.Cryptography.RSACryptoServiceProvider(CSPParam)
publicKey = rsa.ToXmlString(False)
privateKey = rsa.ToXmlString(True)
End Sub
Public Shared Function Encrypt(ByVal str As String, _
ByVal publicKey As String) As String
Dim CSPParam As New System.Security.Cryptography.CspParameters
CSPParam.Flags = _
System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore
Dim rsa As New _
System.Security.Cryptography.RSACryptoServiceProvider(CSPParam)
rsa.FromXmlString(publicKey)
Dim data As Byte() = System.Text.Encoding.UTF8.GetBytes(str)
Dim encryptedData As Byte() = rsa.Encrypt(data, False)
Return System.Convert.ToBase64String(encryptedData)
End Function
Public Shared Function Decrypt(ByVal str As String, _
ByVal privateKey As String) As String
Dim CSPParam As New System.Security.Cryptography.CspParameters
CSPParam.Flags = _
System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore
Dim rsa As New _
System.Security.Cryptography.RSACryptoServiceProvider(CSPParam)
rsa.FromXmlString(privateKey)
Dim data As Byte() = System.Convert.FromBase64String(str)
Dim decryptedData As Byte() = rsa.Decrypt(data, False)
Return System.Text.Encoding.UTF8.GetString(decryptedData)
End Function
|
.NET質問箱 †
フォームのイメージを印刷するには? †
質問:
Visual Basic 6.0ではPrintFormというメソッドがあり、これによりフォームのイメージを印刷することが出来ましたが、同じようなことを.NETで行うにはどのようにすればよいのでしょうか?
答え:
VB6のPrintFormメソッドに代わるものは.NETにはありません。ヘルプによると、
「Visual Basic 6.0 では、フォームのイメージをプリンタに送るとき、フォームの PrintForm メソッドが使用されていました。PrintForm メソッドは Visual Basic .NET ではサポートされていません。PrintForm メソッドの結果は、画面の解像度およびプリンタの解像度に依存するところが大きく、印刷の方法としては推奨されていませんでした。PrintForm メソッドの機能を複製する必要がある場合は、サードパーティ製のグラフィックス ツールに用意されているスクリーン キャプチャ機能を自動化してフォームのイメージをキャプチャおよび印刷できます。」
とあります。
それではサードパーティ製のスクリーンキャプチャ機能を使うしかないかというとそうではなく、Win32 APIでスクリーンキャプチャを行う方法があり、しかもそれは現在ではヘルプに載っています。
ただし、VB6のPrintFormメソッドがフォームの一部が画面に表示されていない場合でもフォーム全体が印刷されるのに対して、この方法では表示されていない部分は印刷されません。
以下にこのサンプルコードを書き直した例を示します。使い方としては、自分自身のフォームを印刷する時、C#では
PrintForm(this);
VB.NETでは
PrintForm(Me)
のようにしてください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| | public void PrintForm(Form frm)
{
CaptureScreen(frm);
System.Drawing.Printing.PrintDocument PrintDocument1 =
new System.Drawing.Printing.PrintDocument();
PrintDocument1.PrintPage +=
new System.Drawing.Printing.PrintPageEventHandler(
PrintDocument1_PrintPage);
PrintDocument1.Print();
}
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hdcDest,
int nXDest, int nYDest, int nWidth, int nHeight,
IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
private Bitmap memoryImage;
private void CaptureScreen(Form frm)
{
Graphics mygraphics = frm.CreateGraphics();
Size s = frm.Size;
memoryImage = new Bitmap(s.Width, s.Height, mygraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
IntPtr dc1 = mygraphics.GetHdc();
IntPtr dc2 = memoryGraphics.GetHdc();
BitBlt(dc2, 0, 0, frm.ClientRectangle.Width,
frm.ClientRectangle.Height, dc1, 0, 0, 13369376);
mygraphics.ReleaseHdc(dc1);
memoryGraphics.ReleaseHdc(dc2);
}
private void PrintDocument1_PrintPage(object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| | Public Sub PrintForm(ByVal frm As Form)
CaptureScreen(frm)
Dim PrintDocument1 As New System.Drawing.Printing.PrintDocument
AddHandler PrintDocument1.PrintPage, _
AddressOf PrintDocument1_PrintPage
PrintDocument1.Print()
End Sub
<System.Runtime.InteropServices.DllImport("gdi32.dll")> _
Private Shared Function BitBlt(ByVal hdcDest As IntPtr, _
ByVal nXDest As Integer, ByVal nYDest As Integer, _
ByVal nWidth As Integer, ByVal nHeight As Integer, _
ByVal hdcSrc As IntPtr, _
ByVal nXSrc As Integer, ByVal nYSrc As Integer, _
ByVal dwRop As Integer) As Boolean
End Function
Private memoryImage As Bitmap
Private Sub CaptureScreen(ByVal frm As Form)
Dim mygraphics As Graphics = frm.CreateGraphics()
Dim s As Size = frm.Size
memoryImage = New Bitmap(s.Width, s.Height, mygraphics)
Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
Dim dc1 As IntPtr = mygraphics.GetHdc()
Dim dc2 As IntPtr = memoryGraphics.GetHdc()
BitBlt(dc2, 0, 0, _
frm.ClientRectangle.Width, frm.ClientRectangle.Height, _
dc1, 0, 0, 13369376)
mygraphics.ReleaseHdc(dc1)
memoryGraphics.ReleaseHdc(dc2)
End Sub
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs)
e.Graphics.DrawImage(memoryImage, 0, 0)
End Sub
|
GotFocusとLostFocusイベントはどこにいったか? †
質問:
VB6ではコントロールがフォーカスを受け取った時にGotFocusイベントが、フォーカスを失った時にLostFocusイベントが発生しましたが、.NETではこれらのイベントが見つかりません。.NETではどのようにすればよいのでしょうか?
答え:
.NETでもVB6と同様にGotFocusイベント及びLostFocusイベントは存在しています。しかしVisual Studio .NETでは、VB.NETの場合はコードエディタ上の「メソッド名ボックス」に、C#の場合はプロパティウィンドウの「イベント」にGotFocusとLostFocusが表示されません。
GotFocusイベントとLostFocusイベントについて、ヘルプには次のように書いてあります。
「GotFocus イベントおよび LostFocus イベントは、WM_KILLFOCUS Windows メッセージおよび WM_SETFOCUS Windows メッセージに結び付けられた、低水準のフォーカス イベントです。一般的に、 GotFocus イベントおよび LostFocus イベントは、 UICues を更新するときにだけ使用されます。 Activated イベントおよび Deactivate イベントを使用する Form クラス以外のすべてのコントロールに対して、 Enter イベントおよび Leave イベントを使用する必要があります。」
このことから推測すると、GotFocus及びLostFocusイベントの代わりに、Enter及びLeaveイベントを使うべきという意味でこれらが表示されないのかもしれません。
また、ヘルプの「Visual Basic .NET における TextBox コントロールの変更点」では、VB6のGotFocus及びLostFocusイベントに代わるものは、.NETではEnter及びLeaveイベントとなっています。
以下にLostFocusイベントを使ったコードを一応書いておきます。
1
2
3
4
5
6
7
8
9
10
11
| | private void Form1_Load(object sender, System.EventArgs e)
{
TextBox1.LostFocus += new EventHandler(TextBox1_LostFocus);
}
private void TextBox1_LostFocus(object sender, EventArgs e)
{
Console.WriteLine("LostFocusイベントが発生しました。");
}
|
1
2
3
4
5
6
7
8
9
10
11
| | Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
AddHandler TextBox1.LostFocus, AddressOf TextBox1_LostFocus
End Sub
Private Sub TextBox1_LostFocus(ByVal sender As Object, _
ByVal e As EventArgs)
Console.WriteLine("LostFocusイベントが発生しました。")
End Sub
|
コメント †