연습: 암호화 응용 프로그램 만들기

업데이트: 2007년 11월

이 연습에서는 내용을 암호화하고 해독하는 방법을 보여 줍니다. 이 코드 예제는 Windows Forms 응용 프로그램용으로 디자인되었습니다. 이 응용 프로그램에서는 스마트 카드 사용과 같은 실제 시나리오를 보여 주지는 않지만 대신 기본적인 암호화 및 해독 방법을 보여 줍니다.

이 연습에서는 다음과 같은 암호화 지침을 사용합니다.

  • 자동으로 생성된 KeyIV를 사용하여 데이터를 암호화하고 해독하려면 대칭 알고리즘인 RijndaelManaged 클래스를 사용합니다.

  • RijndaelManaged로 암호화된 데이터에 대한 키를 암호화하고 해독하려면 비대칭 알고리즘인 RSACryptoServiceProvider를 사용합니다. 비대칭 알고리즘은 키와 같이 적은 양의 데이터에 가장 적합합니다.

    참고:

    다른 사용자와 암호화된 내용을 교환하는 대신 컴퓨터의 데이터를 보호하려면 ProtectedData 또는 ProtectedMemory 클래스를 사용하는 것이 좋습니다.

다음 표에는 이 항목에서 수행되는 암호화 작업이 요약되어 있습니다.

작업

설명

Windows Forms 응용 프로그램 만들기

응용 프로그램을 실행하는 데 필요한 컨트롤을 나열합니다.

전역 개체 선언

문자열 경로 변수인 CspParametersRSACryptoServiceProvider를 선언하여 Form 클래스의 전역 컨텍스트를 준비합니다.

비대칭 키 만들기

비대칭 공개/개인 키 값 쌍을 만들고 여기에 키 컨테이너 이름을 할당합니다.

파일 암호화

암호화할 파일을 선택하기 위한 대화 상자를 표시하고 파일을 암호화합니다.

파일 해독

해독할 암호화된 파일을 선택하기 위한 대화 상자를 표시하고 파일을 해독합니다.

개인 키 가져오기

키 컨테이너 이름을 사용하여 전체 키 쌍을 가져옵니다.

공개 키 내보내기

공개 매개 변수만 있는 키를 XML 파일에 저장합니다.

공개 키 가져오기

XML 파일의 키를 키 컨테이너로 로드합니다.

응용 프로그램 테스트

이 응용 프로그램을 테스트하기 위한 절차를 나열합니다.

사전 요구 사항

이 연습을 완료하려면 다음 구성 요소가 필요합니다.

Windows Forms 응용 프로그램 만들기

이 연습의 코드 예제는 대부분 단추 컨트롤에 대한 이벤트 처리기로 작성되었습니다. 다음 표에서는 샘플 응용 프로그램에 필요한 컨트롤과 코드 예제와 일치시키기 위해 필요한 이름을 보여 줍니다.

컨트롤

이름

텍스트 속성(필요한 경우)

Button

buttonEncryptFile

Encrypt File

Button

buttonDecryptFile

Decrypt File

Button

buttonCreateAsmKeys

Create Keys

Button

buttonExportPublicKey

Export Public Key

Button

buttonImportPublicKey

Import Public Key

Button

buttonGetPrivateKey

Get Private Key

Label

label1

OpenFileDialog

openFileDialog1

OpenFileDialog

openFileDialog2

이러한 컨트롤의 이벤트 처리기를 만들려면 Visual Studio 디자이너에서 해당 단추를 두 번 클릭합니다.

전역 개체 선언

폼의 생성자에 다음 코드 예제를 추가합니다. 문자열 변수는 사용자의 환경 및 기본 설정에 맞게 편집합니다.

' Declare CspParmeters and RsaCryptoServiceProvider 
' objects with global scope of your Form class.
Dim cspp As CspParameters = New System.Security.Cryptography.CspParameters
Dim rsa As RSACryptoServiceProvider

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

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

' Key container name for
' private/public key value pair.
Dim keyName As String = "Key01"
// Declare CspParmeters and RsaCryptoServiceProvider
// objects with global scope of your Form class.
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";

