Srp6Utilities
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Agreement.Srp
{
public class Srp6Utilities
{
public static BigInteger CalculateK(IDigest digest, BigInteger N, BigInteger g)
{
return HashPaddedPair(digest, N, N, g);
}
public static BigInteger CalculateU(IDigest digest, BigInteger N, BigInteger A, BigInteger B)
{
return HashPaddedPair(digest, N, A, B);
}
public static BigInteger CalculateX(IDigest digest, BigInteger N, byte[] salt, byte[] identity, byte[] password)
{
return CalculateX(digest, N, salt.AsSpan(), identity.AsSpan(), password.AsSpan());
}
public unsafe static BigInteger CalculateX(IDigest digest, BigInteger N, ReadOnlySpan<byte> salt, ReadOnlySpan<byte> identity, ReadOnlySpan<byte> password)
{
int digestSize = digest.GetDigestSize();
Span<byte> span;
if (digestSize <= 128) {
int num = digestSize;
span = new Span<byte>(stackalloc byte[(int)(uint)num], num);
} else
span = new byte[digestSize];
Span<byte> span2 = span;
digest.BlockUpdate(identity);
digest.Update(58);
digest.BlockUpdate(password);
digest.DoFinal(span2);
digest.BlockUpdate(salt);
digest.BlockUpdate(span2);
digest.DoFinal(span2);
return new BigInteger(1, span2);
}
public static BigInteger GeneratePrivateValue(IDigest digest, BigInteger N, BigInteger g, SecureRandom random)
{
int num = System.Math.Min(256, N.BitLength / 2);
BigInteger min = BigInteger.One.ShiftLeft(num - 1);
BigInteger max = N.Subtract(BigInteger.One);
return BigIntegers.CreateRandomInRange(min, max, random);
}
public static BigInteger ValidatePublicValue(BigInteger N, BigInteger val)
{
val = val.Mod(N);
if (val.Equals(BigInteger.Zero))
throw new CryptoException("Invalid public value: 0");
return val;
}
public static BigInteger CalculateM1(IDigest digest, BigInteger N, BigInteger A, BigInteger B, BigInteger S)
{
return HashPaddedTriplet(digest, N, A, B, S);
}
public static BigInteger CalculateM2(IDigest digest, BigInteger N, BigInteger A, BigInteger M1, BigInteger S)
{
return HashPaddedTriplet(digest, N, A, M1, S);
}
public unsafe static BigInteger CalculateKey(IDigest digest, BigInteger N, BigInteger S)
{
int num = (N.BitLength + 7) / 8;
int digestSize = digest.GetDigestSize();
Span<byte> span;
if (num <= 512) {
int num2 = num;
span = new Span<byte>(stackalloc byte[(int)(uint)num2], num2);
} else
span = new byte[num];
Span<byte> span2 = span;
BigIntegers.AsUnsignedByteArray(S, span2);
digest.BlockUpdate(span2);
if (digestSize <= 128) {
int num2 = digestSize;
span = new Span<byte>(stackalloc byte[(int)(uint)num2], num2);
} else
span = new byte[digestSize];
Span<byte> span3 = span;
digest.DoFinal(span3);
return new BigInteger(1, span3);
}
private unsafe static BigInteger HashPaddedTriplet(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2, BigInteger n3)
{
int num = (N.BitLength + 7) / 8;
int digestSize = digest.GetDigestSize();
Span<byte> span;
if (num <= 512) {
int num2 = num;
span = new Span<byte>(stackalloc byte[(int)(uint)num2], num2);
} else
span = new byte[num];
Span<byte> span2 = span;
BigIntegers.AsUnsignedByteArray(n1, span2);
digest.BlockUpdate(span2);
BigIntegers.AsUnsignedByteArray(n2, span2);
digest.BlockUpdate(span2);
BigIntegers.AsUnsignedByteArray(n3, span2);
digest.BlockUpdate(span2);
if (digestSize <= 128) {
int num2 = digestSize;
span = new Span<byte>(stackalloc byte[(int)(uint)num2], num2);
} else
span = new byte[digestSize];
Span<byte> span3 = span;
digest.DoFinal(span3);
return new BigInteger(1, span3);
}
private unsafe static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2)
{
int num = (N.BitLength + 7) / 8;
int digestSize = digest.GetDigestSize();
Span<byte> span;
if (num <= 512) {
int num2 = num;
span = new Span<byte>(stackalloc byte[(int)(uint)num2], num2);
} else
span = new byte[num];
Span<byte> span2 = span;
BigIntegers.AsUnsignedByteArray(n1, span2);
digest.BlockUpdate(span2);
BigIntegers.AsUnsignedByteArray(n2, span2);
digest.BlockUpdate(span2);
if (digestSize <= 128) {
int num2 = digestSize;
span = new Span<byte>(stackalloc byte[(int)(uint)num2], num2);
} else
span = new byte[digestSize];
Span<byte> span3 = span;
digest.DoFinal(span3);
return new BigInteger(1, span3);
}
}
}