using AspNetCore.Xcode.Me;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Win32;
using StackExchange.Redis;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace DataProtectionSample
{
    class Program
    {
        static void Main1(string[] args)
        {
            var serviceCollection = new ServiceCollection();
            serviceCollection.AddDataProtection();
            var services = serviceCollection.BuildServiceProvider();

            //var provider = services.GetRequiredService<IDataProtectionProvider>();
            //var protector = provider.CreateProtector("DataProtectionSample.Program");

            var provider = services.GetDataProtectionProvider();

            var protector1 = services.GetDataProtector("DataProtectionSample.Program1");
            var protector2 = services.GetDataProtector("DataProtectionSample.Program2");

            var protector11 = protector1.CreateProtector("Test1").CreateProtector("Test11");
            var protector12 = protector1.CreateProtector("Test2");

            string input = "this is xcode.me test.";

            string protetedPayload = protector1.Protect(input);

            Console.WriteLine(protetedPayload);

            string unprotectedPayload = protector1.Unprotect(protetedPayload);

            Console.WriteLine(unprotectedPayload);

            Console.ReadKey();

            //%LOCALAPPDATA%\ASP.NET\DataProtection-Keys
        }

        static void Main2(string[] args)
        {
            string password = "www.xcode.me";

            // generate a 128-bit salt using a secure PRNG
            byte[] salt = new byte[128 / 8];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(salt);
            }

            string saltString = Convert.ToBase64String(salt);

            // derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
            var hashedBytes = KeyDerivation.Pbkdf2(password, salt, prf: KeyDerivationPrf.HMACSHA1, 10000, 256 / 8);

            string hashedString = Convert.ToBase64String(hashedBytes);
        }

        static void Main4(string[] args)
        {
            string password = "www.xcode.me";

            PasswordHasher passwordHasher = new PasswordHasher();

            string hashedPassword = passwordHasher.HashPassword(password);

            bool result = passwordHasher.VerifyHashedPassword(hashedPassword, "www.xcode.me");

            string has2 = "AQAAAAEAAAPoAAAAEOEH3LASQOO+9NidtbyI6bKmK0S49VSfq9zI5IIRa/1yRtZkSxsRAAeSS3rxnXhyeQ==";

            string has3 = "AQAAAAEAAAPoAAAAENM4hRhvxpIMpBVOLmpnKAzbRowqjmCFcCTvSOmioqAw3vnYueNMCYBhrjbCd3RdzA==";

            bool result2 = passwordHasher.VerifyHashedPassword(has2, password);

            bool result3 = passwordHasher.VerifyHashedPassword(has3, password);

        }

        static void Main5(string[] args)
        {

            string input = "this is ITimeLimitedDataProtector";

            var serviceCollection = new ServiceCollection();

            serviceCollection.AddDataProtection();

            var services = serviceCollection.BuildServiceProvider();

            var provider = services.GetRequiredService<IDataProtectionProvider>();
            var protector = provider.CreateProtector("DataProtectionSample.Program").ToTimeLimitedDataProtector();

            string protectedData = protector.Protect(input, TimeSpan.FromSeconds(5));

            string stringDatas = protector.Unprotect(protectedData);

            Task.Delay(TimeSpan.FromSeconds(6)).Wait();

            string stringDatas2 = protector.Unprotect(protectedData);
        }

        static void Main6(string[] args)
        {
            var serviceCollection = new ServiceCollection();

            serviceCollection.AddDataProtection()
            .PersistKeysToFileSystem(new System.IO.DirectoryInfo(@"d:\temp-keys\"))
            .PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Sample\keys"));

            serviceCollection
                .AddDataProtection()
                .PersistKeysToAzureBlobStorage(new Uri("<blob URI including SAS token>"))
                .ProtectKeysWithAzureKeyVault("", "", "");

            var redis = ConnectionMultiplexer.Connect("<URI>");

            serviceCollection.AddDataProtection()
                .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys");


            serviceCollection.AddDbContext<MyKeysContext>(options => options.UseSqlServer("connectionString"));

            serviceCollection.AddDataProtection()
                .PersistKeysToDbContext<MyKeysContext>()
                .ProtectKeysWithCertificate(new X509Certificate2("test.pfx"))
                .SetDefaultKeyLifetime(TimeSpan.FromDays(15))
                .SetApplicationName("xcode1")
                .DisableAutomaticKeyGeneration()
                .UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
                {
                    EncryptionAlgorithm = Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.EncryptionAlgorithm.AES_128_GCM
                });
        }

        public static void Main(string[] args)
        {
            var keysFolder = Path.Combine(Directory.GetCurrentDirectory(), "temp-keys");

            // instantiate the data protection system at this folder
            var dataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(keysFolder),
                configuration =>
                {
                    configuration.SetApplicationName("my app name");
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        configuration.ProtectKeysWithDpapi();
                    }
                });

            var protector = dataProtectionProvider.CreateProtector("Program.No-DI");

            // protect the payload
            var protectedPayload = protector.Protect("Hello World!");
            Console.WriteLine($"Protect returned: {protectedPayload}");

            // unprotect the payload
            var unprotectedPayload = protector.Unprotect(protectedPayload);
            Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
        }
    }

    public class MyKeysContext : DbContext, IDataProtectionKeyContext
    {
        // A recommended constructor overload when using EF Core 
        // with dependency injection.
        public MyKeysContext(DbContextOptions<MyKeysContext> options) : base(options)
        {

        }

        // This maps to the table that stores keys.
        public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
    }
}
