培训考核三期,新版培训,网页版培训登录器
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.
 
 

150 lines
4.4 KiB

#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng
{
internal class X931Rng
{
private const long BLOCK64_RESEED_MAX = 1L << (16 - 1);
private const long BLOCK128_RESEED_MAX = 1L << (24 - 1);
private const int BLOCK64_MAX_BITS_REQUEST = 1 << (13 - 1);
private const int BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
private readonly IBlockCipher mEngine;
private readonly IEntropySource mEntropySource;
private readonly byte[] mDT;
private readonly byte[] mI;
private readonly byte[] mR;
private byte[] mV;
private long mReseedCounter = 1;
/**
*
* @param engine
* @param entropySource
*/
internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource)
{
this.mEngine = engine;
this.mEntropySource = entropySource;
this.mDT = new byte[engine.GetBlockSize()];
Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length);
this.mI = new byte[engine.GetBlockSize()];
this.mR = new byte[engine.GetBlockSize()];
}
/**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
* @param predictionResistant true if a reseed should be forced, false otherwise.
*
* @return number of bits generated, -1 if a reseed required.
*/
internal int Generate(byte[] output, bool predictionResistant)
{
if (mR.Length == 8) // 64 bit block size
{
if (mReseedCounter > BLOCK64_RESEED_MAX)
return -1;
if (IsTooLarge(output, BLOCK64_MAX_BITS_REQUEST / 8))
throw new ArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST, "output");
}
else
{
if (mReseedCounter > BLOCK128_RESEED_MAX)
return -1;
if (IsTooLarge(output, BLOCK128_MAX_BITS_REQUEST / 8))
throw new ArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST, "output");
}
if (predictionResistant || mV == null)
{
mV = mEntropySource.GetEntropy();
if (mV.Length != mEngine.GetBlockSize())
throw new InvalidOperationException("Insufficient entropy returned");
}
int m = output.Length / mR.Length;
for (int i = 0; i < m; i++)
{
mEngine.ProcessBlock(mDT, 0, mI, 0);
Process(mR, mI, mV);
Process(mV, mR, mI);
Array.Copy(mR, 0, output, i * mR.Length, mR.Length);
Increment(mDT);
}
int bytesToCopy = (output.Length - m * mR.Length);
if (bytesToCopy > 0)
{
mEngine.ProcessBlock(mDT, 0, mI, 0);
Process(mR, mI, mV);
Process(mV, mR, mI);
Array.Copy(mR, 0, output, m * mR.Length, bytesToCopy);
Increment(mDT);
}
mReseedCounter++;
return output.Length;
}
/**
* Reseed the RNG.
*/
internal void Reseed()
{
mV = mEntropySource.GetEntropy();
if (mV.Length != mEngine.GetBlockSize())
throw new InvalidOperationException("Insufficient entropy returned");
mReseedCounter = 1;
}
internal IEntropySource EntropySource
{
get { return mEntropySource; }
}
private void Process(byte[] res, byte[] a, byte[] b)
{
for (int i = 0; i != res.Length; i++)
{
res[i] = (byte)(a[i] ^ b[i]);
}
mEngine.ProcessBlock(res, 0, res, 0);
}
private void Increment(byte[] val)
{
for (int i = val.Length - 1; i >= 0; i--)
{
if (++val[i] != 0)
break;
}
}
private static bool IsTooLarge(byte[] bytes, int maxBytes)
{
return bytes != null && bytes.Length > maxBytes;
}
}
}
#pragma warning restore
#endif