如何:使用数据保护
.NET 提供对数据保护 API (DPAPI) 的访问,这允许你使用来自当前用户帐户或计算机的信息对数据进行加密。 当使用 DPAPI 时,你会使显式生成和存储加密密钥的困难问题得到缓解。
使用 ProtectedData 类来加密字节数组的副本。 你可以指定由当前用户帐户加密的数据仅能通过相同的用户帐户解密,也可以指定由当前用户帐户加密的数据可以通过计算机上的任何帐户进行解密。 请参阅 DataProtectionScope 枚举以获取 ProtectedData 选项的详细说明。
使用数据保护将数据加密到文件或流
创建随机平均信息量。
调用静态 Protect 方法,同时传递要加密的字节数组、平均信息量和数据保护范围。
将加密的数据写入文件或流。
若要使用数据保护从文件或流解密数据
从文件或流中读取加密的数据。
调用静态 Unprotect 方法,同时传递要解密的字节数组和数据保护范围。
示例
下面的代码示例演示加密和解密的两种形式。 首先,该代码示例对内存中的字节数组进行加密,然后将其解密。 接下来,该代码示例对字节数组的副本进行加密、将其保存到文件、从文件加载回数据,然后对数据进行解密。 此示例显示原始数据、加密的数据和已解密的数据。
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 == null)
throw new ArgumentNullException(nameof(Buffer));
if (Buffer.Length <= 0)
throw new ArgumentException("The buffer length was 0.", nameof(Buffer));
// Encrypt the data in memory. The result is stored in the same array as the original data.
ProtectedMemory.Protect(Buffer, Scope);
}
public static void DecryptInMemoryData(byte[] Buffer, MemoryProtectionScope Scope)
{
if (Buffer == null)
throw new ArgumentNullException(nameof(Buffer));
if (Buffer.Length <= 0)
throw new ArgumentException("The buffer length was 0.", nameof(Buffer));
// Decrypt the data in memory. The result is stored in the 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 == null)
throw new ArgumentNullException(nameof(Buffer));
if (Buffer.Length <= 0)
throw new ArgumentException("The buffer length was 0.", nameof(Buffer));
if (Entropy == null)
throw new ArgumentNullException(nameof(Entropy));
if (Entropy.Length <= 0)
throw new ArgumentException("The entropy length was 0.", nameof(Entropy));
if (S == null)
throw new ArgumentNullException(nameof(S));
int length = 0;
// Encrypt the data and store the result in a new byte array. The original data remains unchanged.
byte[] encryptedData = ProtectedData.Protect(Buffer, Entropy, Scope);
// Write the encrypted data to a stream.
if (S.CanWrite && encryptedData != null)
{
S.Write(encryptedData, 0, encryptedData.Length);
length = encryptedData.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(nameof(S));
if (Length <= 0 )
throw new ArgumentException("The given length was 0.", nameof(Length));
if (Entropy == null)
throw new ArgumentNullException(nameof(Entropy));
if (Entropy.Length <= 0)
throw new ArgumentException("The entropy length was 0.", nameof(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 decrypted data
return outBuffer;
}
}
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Public Module MemoryProtectionSample
Sub Main()
Run()
End Sub
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
Sub EncryptInMemoryData(ByVal Buffer() As Byte, ByVal Scope As MemoryProtectionScope)
If Buffer Is Nothing Then
Throw New ArgumentNullException("Buffer")
End If
If Buffer.Length <= 0 Then
Throw New ArgumentException("Buffer")
End If
' Encrypt the data in memory. The result is stored in the same array as the original data.
ProtectedMemory.Protect(Buffer, Scope)
End Sub
Sub DecryptInMemoryData(ByVal Buffer() As Byte, ByVal Scope As MemoryProtectionScope)
If Buffer Is Nothing Then
Throw New ArgumentNullException("Buffer")
End If
If Buffer.Length <= 0 Then
Throw New ArgumentException("Buffer")
End If
' Decrypt the data in memory. The result is stored in the same array as the original data.
ProtectedMemory.Unprotect(Buffer, Scope)
End Sub
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 Is Nothing Then
Throw New ArgumentNullException("Buffer")
End If
If Buffer.Length <= 0 Then
Throw New ArgumentException("Buffer")
End If
If Entropy Is Nothing Then
Throw New ArgumentNullException("Entropy")
End If
If Entropy.Length <= 0 Then
Throw New ArgumentException("Entropy")
End If
If S Is Nothing Then
Throw New ArgumentNullException("S")
End If
Dim length As Integer = 0
' Encrypt the data and store the result in a new byte array. The original data remains unchanged.
Dim encryptedData As Byte() = ProtectedData.Protect(Buffer, Entropy, Scope)
' Write the encrypted data to a stream.
If S.CanWrite AndAlso Not (encryptedData Is Nothing) Then
S.Write(encryptedData, 0, encryptedData.Length)
length = encryptedData.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 - 1) 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 unencrypted data as byte array.
Return outBuffer
End Function 'DecryptDataFromStream
End Module 'MemoryProtectionSample
编译代码
此示例仅在将目标定位到 .NET Framework 并运行 Windows 时编译并运行。
包括对
System.Security.dll
的引用。包括 System、System.IO、System.Security.Cryptography 和 System.Text 命名空间。