public void UniqueOutput() { // Verify that we generate and use a unique IV for // every encryption run such that encrypting the same // data will return different results. This is an // important security best practice. const int iterations = 1000; var decrypted = "We hold these truths to be self-evident, that all men are created equal."; var encryptions = new HashSet <string>(); using (var cipher = new AesCipher()) { for (int i = 0; i < iterations; i++) { var encrypted = cipher.EncryptToBase64(decrypted); Assert.DoesNotContain(encrypted, encryptions); Assert.Equal(decrypted, cipher.DecryptStringFrom(encrypted)); encryptions.Add(encrypted); } } }
public async Task BlazorAsync() { await SyncContext.Clear; var cookie = HttpContext.Request.Cookies.Where(c => c.Key == Service.SessionCookieName).First(); var sessionId = cipher.DecryptStringFrom(cookie.Value); var session = NeonHelper.JsonDeserialize <Session>(await cache.GetAsync(sessionId)); session.ConnectionId = HttpContext.Connection.Id; await cache.SetAsync(session.Id, NeonHelper.JsonSerializeToBytes(session)); WebsocketMetrics.CurrentConnections.Inc(); WebsocketMetrics.ConnectionsEstablished.Inc(); blazorProxyService.CurrentConnections.Add(session.ConnectionId); LogDebug($"Fwd [{session.Id}] to [{session.UpstreamHost}]."); var error = await forwarder.SendAsync(HttpContext, $"{config.Backend.Scheme}://{session.UpstreamHost}", httpClient, forwarderRequestConfig, transformer); LogDebug($"Session [{session.Id}] closed."); if (error != ForwarderError.None) { var errorFeature = HttpContext.GetForwarderErrorFeature(); var exception = errorFeature.Exception; if (exception.GetType() != typeof(TaskCanceledException) && exception.GetType() != typeof(OperationCanceledException)) { LogError("_blazor", exception); } } }
/// <summary> /// <para> /// Upserts the cache entry with an expiration time defined by <see cref="Cache.DurationSeconds"/>. /// After this period, it's no longer possible to reconnect a Blazor session back to the server, /// so we remove the entry from the cache. /// </para> /// </summary> /// <param name="context">The <see cref="HttpContext"/>.</param> /// <param name="cache">The Cache.</param> /// <param name="cipher">The AES Cipher used to encrypt/decrypt cookies.</param> /// <param name="cacheOptions">The Cache options.</param> /// <param name="logger">The <see cref="INeonLogger"/></param> /// <returns></returns> public async Task InvokeAsync( HttpContext context, Service service, IDistributedCache cache, AesCipher cipher, DistributedCacheEntryOptions cacheOptions, INeonLogger logger) { await SyncContext.Clear; await _next(context); if (service.CurrentConnections.Contains(context.Connection.Id)) { var cookie = context.Request.Cookies.Where(c => c.Key == Service.SessionCookieName).First(); var sessionId = cipher.DecryptStringFrom(cookie.Value); var session = NeonHelper.JsonDeserialize <Session>(await cache.GetAsync(sessionId)); if (session.ConnectionId == context.Connection.Id) { await cache.SetAsync(session.Id, NeonHelper.JsonSerializeToBytes(session), cacheOptions); WebsocketMetrics.CurrentConnections.Dec(); service.CurrentConnections.Remove(context.Connection.Id); } } }
public void Encrypt_ToBase64() { // Encrypt a byte array: using (var cipher = new AesCipher()) { var decrypted = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var encrypted = cipher.EncryptToBase64(decrypted); Assert.Equal(decrypted, cipher.DecryptBytesFrom(encrypted)); } // Encrypt a string: using (var cipher = new AesCipher()) { var decrypted = "1234567890"; var encrypted = cipher.EncryptToBase64(decrypted); Assert.Equal(decrypted, cipher.DecryptStringFrom(encrypted)); } }