ログインしている自分or自OS（Windows資格情報）でのみ暗号化・復号できる・・・ProtectedDataクラス（.NET標準提供） 

# この記事で知れること

ログインしている Windows ユーザーまたはコンピューターの資格情報を用いて暗号化・復号する
[System.Security.Cryptography.ProtectedData](https://docs.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.protecteddata) クラスという存在、および使用法がわかると思います。

# 環境

.NET Framework 2.0以降 （古くからあるのですね）、.NET Core 1.0以降（Windowsのみ）
要参照設定 : System.Security.dll

Visual Studio 2019 (16.9.4) で実験しました

# 説明

Microsoft Docs の説明
> このクラスは、Windows オペレーティングシステムで使用可能なデータ保護 API ( [DPAPI](https://ja.wikipedia.org/wiki/DPAPI) ) へのアクセスを提供します。 これはオペレーティングシステムによって提供されるサービスであり、追加のライブラリは必要ありません。 ユーザーまたはコンピューターの資格情報を使用してデータを暗号化または復号化することにより、保護を提供します。

主たるメソッドは、静的な [Protect](https://docs.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.protecteddata.protect) と [Unprotect](https://docs.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.protecteddata.unprotect) の2つのみ、というシンプルな構成。

## 実験

### サンプルコード

.NET Framework コンソールアプリケーションで作成してみました。
ProtectedData クラスは Byte 配列を扱いますが、わかりやすくするために文字列を扱います。

※アセンブリ System.Security の参照追加が必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1548956/a61b7dfd-a558-a83c-bd18-fe767b13d857.png)

```C#:Program.cs
using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var protectionScope = System.Security.Cryptography.DataProtectionScope.LocalMachine; // or CurrentUser;
            var salt = System.Text.Encoding.UTF8.GetBytes("AnyText"); // バイト配列になればなんでもOK

            while (true)
            {
                Console.Write("Original Text (Empty to exit): ");
                var originalText = Console.ReadLine();  // オリジナル文字列受付(空文字でループ終了)
                if (string.IsNullOrEmpty(originalText))
                    break;
                Console.WriteLine();

                // UTF8エンコード->暗号化->BASE64化
                var utf8OriginalTextBytes = System.Text.Encoding.UTF8.GetBytes(originalText);
                var encryptedUtf8OriginalTextBytes = System.Security.Cryptography.ProtectedData.Protect(utf8OriginalTextBytes, salt, protectionScope); // <-- Protect
                var encryptedUtf8OriginalTextBytesAsBase64Encoding = System.Convert.ToBase64String(encryptedUtf8OriginalTextBytes);
                Console.WriteLine($"Encryped Text : {encryptedUtf8OriginalTextBytesAsBase64Encoding}");
                Console.WriteLine();

                // BASE64からByte[]に復元->復号->UTF8デコード
                var encryptedUtf8TextBytes = System.Convert.FromBase64String(encryptedUtf8OriginalTextBytesAsBase64Encoding);
                var decryptedUtf8TextBytes = System.Security.Cryptography.ProtectedData.Unprotect(encryptedUtf8TextBytes, salt, protectionScope); // <-- Unprotect
                var decryptedText = System.Text.Encoding.UTF8.GetString(decryptedUtf8TextBytes);

                Console.WriteLine($"Decryped Text : {decryptedText}");
                Console.WriteLine();
            }

            Console.Write("Push any key");
            Console.ReadKey();
        }
    }
}

```

### 実行結果

#### コンピューター1
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1548956/d677f16f-fe36-54c5-164b-656eee3ffa41.png)

#### ユーザーA on コンピューター1
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1548956/5604a01c-1129-e887-530d-79192aa24ec4.png)

#### ユーザーB on コンピューター1
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1548956/0f9990be-f3fe-5912-38b8-5779b63f8795.png)

とにかく、もとの文字列に比べてめちゃくちゃ長い。
同じコンピューター上での実行であるためか、はじめのほうのフレーズ（データ）が共通しています。しかし解析は困難でしょう。

OS管理のアカウントと紐ついているので、デジタル証明書のように秘密鍵を第三者に盗まれて復号される心配もなし。
仮にこのデータ（文字列）を共有ファイルサーバー内に保存しても、他のユーザー or コンピューターには解読できない（超困難な）仕様です。
ローカルでのパスワードの安全な保存はもとより、共有ファイルサーバーをクラウドストレージの「個人用Vault」のようにも使えますね。

-- 以上です [記事作成時間 約1:30] --