Package Description
$ dotnet add package Rainbow.CSharp.SDK.CryptographyProvides ability to create objects implementing SASLMechanism.
These objects handle the SCRAM mechanism of SASL.
No strings are allocated during challenge. Only client-side mechanisms are provided.
Based on https://github.com/stazz/FluentCryptography and https://github.com/stazz/UtilPack
Code has been reworked:
Unnecessary code has been removed.
Example of use:
var credentials = new SASLCredentialsSCRAMForClient(
userName,
password // password may be clear-text password as string, or result of PBKDF2 iteration as byte array.
);
String type = "SCRAM-SHA-512"; // To define which encryption must be used
switch (type)
{
case "SCRAM-SHA-1":
var sha1 = new Rainbow.Cryptography.Digest.SHA128();
client = sha1.CreateSASLClientSCRAM();
break;
case "SCRAM-SHA-256":
var sha256 = new Rainbow.Cryptography.Digest.SHA256();
client = sha256.CreateSASLClientSCRAM();
break;
case "SCRAM-SHA-512":
var sha512 = new Rainbow.Cryptography.Digest.SHA512();
client = sha512.CreateSASLClientSCRAM();
break;
}
var encoding = new UTF8Encoding(false, false).CreateDefaultEncodingInfo();
var writeArray = new ResizableArray<Byte>();
var firstMessageToServer = Convert.ToBase64String( ComputeInitialResponse());
// => Need to send the first message to the server and read it's answer
var firstMessageFromServer = "..."; // <= Here it's the content of the server reponse
byte[] data = Convert.FromBase64String(firstMessageFromServer);
var secondMessageToServer = Convert.ToBase64String( ComputeFinalResponse(data));
// => Need to send the second message to the server and read it's answer
var secondMessageFromServer = "..."; // <= Here it's the content of the server reponse
data = Convert.FromBase64String(secondMessageFromServer);
VerifyServerSignature(data); // => If no exception, the authentication process is a success
private byte[] ComputeInitialResponse()
{
var challengeArguments = credentials.CreateChallengeArguments(
null, // Initial phase does not read anything
-1,
-1,
writeArray,
0,
encoding
);
try
{
var task = client.ChallengeOrThrowOnErrorAsync(challengeArguments);
(var bytesWritten, var challengeResult) = task.Result;
if (bytesWritten > 0)
{
byte[] result = new byte[bytesWritten];
Array.Copy(writeArray.Array, result, bytesWritten);
return result;
}
}
catch
{
}
return new byte[0];
}
private byte[] ComputeFinalResponse(byte[] challenge)
{
var challengeArguments = credentials.CreateChallengeArguments(
challenge,
0,
challenge.Length,
writeArray,
0,
encoding
);
try
{
var task = client.ChallengeOrThrowOnErrorAsync(challengeArguments);
(var bytesWritten, var challengeResult) = task.Result;
if (bytesWritten > 0)
{
byte[] result = new byte[bytesWritten];
Array.Copy(writeArray.Array, result, bytesWritten);
return result;
}
}
catch
{
}
return new byte[0];
}
private byte[] VerifyServerSignature(byte[] challenge)
{
var challengeArguments = credentials.CreateChallengeArguments(
challenge,
0,
challenge.Length,
writeArray,
0,
encoding
);
var task = client.ChallengeOrThrowOnErrorAsync(challengeArguments);
(var bytesWritten, var challengeResult) = task.Result;
if(challengeResult == SASLChallengeResult.Completed)
return new byte[0];
throw new Exception("Server signature has not been verified with success");
}