演练:创建加密应用程序

注意

本文适用于 Windows。

有关 ASP.NET Core 的信息,请参阅 ASP.NET Core 数据保护

本演练演示如何对文件的内容进行加密和解密。 下面的代码示例是特为 Windows 窗体应用程序设计的。 此应用程序不演示实际方案,例如使用智能卡。 而演示加密和解密的基础知识。

本演练使用以下加密原则:

  • 使用 Aes 类(一种对称算法),用于通过使用其自动生成的 KeyIV 来加密和解密数据。

  • 使用 RSA(一种非对称算法),对由 Aes 加密的数据的密钥进行加密和解密。 非对称算法最适用于较少的数据,如密钥。

    注意

    如果要保护计算机上的数据(而不是与他人交换加密内容),可考虑使用 ProtectedData 类。

下表总结了本主题中的加密任务。

任务 说明
创建 Windows 窗体应用程序 列出运行该应用程序所需的控件。
声明全局对象 声明字符串路径变量 CspParametersRSACryptoServiceProvider 具有 Form 类的全局上下文。
创建非对称密钥 创建非对称公钥和私钥值对,并为其分配一个密钥容器名称。
加密文件 显示对话框,以便选择供加密的文件,并对该文件进行加密。
解密文件 显示对话框,以便选择供解密的已加密文件,并对该文件进行解密。
获取私钥 获取使用密钥容器名称的完整密钥对。
导出公钥 将密钥保存到只带有公共参数的 XML 文件中。
导入公钥 将密钥从 XML 文件加载到密钥容器中。
测试应用程序 列出用于测试此应用程序的步骤。

先决条件

您需要满足以下条件才能完成本演练:

创建 Windows 窗体应用程序

本演练中的大多数代码示例均设计为按钮控件的事件处理程序。 下表列出了示例应用程序所需的控件及其匹配代码示例所需的名称。

控制 名称 文本属性(根据需要)
Button buttonEncryptFile 加密文件
Button buttonDecryptFile 解密文件
Button buttonCreateAsmKeys 创建密钥
Button buttonExportPublicKey 导出公钥
Button buttonImportPublicKey 导入公钥
Button buttonGetPrivateKey 获取私钥
Label label1 未设置密钥
OpenFileDialog _encryptOpenFileDialog
OpenFileDialog _decryptOpenFileDialog

双击 Visual Studio 设计器中的按钮可创建其事件处理程序。

声明全局对象

添加以下代码作为类 Form1 的声明的一部分。 编辑环境和首选项的字符串变量。

// Declare CspParameters and RsaCryptoServiceProvider
// objects with global scope of your Form class.
readonly CspParameters _cspp = new CspParameters();
RSACryptoServiceProvider _rsa;

// Path variables for source, encryption, and
// decryption folders. Must end with a backslash.
const string EncrFolder = @"c:\Encrypt\";
const string DecrFolder = @"c:\Decrypt\";
const string SrcFolder = @"c:\docs\";

// Public key file
const string PubKeyFile = @"c:\encrypt\rsaPublicKey.txt";

// Key container name for
// private/public key value pair.
const string KeyName = "Key01";
' Declare CspParameters and RsaCryptoServiceProvider
' objects with global scope of your Form class.
ReadOnly _cspp As New CspParameters
Dim _rsa As RSACryptoServiceProvider

' Path variables for source, encryption, and
' decryption folders. Must end with a backslash.
Const EncrFolder As String = "c:\Encrypt\"
Const DecrFolder As String = "c:\Decrypt\"
Const SrcFolder As String = "c:\docs\"

' Public key file
Const PubKeyFile As String = "c:\encrypt\rsaPublicKey.txt"

' Key container name for
' private/public key value pair.
Const KeyName As String = "Key01"

创建非对称密钥

此任务创建可对 Aes 密钥进行加密和解密的非对称密钥。 此密钥用于加密内容,并且它将显示标签控件上的密钥容器名称。

