- Initial commit

This commit is contained in:
Timur Kozanov
2026-07-03 05:02:26 +03:00
commit 374ff1e689
4080 changed files with 388870 additions and 0 deletions

View File

@ -0,0 +1,775 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders;
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng.Drbg
{
/**
* A SP800-90A CTR DRBG.
*/
public sealed class CtrSP800Drbg
: ISP80090Drbg
{
private static readonly long TDEA_RESEED_MAX = 1L << (32 - 1);
private static readonly long AES_RESEED_MAX = 1L << (48 - 1);
private static readonly int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
private static readonly int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
private readonly IEntropySource mEntropySource;
private readonly IBlockCipher mEngine;
private readonly int mKeySizeInBits;
private readonly int mSeedLength;
private readonly int mSecurityStrength;
// internal state
private byte[] mKey;
private byte[] mV;
private long mReseedCounter = 0;
private bool mIsTdea = false;
/**
* Construct a SP800-90A CTR DRBG.
* <p>
* Minimum entropy requirement is the security strength requested.
* </p>
* @param engine underlying block cipher to use to support DRBG
* @param keySizeInBits size of the key to use with the block cipher.
* @param securityStrength security strength required (in bits)
* @param entropySource source of entropy to use for seeding/reseeding.
* @param personalizationString personalization string to distinguish this DRBG (may be null).
* @param nonce nonce to further distinguish this DRBG (may be null).
*/
public CtrSP800Drbg(IBlockCipher engine, int keySizeInBits, int securityStrength, IEntropySource entropySource,
byte[] personalizationString, byte[] nonce)
{
if (securityStrength > 256)
throw new ArgumentException("Requested security strength is not supported by the derivation function");
if (GetMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
throw new ArgumentException("Requested security strength is not supported by block cipher and key size");
if (entropySource.EntropySize < securityStrength)
throw new ArgumentException("Not enough entropy for security strength required");
mEntropySource = entropySource;
mEngine = engine;
mKeySizeInBits = keySizeInBits;
mSecurityStrength = securityStrength;
mSeedLength = keySizeInBits + engine.GetBlockSize() * 8;
mIsTdea = IsTdea(engine);
CTR_DRBG_Instantiate_algorithm(nonce, personalizationString);
}
private void CTR_DRBG_Instantiate_algorithm(byte[] nonce, byte[] personalisationString)
{
byte[] entropy = GetEntropy(); // Get_entropy_input
byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
byte[] seed = BlockCipherDF(seedMaterial, mSeedLength / 8);
int blockSize = mEngine.GetBlockSize();
mKey = new byte[(mKeySizeInBits + 7) / 8];
mV = new byte[blockSize];
// mKey & mV are modified by this call
CTR_DRBG_Update(seed, mKey, mV);
mReseedCounter = 1;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void CTR_DRBG_Update(ReadOnlySpan<byte> seed, Span<byte> key, Span<byte> v)
{
int seedLength = seed.Length;
Span<byte> temp = seedLength <= 256
? stackalloc byte[seedLength]
: new byte[seedLength];
int blockSize = mEngine.GetBlockSize();
Span<byte> block = blockSize <= 64
? stackalloc byte[blockSize]
: new byte[blockSize];
mEngine.Init(true, ExpandToKeyParameter(key));
for (int i = 0; i * blockSize < seed.Length; ++i)
{
AddOneTo(v);
mEngine.ProcessBlock(v, block);
int bytesToCopy = System.Math.Min(blockSize, temp.Length - i * blockSize);
block[..bytesToCopy].CopyTo(temp[(i * blockSize)..]);
}
XorWith(seed, temp);
key.CopyFrom(temp);
v.CopyFrom(temp[key.Length..]);
}
#else
private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
{
byte[] temp = new byte[seed.Length];
byte[] outputBlock = new byte[mEngine.GetBlockSize()];
int i = 0;
int outLen = mEngine.GetBlockSize();
mEngine.Init(true, ExpandToKeyParameter(key));
while (i * outLen < seed.Length)
{
AddOneTo(v);
mEngine.ProcessBlock(v, 0, outputBlock, 0);
int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen);
Array.Copy(outputBlock, 0, temp, i * outLen, bytesToCopy);
++i;
}
Xor(temp, seed, temp, 0);
Array.Copy(temp, 0, key, 0, key.Length);
Array.Copy(temp, key.Length, v, 0, v.Length);
}
#endif
private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
CTR_DRBG_Reseed_algorithm(Spans.FromNullableReadOnly(additionalInput));
#else
byte[] seedMaterial = Arrays.Concatenate(GetEntropy(), additionalInput);
seedMaterial = BlockCipherDF(seedMaterial, mSeedLength / 8);
CTR_DRBG_Update(seedMaterial, mKey, mV);
mReseedCounter = 1;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void CTR_DRBG_Reseed_algorithm(ReadOnlySpan<byte> additionalInput)
{
int entropyLength = GetEntropyLength();
int seedLength = entropyLength + additionalInput.Length;
Span<byte> seedMaterial = seedLength <= 256
? stackalloc byte[seedLength]
: new byte[seedLength];
GetEntropy(seedMaterial[..entropyLength]);
additionalInput.CopyTo(seedMaterial[entropyLength..]);
seedMaterial = BlockCipherDF(seedMaterial, mSeedLength / 8);
CTR_DRBG_Update(seedMaterial, mKey, mV);
mReseedCounter = 1;
}
#endif
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void Xor(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y, Span<byte> z)
{
for (int i = 0; i < z.Length; ++i)
{
z[i] = (byte)(x[i] ^ y[i]);
}
}
private void XorWith(ReadOnlySpan<byte> x, Span<byte> z)
{
for (int i = 0; i < z.Length; ++i)
{
z[i] ^= x[i];
}
}
#else
private void Xor(byte[] output, byte[] a, byte[] b, int bOff)
{
for (int i = 0; i < output.Length; i++)
{
output[i] = (byte)(a[i] ^ b[bOff + i]);
}
}
#endif
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void AddOneTo(Span<byte> longer)
#else
private void AddOneTo(byte[] longer)
#endif
{
uint carry = 1;
int i = longer.Length;
while (--i >= 0)
{
carry += longer[i];
longer[i] = (byte)carry;
carry >>= 8;
}
}
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return entropy;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private int GetEntropy(Span<byte> output)
{
int length = mEntropySource.GetEntropy(output);
if (length < (mSecurityStrength + 7) / 8)
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return length;
}
private int GetEntropyLength()
{
return (mEntropySource.EntropySize + 7) / 8;
}
#endif
// -- Internal state migration ---
private static readonly byte[] K_BITS = Hex.DecodeStrict(
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
// 1. If (number_of_bits_to_return > max_number_of_bits), then return an
// ERROR_FLAG.
// 2. L = len (input_string)/8.
// 3. N = number_of_bits_to_return/8.
// Comment: L is the bitstring represention of
// the integer resulting from len (input_string)/8.
// L shall be represented as a 32-bit integer.
//
// Comment : N is the bitstring represention of
// the integer resulting from
// number_of_bits_to_return/8. N shall be
// represented as a 32-bit integer.
//
// 4. S = L || N || input_string || 0x80.
// 5. While (len (S) mod outlen)
// Comment : Pad S with zeros, if necessary.
// 0, S = S || 0x00.
//
// Comment : Compute the starting value.
// 6. temp = the Null string.
// 7. i = 0.
// 8. K = Leftmost keylen bits of 0x00010203...1D1E1F.
// 9. While len (temp) < keylen + outlen, do
//
// IV = i || 0outlen - len (i).
//
// 9.1
//
// temp = temp || BCC (K, (IV || S)).
//
// 9.2
//
// i = i + 1.
//
// 9.3
//
// Comment : i shall be represented as a 32-bit
// integer, i.e., len (i) = 32.
//
// Comment: The 32-bit integer represenation of
// i is padded with zeros to outlen bits.
//
// Comment: Compute the requested number of
// bits.
//
// 10. K = Leftmost keylen bits of temp.
//
// 11. X = Next outlen bits of temp.
//
// 12. temp = the Null string.
//
// 13. While len (temp) < number_of_bits_to_return, do
//
// 13.1 X = Block_Encrypt (K, X).
//
// 13.2 temp = temp || X.
//
// 14. requested_bits = Leftmost number_of_bits_to_return of temp.
//
// 15. Return SUCCESS and requested_bits.
private byte[] BlockCipherDF(byte[] input, int N)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
return BlockCipherDF(input.AsSpan(), N);
#else
int outLen = mEngine.GetBlockSize();
int L = input.Length; // already in bytes
// 4 S = L || N || input || 0x80
int sLen = 4 + 4 + L + 1;
int blockLen = ((sLen + outLen - 1) / outLen) * outLen;
byte[] S = new byte[blockLen];
Pack.UInt32_To_BE((uint)L, S, 0);
Pack.UInt32_To_BE((uint)N, S, 4);
Array.Copy(input, 0, S, 8, L);
S[8 + L] = 0x80;
// S already padded with zeros
byte[] temp = new byte[mKeySizeInBits / 8 + outLen];
byte[] bccOut = new byte[outLen];
byte[] IV = new byte[outLen];
int i = 0;
byte[] K = new byte[mKeySizeInBits / 8];
Array.Copy(K_BITS, 0, K, 0, K.Length);
var K1 = ExpandToKeyParameter(K);
mEngine.Init(true, K1);
while (i*outLen*8 < mKeySizeInBits + outLen *8)
{
Pack.UInt32_To_BE((uint)i, IV, 0);
BCC(bccOut, IV, S);
int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen);
Array.Copy(bccOut, 0, temp, i * outLen, bytesToCopy);
++i;
}
byte[] X = new byte[outLen];
Array.Copy(temp, 0, K, 0, K.Length);
Array.Copy(temp, K.Length, X, 0, X.Length);
temp = new byte[N];
i = 0;
mEngine.Init(true, ExpandToKeyParameter(K));
while (i * outLen < temp.Length)
{
mEngine.ProcessBlock(X, 0, X, 0);
int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen);
Array.Copy(X, 0, temp, i * outLen, bytesToCopy);
i++;
}
return temp;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private byte[] BlockCipherDF(ReadOnlySpan<byte> input, int N)
{
int blockSize = mEngine.GetBlockSize();
int L = input.Length; // already in bytes
// 4 S = L || N || input || 0x80
int sLen = 4 + 4 + L + 1;
int blockLen = ((sLen + blockSize - 1) / blockSize) * blockSize;
Span<byte> S = blockLen <= 256
? stackalloc byte[blockLen]
: new byte[blockLen];
Pack.UInt32_To_BE((uint)L, S);
Pack.UInt32_To_BE((uint)N, S[4..]);
input.CopyTo(S[8..]);
S[8 + L] = 0x80;
// S already padded with zeros
int keySize = mKeySizeInBits / 8;
int tempSize = keySize + blockSize;
Span<byte> temp = tempSize <= 128
? stackalloc byte[tempSize]
: new byte[tempSize];
Span<byte> bccOut = blockSize <= 64
? stackalloc byte[blockSize]
: new byte[blockSize];
Span<byte> IV = blockSize <= 64
? stackalloc byte[blockSize]
: new byte[blockSize];
var K1 = ExpandToKeyParameter(K_BITS.AsSpan(0, keySize));
mEngine.Init(true, K1);
for (int i = 0; i * blockSize < tempSize; ++i)
{
Pack.UInt32_To_BE((uint)i, IV);
BCC(bccOut, IV, S);
int bytesToCopy = System.Math.Min(blockSize, tempSize - i * blockSize);
bccOut[..bytesToCopy].CopyTo(temp[(i * blockSize)..]);
}
var K2 = ExpandToKeyParameter(temp[..keySize]);
mEngine.Init(true, K2);
var X = temp[keySize..];
byte[] result = new byte[N];
for (int i = 0; i * blockSize < result.Length; ++i)
{
mEngine.ProcessBlock(X, X);
int bytesToCopy = System.Math.Min(blockSize, result.Length - i * blockSize);
X[..bytesToCopy].CopyTo(result.AsSpan(i * blockSize));
}
return result;
}
#endif
/*
* 1. chaining_value = 0^outlen
* . Comment: Set the first chaining value to outlen zeros.
* 2. n = len (data)/outlen.
* 3. Starting with the leftmost bits of data, split the data into n blocks of outlen bits
* each, forming block(1) to block(n).
* 4. For i = 1 to n do
* 4.1 input_block = chaining_value ^ block(i) .
* 4.2 chaining_value = Block_Encrypt (Key, input_block).
* 5. output_block = chaining_value.
* 6. Return output_block.
*/
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void BCC(Span<byte> bccOut, ReadOnlySpan<byte> iV, ReadOnlySpan<byte> data)
{
int blockSize = mEngine.GetBlockSize();
Span<byte> chainingValue = blockSize <= 64
? stackalloc byte[blockSize]
: new byte[blockSize];
Span<byte> inputBlock = blockSize <= 64
? stackalloc byte[blockSize]
: new byte[blockSize];
mEngine.ProcessBlock(iV, chainingValue);
int n = data.Length / blockSize;
for (int i = 0; i < n; i++)
{
Xor(chainingValue, data[(i * blockSize)..], inputBlock);
mEngine.ProcessBlock(inputBlock, chainingValue);
}
bccOut.CopyFrom(chainingValue);
}
#else
private void BCC(byte[] bccOut, byte[] iV, byte[] data)
{
int outlen = mEngine.GetBlockSize();
byte[] chainingValue = new byte[outlen]; // initial values = 0
int n = data.Length / outlen;
byte[] inputBlock = new byte[outlen];
mEngine.ProcessBlock(iV, 0, chainingValue, 0);
for (int i = 0; i < n; i++)
{
Xor(inputBlock, chainingValue, data, i*outlen);
mEngine.ProcessBlock(inputBlock, 0, chainingValue, 0);
}
Array.Copy(chainingValue, 0, bccOut, 0, bccOut.Length);
}
#endif
/**
* Return the block size (in bits) of the DRBG.
*
* @return the number of bits produced on each internal round of the DRBG.
*/
public int BlockSize
{
get { return mV.Length * 8; }
}
/**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
* @param additionalInput additional input to be added to the DRBG in this step.
* @param predictionResistant true if a reseed should be forced, false otherwise.
*
* @return number of bits generated, -1 if a reseed required.
*/
public int Generate(byte[] output, int outputOff, int outputLen, byte[] additionalInput,
bool predictionResistant)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
return additionalInput == null
? Generate(output.AsSpan(outputOff, outputLen), predictionResistant)
: GenerateWithInput(output.AsSpan(outputOff, outputLen), additionalInput.AsSpan(), predictionResistant);
#else
if (mIsTdea)
{
if (mReseedCounter > TDEA_RESEED_MAX)
return -1;
if (outputLen > TDEA_MAX_BITS_REQUEST / 8)
throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
}
else
{
if (mReseedCounter > AES_RESEED_MAX)
return -1;
if (outputLen > AES_MAX_BITS_REQUEST / 8)
throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
}
if (predictionResistant)
{
CTR_DRBG_Reseed_algorithm(additionalInput);
additionalInput = null;
}
if (additionalInput != null)
{
additionalInput = BlockCipherDF(additionalInput, mSeedLength / 8);
CTR_DRBG_Update(additionalInput, mKey, mV);
}
else
{
additionalInput = new byte[mSeedLength];
}
byte[] tmp = new byte[mV.Length];
mEngine.Init(true, ExpandToKeyParameter(mKey));
for (int i = 0, limit = outputLen / tmp.Length; i <= limit; i++)
{
int bytesToCopy = System.Math.Min(tmp.Length, outputLen - i * tmp.Length);
if (bytesToCopy != 0)
{
AddOneTo(mV);
mEngine.ProcessBlock(mV, 0, tmp, 0);
Array.Copy(tmp, 0, output, outputOff + i * tmp.Length, bytesToCopy);
}
}
CTR_DRBG_Update(additionalInput, mKey, mV);
mReseedCounter++;
return outputLen * 8;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
public int Generate(Span<byte> output, bool predictionResistant)
{
int outputLen = output.Length;
if (mIsTdea)
{
if (mReseedCounter > TDEA_RESEED_MAX)
return -1;
if (outputLen > TDEA_MAX_BITS_REQUEST / 8)
throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
}
else
{
if (mReseedCounter > AES_RESEED_MAX)
return -1;
if (outputLen > AES_MAX_BITS_REQUEST / 8)
throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
}
if (predictionResistant)
{
CTR_DRBG_Reseed_algorithm(ReadOnlySpan<byte>.Empty);
}
byte[] seed = new byte[mSeedLength / 8];
return ImplGenerate(seed, output);
}
public int GenerateWithInput(Span<byte> output, ReadOnlySpan<byte> additionalInput, bool predictionResistant)
{
int outputLen = output.Length;
if (mIsTdea)
{
if (mReseedCounter > TDEA_RESEED_MAX)
return -1;
if (outputLen > TDEA_MAX_BITS_REQUEST / 8)
throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
}
else
{
if (mReseedCounter > AES_RESEED_MAX)
return -1;
if (outputLen > AES_MAX_BITS_REQUEST / 8)
throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
}
int seedLength = mSeedLength / 8;
byte[] seed;
if (predictionResistant)
{
CTR_DRBG_Reseed_algorithm(additionalInput);
seed = new byte[seedLength];
}
else
{
seed = BlockCipherDF(additionalInput, seedLength);
CTR_DRBG_Update(seed, mKey, mV);
}
return ImplGenerate(seed, output);
}
private int ImplGenerate(ReadOnlySpan<byte> seed, Span<byte> output)
{
byte[] tmp = new byte[mV.Length];
mEngine.Init(true, ExpandToKeyParameter(mKey));
int outputLen = output.Length;
for (int i = 0, limit = outputLen / tmp.Length; i <= limit; i++)
{
int bytesToCopy = System.Math.Min(tmp.Length, outputLen - i * tmp.Length);
if (bytesToCopy != 0)
{
AddOneTo(mV);
mEngine.ProcessBlock(mV, 0, tmp, 0);
tmp[..bytesToCopy].CopyTo(output[(i * tmp.Length)..]);
}
}
CTR_DRBG_Update(seed, mKey, mV);
mReseedCounter++;
return outputLen * 8;
}
#endif
/**
* Reseed the DRBG.
*
* @param additionalInput additional input to be added to the DRBG in this step.
*/
public void Reseed(byte[] additionalInput)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
Reseed(Spans.FromNullableReadOnly(additionalInput));
#else
CTR_DRBG_Reseed_algorithm(additionalInput);
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
public void Reseed(ReadOnlySpan<byte> additionalInput)
{
CTR_DRBG_Reseed_algorithm(additionalInput);
}
#endif
private bool IsTdea(IBlockCipher cipher)
{
return cipher.AlgorithmName.Equals("DESede") || cipher.AlgorithmName.Equals("TDEA");
}
private int GetMaxSecurityStrength(IBlockCipher cipher, int keySizeInBits)
{
if (IsTdea(cipher) && keySizeInBits == 168)
{
return 112;
}
if (cipher.AlgorithmName.Equals("AES"))
{
return keySizeInBits;
}
return -1;
}
private KeyParameter ExpandToKeyParameter(byte[] key)
{
if (!mIsTdea)
return new KeyParameter(key);
// expand key to 192 bits.
byte[] tmp = new byte[24];
PadKey(key, 0, tmp, 0);
PadKey(key, 7, tmp, 8);
PadKey(key, 14, tmp, 16);
return new KeyParameter(tmp);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private KeyParameter ExpandToKeyParameter(ReadOnlySpan<byte> key)
{
if (!mIsTdea)
return new KeyParameter(key);
// expand key to 192 bits.
Span<byte> tmp = stackalloc byte[24];
PadKey(key, tmp);
PadKey(key[7..], tmp[8..]);
PadKey(key[14..], tmp[16..]);
return new KeyParameter(tmp);
}
#endif
/**
* Pad out a key for TDEA, setting odd parity for each byte.
*
* @param keyMaster
* @param keyOff
* @param tmp
* @param tmpOff
*/
private void PadKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
{
tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >> 1));
tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >> 2));
tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >> 3));
tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >> 4));
tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >> 5));
tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >> 6));
tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
DesParameters.SetOddParity(tmp, tmpOff, 8);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void PadKey(ReadOnlySpan<byte> keyMaster, Span<byte> tmp)
{
tmp[0] = (byte)(keyMaster[0] & 0xFE);
tmp[1] = (byte)((keyMaster[0] << 7) | ((keyMaster[1] & 0xfc) >> 1));
tmp[2] = (byte)((keyMaster[1] << 6) | ((keyMaster[2] & 0xf8) >> 2));
tmp[3] = (byte)((keyMaster[2] << 5) | ((keyMaster[3] & 0xf0) >> 3));
tmp[4] = (byte)((keyMaster[3] << 4) | ((keyMaster[4] & 0xe0) >> 4));
tmp[5] = (byte)((keyMaster[4] << 3) | ((keyMaster[5] & 0xc0) >> 5));
tmp[6] = (byte)((keyMaster[5] << 2) | ((keyMaster[6] & 0x80) >> 6));
tmp[7] = (byte)(keyMaster[6] << 1);
DesParameters.SetOddParity(tmp[..8]);
}
#endif
}
}
#pragma warning restore
#endif

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 74a60b4f0c626d946a8f1cd50fd12295
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 267636
packageName: Best HTTP
packageVersion: 3.0.17
assetPath: Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/prng/drbg/CtrSP800Drbg.cs
uploadId: 783279