비대칭 키 만들기

이 작업에서는 RijndaelManaged 키를 암호화하고 해독하는 비대칭 키를 만듭니다. 이 키는 내용을 암호화하고 레이블 컨트롤에 키 컨테이너 이름을 표시하는 데 사용됩니다.

다음 코드를 Create Keys 단추에 대한 Click 이벤트 처리기(buttonCreateAsmKeys_Click)로 추가합니다.

Private Sub buttonCreateAsmKeys_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonCreateAsmKeys.Click
    ' Stores a key pair in the key container.
    cspp.KeyContainerName = keyName
    rsa = New RSACryptoServiceProvider(cspp)
    rsa.PersistKeyInCsp = True

    If rsa.PublicOnly = True Then
        Label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only"
    Else
        Label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair"
    End If

End Sub
private void buttonCreateAsmKeys_Click(object sender, System.EventArgs e)
{
    // Stores a key pair in the key container.
    cspp.KeyContainerName = keyName;
    rsa = new RSACryptoServiceProvider(cspp);
    rsa.PersistKeyInCsp = true;
    if (rsa.PublicOnly == true)
       label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only";
    else
       label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair";

}

파일 암호화

이 작업에는 Encrypt File단추에 대한 이벤트 처리기 메서드(buttonEncryptFile_Click)와 EncryptFile 메서드가 사용됩니다. 첫 번째 메서드는 파일을 선택할 수 있는 대화 상자를 표시하고 암호화를 수행하는 두 번째 메서드에 파일 이름을 전달합니다.

암호화된 내용, 키 및 IV는 모두 암호화 패키지라는 하나의 FileStream에 저장됩니다.

EncryptFile 메서드는 다음 작업을 수행합니다.

  1. RijndaelManaged 대칭 알고리즘을 만들어 내용을 암호화합니다.

  2. RSACryptoServiceProvider 개체를 만들어 RijndaelManaged 키를 암호화합니다.

  3. CryptoStream 개체를 사용하여 소스 파일의 FileStream을 바이트 블록 단위로 읽고 암호화된 파일을 위한 대상 FileStream 개체에 암호화하여 넣습니다.

  4. 암호화된 키와 IV의 길이를 확인하고 해당 길이 값의 바이트 배열을 만듭니다.

  5. 키, IV 및 해당 길이 값을 암호화된 패키지에 씁니다.

암호화 패키지는 다음과 같은 형식을 사용합니다.

  • 키 길이: 0 - 3바이트

  • IV 길이: 4 - 7바이트

  • 암호화된 키

  • IV

  • 암호화 텍스트

키 및 IV 길이를 사용하여 파일을 해독하는 데 사용할 수 있는 암호화 패키지의 모든 부분에 대한 시작 지점과 길이를 결정할 수 있습니다.

다음 코드를 Encrypt File 단추에 대한 Click 이벤트 처리기(buttonEncryptFile_Click)로 추가합니다.

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

        // Display a dialog box to select a file to encrypt.
        openFileDialog1.InitialDirectory = SrcFolder;
        if (openFileDialog1.ShowDialog() == DialogResult.OK)
        {
            string fName = openFileDialog1.FileName;
            if (fName != null)
            {
                FileInfo fInfo = new FileInfo(fName);
                // Pass the file name without the path.
                string name = fInfo.Name;
                EncryptFile(name);
            }
        }
    }
}

폼에 다음 EncryptFile 메서드를 추가합니다.

