方法: データ保護の使用

注意

この記事は Windows に適用されます。

ASP.NET Core の詳細については、「ASP.NET Core のデータ保護」を参照してください。

.NET では、データ保護 API (DPAPI) へのアクセスを提供しています。これを使用すると、現在のユーザー アカウントまたはコンピューターからの情報を使用してデータを暗号化できます。 DPAPI を使用すると、暗号化キーを明示的に生成および格納するという困難な問題を軽減できます。

バイト配列のコピーを暗号化するには、ProtectedData クラスを使用します。 この機能は、.NET Framework、.NET Core、.NET 5 で使用できます。 現在のユーザー アカウントによって暗号化されたデータは、同じユーザー アカウントによってのみ復号化できることを指定できます。あるいは、現在のユーザー アカウントによって暗号化されたデータは、コンピューター上の任意のアカウントによって復号化できることを指定できます。 ProtectedData オプションの詳しい説明については、「DataProtectionScope 列挙型」を参照してください。

データ保護を使用してファイルやストリームのデータを暗号化する

  1. ランダム エントロピを作成します。

  2. 暗号化するバイト配列、エントロピ、およびデータ保護スコープを渡す際に、静的な Protect メソッドを呼び出します。

  3. ファイルまたはストリームに暗号化されたデータを書き込みます。

データ保護を使用してファイルやストリームからデータを復号化するには

  1. ファイルまたはストリームから暗号化されたデータを読み取ります。

  2. 復号化するバイト配列およびデータ保護スコープを渡す際に、静的な Unprotect メソッドを呼び出します。

次のコード例は、暗号化と復号化の 2 つの形式を示しています。 最初に、コード例では、メモリ内のバイト配列を暗号化してから復号化します。 次に、コード例では、バイト配列のコピーを暗号化し、ファイルに保存して、そのファイルからデータを読み込み、その後データを復号化しています。 例では、元のデータ、暗号化されたデータ、および復号化されたデータが表示されます。

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 で実行している場合にのみ、コンパイルして実行します。

関連項目