View File

@ -0,0 +1,115 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Collections.Generic;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng.Drbg
{
internal class DrbgUtilities
{
private static readonly IDictionary<string, int> MaxSecurityStrengths =
new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
static DrbgUtilities()
{
MaxSecurityStrengths.Add("SHA-1", 128);
MaxSecurityStrengths.Add("SHA-224", 192);
MaxSecurityStrengths.Add("SHA-256", 256);
MaxSecurityStrengths.Add("SHA-384", 256);
MaxSecurityStrengths.Add("SHA-512", 256);
MaxSecurityStrengths.Add("SHA-512/224", 192);
MaxSecurityStrengths.Add("SHA-512/256", 256);
}
internal static int GetMaxSecurityStrength(IDigest d)
{
return MaxSecurityStrengths[d.AlgorithmName];
}
internal static int GetMaxSecurityStrength(IMac m)
{
string name = m.AlgorithmName;
return MaxSecurityStrengths[name.Substring(0, name.IndexOf("/"))];
}
/**
* Used by both Dual EC and Hash.
*/
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
internal static void HashDF(IDigest digest, ReadOnlySpan<byte> seedMaterial, int seedLength, Span<byte> output)
#else
internal static void HashDF(IDigest digest, byte[] seedMaterial, int seedLength, byte[] output)
#endif
{
// 1. temp = the Null string.
// 2. .
// 3. counter = an 8-bit binary value representing the integer "1".
// 4. For i = 1 to len do
// Comment : In step 4.1, no_of_bits_to_return
// is used as a 32-bit string.
// 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
// input_string).
// 4.2 counter = counter + 1.
// 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
// 6. Return SUCCESS and requested_bits.
int outputLength = (seedLength + 7) / 8;
int digestSize = digest.GetDigestSize();
int len = outputLength / digestSize;
int counter = 1;
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
Span<byte> dig = digestSize <= 128
? stackalloc byte[digestSize]
: new byte[digestSize];
Span<byte> header = stackalloc byte[5];
Pack.UInt32_To_BE((uint)seedLength, header[1..]);
#else
byte[] dig = new byte[digestSize];
byte[] header = new byte[5];
Pack.UInt32_To_BE((uint)seedLength, header, 1);
#endif
for (int i = 0; i <= len; i++, counter++)
{
header[0] = (byte)counter;
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
digest.BlockUpdate(header);
digest.BlockUpdate(seedMaterial);
digest.DoFinal(dig);
int bytesToCopy = System.Math.Min(digestSize, outputLength - i * digestSize);
dig[..bytesToCopy].CopyTo(output[(i * digestSize)..]);
#else
digest.BlockUpdate(header, 0, header.Length);
digest.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
digest.DoFinal(dig, 0);
int bytesToCopy = System.Math.Min(digestSize, outputLength - i * digestSize);
Array.Copy(dig, 0, output, i * digestSize, bytesToCopy);
#endif
}
// do a left shift to get rid of excess bits.
if (seedLength % 8 != 0)
{
int shift = 8 - (seedLength % 8);
uint carry = 0;
for (int i = 0; i != outputLength; i++)
{
uint b = output[i];
output[i] = (byte)((b >> shift) | (carry << (8 - shift)));
carry = b;
}
}
}
}
}
#pragma warning restore
#endif

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 37ddcc3b4b61995479b0c93d93b23359
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 267636
packageName: Best HTTP
packageVersion: 3.0.17
assetPath: Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/prng/drbg/DrbgUtilities.cs
uploadId: 783279

