WowSrp 0.1.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package WowSrp --version 0.1.3
NuGet\Install-Package WowSrp -Version 0.1.3
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="WowSrp" Version="0.1.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add WowSrp --version 0.1.3
#r "nuget: WowSrp, 0.1.3"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install WowSrp as a Cake Addin
#addin nuget:?package=WowSrp&version=0.1.3

// Install WowSrp as a Cake Tool
#tool nuget:?package=WowSrp&version=0.1.3

WowSrp for .NET (C#)

.NET Standard 2.1 library for World of Warcraft authentication servers. Includes functionality for:

  • Logging in (SRP6)
  • Header encryption/decryption for Vanilla, TBC, and Wrath
  • Calculation of world proof sent in CMSG_AUTH_SESSION
  • Integrity checking
  • PIN codes for 1.12+
  • Matrix Cards for 2.0+

Getting started

Install the library from nuget:

dotnet add package WowSrp

Usage

Authentication

For Servers

The module is split into functionality used by a server implementation and a client implementation.

Server

SrpVerifier -> SrpProof -> SrpServer

You will only want to save the username, salt, and password verifier for an account. Do not save the raw passwords on the server.

Construct an SrpVerifier through

var verifier = new SrpVerifier(username, password);

Save the Username, Salt, and PasswordVerifier in your database.

When a client connects, retrieve the Username, Salt, and PasswordVerifier from your database and create an SrpVerifier through the constructor and convert it to an SrpProof:

var proof = new SrpVerifier(username, passwordVerifier, salt).IntoProof();

The Salt, ServerPublicKey, Generator, and LargeSafePrime can then be sent to the client: The internal calculations use the generator and large safe prime from the functions, and these MUST be the ones sent to the client.

After receiving the clientPublicKey and clientProof, the proof can be attempted converted to an SrpServer.

var success = server.into_server(client_public_key, client_proof)
if (!success.HasValue) {
    // Password was incorrect
}
var (server, serverProof) = success!.Value;

The client is now logged in and can be sent the realm list.

If the client loses connection it will attempt to reconnect. This requires a valid SrpServer to exist. In my opinion the reconnect method is insecure since it uses the session key that can easily be deduced by any third party and it should not be implemented in a production auth server.

var success = server.VerifyReconnect(clientData, clientProof);
For Clients
SrpClientUser -> SrpClientChallenge -> SrpClient | -> SrpClientReconnection

The SrpClientReconnection is just a data struct that contains reconnection values.

The client does not have to save any values except for the username and password.

var challenge = new SrpClientChallenge(username, password, generator, largeSafePrime, serverPublicKey, salt)

The client can then verify that the server also has the correct password through the serverProof: This creates an SrpClient.

var success = challenge.VerifyServerProof(serverProof)
if (!success.HasValue) {
    // Server didn't get the same hash as you did
}
var client = success!.Value;

The SrpClient can attempt to reconnect using the serverReconnectData:

var reconnect_data = client.CalculateReconnectValues(serverReconnectData)

And then access the reconnect values from reconnectData:

var challenge_data = reconnectData.ChallengeData;
var client_proof = reconnectData.ClientProof;

Header Encryption

Server

First, create a random seed from WorldProof.RandomSeed() and send it to the client in SMSG_AUTH_CHALLENGE.

After receiving CMSG_AUTH_SESSION from the client, instantiate the encrypter and decrypter for your version.

var encrypter = new VanillaEncrypter();
encrypter.WriteServerHeader(stream, size, opcode);

var decrypter = new VanillaDecrypter();
var header = decrypter.ReadServerHeader(stream);

Integrity Checking

Use the relevant function for either Windows, Mac, or the general purpose version:

var hash = Integrity.GenericCheck(allFiles, checksumSalt, clientPublicKey)

PIN Code

For both server and client, create a PinCode object and call CalculateHash. Other arguments are random values sent to both client and server.

var pinGridSeed = Pin.RandomPinGridSeed();
var server/clientSalt = Pin.RandomPinSalt();
// Send these to client/server

// Each byte in the array is a digit of the pin
// Must be at least 4 and no longer than 10, values can not be greater than 9
var pin = [1, 2, 3, 4];
var hash = Pin.CalculateHash(pinGridSeed, serverSalt, clientSalt);

If the server hash matches the client hash, the client has the correct PIN.

Matrix Card

The MatrixCard class represents the physical card and the data on it. The VerifyHash function takes in all the necessary parameters and should be preferred.

MatrixCardVerifier is used for verification whenever the full MatrixCard data is not available, such as when a physical card has been issued.

// Completely random data
new card = MatrixCard();
// Save to database
// Send to client

var success = card.VerifyHash(challengeCount, seed, sessionKey, clientProof);

Additional documentation

The WoWDev wiki has an article on the big picture of authentication. My blog has articles that detail the implementation of this library.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • 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
0.3.0 54 6/1/2024
0.2.0 55 5/31/2024
0.1.3 65 5/23/2024
0.1.2 87 5/22/2024
0.1.1 86 5/22/2024
0.1.0 80 5/22/2024
0.1.0-alpha 72 5/21/2024

# 0.1.3 - 2024-05-23

## Added

* Implicit implementations for all header classes.

# 0.1.2 - 2024-05-22

## Added

* Removed implicit implementations for all header classes due to stack overflows.

# 0.1.1 - 2024-05-22

## Added

* Implicit implementations for all header classes.

# 0.1.0 - 2024-05-22

## Added

* Initial release.