방법: 데이터 보호 사용
.NET Framework에서는 사용자 계정이나 컴퓨터의 정보를 사용하여 데이터를 암호화할 수 있는 DPAPI(데이터 보호 API)에 대한 액세스를 제공합니다. DPAPI를 사용하면 암호화 키를 명시적으로 생성하고 저장하는 어려운 문제를 해결할 수 있습니다.
메모리 내 바이트 배열을 암호화하려면 ProtectedMemory 클래스를 사용합니다. 이 기능은 Microsoft Windows XP 이상의 운영 체제에서 사용할 수 있습니다. 현재 프로세스에 의해 암호화된 메모리를 현재 프로세스에서만 해독할 수 있도록 할지 모든 프로세스에서 해독할 수 있도록 할지 또는 동일한 사용자 컨텍스트에서 해독할 수 있도록 할지 지정할 수 있습니다. ProtectedMemory 옵션에 대한 자세한 내용은 MemoryProtectionScope 열거형을 참조하십시오.
바이트 배열의 복사본을 암호화하려면 ProtectedData 클래스를 사용합니다. 이 기능은 Microsoft Windows 2000 이상의 운영 체제에서 사용할 수 있습니다. 현재 사용자가 암호화한 데이터를 동일한 사용자 계정에서만 해독할 수 있도록 할지 아니면 컴퓨터의 모든 계정에서 해독할 수 있도록 할지 지정할 수 있습니다. ProtectedData 옵션에 대한 자세한 내용은 DataProtectionScope 열거형을 참조하십시오.
데이터 보호를 사용하여 메모리 내 데이터를 암호화하려면
- 암호화할 바이트 배열, 엔트로피 및 메모리 보호 범위를 전달하는 동안 정적 Protect 메서드를 호출합니다.
데이터 보호를 사용하여 메모리 내 데이터를 해독하려면
- 해독할 바이트 배열과 메모리 보호 범위를 전달하는 동안 정적 Unprotect 메서드를 호출합니다.
데이터 보호를 사용하여 데이터를 파일 또는 스트림으로 암호화하려면
임의의 엔트로피를 만듭니다.
암호화할 바이트 배열, 엔트로피 및 데이터 보호 범위를 전달하는 동안 정적 Protect 메서드를 호출합니다.
암호화된 데이터를 파일이나 스트림에 씁니다.
데이터 보호를 사용하여 파일 또는 스트림에서 데이터를 해독하려면
파일이나 스트림에서 암호화된 데이터를 읽습니다.
해독할 바이트 배열과 데이터 보호 범위를 전달하는 동안 정적 Unprotect 메서드를 호출합니다.
예제
다음 코드 예제에서는 두 가지 형식의 암호화와 해독을 보여 줍니다. 첫 번째 코드 예제에서는 메모리 내 바이트 배열을 암호화한 다음 해독합니다. 두 번째 코드 예제에서는 바이트 배열의 복사본을 암호화하여 파일에 저장하고 데이터를 다시 파일에서 로드한 다음 데이터를 해독합니다. 이 예제에서는 원래 데이터, 암호화된 데이터 및 해독된 데이터를 표시합니다.
Imports System
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Public Module MemoryProtectionSample
Sub Main()
Run()
End Sub 'Main
Sub Run()
Try
''''''''''''''''''''''''''''''''''''
'
' Memory Encryption - ProtectedMemory
'
''''''''''''''''''''''''''''''''''''
' Create the original data to be encrypted (The data length should be a multiple of 16).
Dim toEncrypt As Byte() = UnicodeEncoding.ASCII.GetBytes("ThisIsSomeData16")
Console.WriteLine("Original data: " + UnicodeEncoding.ASCII.GetString(toEncrypt))
Console.WriteLine("Encrypting...")
' Encrypt the data in memory.
EncryptInMemoryData(toEncrypt, MemoryProtectionScope.SameLogon)
Console.WriteLine("Encrypted data: " + UnicodeEncoding.ASCII.GetString(toEncrypt))
Console.WriteLine("Decrypting...")
' Decrypt the data in memory.
DecryptInMemoryData(toEncrypt, MemoryProtectionScope.SameLogon)
Console.WriteLine("Decrypted data: " + UnicodeEncoding.ASCII.GetString(toEncrypt))
''''''''''''''''''''''''''''''''''''
'
' Data Encryption - ProtectedData
'
''''''''''''''''''''''''''''''''''''
' Create the original data to be encrypted
toEncrypt = UnicodeEncoding.ASCII.GetBytes("This is some data of any length.")
' Create a file.
Dim fStream As New FileStream("Data.dat", FileMode.OpenOrCreate)
' Create some random entropy.
Dim entropy As Byte() = CreateRandomEntropy()
Console.WriteLine()
Console.WriteLine("Original data: " + UnicodeEncoding.ASCII.GetString(toEncrypt))
Console.WriteLine("Encrypting and writing to disk...")
' Encrypt a copy of the data to the stream.
Dim bytesWritten As Integer = EncryptDataToStream(toEncrypt, entropy, DataProtectionScope.CurrentUser, fStream)
fStream.Close()
Console.WriteLine("Reading data from disk and decrypting...")
' Open the file.
fStream = New FileStream("Data.dat", FileMode.Open)
' Read from the stream and decrypt the data.
Dim decryptData As Byte() = DecryptDataFromStream(entropy, DataProtectionScope.CurrentUser, fStream, bytesWritten)
fStream.Close()
Console.WriteLine("Decrypted data: " + UnicodeEncoding.ASCII.GetString(decryptData))
Catch e As Exception
Console.WriteLine("ERROR: " + e.Message)
End Try
End Sub 'Run
Sub EncryptInMemoryData(ByVal Buffer() As Byte, ByVal Scope As MemoryProtectionScope)
If Buffer.Length <= 0 Then
Throw New ArgumentException("Buffer")
End If
If Buffer Is Nothing Then
Throw New ArgumentNullException("Buffer")
End If
' Encrypt the data in memory. The result is stored in the same same array as the original data.
ProtectedMemory.Protect(Buffer, Scope)
End Sub 'EncryptInMemoryData
Sub DecryptInMemoryData(ByVal Buffer() As Byte, ByVal Scope As MemoryProtectionScope)
If Buffer.Length <= 0 Then
Throw New ArgumentException("Buffer")
End If
If Buffer Is Nothing Then
Throw New ArgumentNullException("Buffer")
End If
' Decrypt the data in memory. The result is stored in the same same array as the original data.
ProtectedMemory.Unprotect(Buffer, Scope)
End Sub 'DecryptInMemoryData
Function CreateRandomEntropy() As Byte()
' Create a byte array to hold the random value.
Dim entropy(15) As Byte
' Create a new instance of the RNGCryptoServiceProvider.
' Fill the array with a random value.
Dim RNG As New RNGCryptoServiceProvider()
RNG.GetBytes(entropy)
' Return the array.
Return entropy
End Function 'CreateRandomEntropy
Function EncryptDataToStream(ByVal Buffer() As Byte, ByVal Entropy() As Byte, ByVal Scope As DataProtectionScope, ByVal S As Stream) As Integer
If Buffer.Length <= 0 Then
Throw New ArgumentException("Buffer")
End If
If Buffer Is Nothing Then
Throw New ArgumentNullException("Buffer")
End If
If Entropy.Length <= 0 Then
Throw New ArgumentException("Entropy")
End If
If Entropy Is Nothing Then
Throw New ArgumentNullException("Entropy")
End If
If S Is Nothing Then
Throw New ArgumentNullException("S")
End If
Dim length As Integer = 0
' Encrypt the data in memory. The result is stored in the same same array as the original data.
Dim encrptedData As Byte() = ProtectedData.Protect(Buffer, Entropy, Scope)
' Write the encrypted data to a stream.
If S.CanWrite AndAlso Not (encrptedData Is Nothing) Then
S.Write(encrptedData, 0, encrptedData.Length)
length = encrptedData.Length
End If
' Return the length that was written to the stream.
Return length
End Function 'EncryptDataToStream
Function DecryptDataFromStream(ByVal Entropy() As Byte, ByVal Scope As DataProtectionScope, ByVal S As Stream, ByVal Length As Integer) As Byte()
If S Is Nothing Then
Throw New ArgumentNullException("S")
End If
If Length <= 0 Then
Throw New ArgumentException("Length")
End If
If Entropy Is Nothing Then
Throw New ArgumentNullException("Entropy")
End If
If Entropy.Length <= 0 Then
Throw New ArgumentException("Entropy")
End If
Dim inBuffer(Length) As Byte
Dim outBuffer() As Byte
' Read the encrypted data from a stream.
If S.CanRead Then
S.Read(inBuffer, 0, Length)
outBuffer = ProtectedData.Unprotect(inBuffer, Entropy, Scope)
Else
Throw New IOException("Could not read the stream.")
End If
' Return the length that was written to the stream.
Return outBuffer
End Function 'DecryptDataFromStream
End Module 'MemoryProtectionSample
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
public class MemoryProtectionSample
{
public static void Main()
{
Run();
}
public static void Run()
{
try
{
///////////////////////////////
//
// Memory Encryption - ProtectedMemory
//
///////////////////////////////
// Create the original data to be encrypted (The data length should be a multiple of 16).
byte[] toEncrypt = UnicodeEncoding.ASCII.GetBytes("ThisIsSomeData16");
Console.WriteLine("Original data: " + UnicodeEncoding.ASCII.GetString(toEncrypt));
Console.WriteLine("Encrypting...");
// Encrypt the data in memory.
EncryptInMemoryData(toEncrypt, MemoryProtectionScope.SameLogon);
Console.WriteLine("Encrypted data: " + UnicodeEncoding.ASCII.GetString(toEncrypt));
Console.WriteLine("Decrypting...");
// Decrypt the data in memory.
DecryptInMemoryData(toEncrypt, MemoryProtectionScope.SameLogon);
Console.WriteLine("Decrypted data: " + UnicodeEncoding.ASCII.GetString(toEncrypt));
///////////////////////////////
//
// Data Encryption - ProtectedData
//
///////////////////////////////
// Create the original data to be encrypted
toEncrypt = UnicodeEncoding.ASCII.GetBytes("This is some data of any length.");
// Create a file.
FileStream fStream = new FileStream("Data.dat", FileMode.OpenOrCreate);
// Create some random entropy.
byte[] entropy = CreateRandomEntropy();
Console.WriteLine();
Console.WriteLine("Original data: " + UnicodeEncoding.ASCII.GetString(toEncrypt));
Console.WriteLine("Encrypting and writing to disk...");
// Encrypt a copy of the data to the stream.
int bytesWritten = EncryptDataToStream(toEncrypt, entropy, DataProtectionScope.CurrentUser, fStream);
fStream.Close();
Console.WriteLine("Reading data from disk and decrypting...");
// Open the file.
fStream = new FileStream("Data.dat", FileMode.Open);
// Read from the stream and decrypt the data.
byte[] decryptData = DecryptDataFromStream(entropy, DataProtectionScope.CurrentUser, fStream, bytesWritten);
fStream.Close();
Console.WriteLine("Decrypted data: " + UnicodeEncoding.ASCII.GetString(decryptData));
}
catch (Exception e)
{
Console.WriteLine("ERROR: " + e.Message);
}
}
public static void EncryptInMemoryData(byte[] Buffer, MemoryProtectionScope Scope )
{
if (Buffer.Length <= 0)
throw new ArgumentException("Buffer");
if (Buffer == null)
throw new ArgumentNullException("Buffer");
// Encrypt the data in memory. The result is stored in the same same array as the original data.
ProtectedMemory.Protect(Buffer, Scope);
}
public static void DecryptInMemoryData(byte[] Buffer, MemoryProtectionScope Scope)
{
if (Buffer.Length <= 0)
throw new ArgumentException("Buffer");
if (Buffer == null)
throw new ArgumentNullException("Buffer");
// Decrypt the data in memory. The result is stored in the same same array as the original data.
ProtectedMemory.Unprotect(Buffer, Scope);
}
public static byte[] CreateRandomEntropy()
{
// Create a byte array to hold the random value.
byte[] entropy = new byte[16];
// Create a new instance of the RNGCryptoServiceProvider.
// Fill the array with a random value.
new RNGCryptoServiceProvider().GetBytes(entropy);
// Return the array.
return entropy;
}
public static int EncryptDataToStream(byte[] Buffer, byte[] Entropy, DataProtectionScope Scope, Stream S)
{
if (Buffer.Length <= 0)
throw new ArgumentException("Buffer");
if (Buffer == null)
throw new ArgumentNullException("Buffer");
if (Entropy.Length <= 0)
throw new ArgumentException("Entropy");
if (Entropy == null)
throw new ArgumentNullException("Entropy");
if (S == null)
throw new ArgumentNullException("S");
int length = 0;
// Encrypt the data in memory. The result is stored in the same same array as the original data.
byte[] encrptedData = ProtectedData.Protect(Buffer, Entropy, Scope);
// Write the encrypted data to a stream.
if (S.CanWrite && encrptedData != null)
{
S.Write(encrptedData, 0, encrptedData.Length);
length = encrptedData.Length;
}
// Return the length that was written to the stream.
return length;
}
public static byte[] DecryptDataFromStream(byte[] Entropy, DataProtectionScope Scope, Stream S, int Length)
{
if (S == null)
throw new ArgumentNullException("S");
if (Length <= 0 )
throw new ArgumentException("Length");
if (Entropy == null)
throw new ArgumentNullException("Entropy");
if (Entropy.Length <= 0)
throw new ArgumentException("Entropy");
byte[] inBuffer = new byte[Length];
byte[] outBuffer;
// Read the encrypted data from a stream.
if (S.CanRead)
{
S.Read(inBuffer, 0, Length);
outBuffer = ProtectedData.Unprotect(inBuffer, Entropy, Scope);
}
else
{
throw new IOException("Could not read the stream.");
}
// Return the length that was written to the stream.
return outBuffer;
}
}
코드 컴파일
System.Security.dll에 대한 참조를 포함합니다.
System, System.IO, System.Security.Cryptography 및 System.Text 네임스페이스를 포함합니다.