View File

@ -0,0 +1,351 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng.Drbg
{
/**
* A SP800-90A HMAC DRBG.
*/
public sealed class HMacSP800Drbg
: ISP80090Drbg
{
private readonly static long RESEED_MAX = 1L << (48 - 1);
private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
private readonly byte[] mK;
private readonly byte[] mV;
private readonly IEntropySource mEntropySource;
private readonly IMac mHMac;
private readonly int mSecurityStrength;
private long mReseedCounter;
/**
* Construct a SP800-90A Hash DRBG.
* <p>
* Minimum entropy requirement is the security strength requested.
* </p>
* @param hMac Hash MAC to base the DRBG on.
* @param securityStrength security strength required (in bits)
* @param entropySource source of entropy to use for seeding/reseeding.
* @param personalizationString personalization string to distinguish this DRBG (may be null).
* @param nonce nonce to further distinguish this DRBG (may be null).
*/
public HMacSP800Drbg(IMac hMac, int securityStrength, IEntropySource entropySource,
byte[] personalizationString, byte[] nonce)
{
if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(hMac))
throw new ArgumentException("Requested security strength is not supported by the derivation function");
if (entropySource.EntropySize < securityStrength)
throw new ArgumentException("Not enough entropy for security strength required");
mHMac = hMac;
mSecurityStrength = securityStrength;
mEntropySource = entropySource;
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
mK = new byte[hMac.GetMacSize()];
mV = new byte[mK.Length];
Arrays.Fill(mV, (byte)1);
hmac_DRBG_Update(seedMaterial);
mReseedCounter = 1;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void hmac_DRBG_Update()
{
hmac_DRBG_Update_Func(ReadOnlySpan<byte>.Empty, 0x00);
}
private void hmac_DRBG_Update(ReadOnlySpan<byte> seedMaterial)
{
hmac_DRBG_Update_Func(seedMaterial, 0x00);
hmac_DRBG_Update_Func(seedMaterial, 0x01);
}
private void hmac_DRBG_Update_Func(ReadOnlySpan<byte> seedMaterial, byte vValue)
{
mHMac.Init(new KeyParameter(mK));
mHMac.BlockUpdate(mV);
mHMac.Update(vValue);
if (!seedMaterial.IsEmpty)
{
mHMac.BlockUpdate(seedMaterial);
}
mHMac.DoFinal(mK);
mHMac.Init(new KeyParameter(mK));
mHMac.BlockUpdate(mV);
mHMac.DoFinal(mV);
}
#else
private void hmac_DRBG_Update(byte[] seedMaterial)
{
hmac_DRBG_Update_Func(seedMaterial, 0x00);
if (seedMaterial != null)
{
hmac_DRBG_Update_Func(seedMaterial, 0x01);
}
}
private void hmac_DRBG_Update_Func(byte[] seedMaterial, byte vValue)
{
mHMac.Init(new KeyParameter(mK));
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.Update(vValue);
if (seedMaterial != null)
{
mHMac.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
}
mHMac.DoFinal(mK, 0);
mHMac.Init(new KeyParameter(mK));
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.DoFinal(mV, 0);
}
#endif
/**
* Return the block size (in bits) of the DRBG.
*
* @return the number of bits produced on each round of the DRBG.
*/
public int BlockSize
{
get { return mV.Length * 8; }
}
/**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
* @param additionalInput additional input to be added to the DRBG in this step.
* @param predictionResistant true if a reseed should be forced, false otherwise.
*
* @return number of bits generated, -1 if a reseed required.
*/
public int Generate(byte[] output, int outputOff, int outputLen, byte[] additionalInput,
bool predictionResistant)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
return additionalInput == null
? Generate(output.AsSpan(outputOff, outputLen), predictionResistant)
: GenerateWithInput(output.AsSpan(outputOff, outputLen), additionalInput.AsSpan(), predictionResistant);
#else
int numberOfBits = outputLen * 8;
if (numberOfBits > MAX_BITS_REQUEST)
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
if (mReseedCounter > RESEED_MAX)
return -1;
if (predictionResistant)
{
Reseed(additionalInput);
additionalInput = null;
}
// 2.
if (additionalInput != null)
{
hmac_DRBG_Update(additionalInput);
}
// 3.
byte[] rv = new byte[outputLen];
int m = outputLen / mV.Length;
mHMac.Init(new KeyParameter(mK));
for (int i = 0; i < m; i++)
{
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.DoFinal(mV, 0);
Array.Copy(mV, 0, rv, i * mV.Length, mV.Length);
}
if (m * mV.Length < rv.Length)
{
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.DoFinal(mV, 0);
Array.Copy(mV, 0, rv, m * mV.Length, rv.Length - (m * mV.Length));
}
hmac_DRBG_Update(additionalInput);
mReseedCounter++;
Array.Copy(rv, 0, output, outputOff, outputLen);
return numberOfBits;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
public int Generate(Span<byte> output, bool predictionResistant)
{
int numberOfBits = output.Length * 8;
if (numberOfBits > MAX_BITS_REQUEST)
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
if (mReseedCounter > RESEED_MAX)
return -1;
if (predictionResistant)
{
Reseed(ReadOnlySpan<byte>.Empty);
}
// 3.
ImplGenerate(output);
hmac_DRBG_Update();
mReseedCounter++;
return numberOfBits;
}
public int GenerateWithInput(Span<byte> output, ReadOnlySpan<byte> additionalInput, bool predictionResistant)
{
int numberOfBits = output.Length * 8;
if (numberOfBits > MAX_BITS_REQUEST)
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
if (mReseedCounter > RESEED_MAX)
return -1;
if (predictionResistant)
{
Reseed(additionalInput);
}
else
{
// 2.
hmac_DRBG_Update(additionalInput);
}
// 3.
ImplGenerate(output);
if (predictionResistant)
{
hmac_DRBG_Update();
}
else
{
hmac_DRBG_Update(additionalInput);
}
mReseedCounter++;
return numberOfBits;
}
private void ImplGenerate(Span<byte> output)
{
int outputLen = output.Length;
int m = outputLen / mV.Length;
mHMac.Init(new KeyParameter(mK));
for (int i = 0; i < m; i++)
{
mHMac.BlockUpdate(mV);
mHMac.DoFinal(mV);
mV.CopyTo(output[(i * mV.Length)..]);
}
int remaining = outputLen - m * mV.Length;
if (remaining > 0)
{
mHMac.BlockUpdate(mV);
mHMac.DoFinal(mV);
mV[..remaining].CopyTo(output[(m * mV.Length)..]);
}
}
#endif
/**
* Reseed the DRBG.
*
* @param additionalInput additional input to be added to the DRBG in this step.
*/
public void Reseed(byte[] additionalInput)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
Reseed(Spans.FromNullableReadOnly(additionalInput));
#else
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.Concatenate(entropy, additionalInput);
hmac_DRBG_Update(seedMaterial);
mReseedCounter = 1;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
public void Reseed(ReadOnlySpan<byte> additionalInput)
{
int entropyLength = GetEntropyLength();
int seedMaterialLength = entropyLength + additionalInput.Length;
Span<byte> seedMaterial = seedMaterialLength <= 256
? stackalloc byte[seedMaterialLength]
: new byte[seedMaterialLength];
GetEntropy(seedMaterial);
additionalInput.CopyTo(seedMaterial[entropyLength..]);
hmac_DRBG_Update(seedMaterial);
mReseedCounter = 1;
}
#endif
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return entropy;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private int GetEntropy(Span<byte> output)
{
int length = mEntropySource.GetEntropy(output);
if (length < (mSecurityStrength + 7) / 8)
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return length;
}
private int GetEntropyLength()
{
return (mEntropySource.EntropySize + 7) / 8;
}
#endif
}
}
#pragma warning restore
#endif

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 5e1b0fc602d5dfe4493f15095e54e608
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 267636
packageName: Best HTTP
packageVersion: 3.0.17
assetPath: Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/prng/drbg/HMacSP800Drbg.cs
uploadId: 783279