Private Sub EncryptFile(ByVal inFile As String)

    ' Create instance of Rijndael for
    ' symetric encryption of the data.
    Dim rjndl As RijndaelManaged = New RijndaelManaged
    rjndl.KeySize = 256
    rjndl.BlockSize = 256
    rjndl.Mode = CipherMode.CBC
    Dim transform As ICryptoTransform = rjndl.CreateEncryptor

    ' Use RSACryptoServiceProvider to 
    ' enrypt the Rijndael key.
    Dim keyEncrypted() As Byte = rsa.Encrypt(rjndl.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 = rjndl.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
    ' - ecrypted key
    ' - the IV
    ' - the encrypted cipher content
    ' Change the file's extension to ".enc"

    Dim outFile As String = (EncrFolder _
                + (inFile.Substring(0, inFile.LastIndexOf(".")) + ".enc"))

    Using outFs As FileStream = New FileStream(outFile, FileMode.Create)

        outFs.Write(LenK, 0, 4)
        outFs.Write(LenIV, 0, 4)
        outFs.Write(keyEncrypted, 0, lKey)
        outFs.Write(rjndl.IV, 0, lIV)

        ' Now write the cipher text using
        ' a CryptoStream for encrypting.
        Using outStreamEncrypted As CryptoStream = 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 = (rjndl.BlockSize / 8)
            Dim data() As Byte = New Byte((blockSizeBytes) - 1) {}
            Dim bytesRead As Integer = 0
            Using inFs As FileStream = 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
private void EncryptFile(string inFile)
{

    // Create instance of Rijndael for
    // symetric encryption of the data.
    RijndaelManaged rjndl = new RijndaelManaged();
    rjndl.KeySize = 256;
    rjndl.BlockSize = 256;
    rjndl.Mode = CipherMode.CBC;
    ICryptoTransform transform = rjndl.CreateEncryptor();

    // Use RSACryptoServiceProvider to
    // enrypt the Rijndael key.
    byte[] keyEncrypted = rsa.Encrypt(rjndl.Key, false);

    // Create byte arrays to contain
    // the length values of the key and IV.
    byte[] LenK = new byte[4];
    byte[] LenIV = new byte[4];

    int lKey = keyEncrypted.Length;
    LenK = BitConverter.GetBytes(lKey);
    int lIV = rjndl.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
    // - ecrypted key
    // - the IV
    // - the encrypted cipher content

   // Change the file's extension to ".enc"
    string outFile = EncrFolder + inFile.Substring(0, inFile.LastIndexOf(".")) + ".enc";

    using (FileStream outFs = new FileStream(outFile, FileMode.Create))
    {

            outFs.Write(LenK, 0, 4);
            outFs.Write(LenIV, 0, 4);
            outFs.Write(keyEncrypted, 0, lKey);
            outFs.Write(rjndl.IV, 0, lIV);

            // Now write the cipher text using
            // a CryptoStream for encrypting.
            using (CryptoStream 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 = rjndl.BlockSize / 8;
                byte[] data = new byte[blockSizeBytes];
                int bytesRead = 0;

                using (FileStream inFs = new FileStream(inFile, FileMode.Open))
                {
                    do
                    {
                        count = inFs.Read(data, 0, blockSizeBytes);
                        offset += count;
                        outStreamEncrypted.Write(data, 0, count);
                        bytesRead += blockSizeBytes;
                    }
                    while (count > 0);
                inFs.Close();
                }
                outStreamEncrypted.FlushFinalBlock();
                outStreamEncrypted.Close();
            }
            outFs.Close();
    }

}

파일 해독

이 작업에는 Decrypt File 단추에 대한 이벤트 처리기 메서드(buttonDecryptFile_Click)와 DecryptFile 메서드가 사용됩니다. 첫 번째 메서드는 파일을 선택할 수 있는 대화 상자를 표시하고 해독을 수행하는 두 번째 메서드에 파일 이름을 전달합니다.

Decrypt 메서드는 다음 작업을 수행합니다.

  1. RijndaelManaged 대칭 알고리즘을 만들어 내용을 해독합니다.

  2. 암호화된 패키지의 FileStream에서 처음 8바이트를 바이트 배열로 읽어 들이고 암호화된 키 및 IV의 길이를 확인합니다.

  3. 암호화 패키지에서 키 및 IV를 바이트 배열로 추출합니다.

  4. RSACryptoServiceProvider 개체를 만들어 RijndaelManaged 키를 해독합니다.

  5. CryptoStream 개체를 사용하여 FileStream 암호화 패키지의 암호화 텍스트 섹션을 바이트 블록 단위로 읽고 해독된 파일을 위한 FileStream 개체에 해독하여 넣습니다. 이 작업이 끝나면 해독이 완료됩니다.

다음 코드를 Decrypt File 단추에 대한 Click 이벤트 처리기로 추가합니다.

Private Sub buttonDecryptFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonDecryptFile.Click
    If rsa Is Nothing Then
        MsgBox("Key not set.")
    Else
        ' Display a dialog box to select the encrypted file.
        OpenFileDialog2.InitialDirectory = EncrFolder
        If (OpenFileDialog2.ShowDialog = Windows.Forms.DialogResult.OK) Then
            Try
                Dim fName As String = OpenFileDialog2.FileName
                If (Not (fName) Is Nothing) Then
                    Dim fi As FileInfo = 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
private void buttonDecryptFile_Click(object sender, EventArgs e)
{
    if (rsa == null)
        MessageBox.Show("Key not set.");
    else
    {
        // Display a dialog box to select the encrypted file.
        openFileDialog2.InitialDirectory = EncrFolder;
        if (openFileDialog2.ShowDialog() == DialogResult.OK)
        {
            string fName = openFileDialog2.FileName;
            if (fName != null)
            {
                FileInfo fi = new FileInfo(fName);
                string name = fi.Name;
                DecryptFile(name);
            }
        }
    }
}

폼에 다음 DecryptFile 메서드를 추가합니다.

Private Sub DecryptFile(ByVal inFile As String)
    ' Create instance of Rijndael for
    ' symetric decryption of the data.
    Dim rjndl As RijndaelManaged = New RijndaelManaged
    rjndl.KeySize = 256
    rjndl.BlockSize = 256
    rjndl.Mode = CipherMode.CBC

    ' 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 FileStream = 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)
        Dim KeyDecrypted() As Byte = rsa.Decrypt(KeyEncrypted, False)

        ' Decrypt the key.
        Dim transform As ICryptoTransform = rjndl.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 FileStream = 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 = (rjndl.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 CryptoStream = New CryptoStream(outFs, transform, CryptoStreamMode.Write)
                Do
                    count = inFs.Read(data, 0, blockSizeBytes)
                    offset = (offset + count)
                    outStreamDecrypted.Write(data, 0, count)
                Loop Until (count = 0)

                outStreamDecrypted.FlushFinalBlock()
                outStreamDecrypted.Close()
            End Using
            outFs.Close()
        End Using
        inFs.Close()
    End Using
End Sub
private void DecryptFile(string inFile)
{

    // Create instance of Rijndael for
    // symetric decryption of the data.
    RijndaelManaged rjndl = new RijndaelManaged();
    rjndl.KeySize = 256;
    rjndl.BlockSize = 256;
    rjndl.Mode = CipherMode.CBC;
    rjndl.Padding = PaddingMode.None;

    // 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];

    // Consruct the file name for the decrypted file.
    string outFile = DecrFolder + inFile.Substring(0, inFile.LastIndexOf(".")) + ".txt";

    // Use FileStream objects to read the encrypted
    // file (inFs) and save the decrypted file (outFs).
    using (FileStream inFs = new FileStream(EncrFolder + inFile, FileMode.Open))
    {

        inFs.Seek(0, SeekOrigin.Begin);
        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 postition of
        // the ciphter text (startC)
        // and its length(lenC).
        int startC = lenK + lenIV + 8;
        int lenC = (int)inFs.Length - startC;

        // Create the byte arrays for
        // the encrypted Rijndael 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);

        // Use RSACryptoServiceProvider
        // to decrypt the Rijndael key.
        byte[] KeyDecrypted = rsa.Decrypt(KeyEncrypted, false);

        // Decrypt the key.
        ICryptoTransform transform = rjndl.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 (FileStream outFs = new FileStream(outFile, FileMode.Create))
        {

            int count = 0;
            int offset = 0;

            // blockSizeBytes can be any arbitrary size.
            int blockSizeBytes = rjndl.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 (CryptoStream 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();
                outStreamDecrypted.Close();
            }
            outFs.Close();
        }
        inFs.Close();
    }

}

공개 키 내보내기

이 작업에서는 Create Keys 단추로 만들어진 키를 파일에 저장합니다. 이때 공개 매개 변수만 내보냅니다.

이 작업에서는 Alice가 Bob에게 자신을 대신해서 파일을 암호화할 수 있도록 공개 키를 제공한다고 가정합니다. Bob과 해당 공개 키가 있는 다른 사용자는 개인 매개 변수가 있는 전체 키 쌍이 없으므로 파일을 해독할 수 없습니다.

다음 코드를 Export Public Key 단추에 대한 Click 이벤트 처리기(buttonExportPublicKey_Click)로 추가합니다.

Private Sub buttonExportPublicKey_Click(ByVal sender As System.Object, ByVal e As System.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.
    Dim sw As StreamWriter = New StreamWriter(PubKeyFile)
    sw.Write(rsa.ToXmlString(False))
    sw.Close()
End Sub
void buttonExportPublicKey_Click(object sender, System.EventArgs e)
{
    // Save the public key created by the RSA
    // to a file. Caution, persisting the
    // key to a file is a security risk.
    StreamWriter sw = new StreamWriter(PubKeyFile);
    sw.Write(rsa.ToXmlString(false));
    sw.Close();
}

공개 키 가져오기

이 작업에서는 Export Public Key 단추로 만들어진 공개 매개 변수만 있는 키를 로드하고 이를 키 컨테이너 이름으로 설정합니다.

이 작업에서는 Bob이 Alice를 대신해서 파일을 암호화할 수 있도록 공개 매개 변수만 있는 Alice의 키를 로드한다고 가정합니다.

다음 코드를 Import Public Key 단추에 대한 Click 이벤트 처리기(buttonImportPublicKey_Click)로 추가합니다.

Private Sub buttonImportPublicKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonImportPublicKey.Click
    Dim sr As StreamReader = 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 = True Then
        Label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only"
    Else
        Label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair"
    End If
    sr.Close()
End Sub
void buttonImportPublicKey_Click(object sender, System.EventArgs e)
{
    StreamReader sr = new StreamReader(PubKeyFile);
    cspp.KeyContainerName = keyName;
    rsa = new RSACryptoServiceProvider(cspp);
    string keytxt = sr.ReadToEnd();
    rsa.FromXmlString(keytxt);
    rsa.PersistKeyInCsp = true;
    if (rsa.PublicOnly == true)
        label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only";
    else
        label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair";
    sr.Close();
}

개인 키 가져오기

이 작업에서는 Create Keys 단추를 사용하여 만들어진 키의 이름으로 키 컨테이너 이름을 설정합니다. 키 컨테이너는 개인 매개 변수가 있는 전체 키 쌍을 포함합니다.

이 작업에서는 Alice가 자신의 개인 키를 사용하여 Bob이 암호화한 파일을 해독한다고 가정합니다.

다음 코드를 Get Private Key 단추에 대한 Click 이벤트 처리기(buttonGetPrivateKey_Click)로 추가합니다.

Private Sub buttonGetPrivateKey_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles buttonGetPrivateKey.Click
    cspp.KeyContainerName = keyName
    rsa = New RSACryptoServiceProvider(cspp)
    rsa.PersistKeyInCsp = True
    If rsa.PublicOnly = True Then
        Label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only"
    Else
        Label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair"
    End If
End Sub
private void buttonGetPrivateKey_Click(object sender, EventArgs e)
{
    cspp.KeyContainerName = keyName;

    rsa = new RSACryptoServiceProvider(cspp);
    rsa.PersistKeyInCsp = true;

    if (rsa.PublicOnly == true)
        label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only";
    else
        label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair";

}

응용 프로그램 테스트

응용 프로그램을 빌드한 후 다음 테스트 시나리오를 수행합니다.

키를 만들고 암호화한 다음 해독하려면

  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 단추를 클릭하고 방금 암호화한 파일을 선택합니다. 이번에는 해독하기 위한 전체 키 쌍이 있으므로 해독에 성공합니다.

참고 항목

기타 리소스

암호화 작업

암호화 서비스