diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj
index 6505fdab5b..96b248f90b 100644
--- a/src/Api/Api.csproj
+++ b/src/Api/Api.csproj
@@ -39,4 +39,8 @@
+
+
+
+
diff --git a/src/Api/Auth/Controllers/OpaqueKeyExchangeController.cs b/src/Api/Auth/Controllers/OpaqueKeyExchangeController.cs
new file mode 100644
index 0000000000..8c9697f04b
--- /dev/null
+++ b/src/Api/Auth/Controllers/OpaqueKeyExchangeController.cs
@@ -0,0 +1,63 @@
+using Bit.Api.Auth.Models.Request.Opaque;
+using Bit.Api.Auth.Models.Response.Opaque;
+using Bit.Core.Services;
+using Bitwarden.OPAQUE;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Bit.Api.Auth.Controllers;
+
+[Route("opaque")]
+public class OpaqueKeyExchangeController : Controller
+{
+ private readonly IUserService _userService;
+ private readonly BitwardenOpaque _bitwardenOpaque;
+ private CipherConfiguration _cipherConfiguration = new CipherConfiguration();
+
+ public OpaqueKeyExchangeController(
+ IUserService userService
+ )
+ {
+ _userService = userService;
+ _bitwardenOpaque = new BitwardenOpaque();
+ _cipherConfiguration.KeGroup = KeGroup.Ristretto255;
+ _cipherConfiguration.OprfCS = OprfCS.Ristretto255;
+ _cipherConfiguration.KeyExchange = KeyExchange.TripleDH;
+ _cipherConfiguration.KSF = new Argon2id(3, 256 * 1024, 4);
+ }
+
+ [HttpGet("~/opaque/start-registration")]
+ public async Task StartRegistration(RegisterStartRequest request)
+ {
+ var user = await _userService.GetUserByPrincipalAsync(User);
+ var registrationRequest = _bitwardenOpaque.StartServerRegistration(_cipherConfiguration, System.Convert.FromBase64String(request.ClientRegistrationStartResult), user.Id.ToString());
+ var message = registrationRequest.Item1;
+ var serverSetup = registrationRequest.Item2;
+ // persist server setup
+ var sessionId = Guid.NewGuid();
+ SessionStore.RegisterSessions.Add(sessionId, new RegisterSession() { SessionId = sessionId, ServerSetup = serverSetup, cipherConfiguration = _cipherConfiguration });
+ return new RegisterStartResponse(sessionId, System.Convert.ToBase64String(message));
+ }
+
+
+ [HttpGet("~/opaque/finish-registration")]
+ public async Task FinishRegistration(RegisterFinishRequest request)
+ {
+ var registrationFinish = _bitwardenOpaque.FinishServerRegistration(_cipherConfiguration, System.Convert.FromBase64String(request.ClientRegisterFinishResult));
+ Console.WriteLine("Registration Finish: " + registrationFinish);
+ return "Registration Finish";
+ }
+
+}
+
+public class RegisterSession
+{
+ public Guid SessionId { get; set; }
+ public byte[] ServerSetup { get; set; }
+ public CipherConfiguration cipherConfiguration { get; set; }
+}
+
+public class SessionStore()
+{
+ public static Dictionary RegisterSessions = new Dictionary();
+ public static Dictionary LoginSessions = new Dictionary();
+}
diff --git a/src/Api/Auth/Models/Request/Opaque/RegisterFinishRequest.cs b/src/Api/Auth/Models/Request/Opaque/RegisterFinishRequest.cs
new file mode 100644
index 0000000000..b0933f5f20
--- /dev/null
+++ b/src/Api/Auth/Models/Request/Opaque/RegisterFinishRequest.cs
@@ -0,0 +1,14 @@
+namespace Bit.Api.Auth.Models.Request.Opaque;
+
+public class RegisterFinishRequest
+{
+ public String ClientRegisterFinishResult { get; set; }
+ public Guid SessionId { get; set; }
+}
+
+public class RotateableKeyset
+{
+ public String EncryptedUserKey { get; set; }
+ public String EncryptedPublicKey { get; set; }
+ public String EncryptedPrivateKey { get; set; }
+}
diff --git a/src/Api/Auth/Models/Request/Opaque/RegisterStartRequest.cs b/src/Api/Auth/Models/Request/Opaque/RegisterStartRequest.cs
new file mode 100644
index 0000000000..8115ee7eef
--- /dev/null
+++ b/src/Api/Auth/Models/Request/Opaque/RegisterStartRequest.cs
@@ -0,0 +1,9 @@
+using Bitwarden.OPAQUE;
+
+namespace Bit.Api.Auth.Models.Request.Opaque;
+
+public class RegisterStartRequest
+{
+ public String ClientRegistrationStartResult { get; set; }
+ public CipherConfiguration CipherConfiguration { get; set; }
+}
diff --git a/src/Api/Auth/Models/Response/Opaque/RegisterStartResponse.cs b/src/Api/Auth/Models/Response/Opaque/RegisterStartResponse.cs
new file mode 100644
index 0000000000..11f05b8965
--- /dev/null
+++ b/src/Api/Auth/Models/Response/Opaque/RegisterStartResponse.cs
@@ -0,0 +1,17 @@
+using Bit.Core.Models.Api;
+
+namespace Bit.Api.Auth.Models.Response.Opaque;
+
+public class RegisterStartResponse : ResponseModel
+{
+ public RegisterStartResponse(Guid sessionId, string serverRegistrationStartResult, string obj = "register-start-response")
+ : base(obj)
+ {
+ ServerRegistrationStartResult = serverRegistrationStartResult;
+ SessionId = sessionId;
+ }
+
+ public String ServerRegistrationStartResult { get; set; }
+ public Guid SessionId { get; set; }
+}
+