将以下代码添加为 Create Keys 按钮 (buttonCreateAsmKeys_Click) 的 Click 事件处理程序。

private void buttonCreateAsmKeys_Click(object sender, EventArgs e)
{
    // Stores a key pair in the key container.
    _cspp.KeyContainerName = KeyName;
    _rsa = new RSACryptoServiceProvider(_cspp)
    {
        PersistKeyInCsp = true
    };

    label1.Text = _rsa.PublicOnly
        ? $"Key: {_cspp.KeyContainerName} - Public Only"
        : $"Key: {_cspp.KeyContainerName} - Full Key Pair";
}
Private Sub buttonCreateAsmKeys_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonCreateAsmKeys.Click
    ' Stores a key pair in the key container.
    _cspp.KeyContainerName = KeyName
    _rsa = New RSACryptoServiceProvider(_cspp) With {
        .PersistKeyInCsp = True
    }

    If _rsa.PublicOnly Then
        Label1.Text = $"Key: {_cspp.KeyContainerName} - Public Only"
    Else
        Label1.Text = $"Key: {_cspp.KeyContainerName} - Full Key Pair"
    End If

End Sub

加密文件

此任务涉及两种方法,即 Encrypt File 按钮 (buttonEncryptFile_Click) 的事件处理程序方法和 EncryptFile 方法。 第一种方法显示一个用于选择文件的对话框,并将文件名传递给第二种方法,后者将执行加密。

加密的内容、密钥和 IV 全都保存到一个 FileStream 中,这被称为加密包。

EncryptFile 方法执行以下操作:

  1. 创建 Aes 对称算法,以便对内容进行加密。
  2. 创建 RSACryptoServiceProvider 对象,以便对 Aes 密钥进行加密。
  3. 使用 CryptoStream 对象读取源文件的 FileStream,并将其加密到已加密文件的目标 FileStream 对象中(以字节块为单位)。
  4. 确定加密密钥和 IV 的长度并创建其长度值的字节数组。
  5. 将密钥、IV 及其长度值写入已加密的包。

加密包使用以下格式:

  • 密钥长度,字节数 0 - 3
  • IV 长度,字节数 4 - 7
  • 已加密的密钥
  • IV
  • 密码文本

可使用密钥和 IV 的长度来确定起点和加密包所有部件的长度,然后可使用它们来解密文件。

将以下代码添加为 Encrypt File 按钮 (buttonEncryptFile_Click) 的 Click 事件处理程序。

private void buttonEncryptFile_Click(object sender, EventArgs e)
{
    if (_rsa is null)
    {
        MessageBox.Show("Key not set.");
    }
    else
    {
        // Display a dialog box to select a file to encrypt.
        _encryptOpenFileDialog.InitialDirectory = SrcFolder;
        if (_encryptOpenFileDialog.ShowDialog() == DialogResult.OK)
        {
            string fName = _encryptOpenFileDialog.FileName;
            if (fName != null)
            {
                // Pass the file name without the path.
                EncryptFile(new FileInfo(fName));
            }
        }
    }
}
Private Sub buttonEncryptFile_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonEncryptFile.Click
    If _rsa Is Nothing Then
        MsgBox("Key not set.")
    Else
        ' Display a dialog box to select a file to encrypt.
        _encryptOpenFileDialog.InitialDirectory = SrcFolder
        If _encryptOpenFileDialog.ShowDialog = Windows.Forms.DialogResult.OK Then
            Try
                Dim fName As String = _encryptOpenFileDialog.FileName
                If (Not (fName) Is Nothing) Then
                    Dim fInfo As New FileInfo(fName)
                    ' Use just the file name without path.
                    Dim name As String = fInfo.FullName
                    EncryptFile(name)
                End If
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
        End If
    End If
End Sub

将下面的 EncryptFile 方法添加到窗体中。

