Vaultic.OPAQUE.Net
1.1.6
Prefix Reserved
See the version list below for details.
dotnet add package Vaultic.OPAQUE.Net --version 1.1.6
NuGet\Install-Package Vaultic.OPAQUE.Net -Version 1.1.6
<PackageReference Include="Vaultic.OPAQUE.Net" Version="1.1.6" />
<PackageVersion Include="Vaultic.OPAQUE.Net" Version="1.1.6" />
<PackageReference Include="Vaultic.OPAQUE.Net" />
paket add Vaultic.OPAQUE.Net --version 1.1.6
#r "nuget: Vaultic.OPAQUE.Net, 1.1.6"
#addin nuget:?package=Vaultic.OPAQUE.Net&version=1.1.6
#tool nuget:?package=Vaultic.OPAQUE.Net&version=1.1.6
Opaque
Secure password based client-server authentication without the server ever obtaining knowledge of the password.
A C# implementation of the OPAQUE protocol forked from serenity-key/opaque.
Benefits
- Never accidentally log passwords
- Security against pre-computation attacks upon server compromise
- Foundation for encrypted backups and end-to-end encryption apps
- Original repo had a penetration test and whitebox security review done through OTF’s Red Team Lab, via 7ASecurity
Documentation
In depth documentation can be found at https://opaque-auth.com/ (written for the original repo)
Requirements
This package will only work when running on the x64 platform. This is due to the rust dll. See Configuring build platforms for assistance.
Install
The package is available via nuget as Vaultic.OPAQUE.Net. You can use the GUI within Visual Studio or run the command from the nuget package manager console to install it
Install-Package Vaultic.OPAQUE.Net
Usage
The API is exposed through the OpaqueServer
and OpaqueClient
objects.
OpaqueServer server = OpaqueFactory.CreateServer();
OpaqueClient client = OpaqueFactory.CreateClient();
Server Setup
The server setup is a one-time operation. It is used to generate the server's long-term private key. The result is a 171 long string. Only store it in a secure location and make sure you have it available in your application e.g. via an environment variable.
You can generate a new server setup on the fly:
server.CreateSetup(out string? serverSetup);
Keep in mind that changing the serverSetup will invalidate all existing password files.
Registration Flow
// client
string password = "sup-krah.42-UOI"; // user password
if (!client.StartRegistration(
password,
out StartClientRegistrationResult? startClientRegistrationResult))
{
// handle failed
}
// server
string userIdentifier = "20e14cd8-ab09-4f4b-87a8-06d2e2e9ff68"; // userId/email/username
if (!server.CreateRegistrationResponse(
serverSetup,
userIdentifier,
startClientRegistrationResult.RegistrationRequest,
out string? registrationResponse))
{
// handle failed
}
// client
if (!client.FinishRegistration(
password,
registrationResponse,
startClientRegistrationResult.ClientRegistrationState,
out FinishClientRegistrationResult? finishClientRegistrationResult))
{
// handle failed
}
// send finishClientRegistrationResult.RegistrationRecord to server and create user account
Login Flow
// client
string password = "sup-krah.42-UOI"; // user password
if (!client.StartLogin(
password,
out StartClientLoginResult? startClientLoginResult))
{
// handle failed
}
// server
string userIdentifier = "20e14cd8-ab09-4f4b-87a8-06d2e2e9ff68"; // userId/email/username
string registrationRecord; // retrieve original registration record
if (!server.StartLogin(
serverSetup,
startClientLoginResult.StartLoginRequest,
userIdentifier,
registrationRecord,
out StartServerLoginResult? startServerLoginResult))
{
// handle failed
}
// client
if (!client.FinishLogin(
startClientLoginResult.ClientLoginState,
startServerLoginResult.LoginResponse,
password,
out FinishClientLoginResult? finishClientLoginResult))
{
// handle failed
}
// server
if (!server.FinishLogin(
startServerLoginResult.ServerLoginState,
finishClientLoginResult.FinishLoginRequest,
out string? sessionKey))
{
// handle failed
}
Advanced usage
ExportKey
After the initial registration flow as well as every login flow, the client has access to a private key only available to the client. This is the exportKey
. The key is not available to the server and it is stable. Meaning if you log in multiple times your exportKey
will stay the same.
Example usage
Registration
// client
if (!client.FinishRegistration(
password,
registrationResponse,
startClientRegistrationResult.ClientRegistrationState,
out FinishClientRegistrationResult? finishClientRegistrationResult))
{
// handle failed
}
finishClientRegistrationResult.ExportKey;
Login
// client
if (!client.FinishLogin(
startClientLoginResult.ClientLoginState,
startServerLoginResult.LoginResponse,
password,
out FinishClientLoginResult? finishClientLoginResult))
{
// handle failed
}
finishClientLoginResult.ExportKey;
Server Static Public Key
The result of client.FinishRegistration
and client.FinishLogin
also contains a property ServerStaticPublicKey
. It can be used to verify the authenticity of the server.
It's recommended to verify the server static public key in the application layer e.g. hard-code it into the application code and verify it's correctness.
Example usage
Server
The ServerStaticPublicKey
can be extracted like so:
if (!server.GetPublicKey(
serverSetupString,
out string? publicKey))
{
// handle failed
}
Client
Registration
// client
if (!client.FinishRegistration(
password,
registrationResponse,
startClientRegistrationResult.ClientRegistrationState,
out FinishClientRegistrationResult? finishClientRegistrationResult))
{
// handle failed
}
finishClientRegistrationResult.ServerStaticPublicKey;
Login
// client
if (!client.FinishLogin(
startClientLoginResult.ClientLoginState,
startServerLoginResult.LoginResponse,
password,
out FinishClientLoginResult? finishClientLoginResult))
{
// handle failed
}
finishClientLoginResult.ServerStaticPublicKey;
Identifiers
By default the server-side sets a userIdentifier
during the registration and login process. This userIdentifier
does not even need to be exposed to be exposed to a client.
client.FinishRegistration
, server.StartLogin
and client.FinishLogin
all have overloads that take a optional string value for clientIdentifier
and serverIdentifier
.
client.FinishRegistration(
password,
registrationResponse,
clientRegistrationState,
clientIdentifier,
serverIdentifier,
out FinishClientRegistrationResult? result);
server.StartLogin(
serverSetup,
startLoginRequest,
userIdentifier,
registrationRecord,
clientIdentitiy,
serverIdentity,
out StartServerLoginResult? result);
client.FinishLogin(
clientLoginState,
serverLoginResponse,
password,
clientIdentifier,
serverIdentifier,
out FinishClientLoginResult? result);
The identifiers will be public, but cryptographically bound to the registration record.
Once provided in the client.FinishRegistration
function call, the identical identifiers must be provided in the server.StartLogin
and client.FinishLogin
function call. Otherwise the login will result in an error.
Example Registration
// client
if (!client.FinishRegistration(
password,
registrationResponse,
startClientRegistrationResult.ClientRegistrationState,
"jane@example.com",
"mastodon.example.com",
out FinishClientRegistrationResult? result))
{
// handle failed
}
// send registrationRecord to server and create user account
Example Login
// server
if (!server.StartLogin(
serverSetup,
startClientLoginResult.StartLoginRequest,
userIdentifier,
registrationRecord,
"jane@example.com",
"mastodon.example.com",
out StartServerLoginResult? startServerLoginResult))
{
// handle failed
}
// client
if (!client.FinishLogin(
startClientLoginResult.ClientLoginState,
startServerLoginResult.LoginResponse,
password,
"jane@example.com",
"mastodon.example.com",
out FinishClientLoginResult? finishClientLoginResult))
{
// handle failed
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.3.0 | 140 | 4/7/2025 |
1.2.2 | 151 | 7/9/2024 |
1.2.1 | 98 | 7/9/2024 |
1.2.0 | 106 | 7/8/2024 |
1.1.14 | 125 | 7/8/2024 |
1.1.13 | 122 | 7/6/2024 |
1.1.12 | 142 | 7/6/2024 |
1.1.11 | 114 | 7/6/2024 |
1.1.9 | 128 | 7/6/2024 |
1.1.8 | 109 | 7/6/2024 |
1.1.7 | 96 | 7/6/2024 |
1.1.6 | 123 | 7/6/2024 |
1.1.5 | 97 | 7/6/2024 |
1.1.4 | 106 | 7/6/2024 |
1.1.3 | 119 | 7/6/2024 |
1.1.2 | 114 | 7/6/2024 |
1.1.1 | 117 | 7/6/2024 |
1.1.0 | 119 | 7/5/2024 |
1.0.7 | 103 | 7/5/2024 |
1.0.6 | 118 | 7/5/2024 |
1.0.5 | 99 | 7/5/2024 |
1.0.4 | 119 | 6/13/2024 |
1.0.3 | 102 | 6/13/2024 |
1.0.2 | 101 | 6/13/2024 |
1.0.1 | 100 | 6/13/2024 |
1.0.0 | 101 | 6/13/2024 |