init commit

This commit is contained in:
2025-10-09 09:57:24 +09:00
commit 4d551bd74f
6636 changed files with 1218703 additions and 0 deletions

View File

@@ -0,0 +1,303 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
public class CtrSP800Drbg : ISP80090Drbg
{
private static readonly long TDEA_RESEED_MAX = 2147483648L;
private static readonly long AES_RESEED_MAX = 140737488355328L;
private static readonly int TDEA_MAX_BITS_REQUEST = 4096;
private static readonly int AES_MAX_BITS_REQUEST = 262144;
private readonly IEntropySource mEntropySource;
private readonly IBlockCipher mEngine;
private readonly int mKeySizeInBits;
private readonly int mSeedLength;
private readonly int mSecurityStrength;
private byte[] mKey;
private byte[] mV;
private long mReseedCounter = 0L;
private bool mIsTdea = false;
private static readonly byte[] K_BITS = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
public int BlockSize => mV.Length * 8;
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);
byte[] entropy = GetEntropy();
CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
}
private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce, byte[] personalisationString)
{
byte[] inputString = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
byte[] seed = Block_Cipher_df(inputString, mSeedLength);
int blockSize = mEngine.GetBlockSize();
mKey = new byte[(mKeySizeInBits + 7) / 8];
mV = new byte[blockSize];
CTR_DRBG_Update(seed, mKey, mV);
mReseedCounter = 1L;
}
private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
{
byte[] array = new byte[seed.Length];
byte[] array2 = new byte[mEngine.GetBlockSize()];
int i = 0;
int blockSize = mEngine.GetBlockSize();
mEngine.Init(forEncryption: true, new KeyParameter(ExpandKey(key)));
for (; i * blockSize < seed.Length; i++)
{
AddOneTo(v);
mEngine.ProcessBlock(v, 0, array2, 0);
int length = ((array.Length - i * blockSize > blockSize) ? blockSize : (array.Length - i * blockSize));
Array.Copy(array2, 0, array, i * blockSize, length);
}
XOR(array, seed, array, 0);
Array.Copy(array, 0, key, 0, key.Length);
Array.Copy(array, key.Length, v, 0, v.Length);
}
private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput)
{
byte[] inputString = Arrays.Concatenate(GetEntropy(), additionalInput);
inputString = Block_Cipher_df(inputString, mSeedLength);
CTR_DRBG_Update(inputString, mKey, mV);
mReseedCounter = 1L;
}
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]);
}
}
private void AddOneTo(byte[] longer)
{
uint num = 1u;
int num2 = longer.Length;
while (--num2 >= 0)
{
num += longer[num2];
longer[num2] = (byte)num;
num >>= 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;
}
private byte[] Block_Cipher_df(byte[] inputString, int bitLength)
{
int blockSize = mEngine.GetBlockSize();
int num = inputString.Length;
int value = bitLength / 8;
int num2 = 8 + num + 1;
int num3 = (num2 + blockSize - 1) / blockSize * blockSize;
byte[] array = new byte[num3];
copyIntToByteArray(array, num, 0);
copyIntToByteArray(array, value, 4);
Array.Copy(inputString, 0, array, 8, num);
array[8 + num] = 128;
byte[] array2 = new byte[mKeySizeInBits / 8 + blockSize];
byte[] array3 = new byte[blockSize];
byte[] array4 = new byte[blockSize];
int i = 0;
byte[] array5 = new byte[mKeySizeInBits / 8];
Array.Copy(K_BITS, 0, array5, 0, array5.Length);
for (; i * blockSize * 8 < mKeySizeInBits + blockSize * 8; i++)
{
copyIntToByteArray(array4, i, 0);
BCC(array3, array5, array4, array);
int length = ((array2.Length - i * blockSize > blockSize) ? blockSize : (array2.Length - i * blockSize));
Array.Copy(array3, 0, array2, i * blockSize, length);
}
byte[] array6 = new byte[blockSize];
Array.Copy(array2, 0, array5, 0, array5.Length);
Array.Copy(array2, array5.Length, array6, 0, array6.Length);
array2 = new byte[bitLength / 2];
i = 0;
mEngine.Init(forEncryption: true, new KeyParameter(ExpandKey(array5)));
for (; i * blockSize < array2.Length; i++)
{
mEngine.ProcessBlock(array6, 0, array6, 0);
int length2 = ((array2.Length - i * blockSize > blockSize) ? blockSize : (array2.Length - i * blockSize));
Array.Copy(array6, 0, array2, i * blockSize, length2);
}
return array2;
}
private void BCC(byte[] bccOut, byte[] k, byte[] iV, byte[] data)
{
int blockSize = mEngine.GetBlockSize();
byte[] array = new byte[blockSize];
int num = data.Length / blockSize;
byte[] array2 = new byte[blockSize];
mEngine.Init(forEncryption: true, new KeyParameter(ExpandKey(k)));
mEngine.ProcessBlock(iV, 0, array, 0);
for (int i = 0; i < num; i++)
{
XOR(array2, array, data, i * blockSize);
mEngine.ProcessBlock(array2, 0, array, 0);
}
Array.Copy(array, 0, bccOut, 0, bccOut.Length);
}
private void copyIntToByteArray(byte[] buf, int value, int offSet)
{
buf[offSet] = (byte)(value >> 24);
buf[offSet + 1] = (byte)(value >> 16);
buf[offSet + 2] = (byte)(value >> 8);
buf[offSet + 3] = (byte)value;
}
public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
{
if (mIsTdea)
{
if (mReseedCounter > TDEA_RESEED_MAX)
{
return -1;
}
if (DrbgUtilities.IsTooLarge(output, 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 (DrbgUtilities.IsTooLarge(output, 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 = Block_Cipher_df(additionalInput, mSeedLength);
CTR_DRBG_Update(additionalInput, mKey, mV);
}
else
{
additionalInput = new byte[mSeedLength];
}
byte[] array = new byte[mV.Length];
mEngine.Init(forEncryption: true, new KeyParameter(ExpandKey(mKey)));
for (int i = 0; i <= output.Length / array.Length; i++)
{
int num = ((output.Length - i * array.Length > array.Length) ? array.Length : (output.Length - i * mV.Length));
if (num != 0)
{
AddOneTo(mV);
mEngine.ProcessBlock(mV, 0, array, 0);
Array.Copy(array, 0, output, i * array.Length, num);
}
}
CTR_DRBG_Update(additionalInput, mKey, mV);
mReseedCounter++;
return output.Length * 8;
}
public void Reseed(byte[] additionalInput)
{
CTR_DRBG_Reseed_algorithm(additionalInput);
}
private bool IsTdea(IBlockCipher cipher)
{
if (!cipher.AlgorithmName.Equals("DESede"))
{
return cipher.AlgorithmName.Equals("TDEA");
}
return true;
}
private int GetMaxSecurityStrength(IBlockCipher cipher, int keySizeInBits)
{
if (IsTdea(cipher) && keySizeInBits == 168)
{
return 112;
}
if (cipher.AlgorithmName.Equals("AES"))
{
return keySizeInBits;
}
return -1;
}
private byte[] ExpandKey(byte[] key)
{
if (mIsTdea)
{
byte[] array = new byte[24];
PadKey(key, 0, array, 0);
PadKey(key, 7, array, 8);
PadKey(key, 14, array, 16);
return array;
}
return key;
}
private void PadKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
{
tmp[tmpOff] = (byte)(keyMaster[keyOff] & 0xFE);
tmp[tmpOff + 1] = (byte)((keyMaster[keyOff] << 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);
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
internal class DrbgUtilities
{
private static readonly IDictionary maxSecurityStrengths;
static DrbgUtilities()
{
maxSecurityStrengths = Platform.CreateHashtable();
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 (int)maxSecurityStrengths[d.AlgorithmName];
}
internal static int GetMaxSecurityStrength(IMac m)
{
string algorithmName = m.AlgorithmName;
return (int)maxSecurityStrengths[algorithmName.Substring(0, algorithmName.IndexOf("/"))];
}
internal static byte[] HashDF(IDigest digest, byte[] seedMaterial, int seedLength)
{
byte[] array = new byte[(seedLength + 7) / 8];
int num = array.Length / digest.GetDigestSize();
int num2 = 1;
byte[] array2 = new byte[digest.GetDigestSize()];
for (int i = 0; i <= num; i++)
{
digest.Update((byte)num2);
digest.Update((byte)(seedLength >> 24));
digest.Update((byte)(seedLength >> 16));
digest.Update((byte)(seedLength >> 8));
digest.Update((byte)seedLength);
digest.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
digest.DoFinal(array2, 0);
int length = ((array.Length - i * array2.Length > array2.Length) ? array2.Length : (array.Length - i * array2.Length));
Array.Copy(array2, 0, array, i * array2.Length, length);
num2++;
}
if (seedLength % 8 != 0)
{
int num3 = 8 - seedLength % 8;
uint num4 = 0u;
for (int j = 0; j != array.Length; j++)
{
uint num5 = array[j];
array[j] = (byte)((num5 >> num3) | (num4 << 8 - num3));
num4 = num5;
}
}
return array;
}
internal static bool IsTooLarge(byte[] bytes, int maxBytes)
{
if (bytes != null)
{
return bytes.Length > maxBytes;
}
return false;
}
}

View File

@@ -0,0 +1,131 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
public class HMacSP800Drbg : ISP80090Drbg
{
private static readonly long RESEED_MAX = 140737488355328L;
private static readonly int MAX_BITS_REQUEST = 262144;
private readonly byte[] mK;
private readonly byte[] mV;
private readonly IEntropySource mEntropySource;
private readonly IMac mHMac;
private readonly int mSecurityStrength;
private long mReseedCounter;
public int BlockSize => mV.Length * 8;
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, 1);
hmac_DRBG_Update(seedMaterial);
mReseedCounter = 1L;
}
private void hmac_DRBG_Update(byte[] seedMaterial)
{
hmac_DRBG_Update_Func(seedMaterial, 0);
if (seedMaterial != null)
{
hmac_DRBG_Update_Func(seedMaterial, 1);
}
}
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);
}
public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
{
int num = output.Length * 8;
if (num > 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;
}
if (additionalInput != null)
{
hmac_DRBG_Update(additionalInput);
}
byte[] array = new byte[output.Length];
int num2 = output.Length / mV.Length;
mHMac.Init(new KeyParameter(mK));
for (int i = 0; i < num2; i++)
{
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.DoFinal(mV, 0);
Array.Copy(mV, 0, array, i * mV.Length, mV.Length);
}
if (num2 * mV.Length < array.Length)
{
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.DoFinal(mV, 0);
Array.Copy(mV, 0, array, num2 * mV.Length, array.Length - num2 * mV.Length);
}
hmac_DRBG_Update(additionalInput);
mReseedCounter++;
Array.Copy(array, 0, output, 0, output.Length);
return num;
}
public void Reseed(byte[] additionalInput)
{
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.Concatenate(entropy, additionalInput);
hmac_DRBG_Update(seedMaterial);
mReseedCounter = 1L;
}
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
{
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
}
return entropy;
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Collections;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
public class HashSP800Drbg : ISP80090Drbg
{
private static readonly byte[] ONE;
private static readonly long RESEED_MAX;
private static readonly int MAX_BITS_REQUEST;
private static readonly IDictionary seedlens;
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;
public int BlockSize => mDigest.GetDigestSize() * 8;
static HashSP800Drbg()
{
ONE = new byte[1] { 1 };
RESEED_MAX = 140737488355328L;
MAX_BITS_REQUEST = 262144;
seedlens = Platform.CreateHashtable();
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);
}
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 = (int)seedlens[digest.AlgorithmName];
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
byte[] array = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
mV = array;
byte[] array2 = new byte[mV.Length + 1];
Array.Copy(mV, 0, array2, 1, mV.Length);
mC = DrbgUtilities.HashDF(mDigest, array2, mSeedLength);
mReseedCounter = 1L;
}
public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
{
int num = output.Length * 8;
if (num > 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;
}
if (additionalInput != null)
{
byte[] array = new byte[1 + mV.Length + additionalInput.Length];
array[0] = 2;
Array.Copy(mV, 0, array, 1, mV.Length);
Array.Copy(additionalInput, 0, array, 1 + mV.Length, additionalInput.Length);
byte[] shorter = Hash(array);
AddTo(mV, shorter);
}
byte[] sourceArray = hashgen(mV, num);
byte[] array2 = new byte[mV.Length + 1];
Array.Copy(mV, 0, array2, 1, mV.Length);
array2[0] = 3;
byte[] shorter2 = Hash(array2);
AddTo(mV, shorter2);
AddTo(mV, mC);
AddTo(shorter: new byte[4]
{
(byte)(mReseedCounter >> 24),
(byte)(mReseedCounter >> 16),
(byte)(mReseedCounter >> 8),
(byte)mReseedCounter
}, longer: mV);
mReseedCounter++;
Array.Copy(sourceArray, 0, output, 0, output.Length);
return num;
}
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
{
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
}
return entropy;
}
private void AddTo(byte[] longer, byte[] shorter)
{
int num = longer.Length - shorter.Length;
uint num2 = 0u;
int num3 = shorter.Length;
while (--num3 >= 0)
{
num2 += (uint)(longer[num + num3] + shorter[num3]);
longer[num + num3] = (byte)num2;
num2 >>= 8;
}
num3 = num;
while (--num3 >= 0)
{
num2 += longer[num3];
longer[num3] = (byte)num2;
num2 >>= 8;
}
}
public void Reseed(byte[] additionalInput)
{
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.ConcatenateAll(ONE, mV, entropy, additionalInput);
byte[] array = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
mV = array;
byte[] array2 = new byte[mV.Length + 1];
array2[0] = 0;
Array.Copy(mV, 0, array2, 1, mV.Length);
mC = DrbgUtilities.HashDF(mDigest, array2, mSeedLength);
mReseedCounter = 1L;
}
private byte[] Hash(byte[] input)
{
byte[] array = new byte[mDigest.GetDigestSize()];
DoHash(input, array);
return array;
}
private void DoHash(byte[] input, byte[] output)
{
mDigest.BlockUpdate(input, 0, input.Length);
mDigest.DoFinal(output, 0);
}
private byte[] hashgen(byte[] input, int lengthInBits)
{
int digestSize = mDigest.GetDigestSize();
int num = lengthInBits / 8 / digestSize;
byte[] array = new byte[input.Length];
Array.Copy(input, 0, array, 0, input.Length);
byte[] array2 = new byte[lengthInBits / 8];
byte[] array3 = new byte[mDigest.GetDigestSize()];
for (int i = 0; i <= num; i++)
{
DoHash(array, array3);
int length = ((array2.Length - i * array3.Length > array3.Length) ? array3.Length : (array2.Length - i * array3.Length));
Array.Copy(array3, 0, array2, i * array3.Length, length);
AddTo(array, ONE);
}
return array2;
}
}

View File

@@ -0,0 +1,10 @@
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
public interface ISP80090Drbg
{
int BlockSize { get; }
int Generate(byte[] output, byte[] additionalInput, bool predictionResistant);
void Reseed(byte[] additionalInput);
}