View File

@ -0,0 +1,502 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Collections.Generic;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng.Drbg
{
/**
* A SP800-90A Hash DRBG.
*/
public sealed class HashSP800Drbg
: ISP80090Drbg
{
private readonly static byte[] ONE = { 0x01 };
private readonly static long RESEED_MAX = 1L << (48 - 1);
private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
private static readonly IDictionary<string, int> SeedLens =
new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
static HashSP800Drbg()
{
SeedLens.Add("SHA-1", 440);
SeedLens.Add("SHA-224", 440);
SeedLens.Add("SHA-256", 440);
SeedLens.Add("SHA-512/256", 440);
SeedLens.Add("SHA-512/224", 440);
SeedLens.Add("SHA-384", 888);
SeedLens.Add("SHA-512", 888);
}
private readonly IDigest mDigest;
private readonly IEntropySource mEntropySource;
private readonly int mSecurityStrength;
private readonly int mSeedLength;
private byte[] mV;
private byte[] mC;
private long mReseedCounter;
/**
* Construct a SP800-90A Hash DRBG.
* <p>
* Minimum entropy requirement is the security strength requested.
* </p>
* @param digest source digest to use for DRB stream.
* @param securityStrength security strength required (in bits)
* @param entropySource source of entropy to use for seeding/reseeding.
* @param personalizationString personalization string to distinguish this DRBG (may be null).
* @param nonce nonce to further distinguish this DRBG (may be null).
*/
public HashSP800Drbg(IDigest digest, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(digest))
throw new ArgumentException("Requested security strength is not supported by the derivation function");
if (entropySource.EntropySize < securityStrength)
throw new ArgumentException("Not enough entropy for security strength required");
mDigest = digest;
mEntropySource = entropySource;
mSecurityStrength = securityStrength;
mSeedLength = SeedLens[digest.AlgorithmName];
// 1. seed_material = entropy_input || nonce || personalization_string.
// 2. seed = Hash_df (seed_material, seedlen).
// 3. V = seed.
// 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed V with a byte
// of zeros.
// 5. reseed_counter = 1.
// 6. Return V, C, and reseed_counter as the initial_working_state
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
mV = new byte[(mSeedLength + 7) / 8];
DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength, mV);
byte[] subV = new byte[mV.Length + 1];
Array.Copy(mV, 0, subV, 1, mV.Length);
mC = new byte[(mSeedLength + 7) / 8];
DrbgUtilities.HashDF(mDigest, subV, mSeedLength, mC);
mReseedCounter = 1;
}
/**
* Return the block size (in bits) of the DRBG.
*
* @return the number of bits produced on each internal round of the DRBG.
*/
public int BlockSize
{
get { return mDigest.GetDigestSize() * 8; }
}
/**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
* @param additionalInput additional input to be added to the DRBG in this step.
* @param predictionResistant true if a reseed should be forced, false otherwise.
*
* @return number of bits generated, -1 if a reseed required.
*/
public int Generate(byte[] output, int outputOff, int outputLen, byte[] additionalInput,
bool predictionResistant)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
return additionalInput == null
? Generate(output.AsSpan(outputOff, outputLen), predictionResistant)
: GenerateWithInput(output.AsSpan(outputOff, outputLen), additionalInput.AsSpan(), predictionResistant);
#else
// 1. If reseed_counter > reseed_interval, then return an indication that a
// reseed is required.
// 2. If (additional_input != Null), then do
// 2.1 w = Hash (0x02 || V || additional_input).
// 2.2 V = (V + w) mod 2^seedlen
// .
// 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
// 4. H = Hash (0x03 || V).
// 5. V = (V + H + C + reseed_counter) mod 2^seedlen
// .
// 6. reseed_counter = reseed_counter + 1.
// 7. Return SUCCESS, returned_bits, and the new values of V, C, and
// reseed_counter for the new_working_state.
int numberOfBits = outputLen * 8;
if (numberOfBits > MAX_BITS_REQUEST)
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
if (mReseedCounter > RESEED_MAX)
return -1;
if (predictionResistant)
{
Reseed(additionalInput);
additionalInput = null;
}
// 2.
if (additionalInput != null)
{
byte[] newInput = new byte[1 + mV.Length + additionalInput.Length];
newInput[0] = 0x02;
Array.Copy(mV, 0, newInput, 1, mV.Length);
Array.Copy(additionalInput, 0, newInput, 1 + mV.Length, additionalInput.Length);
byte[] w = Hash(newInput);
AddTo(mV, w);
}
// 3.
byte[] rv = Hashgen(mV, outputLen);
// 4.
byte[] subH = new byte[mV.Length + 1];
Array.Copy(mV, 0, subH, 1, mV.Length);
subH[0] = 0x03;
byte[] H = Hash(subH);
// 5.
AddTo(mV, H);
AddTo(mV, mC);
byte[] c = new byte[4];
Pack.UInt32_To_BE((uint)mReseedCounter, c);
AddTo(mV, c);
mReseedCounter++;
Array.Copy(rv, 0, output, outputOff, outputLen);
return numberOfBits;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
public int Generate(Span<byte> output, bool predictionResistant)
{
// 1. If reseed_counter > reseed_interval, then return an indication that a
// reseed is required.
// 2. If (additional_input != Null), then do
// 2.1 w = Hash (0x02 || V || additional_input).
// 2.2 V = (V + w) mod 2^seedlen
// .
// 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
// 4. H = Hash (0x03 || V).
// 5. V = (V + H + C + reseed_counter) mod 2^seedlen
// .
// 6. reseed_counter = reseed_counter + 1.
// 7. Return SUCCESS, returned_bits, and the new values of V, C, and
// reseed_counter for the new_working_state.
int numberOfBits = output.Length * 8;
if (numberOfBits > MAX_BITS_REQUEST)
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
if (mReseedCounter > RESEED_MAX)
return -1;
if (predictionResistant)
{
Reseed(ReadOnlySpan<byte>.Empty);
}
return ImplGenerate(output);
}
public int GenerateWithInput(Span<byte> output, ReadOnlySpan<byte> additionalInput, bool predictionResistant)
{
// 1. If reseed_counter > reseed_interval, then return an indication that a
// reseed is required.
// 2. If (additional_input != Null), then do
// 2.1 w = Hash (0x02 || V || additional_input).
// 2.2 V = (V + w) mod 2^seedlen
// .
// 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
// 4. H = Hash (0x03 || V).
// 5. V = (V + H + C + reseed_counter) mod 2^seedlen
// .
// 6. reseed_counter = reseed_counter + 1.
// 7. Return SUCCESS, returned_bits, and the new values of V, C, and
// reseed_counter for the new_working_state.
int numberOfBits = output.Length * 8;
if (numberOfBits > MAX_BITS_REQUEST)
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
if (mReseedCounter > RESEED_MAX)
return -1;
if (predictionResistant)
{
Reseed(additionalInput);
}
else
{
// 2.
mDigest.Update(0x02);
mDigest.BlockUpdate(mV);
mDigest.BlockUpdate(additionalInput);
int digestSize = mDigest.GetDigestSize();
Span<byte> w = digestSize <= 128
? stackalloc byte[digestSize]
: new byte[digestSize];
mDigest.DoFinal(w);
AddTo(mV, w);
}
return ImplGenerate(output);
}
private int ImplGenerate(Span<byte> output)
{
// 3.
Hashgen(mV, output);
// 4.
mDigest.Update(0x03);
mDigest.BlockUpdate(mV);
int digestSize = mDigest.GetDigestSize();
Span<byte> H = digestSize <= 128
? stackalloc byte[digestSize]
: new byte[digestSize];
mDigest.DoFinal(H);
// 5.
AddTo(mV, H);
AddTo(mV, mC);
Span<byte> c = stackalloc byte[4];
Pack.UInt32_To_BE((uint)mReseedCounter, c);
AddTo(mV, c);
mReseedCounter++;
return output.Length * 8;
}
#endif
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return entropy;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private int GetEntropy(Span<byte> output)
{
int length = mEntropySource.GetEntropy(output);
if (length < (mSecurityStrength + 7) / 8)
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return length;
}
private int GetEntropyLength()
{
return (mEntropySource.EntropySize + 7) / 8;
}
#endif
// this will always add the shorter length byte array mathematically to the
// longer length byte array.
// be careful....
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void AddTo(Span<byte> longer, ReadOnlySpan<byte> shorter)
#else
private void AddTo(byte[] longer, byte[] shorter)
#endif
{
int off = longer.Length - shorter.Length;
uint carry = 0;
int i = shorter.Length;
while (--i >= 0)
{
carry += (uint)longer[off + i] + shorter[i];
longer[off + i] = (byte)carry;
carry >>= 8;
}
i = off;
while (--i >= 0)
{
carry += longer[i];
longer[i] = (byte)carry;
carry >>= 8;
}
}
/**
* Reseed the DRBG.
*
* @param additionalInput additional input to be added to the DRBG in this step.
*/
public void Reseed(byte[] additionalInput)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
Reseed(Spans.FromNullableReadOnly(additionalInput));
#else
// 1. seed_material = 0x01 || V || entropy_input || additional_input.
//
// 2. seed = Hash_df (seed_material, seedlen).
//
// 3. V = seed.
//
// 4. C = Hash_df ((0x00 || V), seedlen).
//
// 5. reseed_counter = 1.
//
// 6. Return V, C, and reseed_counter for the new_working_state.
//
// Comment: Precede with a byte of all zeros.
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.ConcatenateAll(ONE, mV, entropy, additionalInput);
DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength, mV);
byte[] subV = new byte[mV.Length + 1];
subV[0] = 0x00;
Array.Copy(mV, 0, subV, 1, mV.Length);
DrbgUtilities.HashDF(mDigest, subV, mSeedLength, mC);
mReseedCounter = 1;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
public void Reseed(ReadOnlySpan<byte> additionalInput)
{
// 1. seed_material = 0x01 || V || entropy_input || additional_input.
//
// 2. seed = Hash_df (seed_material, seedlen).
//
// 3. V = seed.
//
// 4. C = Hash_df ((0x00 || V), seedlen).
//
// 5. reseed_counter = 1.
//
// 6. Return V, C, and reseed_counter for the new_working_state.
//
// Comment: Precede with a byte of all zeros.
int entropyLength = GetEntropyLength();
int seedMaterialLength = 1 + mV.Length + entropyLength + additionalInput.Length;
Span<byte> seedMaterial = seedMaterialLength <= 256
? stackalloc byte[seedMaterialLength]
: new byte[seedMaterialLength];
seedMaterial[0] = 0x01;
mV.CopyTo(seedMaterial[1..]);
GetEntropy(seedMaterial[(1 + mV.Length)..]);
additionalInput.CopyTo(seedMaterial[(1 + mV.Length + entropyLength)..]);
DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength, mV);
int subVLength = 1 + mV.Length;
Span<byte> subV = subVLength <= 128
? stackalloc byte[subVLength]
: new byte[subVLength];
subV[0] = 0x00;
mV.CopyTo(subV[1..]);
DrbgUtilities.HashDF(mDigest, subV, mSeedLength, mC);
mReseedCounter = 1;
}
#endif
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void DoHash(ReadOnlySpan<byte> input, Span<byte> output)
{
mDigest.BlockUpdate(input);
mDigest.DoFinal(output);
}
#else
private void DoHash(byte[] input, byte[] output)
{
mDigest.BlockUpdate(input, 0, input.Length);
mDigest.DoFinal(output, 0);
}
private byte[] Hash(byte[] input)
{
byte[] hash = new byte[mDigest.GetDigestSize()];
DoHash(input, hash);
return hash;
}
#endif
// 1. m = [requested_number_of_bits / outlen]
// 2. data = V.
// 3. W = the Null string.
// 4. For i = 1 to m
// 4.1 wi = Hash (data).
// 4.2 W = W || wi.
// 4.3 data = (data + 1) mod 2^seedlen
// .
// 5. returned_bits = Leftmost (requested_no_of_bits) bits of W.
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
private void Hashgen(ReadOnlySpan<byte> input, Span<byte> output)
{
int digestSize = mDigest.GetDigestSize();
int m = output.Length / digestSize;
int dataSize = input.Length;
Span<byte> data = dataSize <= 256
? stackalloc byte[input.Length]
: new byte[input.Length];
input.CopyTo(data);
Span<byte> dig = digestSize <= 128
? stackalloc byte[digestSize]
: new byte[digestSize];
for (int i = 0; i <= m; i++)
{
DoHash(data, dig);
int bytesToCopy = System.Math.Min(digestSize, output.Length - i * digestSize);
dig[..bytesToCopy].CopyTo(output[(i * digestSize)..]);
AddTo(data, ONE);
}
}
#else
private byte[] Hashgen(byte[] input, int length)
{
int digestSize = mDigest.GetDigestSize();
int m = length / digestSize;
byte[] data = (byte[])input.Clone();
byte[] W = new byte[length];
byte[] dig = new byte[digestSize];
for (int i = 0; i <= m; i++)
{
DoHash(data, dig);
int bytesToCopy = System.Math.Min(digestSize, length - i * digestSize);
Array.Copy(dig, 0, W, i * digestSize, bytesToCopy);
AddTo(data, ONE);
}
return W;
}
#endif
}
}
#pragma warning restore
#endif

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0107b79a063371b4e81b74d67d109eb0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 267636
packageName: Best HTTP
packageVersion: 3.0.17
assetPath: Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/prng/drbg/HashSP800Drbg.cs
uploadId: 783279

