- Initial commit
This commit is contained in:
351
Runtime/3rdParty/BouncyCastle/crypto/prng/drbg/HMacSP800Drbg.cs
vendored
Normal file
351
Runtime/3rdParty/BouncyCastle/crypto/prng/drbg/HMacSP800Drbg.cs
vendored
Normal 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
|
||||
Reference in New Issue
Block a user