You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
5.4 KiB
157 lines
5.4 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
#pragma warning disable |
|
using System; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; |
|
|
|
namespace BestHTTP.SecureProtocol.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) |
|
{ |
|
byte[] output = new byte[digest.GetDigestSize()]; |
|
|
|
digest.BlockUpdate(identity, 0, identity.Length); |
|
digest.Update((byte)':'); |
|
digest.BlockUpdate(password, 0, password.Length); |
|
digest.DoFinal(output, 0); |
|
|
|
digest.BlockUpdate(salt, 0, salt.Length); |
|
digest.BlockUpdate(output, 0, output.Length); |
|
digest.DoFinal(output, 0); |
|
|
|
return new BigInteger(1, output); |
|
} |
|
|
|
public static BigInteger GeneratePrivateValue(IDigest digest, BigInteger N, BigInteger g, SecureRandom random) |
|
{ |
|
int minBits = System.Math.Min(256, N.BitLength / 2); |
|
BigInteger min = BigInteger.One.ShiftLeft(minBits - 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); |
|
|
|
// Check that val % N != 0 |
|
if (val.Equals(BigInteger.Zero)) |
|
throw new CryptoException("Invalid public value: 0"); |
|
|
|
return val; |
|
} |
|
|
|
/** |
|
* Computes the client evidence message (M1) according to the standard routine: |
|
* M1 = H( A | B | S ) |
|
* @param digest The Digest used as the hashing function H |
|
* @param N Modulus used to get the pad length |
|
* @param A The public client value |
|
* @param B The public server value |
|
* @param S The secret calculated by both sides |
|
* @return M1 The calculated client evidence message |
|
*/ |
|
public static BigInteger CalculateM1(IDigest digest, BigInteger N, BigInteger A, BigInteger B, BigInteger S) |
|
{ |
|
BigInteger M1 = HashPaddedTriplet(digest, N, A, B, S); |
|
return M1; |
|
} |
|
|
|
/** |
|
* Computes the server evidence message (M2) according to the standard routine: |
|
* M2 = H( A | M1 | S ) |
|
* @param digest The Digest used as the hashing function H |
|
* @param N Modulus used to get the pad length |
|
* @param A The public client value |
|
* @param M1 The client evidence message |
|
* @param S The secret calculated by both sides |
|
* @return M2 The calculated server evidence message |
|
*/ |
|
public static BigInteger CalculateM2(IDigest digest, BigInteger N, BigInteger A, BigInteger M1, BigInteger S) |
|
{ |
|
BigInteger M2 = HashPaddedTriplet(digest, N, A, M1, S); |
|
return M2; |
|
} |
|
|
|
/** |
|
* Computes the final Key according to the standard routine: Key = H(S) |
|
* @param digest The Digest used as the hashing function H |
|
* @param N Modulus used to get the pad length |
|
* @param S The secret calculated by both sides |
|
* @return |
|
*/ |
|
public static BigInteger CalculateKey(IDigest digest, BigInteger N, BigInteger S) |
|
{ |
|
int padLength = (N.BitLength + 7) / 8; |
|
byte[] _S = GetPadded(S, padLength); |
|
digest.BlockUpdate(_S, 0, _S.Length); |
|
|
|
byte[] output = new byte[digest.GetDigestSize()]; |
|
digest.DoFinal(output, 0); |
|
return new BigInteger(1, output); |
|
} |
|
|
|
private static BigInteger HashPaddedTriplet(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2, BigInteger n3) |
|
{ |
|
int padLength = (N.BitLength + 7) / 8; |
|
|
|
byte[] n1_bytes = GetPadded(n1, padLength); |
|
byte[] n2_bytes = GetPadded(n2, padLength); |
|
byte[] n3_bytes = GetPadded(n3, padLength); |
|
|
|
digest.BlockUpdate(n1_bytes, 0, n1_bytes.Length); |
|
digest.BlockUpdate(n2_bytes, 0, n2_bytes.Length); |
|
digest.BlockUpdate(n3_bytes, 0, n3_bytes.Length); |
|
|
|
byte[] output = new byte[digest.GetDigestSize()]; |
|
digest.DoFinal(output, 0); |
|
|
|
return new BigInteger(1, output); |
|
} |
|
|
|
private static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2) |
|
{ |
|
int padLength = (N.BitLength + 7) / 8; |
|
|
|
byte[] n1_bytes = GetPadded(n1, padLength); |
|
byte[] n2_bytes = GetPadded(n2, padLength); |
|
|
|
digest.BlockUpdate(n1_bytes, 0, n1_bytes.Length); |
|
digest.BlockUpdate(n2_bytes, 0, n2_bytes.Length); |
|
|
|
byte[] output = new byte[digest.GetDigestSize()]; |
|
digest.DoFinal(output, 0); |
|
|
|
return new BigInteger(1, output); |
|
} |
|
|
|
private static byte[] GetPadded(BigInteger n, int length) |
|
{ |
|
byte[] bs = BigIntegers.AsUnsignedByteArray(n); |
|
if (bs.Length < length) |
|
{ |
|
byte[] tmp = new byte[length]; |
|
Array.Copy(bs, 0, tmp, length - bs.Length, bs.Length); |
|
bs = tmp; |
|
} |
|
return bs; |
|
} |
|
} |
|
} |
|
#pragma warning restore |
|
#endif
|
|
|