View File

@ -0,0 +1,49 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng.Drbg
{
/**
* Interface to SP800-90A deterministic random bit generators.
*/
public interface ISP80090Drbg
{
/**
* Return the block size of the DRBG.
*
* @return the block size (in bits) produced by each round of the DRBG.
*/
int BlockSize { get; }
/**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
* @param additionalInput additional input to be added to the DRBG in this step.
* @param predictionResistant true if a reseed should be forced, false otherwise.
*
* @return number of bits generated, -1 if a reseed required.
*/
int Generate(byte[] output, int outputOff, int outputLen, byte[] additionalInput, bool predictionResistant);
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
int Generate(Span<byte> output, bool predictionResistant);
int GenerateWithInput(Span<byte> output, ReadOnlySpan<byte> additionalInput, bool predictionResistant);
#endif
/**
* Reseed the DRBG.
*
* @param additionalInput additional input to be added to the DRBG in this step.
*/
void Reseed(byte[] additionalInput);
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
void Reseed(ReadOnlySpan<byte> additionalInput);
#endif
}
}
#pragma warning restore
#endif

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 3b5b62d297e2ef945ab39de2e2f84832
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 267636
packageName: Best HTTP
packageVersion: 3.0.17
assetPath: Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/prng/drbg/ISP80090Drbg.cs
uploadId: 783279