private void EncryptFile(FileInfo file)
{
    // Create instance of Aes for
    // symmetric encryption of the data.
    Aes aes = Aes.Create();
    ICryptoTransform transform = aes.CreateEncryptor();

    // Use RSACryptoServiceProvider to
    // encrypt the AES key.
    // rsa is previously instantiated:
    //    rsa = new RSACryptoServiceProvider(cspp);
    byte[] keyEncrypted = _rsa.Encrypt(aes.Key, false);

    // Create byte arrays to contain
    // the length values of the key and IV.
    int lKey = keyEncrypted.Length;
    byte[] LenK = BitConverter.GetBytes(lKey);
    int lIV = aes.IV.Length;
    byte[] LenIV = BitConverter.GetBytes(lIV);

    // Write the following to the FileStream
    // for the encrypted file (outFs):
    // - length of the key
    // - length of the IV
    // - encrypted key
    // - the IV
    // - the encrypted cipher content

    // Change the file's extension to ".enc"
    string outFile =
        Path.Combine(EncrFolder, Path.ChangeExtension(file.Name, ".enc"));

    using (var outFs = new FileStream(outFile, FileMode.Create))
    {
        outFs.Write(LenK, 0, 4);
        outFs.Write(LenIV, 0, 4);
        outFs.Write(keyEncrypted, 0, lKey);
        outFs.Write(aes.IV, 0, lIV);

        // Now write the cipher text using
        // a CryptoStream for encrypting.
        using (var outStreamEncrypted =
            new CryptoStream(outFs, transform, CryptoStreamMode.Write))
        {
            // By encrypting a chunk at
            // a time, you can save memory
            // and accommodate large files.
            int count = 0;
            int offset = 0;

            // blockSizeBytes can be any arbitrary size.
            int blockSizeBytes = aes.BlockSize / 8;
            byte[] data = new byte[blockSizeBytes];
            int bytesRead = 0;

            using (var inFs = new FileStream(file.FullName, FileMode.Open))
            {
                do
                {
                    count = inFs.Read(data, 0, blockSizeBytes);
                    offset += count;
                    outStreamEncrypted.Write(data, 0, count);
                    bytesRead += blockSizeBytes;
                } while (count > 0);
            }
            outStreamEncrypted.FlushFinalBlock();
        }
    }
}
Private Sub EncryptFile(ByVal inFile As String)
    ' Create instance of Aes for
    ' symmetric encryption of the data.
    Dim aes As Aes = Aes.Create()
    Dim transform As ICryptoTransform = aes.CreateEncryptor

    ' Use RSACryptoServiceProvider to
    ' encrypt the AES key.
    Dim keyEncrypted() As Byte = _rsa.Encrypt(aes.Key, False)

    ' Create byte arrays to contain
    ' the length values of the key and IV.
    Dim LenK() As Byte = New Byte((4) - 1) {}
    Dim LenIV() As Byte = New Byte((4) - 1) {}
    Dim lKey As Integer = keyEncrypted.Length
    LenK = BitConverter.GetBytes(lKey)
    Dim lIV As Integer = aes.IV.Length
    LenIV = BitConverter.GetBytes(lIV)

    ' Write the following to the FileStream
    ' for the encrypted file (outFs):
    ' - length of the key
    ' - length of the IV
    ' - encrypted key
    ' - the IV
    ' - the encrypted cipher content
    ' Change the file's extension to ".enc"
    Dim startFileName As Integer = inFile.LastIndexOf("\") + 1
    Dim outFile As String = (EncrFolder _
                + (inFile.Substring(startFileName, inFile.LastIndexOf(".") - startFileName) + ".enc"))

    Using outFs As New FileStream(outFile, FileMode.Create)
        outFs.Write(LenK, 0, 4)
        outFs.Write(LenIV, 0, 4)
        outFs.Write(keyEncrypted, 0, lKey)
        outFs.Write(aes.IV, 0, lIV)

        ' Now write the cipher text using
        ' a CryptoStream for encrypting.
        Using outStreamEncrypted As New CryptoStream(outFs, transform, CryptoStreamMode.Write)
            ' By encrypting a chunk at
            ' a time, you can save memory
            ' and accommodate large files.
            Dim count As Integer = 0
            Dim offset As Integer = 0

            ' blockSizeBytes can be any arbitrary size.
            Dim blockSizeBytes As Integer = (aes.BlockSize / 8)
            Dim data() As Byte = New Byte((blockSizeBytes) - 1) {}
            Dim bytesRead As Integer = 0
            Using inFs As New FileStream(inFile, FileMode.Open)
                Do
                    count = inFs.Read(data, 0, blockSizeBytes)
                    offset = (offset + count)
                    outStreamEncrypted.Write(data, 0, count)
                    bytesRead = (bytesRead + blockSizeBytes)
                Loop Until (count = 0)

                outStreamEncrypted.FlushFinalBlock()
                inFs.Close()
            End Using
            outStreamEncrypted.Close()
        End Using
        outFs.Close()
    End Using
End Sub

解密文件

此任务涉及两种方法,即 Decrypt File 按钮 (buttonDecryptFile_Click) 的事件处理程序方法和 DecryptFile 方法。 第一种方法显示一个用于选择文件的对话框,并将其文件名传递给第二种方法,后者将执行解密。

Decrypt 方法执行以下操作:

  1. 创建 Aes 对称算法,以便对内容进行解密。
  2. 将已加密包的 FileStream 的前八个字节读取到字节数组中,以便获取已加密的密钥和 IV 的长度。
  3. 将密钥和 IV 从加密包提取到字节数组中。
  4. 创建 RSACryptoServiceProvider 对象,以便对 Aes 密钥进行解密。
  5. 使用 CryptoStream 对象来读取 FileStream 加密包的密码文本部分,并将其解密到已解密文件的 FileStream 对象中(以字节块为单位)。 完成后,解密即完成。

将以下代码添加为 Decrypt File 按钮的 Click 事件处理程序。

private void buttonDecryptFile_Click(object sender, EventArgs e)
{
    if (_rsa is null)
    {
        MessageBox.Show("Key not set.");
    }
    else
    {
        // Display a dialog box to select the encrypted file.
        _decryptOpenFileDialog.InitialDirectory = EncrFolder;
        if (_decryptOpenFileDialog.ShowDialog() == DialogResult.OK)
        {
            string fName = _decryptOpenFileDialog.FileName;
            if (fName != null)
            {
                DecryptFile(new FileInfo(fName));
            }
        }
    }
}
Private Sub buttonDecryptFile_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonDecryptFile.Click
    If _rsa Is Nothing Then
        MsgBox("Key not set.")
    Else
        ' Display a dialog box to select the encrypted file.
        _decryptOpenFileDialog.InitialDirectory = EncrFolder
        If (_decryptOpenFileDialog.ShowDialog = Windows.Forms.DialogResult.OK) Then
            Try
                Dim fName As String = _decryptOpenFileDialog.FileName
                If ((fName) IsNot Nothing) Then
                    Dim fi As New FileInfo(fName)
                    Dim name As String = fi.Name
                    DecryptFile(name)
                End If
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
        End If
    End If
End Sub

将下面的 DecryptFile 方法添加到窗体中。

private void DecryptFile(FileInfo file)
{
    // Create instance of Aes for
    // symmetric decryption of the data.
    Aes aes = Aes.Create();

    // Create byte arrays to get the length of
    // the encrypted key and IV.
    // These values were stored as 4 bytes each
    // at the beginning of the encrypted package.
    byte[] LenK = new byte[4];
    byte[] LenIV = new byte[4];

    // Construct the file name for the decrypted file.
    string outFile =
        Path.ChangeExtension(file.FullName.Replace("Encrypt", "Decrypt"), ".txt");

    // Use FileStream objects to read the encrypted
    // file (inFs) and save the decrypted file (outFs).
    using (var inFs = new FileStream(file.FullName, FileMode.Open))
    {
        inFs.Seek(0, SeekOrigin.Begin);
        inFs.Read(LenK, 0, 3);
        inFs.Seek(4, SeekOrigin.Begin);
        inFs.Read(LenIV, 0, 3);

        // Convert the lengths to integer values.
        int lenK = BitConverter.ToInt32(LenK, 0);
        int lenIV = BitConverter.ToInt32(LenIV, 0);

        // Determine the start position of
        // the cipher text (startC)
        // and its length(lenC).
        int startC = lenK + lenIV + 8;
        int lenC = (int)inFs.Length - startC;

        // Create the byte arrays for
        // the encrypted Aes key,
        // the IV, and the cipher text.
        byte[] KeyEncrypted = new byte[lenK];
        byte[] IV = new byte[lenIV];

        // Extract the key and IV
        // starting from index 8
        // after the length values.
        inFs.Seek(8, SeekOrigin.Begin);
        inFs.Read(KeyEncrypted, 0, lenK);
        inFs.Seek(8 + lenK, SeekOrigin.Begin);
        inFs.Read(IV, 0, lenIV);

        Directory.CreateDirectory(DecrFolder);
        // Use RSACryptoServiceProvider
        // to decrypt the AES key.
        byte[] KeyDecrypted = _rsa.Decrypt(KeyEncrypted, false);

        // Decrypt the key.
        ICryptoTransform transform = aes.CreateDecryptor(KeyDecrypted, IV);

        // Decrypt the cipher text from
        // from the FileSteam of the encrypted
        // file (inFs) into the FileStream
        // for the decrypted file (outFs).
        using (var outFs = new FileStream(outFile, FileMode.Create))
        {
            int count = 0;
            int offset = 0;

            // blockSizeBytes can be any arbitrary size.
            int blockSizeBytes = aes.BlockSize / 8;
            byte[] data = new byte[blockSizeBytes];

            // By decrypting a chunk a time,
            // you can save memory and
            // accommodate large files.

            // Start at the beginning
            // of the cipher text.
            inFs.Seek(startC, SeekOrigin.Begin);
            using (var outStreamDecrypted =
                new CryptoStream(outFs, transform, CryptoStreamMode.Write))
            {
                do
                {
                    count = inFs.Read(data, 0, blockSizeBytes);
                    offset += count;
                    outStreamDecrypted.Write(data, 0, count);
                } while (count > 0);

                outStreamDecrypted.FlushFinalBlock();
            }
        }
    }
}
Private Sub DecryptFile(ByVal inFile As String)
    ' Create instance of Aes for
    ' symmetric decryption of the data.
    Dim aes As Aes = Aes.Create()

    ' Create byte arrays to get the length of
    ' the encrypted key and IV.
    ' These values were stored as 4 bytes each
    ' at the beginning of the encrypted package.
    Dim LenK() As Byte = New Byte(4 - 1) {}
    Dim LenIV() As Byte = New Byte(4 - 1) {}

    ' Construct the file name for the decrypted file.
    Dim outFile As String = (DecrFolder _
                + (inFile.Substring(0, inFile.LastIndexOf(".")) + ".txt"))

    ' Use FileStream objects to read the encrypted
    ' file (inFs) and save the decrypted file (outFs).
    Using inFs As New FileStream((EncrFolder + inFile), FileMode.Open)

        inFs.Seek(0, SeekOrigin.Begin)
        inFs.Read(LenK, 0, 3)
        inFs.Seek(4, SeekOrigin.Begin)
        inFs.Read(LenIV, 0, 3)

        Dim lengthK As Integer = BitConverter.ToInt32(LenK, 0)
        Dim lengthIV As Integer = BitConverter.ToInt32(LenIV, 0)
        Dim startC As Integer = (lengthK + lengthIV + 8)
        Dim lenC As Integer = (CType(inFs.Length, Integer) - startC)
        Dim KeyEncrypted() As Byte = New Byte(lengthK - 1) {}
        Dim IV() As Byte = New Byte(lengthIV - 1) {}

        ' Extract the key and IV
        ' starting from index 8
        ' after the length values.
        inFs.Seek(8, SeekOrigin.Begin)
        inFs.Read(KeyEncrypted, 0, lengthK)
        inFs.Seek(8 + lengthK, SeekOrigin.Begin)
        inFs.Read(IV, 0, lengthIV)
        Directory.CreateDirectory(DecrFolder)
        ' User RSACryptoServiceProvider
        ' to decrypt the AES key
        Dim KeyDecrypted() As Byte = _rsa.Decrypt(KeyEncrypted, False)

        ' Decrypt the key.
        Dim transform As ICryptoTransform = aes.CreateDecryptor(KeyDecrypted, IV)
        ' Decrypt the cipher text from
        ' from the FileSteam of the encrypted
        ' file (inFs) into the FileStream
        ' for the decrypted file (outFs).
        Using outFs As New FileStream(outFile, FileMode.Create)
            Dim count As Integer = 0
            Dim offset As Integer = 0

            ' blockSizeBytes can be any arbitrary size.
            Dim blockSizeBytes As Integer = (aes.BlockSize / 8)
            Dim data() As Byte = New Byte(blockSizeBytes - 1) {}
            ' By decrypting a chunk a time,
            ' you can save memory and
            ' accommodate large files.
            ' Start at the beginning
            ' of the cipher text.
            inFs.Seek(startC, SeekOrigin.Begin)
            Using outStreamDecrypted As New CryptoStream(outFs, transform, CryptoStreamMode.Write)
                Do
                    count = inFs.Read(data, 0, blockSizeBytes)
                    offset += count
                    outStreamDecrypted.Write(data, 0, count)
                Loop Until (count = 0)

                outStreamDecrypted.FlushFinalBlock()
            End Using
        End Using
    End Using
End Sub

导出公钥

此任务将 Create Keys 按钮创建的密钥保存到文件。 它仅导出公共参数。

此任务模拟以下场景:Alice 把她的公钥给 Bob,从而 Bob 可为她加密文件。 他和其他具有公钥的人将不能对文件进行解密,因为他们没有带专用参数的完整密钥对。

将以下代码添加为 Export Public Key 按钮 (buttonExportPublicKey_Click) 的 Click 事件处理程序。

void buttonExportPublicKey_Click(object sender, EventArgs e)
{
    // Save the public key created by the RSA
    // to a file. Caution, persisting the
    // key to a file is a security risk.
    Directory.CreateDirectory(EncrFolder);
    using (var sw = new StreamWriter(PubKeyFile, false))
    {
        sw.Write(_rsa.ToXmlString(false));
    }
}
Private Sub buttonExportPublicKey_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonExportPublicKey.Click
    ' Save the public key created by the RSA
    ' to a file. Caution, persisting the
    ' key to a file is a security risk.
    Directory.CreateDirectory(EncrFolder)
    Using sw As New StreamWriter(PubKeyFile)
        sw.Write(_rsa.ToXmlString(False))
    End Using
End Sub

导入公钥

此任务将加载只有公共参数的密钥(由 Export Public Key 按钮创建),并将其设置为密钥容器名称。

此任务模拟以下场景:Bob 加载 Alice 的只含公共参数的密钥,从而可以为她加密文件。

将以下代码添加为 Import Public Key 按钮 (buttonImportPublicKey_Click) 的 Click 事件处理程序。

void buttonImportPublicKey_Click(object sender, EventArgs e)
{
    using (var sr = new StreamReader(PubKeyFile))
    {
        _cspp.KeyContainerName = KeyName;
        _rsa = new RSACryptoServiceProvider(_cspp);

        string keytxt = sr.ReadToEnd();
        _rsa.FromXmlString(keytxt);
        _rsa.PersistKeyInCsp = true;

        label1.Text = _rsa.PublicOnly
            ? $"Key: {_cspp.KeyContainerName} - Public Only"
            : $"Key: {_cspp.KeyContainerName} - Full Key Pair";
    }
}
Private Sub buttonImportPublicKey_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonImportPublicKey.Click
    Using sr As New StreamReader(PubKeyFile)
        _cspp.KeyContainerName = KeyName
        _rsa = New RSACryptoServiceProvider(_cspp)
        Dim keytxt As String = sr.ReadToEnd
        _rsa.FromXmlString(keytxt)
        _rsa.PersistKeyInCsp = True

        If _rsa.PublicOnly Then
            Label1.Text = $"Key: {_cspp.KeyContainerName} - Public Only"
        Else
            Label1.Text = $"Key: {_cspp.KeyContainerName} - Full Key Pair"
        End If
    End Using
End Sub

获取私钥

此任务将密钥容器名称设置为使用 Create Keys 按钮创建的密钥的名称。 密钥容器将包含带专用参数的完整密钥对。

此任务模拟以下场景:Alice 使用她的私钥对由 Bob 加密的文件进行解密。

将以下代码添加为 Get Private Key 按钮 (buttonGetPrivateKey_Click) 的 Click 事件处理程序。

private void buttonGetPrivateKey_Click(object sender, EventArgs e)
{
    _cspp.KeyContainerName = KeyName;
    _rsa = new RSACryptoServiceProvider(_cspp)
    {
        PersistKeyInCsp = true
    };

    label1.Text = _rsa.PublicOnly
        ? $"Key: {_cspp.KeyContainerName} - Public Only"
        : $"Key: {_cspp.KeyContainerName} - Full Key Pair";
}
Private Sub buttonGetPrivateKey_Click(ByVal sender As Object,
    ByVal e As EventArgs) Handles buttonGetPrivateKey.Click
    _cspp.KeyContainerName = KeyName
    _rsa = New RSACryptoServiceProvider(_cspp) With {
        .PersistKeyInCsp = True
    }
    If _rsa.PublicOnly Then
        Label1.Text = $"Key: {_cspp.KeyContainerName} - Public Only"
    Else
        Label1.Text = $"Key: {_cspp.KeyContainerName} - Full Key Pair"
    End If
End Sub

测试应用程序

生成应用程序后,执行以下测试方案。

创建密钥、加密和解密

  1. 单击“Create Keys”按钮。 标签显示密钥名称,并显示它是完整密钥对。
  2. 单击“Export Public Key”按钮。 请注意,导出公钥参数并不会更改当前密钥。
  3. 单击 Encrypt File 按钮并选择文件。
  4. 单击 Decrypt File 按钮,然后选择刚刚加密的文件。
  5. 检查刚刚解密的文件。
  6. 关闭应用程序并重启,以便测试检索下一个方案中保留的密钥容器。

使用公钥进行加密

  1. 单击“Import Public Key”按钮。 标签显示密钥名称,并显示它仅是公共的。
  2. 单击 Encrypt File 按钮并选择文件。
  3. 单击 Decrypt File 按钮,然后选择刚刚加密的文件。 这将失败,因为必须使用私钥进行解密。

此方案演示了仅使用公钥为他人加密文件。 通常这个人只会为你提供公钥,而保留供解密的私钥。

使用私钥进行解密

  1. 单击“Get Private Key”按钮。 标签显示密钥名称,并显示它是否是完整密钥对。
  2. 单击 Decrypt File 按钮,然后选择刚刚加密的文件。 这将会成功,因为你具有用于解密的完整密钥对。

另请参阅