Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Security.Cryptography;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
- using static NonCryptographicHelpers;
- using static options;
- var rand = new Random();
- var watch = new Stopwatch();
- var fs = new FileStream("output.txt", FileMode.Create);
- var sw = new StreamWriter(fs);
- Console.SetOut(sw);
- for (int w = 0; w < 5; w++)
- for (int exp = 3; exp < 7; exp++)
- {
- for (int numUsers = 10; numUsers < 40; numUsers += 10)
- {
- int numberOfUsers = (int)Math.Pow(10, exp);
- Console.WriteLine("Control: Using no encryption");
- using (var context = new UnencryptedDbContext())
- {
- context.Database.EnsureDeleted();
- context.Database.EnsureCreated();
- Console.WriteLine($"Seeding DB with {numberOfUsers} users ");
- for (int i = 0; i < numberOfUsers; i++)
- {
- context.Add(new BasicEntity
- {
- EmailAddress = $"{rand.Next()}-{rand.Next()}@example.com"
- });
- }
- Console.WriteLine("Saving changes");
- context.SaveChanges();
- Console.WriteLine($"Adding {numUsers} users individually");
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- context.Add(new BasicEntity
- {
- EmailAddress = $"{rand.Next()}-{rand.Next()}@example.com"
- });
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {i} took {watch.ElapsedTicks} ticks");
- }
- Console.WriteLine($"Changing {numUsers} users email addresses, twice each");
- var ids = context.BasicEntities.Take(numUsers).Select(_ => _.Id).ToArray();
- for (int j = 0; j < 2; j++)
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- var u = context.BasicEntities.Find(ids[i]);
- u.EmailAddress = $"{rand.Next()}-{rand.Next()}@example.com";
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {j} on user {i} took {watch.ElapsedTicks} ticks");
- }
- }
- Console.WriteLine("Control: using a fixed number of buckets");
- using (var context = new BucketedEncryptedDbContext())
- {
- int bucketExponent = GetBucketExponent(numberOfUsers);
- context.Database.EnsureDeleted();
- context.Database.EnsureCreated();
- Console.WriteLine($"Seeding DB with {numberOfUsers} users ");
- for (int i = 0; i < numberOfUsers; i++)
- {
- context.Add(new BucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", bucketExponent));
- }
- Console.WriteLine("Saving changes");
- context.SaveChanges();
- Console.WriteLine($"Adding {numUsers} users individually");
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- BucketedEntity entity;
- bool conflict = false;
- do
- {
- entity = new BucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", bucketExponent);
- foreach (var other in context.BucketedEntities.Where(_ => _.BucketNo == entity.BucketNo))
- {
- if (other.EmailAddress == entity.EmailAddress)
- {
- Console.WriteLine("ERROR: CONFLICT. RESTARTING ITERATION.");
- conflict = true;
- }
- }
- } while (conflict);
- context.Add(entity);
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {i} took {watch.ElapsedTicks} ticks");
- }
- Console.WriteLine($"Changing {numUsers} users email addresses, twice each");
- var ids = context.BucketedEntities.Take(numUsers).Select(_ => _.Id).ToArray();
- for (int j = 0; j < 2; j++)
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- var u = context.BucketedEntities.Find(ids[i]);
- BucketedEntity entity;
- bool conflict = false;
- do
- {
- entity = new BucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", bucketExponent);
- foreach (var other in context.BucketedEntities.Where(_ => _.BucketNo == entity.BucketNo))
- {
- if (other.EmailAddress == entity.EmailAddress)
- {
- Console.WriteLine("ERROR: CONFLICT. RESTARTING ITERATION.");
- conflict = true;
- }
- }
- } while (conflict);
- u.EmailAddress = entity.EmailAddress;
- u.BucketNo = entity.BucketNo;
- context.SaveChanges();
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {j} on user {i} took {watch.ElapsedTicks} ticks");
- }
- }
- Console.WriteLine("Using `SELECT COUNT(*)` for updates to BucketCount, storing BucketExponent in the entity");
- using (var context = new BucketExponentStoringDbContext())
- {
- context.Database.EnsureDeleted();
- context.Database.EnsureCreated();
- Console.WriteLine($"Seeding DB with {numberOfUsers} users ");
- for (int i = 0; i < numberOfUsers; i++)
- {
- context.Add(new BucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", GetBucketExponent(i)));
- }
- Console.WriteLine("Saving changes");
- context.SaveChanges();
- Console.WriteLine($"Adding {numUsers} users individually");
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- BucketExponentStoringBucketedEntity entity;
- bool conflict = false;
- var counts = context.BucketExponentStoringBucketedEntities.Select(_ => _.BucketExponent).Distinct().ToList();
- var currentCount = context.BucketExponentStoringBucketedEntities.Count();
- do
- {
- entity = new BucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", currentCount);
- var buckets = counts.Select(_ => new BucketExponentStoringBucketedEntity(entity.EmailAddress, _)).ToList();
- foreach (var b in buckets)
- {
- var others = context.BucketExponentStoringBucketedEntities.Where(_ => _.BucketNo == b.BucketNo && _.BucketExponent == b.BucketExponent).ToList();
- foreach (var o in others)
- {
- if (o.EmailAddress == entity.EmailAddress)
- {
- conflict = true;
- break;
- }
- }
- if (conflict) { break; }
- }
- } while (conflict);
- context.Add(entity);
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {i} took {watch.ElapsedTicks} ticks");
- }
- Console.WriteLine($"Changing {numUsers} users email addresses, twice each");
- var ids = context.BucketExponentStoringBucketedEntities.Take(numUsers).Select(_ => _.Id).ToArray();
- for (int j = 0; j < 2; j++)
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- var u = context.BucketExponentStoringBucketedEntities.Find(ids[i]);
- BucketExponentStoringBucketedEntity entity;
- bool conflict = false;
- var counts = context.BucketExponentStoringBucketedEntities.Select(_ => _.BucketExponent).Distinct().ToList();
- var currentCount = context.BucketExponentStoringBucketedEntities.Count();
- do
- {
- entity = new BucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", currentCount);
- var buckets = counts.Select(_ => new BucketExponentStoringBucketedEntity(entity.EmailAddress, _)).ToList();
- foreach (var b in buckets)
- {
- var others = context.BucketExponentStoringBucketedEntities.Where(_ => _.BucketNo == b.BucketNo && _.BucketExponent == b.BucketExponent).ToList();
- foreach (var o in others)
- {
- if (o.EmailAddress == entity.EmailAddress)
- {
- conflict = true;
- break;
- }
- }
- if (conflict) { break; }
- }
- } while (conflict);
- u.BucketExponent = entity.BucketExponent;
- u.BucketNo = entity.BucketNo;
- u.EmailAddress = entity.EmailAddress;
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {j} on user {i} took {watch.ElapsedTicks} ticks");
- }
- }
- Console.WriteLine("Using a summary table for updates to BucketCount, storing BucketExponent in the entity");
- using (var context = new KeyValuedBucketExponentStoringDbContext())
- {
- context.Database.EnsureDeleted();
- context.Database.EnsureCreated();
- Console.WriteLine($"Seeding DB with {numberOfUsers} users ");
- for (int i = 0; i < numberOfUsers; i++)
- {
- context.Add(new BucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", GetBucketExponent(i)));
- }
- context.KeyValues.Single().value = numberOfUsers;
- Console.WriteLine("Saving changes");
- context.SaveChanges();
- Console.WriteLine($"Adding {numUsers} users individually");
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- BucketExponentStoringBucketedEntity entity;
- bool conflict = false;
- var counts = context.BucketExponentStoringBucketedEntities.Select(_ => _.BucketExponent).Distinct().ToList();
- var currentCount = context.KeyValues.Single().value;
- do
- {
- entity = new BucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", currentCount);
- var buckets = counts.Select(_ => new BucketExponentStoringBucketedEntity(entity.EmailAddress, _)).ToList();
- foreach (var b in buckets)
- {
- var others = context.BucketExponentStoringBucketedEntities.Where(_ => _.BucketNo == b.BucketNo && _.BucketExponent == b.BucketExponent).ToList();
- foreach (var o in others)
- {
- if (o.EmailAddress == entity.EmailAddress)
- {
- conflict = true;
- break;
- }
- }
- if (conflict) { break; }
- }
- } while (conflict);
- context.Add(entity);
- context.KeyValues.Single().value++;
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {i} took {watch.ElapsedTicks} ticks");
- }
- Console.WriteLine($"Changing {numUsers} users email addresses, twice each");
- var ids = context.BucketExponentStoringBucketedEntities.Take(numUsers).Select(_ => _.Id).ToArray();
- for (int j = 0; j < 2; j++)
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- var u = context.BucketExponentStoringBucketedEntities.Find(ids[i]);
- BucketExponentStoringBucketedEntity entity;
- bool conflict = false;
- var counts = context.BucketExponentStoringBucketedEntities.Select(_ => _.BucketExponent).Distinct().ToList();
- var currentCount = context.KeyValues.Single().value;
- do
- {
- entity = new BucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", currentCount);
- var buckets = counts.Select(_ => new BucketExponentStoringBucketedEntity(entity.EmailAddress, _)).ToList();
- foreach (var b in buckets)
- {
- var others = context.BucketExponentStoringBucketedEntities.Where(_ => _.BucketNo == b.BucketNo && _.BucketExponent == b.BucketExponent).ToList();
- foreach (var o in others)
- {
- if (o.EmailAddress == entity.EmailAddress)
- {
- conflict = true;
- break;
- }
- }
- if (conflict) { break; }
- }
- } while (conflict);
- u.BucketExponent = entity.BucketExponent;
- u.BucketNo = entity.BucketNo;
- u.EmailAddress = entity.EmailAddress;
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {j} on user {i} took {watch.ElapsedTicks} ticks");
- }
- }
- Console.WriteLine("Using autoincremented row numbers");
- using (var context = new RowCountedBucketExponentStoringDbContext())
- {
- context.Database.EnsureDeleted();
- context.Database.EnsureCreated();
- Console.WriteLine($"Seeding DB with {numberOfUsers} users ");
- for (int i = 0; i < numberOfUsers; i++)
- {
- context.Add(new RowCountedBucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", GetBucketExponent(i)));
- }
- Console.WriteLine("Saving changes");
- context.SaveChanges();
- Console.WriteLine($"Adding {numUsers} users individually");
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- RowCountedBucketExponentStoringBucketedEntity entity;
- bool conflict = false;
- var counts = context.RowCountedBucketExponentStoringBucketedEntities.Select(_ => _.BucketExponent).Distinct().ToList();
- var currentCount = context.RowCountedBucketExponentStoringBucketedEntities.Max(_ => _.EntryNo);
- do
- {
- entity = new RowCountedBucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", currentCount);
- var buckets = counts.Select(_ => new RowCountedBucketExponentStoringBucketedEntity(entity.EmailAddress, _)).ToList();
- foreach (var b in buckets)
- {
- var others = context.RowCountedBucketExponentStoringBucketedEntities.Where(_ => _.BucketNo == b.BucketNo && _.BucketExponent == b.BucketExponent).ToList();
- foreach (var o in others)
- {
- if (o.EmailAddress == entity.EmailAddress)
- {
- conflict = true;
- break;
- }
- }
- if (conflict) { break; }
- }
- } while (conflict);
- context.Add(entity);
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {i} took {watch.ElapsedTicks} ticks");
- }
- Console.WriteLine($"Changing {numUsers} users email addresses, twice each");
- var ids = context.RowCountedBucketExponentStoringBucketedEntities.Take(numUsers).Select(_ => _.Id).ToArray();
- for (int j = 0; j < 2; j++)
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- var u = context.RowCountedBucketExponentStoringBucketedEntities.Find(ids[i]);
- RowCountedBucketExponentStoringBucketedEntity entity;
- bool conflict = false;
- var currentCount = context.RowCountedBucketExponentStoringBucketedEntities.Max(_ => _.EntryNo);
- var counts = context.RowCountedBucketExponentStoringBucketedEntities.Select(_ => _.BucketExponent).Distinct().ToList();
- do
- {
- entity = new RowCountedBucketExponentStoringBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", currentCount);
- var buckets = counts.Select(_ => new RowCountedBucketExponentStoringBucketedEntity(entity.EmailAddress, _)).ToList();
- foreach (var b in buckets)
- {
- var others = context.RowCountedBucketExponentStoringBucketedEntities.Where(_ => _.BucketNo == b.BucketNo && _.BucketExponent == b.BucketExponent).ToList();
- foreach (var o in others)
- {
- if (o.EmailAddress == entity.EmailAddress)
- {
- conflict = true;
- break;
- }
- }
- if (conflict) { break; }
- }
- } while (conflict);
- u.BucketExponent = entity.BucketExponent;
- u.BucketNo = entity.BucketNo;
- u.EmailAddress = entity.EmailAddress;
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {j} on user {i} took {watch.ElapsedTicks} ticks");
- }
- }
- Console.WriteLine("Using `SELECT COUNT(*)` for updates to BucketCount, updating all bucket numbers after threshold is passed");
- using (var context = new TimestampedDbContext())
- {
- Console.WriteLine($"Seeding DB with {numberOfUsers} users ");
- context.Database.EnsureDeleted();
- context.Database.EnsureCreated();
- for (int i = 0; i < numberOfUsers; i++)
- {
- int bucketExponent = GetBucketExponent(numberOfUsers);
- context.Add(new TimestampedBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", bucketExponent));
- context.SaveChanges();
- }
- Console.WriteLine("Saving changes");
- context.SaveChanges();
- Console.WriteLine($"Adding {numUsers} users individually");
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- TimestampedBucketedEntity entity;
- bool conflict = false;
- var currentCount = context.TimestampedBucketedEntity.Count();
- int bucketExponent = GetBucketExponent(currentCount + 1);
- if (GetBucketExponent(currentCount) != GetBucketExponent(currentCount - 1))
- {
- foreach (var v in context.TimestampedBucketedEntity)
- {
- v.EmailAddress = v.EmailAddress;
- v.BucketNo = new BucketedEntity(v.EmailAddress, bucketExponent).BucketNo;
- v.EmailUpdated = DateTime.UtcNow;
- }
- }
- do
- {
- entity = new TimestampedBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", bucketExponent);
- foreach (var other in context.TimestampedBucketedEntity.Where(_ => _.BucketNo == entity.BucketNo))
- {
- if (other.EmailAddress == entity.EmailAddress)
- {
- Console.WriteLine("ERROR: CONFLICT. RESTARTING ITERATION.");
- conflict = true;
- }
- }
- } while (conflict);
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {i} took {watch.ElapsedTicks} ticks");
- }
- Console.WriteLine($"Changing {numUsers} users email addresses, twice each");
- var ids = context.TimestampedBucketedEntity.Take(numUsers).Select(_ => _.Id).ToArray();
- for (int j = 0; j < 2; j++)
- for (int i = 0; i < numUsers; i++)
- {
- watch.Restart();
- watch.Start();
- var currentCount = context.TimestampedBucketedEntity.Count();
- var bucketExponent = GetBucketExponent(currentCount);
- var u = context.TimestampedBucketedEntity.Find(ids[i]);
- TimestampedBucketedEntity entity;
- bool conflict = false;
- do
- {
- entity = new TimestampedBucketedEntity($"{rand.Next()}-{rand.Next()}@example.com", bucketExponent);
- foreach (var other in context.TimestampedBucketedEntity.Where(_ => _.BucketNo == entity.BucketNo))
- {
- if (other.EmailAddress == entity.EmailAddress)
- {
- Console.WriteLine("ERROR: CONFLICT. RESTARTING ITERATION.");
- conflict = true;
- }
- }
- } while (conflict);
- u.EmailAddress = entity.EmailAddress;
- u.BucketNo = entity.BucketNo;
- context.SaveChanges();
- context.SaveChanges();
- watch.Stop();
- Console.WriteLine($"Iteration {j} on user {i} took {watch.ElapsedTicks} ticks");
- }
- }
- }
- }
- sw.Close();
- /* RowCountedTimestampedDbContext
- using (var context = new RowCountedTimestampedDbContext())
- {
- context.Database.EnsureDeleted();
- context.Database.EnsureCreated();
- for (int i = 0; i < 333; i++)
- {
- int count = 0;
- try{
- count = context.RowCountedTimestampedBucketedEntity.Select(_ => _.EntryNo).Max();
- }catch{}
- int bucketExponent = GetBucketExponent(count);
- if(GetBucketExponent(count) != GetBucketExponent(count - 1)){
- foreach(var v in context.RowCountedTimestampedBucketedEntity){
- v.EmailAddress = v.EmailAddress;
- v.BucketNo = new BucketedEntity(v.EmailAddress, bucketExponent).BucketNo;
- v.EmailUpdated = DateTime.UtcNow;
- }
- }
- context.Add(new RowCountedTimestampedBucketedEntity($"{i}_{rand.Next()}@example.com", bucketExponent));
- context.SaveChanges();
- }
- }*/
- /* save to TimestampedDbContext
- using (var context = new TimestampedDbContext())
- {
- context.Database.EnsureDeleted();
- context.Database.EnsureCreated();
- for (int i = 0; i < 333; i++)
- {
- int bucketExponent = GetBucketExponent(context.TimestampedBucketedEntity.Count());
- var count = context.TimestampedBucketedEntity.Count();
- if(GetBucketExponent(count) != GetBucketExponent(count - 1)){
- foreach(var v in context.TimestampedBucketedEntity){
- v.EmailAddress = v.EmailAddress;
- v.BucketNo = new BucketedEntity(v.EmailAddress, bucketExponent).BucketNo;
- v.EmailUpdated = DateTime.UtcNow;
- }
- }
- context.Add(new TimestampedBucketedEntity($"{i}_{rand.Next()}@example.com", bucketExponent));
- context.SaveChanges();
- }
- }
- */
- /* Fetch from bucketexponentstoringdbcontext
- using (var context = new BucketExponentStoringDbContext())
- using (var context2 = new BucketExponentStoringDbContext())
- using (var context3 = new BucketExponentStoringDbContext())
- {
- var exponents = context3.BucketExponentStoringBucketedEntities.Select(_ => _.BucketExponent).Distinct().ToList();
- foreach (var v in context.BucketExponentStoringBucketedEntities)
- {
- var bucketNumbers = exponents.Select(_ => new BucketedEntity(v.EmailAddress, _).BucketNo);
- Console.WriteLine($"EmailAddress: {v.EmailAddress}");
- Console.WriteLine($"BucketNo: {v.BucketNo}");
- Console.WriteLine($"Others: {context2.BucketExponentStoringBucketedEntities.Where(_ => bucketNumbers.Contains(_.BucketNo)).Count()}");
- }
- }*/
- // DbContexts
- public static class options
- {
- public static string conn = "server=localhost;port=3306;database=tmp;uid=devuser;pwd=Pa55w0rd!";
- public static ServerVersion srvvrs = ServerVersion.Parse("8.0.27-mysql");
- }
- public class UnencryptedDbContext : DbContext
- {
- public DbSet<BasicEntity> BasicEntities { get; set; }
- public UnencryptedDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<BasicEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.Property(e => e.EmailAddress)
- .IsRequired();
- }
- );
- }
- }
- public class BasicEncryptedDbContext : DbContext
- {
- public DbSet<BasicEntity> BasicEntities { get; set; }
- public BasicEncryptedDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<BasicEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- });
- }
- }
- public class BucketedEncryptedDbContext : DbContext
- {
- public DbSet<BucketedEntity> BucketedEntities { get; set; }
- public BucketedEncryptedDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<BucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasIndex(e => e.BucketNo);
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- public class RowCountedBucketExponentStoringDbContext : DbContext
- {
- public DbSet<RowCountedBucketExponentStoringBucketedEntity> RowCountedBucketExponentStoringBucketedEntities { get; set; }
- public RowCountedBucketExponentStoringDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<RowCountedBucketExponentStoringBucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasIndex(e => e.BucketNo);
- e.HasIndex(e => e.BucketExponent);
- e.HasAlternateKey(e => e.EntryNo);
- e.Property(e => e.EntryNo).ValueGeneratedOnAdd();
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- public class RowCountedTimestampedDbContext : DbContext
- {
- public DbSet<RowCountedTimestampedBucketedEntity> RowCountedTimestampedBucketedEntity { get; set; }
- public RowCountedTimestampedDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<RowCountedTimestampedBucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasAlternateKey(e => e.EntryNo);
- e.Property(e => e.EntryNo).ValueGeneratedOnAdd(); e.HasIndex(e => e.BucketNo);
- e.Property(e => e.EmailUpdated).ValueGeneratedOnAddOrUpdate();
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- public class RowCountedBucketedDbContext : DbContext
- {
- public DbSet<RowCountedBucketedEntity> RowCountedBucketedEntities { get; set; }
- public RowCountedBucketedDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<RowCountedBucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasIndex(e => e.BucketNo);
- e.HasAlternateKey(e => e.EntryNo);
- e.Property(e => e.EntryNo).ValueGeneratedOnAdd();
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- public class BucketExponentStoringDbContext : DbContext
- {
- public DbSet<BucketExponentStoringBucketedEntity> BucketExponentStoringBucketedEntities { get; set; }
- public BucketExponentStoringDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<BucketExponentStoringBucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasIndex(e => e.BucketNo);
- e.HasIndex(e => e.BucketExponent);
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- public class TimestampedDbContext : DbContext
- {
- public DbSet<TimestampedBucketedEntity> TimestampedBucketedEntity { get; set; }
- public TimestampedDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<TimestampedBucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasIndex(e => e.BucketNo);
- e.Property(e => e.EmailUpdated).ValueGeneratedOnAddOrUpdate();
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- public class KeyValuedBucketExponentStoringDbContext : DbContext
- {
- public DbSet<BucketExponentStoringBucketedEntity> BucketExponentStoringBucketedEntities { get; set; }
- public DbSet<KeyValues> KeyValues { get; set; }
- public KeyValuedBucketExponentStoringDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<KeyValues>(e =>
- {
- e.HasKey(k => k.Key);
- e.HasData(new KeyValues
- {
- Key = "UserCount",
- value = 0
- });
- });
- modelBuilder.Entity<BucketExponentStoringBucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasIndex(e => e.BucketNo);
- e.HasIndex(e => e.BucketExponent);
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- public class KeyValuedTimestampedDbContext : DbContext
- {
- public DbSet<TimestampedBucketedEntity> TimestampedBucketedEntity { get; set; }
- public DbSet<KeyValues> KeyValues { get; set; }
- public KeyValuedTimestampedDbContext() : base() { }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<KeyValues>(e =>
- {
- e.HasKey(k => k.Key);
- e.HasData(new KeyValues
- {
- Key = "UserCount",
- value = 0
- });
- });
- modelBuilder.Entity<TimestampedBucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasIndex(e => e.BucketNo);
- e.Property(e => e.EmailUpdated).ValueGeneratedOnAddOrUpdate();
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- public class KeyValuedBucketedDbContext : DbContext
- {
- public DbSet<BucketedEntity> BucketedEntities { get; set; }
- public KeyValuedBucketedDbContext() : base() { }
- public DbSet<KeyValues> KeyValues { get; set; }
- protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(conn, srvvrs);
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<KeyValues>(e =>
- {
- e.HasKey(k => k.Key);
- e.HasData(new KeyValues
- {
- Key = "UserCount",
- value = 0
- });
- });
- modelBuilder.Entity<BucketedEntity>(e =>
- {
- e.HasIndex(e => e.EmailAddress)
- .IsUnique();
- e.HasIndex(e => e.BucketNo);
- e.Property(e => e.EmailAddress)
- .IsRequired().HasConversion<PersonalDataConverter>();
- }
- );
- }
- }
- // Entities
- public class BasicEntity
- {
- public Guid Id { get; set; }
- }
- public class TimestampedBucketedEntity : BucketedEntity
- {
- public TimestampedBucketedEntity() { }
- public TimestampedBucketedEntity(string emailAddress, int bucketExponent) : base(emailAddress, bucketExponent) { }
- public DateTime EmailUpdated { get; set; } = DateTime.UtcNow;
- }
- public class BucketExponentStoringBucketedEntity : BucketedEntity
- {
- public BucketExponentStoringBucketedEntity() { }
- public BucketExponentStoringBucketedEntity(string emailAddress, int bucketExponent) : base(emailAddress, bucketExponent) { BucketExponent = bucketExponent; }
- public int BucketExponent { get; set; }
- }
- public class BucketedEntity
- {
- public BucketedEntity() { }
- public BucketedEntity(string emailAddress, int bucketExponent)
- {
- BucketNo = 0;
- foreach (char c in emailAddress.ToLowerInvariant())
- {
- BucketNo += (int)c;
- }
- BucketNo %= (int)Math.Pow(2, bucketExponent);
- EmailAddress = emailAddress;
- }
- public Guid Id { get; set; }
- public int BucketNo { get; set; } = 0;
- }
- public class RowCountedBasicEntity
- {
- public int EntryNo { get; set; } = 0;
- public Guid Id { get; set; }
- }
- public class RowCountedTimestampedBucketedEntity : RowCountedBucketedEntity
- {
- public RowCountedTimestampedBucketedEntity() { }
- public RowCountedTimestampedBucketedEntity(string emailAddress, int bucketExponent) : base(emailAddress, bucketExponent) { }
- public DateTime EmailUpdated { get; set; } = DateTime.UtcNow;
- }
- public class RowCountedBucketExponentStoringBucketedEntity : RowCountedBucketedEntity
- {
- public RowCountedBucketExponentStoringBucketedEntity() { }
- public RowCountedBucketExponentStoringBucketedEntity(string emailAddress, int bucketExponent) : base(emailAddress, bucketExponent) { BucketExponent = bucketExponent; }
- public int BucketExponent { get; set; }
- }
- public class RowCountedBucketedEntity
- {
- public RowCountedBucketedEntity() { }
- public RowCountedBucketedEntity(string emailAddress, int bucketExponent)
- {
- BucketNo = 0;
- foreach (char c in emailAddress.ToLowerInvariant())
- {
- BucketNo += (int)c;
- }
- BucketNo %= (int)Math.Pow(2, bucketExponent);
- EmailAddress = emailAddress;
- }
- public Guid Id { get; set; }
- public int BucketNo { get; set; } = 0;
- public int EntryNo { get; set; } = 0;
- }
- public class KeyValues
- {
- public string Key { get; set; }
- public int value { get; set; }
- }
- // Conversions
- internal static class TupleExtensions
- {
- public static string ToBase64String(this (string s, byte[] b) input)
- {
- return Convert.ToBase64String(input.b) + " " + input.s;
- }
- }
- internal static class ArrayExtensions
- {
- public static string AesDecrypt(this string[] arr)
- {
- return AesEncryptionHelper.AesDecrypt(arr[1], Key.key, Convert
- .FromBase64String(arr[0]));
- }
- }
- public class PersonalDataConverter : ValueConverter<string, string>
- {
- private const StringSplitOptions Sso =
- StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries;
- public PersonalDataConverter() : base(
- cleartext => (AesEncryptionHelper.AesEncrypt(cleartext, Key.key, null))
- .ToBase64String(),
- ciphertext => ciphertext
- .Split(" ", Sso)
- .AesDecrypt()
- , default
- )
- { }
- }
- // non cryptographic hash functions
- public static class NonCryptographicHelpers
- {
- public static int GetBucketExponent(int userCount)
- {
- if (userCount < 1) { return 1; }
- return Math.Max((int)Math.Floor(Math.Log2(userCount)) - 3, 1);
- }
- }
- // Encryption
- public static class Key
- {
- public static byte[] key = {
- (byte) 33,
- (byte) 40,
- (byte) 212,
- (byte) 209,
- (byte) 219,
- (byte) 205,
- (byte) 88,
- (byte) 100,
- (byte) 20,
- (byte) 23,
- (byte) 131,
- (byte) 149,
- (byte) 104,
- (byte) 200,
- (byte) 215,
- (byte) 17,
- (byte) 36,
- (byte) 102,
- (byte) 106,
- (byte) 19,
- (byte) 165,
- (byte) 234,
- (byte) 163,
- (byte) 139,
- (byte) 133,
- (byte) 63,
- (byte) 139,
- (byte) 249,
- (byte) 224,
- (byte) 41,
- (byte) 186,
- (byte) 209,
- };
- }
- public static class AesEncryptionHelper
- {
- /// <summary>
- /// Encrypt the given secret using AES
- /// </summary>
- /// <param name="secret">plaintext to encrypt</param>
- /// <param name="key">The secret key to use to encrypt</param>
- /// <param name="IV">Optional initialization vector to use</param>
- /// <returns>A tuple containing the base64 encoded, encrypted ciphertext, and the initialization vector used.</returns>
- /// <exception cref="ArgumentException">Key or IV is incorrect length</exception>
- public static (string ciphertext, byte[] IV) AesEncrypt(string secret, in byte[] key, in byte[]? IV = null)
- {
- using (var aes = Aes.Create())
- {
- if (key.Length != aes.Key.Length)
- {
- throw new ArgumentException("key length incorrect");
- }
- if (IV != null && IV.Length != aes.IV.Length)
- {
- throw new ArgumentException("IV length incorrect");
- }
- aes.Key = key;
- if (IV != null)
- {
- aes.IV = IV;
- }
- var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
- using (MemoryStream msEncrypt = new MemoryStream())
- {
- using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
- {
- using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
- {
- swEncrypt.Write(secret);
- }
- return (Convert.ToBase64String(msEncrypt.ToArray()), aes.IV);
- }
- }
- }
- }
- /// <summary>
- /// Decrypt the result of <see cref="AesEncrypt"/>
- /// </summary>
- /// <param name="secret">The base64 encoded, aes encrypted ciphertext</param>
- /// <param name="key">The secret key used to encrypt the secret</param>
- /// <param name="IV">The initialization vector used to encrypt the secret</param>
- /// <returns>The decrypted plaintext</returns>
- /// <exception cref="CryptographicException">Key or IV is incorrect length</exception>
- /// <exception cref="ArgumentNullException"/>
- /// <exception cref="FormatException">Secret is not a valid base 64 string </exception>
- public static string AesDecrypt(string secret, in byte[] key, in byte[] IV)
- {
- using (Aes aesAlg = Aes.Create())
- {
- aesAlg.Key = key;
- aesAlg.IV = IV;
- // Create a decryptor to perform the stream transform.
- ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
- // Create the streams used for decryption.
- using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(secret)))
- {
- using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
- {
- using (StreamReader srDecrypt = new StreamReader(csDecrypt))
- {
- // Read the decrypted bytes from the decrypting stream
- // and place them in a string.
- return srDecrypt.ReadToEnd();
- }
- }
- }
- }
- }
- }
Add Comment
Please, Sign In to add comment