File: SharedSecretProviderTests.cs
Web Access
Project: ..\..\..\test\Microsoft.DotNet.HotReload.Client.Tests\Microsoft.DotNet.HotReload.Client.Tests.csproj (Microsoft.DotNet.HotReload.Client.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Security.Cryptography;
 
namespace Microsoft.DotNet.HotReload.UnitTests;
 
public class SharedSecretProviderTests
{
    private static byte[] GetRandomBytes(int length)
    {
        var result = new byte[length];
        var random = new Random();
        random.NextBytes(result);
        return result;
    }
 
    [Fact]
    public void EncryptDecrypt()
    {
        using var provider = new SharedSecretProvider();
 
        // Server generates public key and sends it over to the middleware:
        var publicKeyNetfx = provider.ExportPublicKeyNetFramework();
        var publicKeyParameters = provider.ExportPublicKeyParameters();
        var publicKey = provider.GetPublicKey();
 
        // Middleware embeds key by in the .js file loaded to the browser:
        Assert.Equal(publicKey, publicKeyNetfx);
 
        // The browser generates 32-byte random secret:
        var secret = GetRandomBytes(32);
        var secretBase64 = Convert.ToBase64String(secret);
 
        // The secret is encrypted using public key and sent
        // as subprotocol when client connects to the server over WebSocket:
        var encrypted = GetEncryptedSecret(publicKey, publicKeyParameters, secret);
 
        // The server decrypts the secret using private key.
        // The secret is sent over to the client with every request over WebSocket.
        // The client validates that the secrete matches the one it generated.
        var decrypted = provider.DecryptSecret(encrypted);
        Assert.Equal(secretBase64, decrypted);
    }
 
    // Equivalent to getSecret function in WebSocketScriptInjection.js:
    public static string GetEncryptedSecret(string key, RSAParameters publicKeyParameters, byte[] secret)
    {
        // Import server key for RSA-OAEP
        using var rsa = RSA.Create();
#if NET
        rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(key), out _);
#else
        rsa.ImportParameters(publicKeyParameters);
#endif
        // Encrypt using RSA-OAEP
        return Convert.ToBase64String(rsa.Encrypt(secret, RSAEncryptionPadding.OaepSHA256));
    }
}