Initial Commit
This commit is contained in:
141
iTechSharp/srcbc/crypto/generators/BaseKdfBytesGenerator.cs
Normal file
141
iTechSharp/srcbc/crypto/generators/BaseKdfBytesGenerator.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
|
||||
* <br/>
|
||||
* This implementation is based on ISO 18033/P1363a.
|
||||
*/
|
||||
public class BaseKdfBytesGenerator
|
||||
: IDerivationFunction
|
||||
{
|
||||
private int counterStart;
|
||||
private IDigest digest;
|
||||
private byte[] shared;
|
||||
private byte[] iv;
|
||||
|
||||
/**
|
||||
* Construct a KDF Parameters generator.
|
||||
*
|
||||
* @param counterStart value of counter.
|
||||
* @param digest the digest to be used as the source of derived keys.
|
||||
*/
|
||||
protected BaseKdfBytesGenerator(
|
||||
int counterStart,
|
||||
IDigest digest)
|
||||
{
|
||||
this.counterStart = counterStart;
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
public void Init(
|
||||
IDerivationParameters parameters)
|
||||
{
|
||||
if (parameters is KdfParameters)
|
||||
{
|
||||
KdfParameters p = (KdfParameters)parameters;
|
||||
|
||||
shared = p.GetSharedSecret();
|
||||
iv = p.GetIV();
|
||||
}
|
||||
else if (parameters is Iso18033KdfParameters)
|
||||
{
|
||||
Iso18033KdfParameters p = (Iso18033KdfParameters)parameters;
|
||||
|
||||
shared = p.GetSeed();
|
||||
iv = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("KDF parameters required for KDF Generator");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying digest.
|
||||
*/
|
||||
public IDigest Digest
|
||||
{
|
||||
get
|
||||
{
|
||||
return digest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fill len bytes of the output buffer with bytes generated from
|
||||
* the derivation function.
|
||||
*
|
||||
* @throws ArgumentException if the size of the request will cause an overflow.
|
||||
* @throws DataLengthException if the out buffer is too small.
|
||||
*/
|
||||
public int GenerateBytes(
|
||||
byte[] output,
|
||||
int outOff,
|
||||
int length)
|
||||
{
|
||||
if ((output.Length - length) < outOff)
|
||||
{
|
||||
throw new DataLengthException("output buffer too small");
|
||||
}
|
||||
|
||||
long oBytes = length;
|
||||
int outLen = digest.GetDigestSize();
|
||||
|
||||
//
|
||||
// this is at odds with the standard implementation, the
|
||||
// maximum value should be hBits * (2^32 - 1) where hBits
|
||||
// is the digest output size in bits. We can't have an
|
||||
// array with a long index at the moment...
|
||||
//
|
||||
if (oBytes > ((2L << 32) - 1))
|
||||
{
|
||||
throw new ArgumentException("Output length too large");
|
||||
}
|
||||
|
||||
int cThreshold = (int)((oBytes + outLen - 1) / outLen);
|
||||
|
||||
byte[] dig = new byte[digest.GetDigestSize()];
|
||||
|
||||
int counter = counterStart;
|
||||
|
||||
for (int i = 0; i < cThreshold; i++)
|
||||
{
|
||||
digest.BlockUpdate(shared, 0, shared.Length);
|
||||
|
||||
digest.Update((byte)(counter >> 24));
|
||||
digest.Update((byte)(counter >> 16));
|
||||
digest.Update((byte)(counter >> 8));
|
||||
digest.Update((byte)counter);
|
||||
|
||||
if (iv != null)
|
||||
{
|
||||
digest.BlockUpdate(iv, 0, iv.Length);
|
||||
}
|
||||
|
||||
digest.DoFinal(dig, 0);
|
||||
|
||||
if (length > outLen)
|
||||
{
|
||||
Array.Copy(dig, 0, output, outOff, outLen);
|
||||
outOff += outLen;
|
||||
length -= outLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(dig, 0, output, outOff, length);
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
digest.Reset();
|
||||
|
||||
return (int)oBytes;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* a basic Diffie-Helman key pair generator.
|
||||
*
|
||||
* This Generates keys consistent for use with the basic algorithm for
|
||||
* Diffie-Helman.
|
||||
*/
|
||||
public class DHBasicKeyPairGenerator
|
||||
: IAsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private DHKeyGenerationParameters param;
|
||||
|
||||
public virtual void Init(
|
||||
KeyGenerationParameters parameters)
|
||||
{
|
||||
this.param = (DHKeyGenerationParameters) parameters;
|
||||
}
|
||||
|
||||
public virtual AsymmetricCipherKeyPair GenerateKeyPair()
|
||||
{
|
||||
DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
|
||||
DHParameters dhParams = param.Parameters;
|
||||
|
||||
BigInteger p = dhParams.P;
|
||||
BigInteger x = helper.CalculatePrivate(p, param.Random, dhParams.L);
|
||||
BigInteger y = helper.CalculatePublic(p, dhParams.G, x);
|
||||
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new DHPublicKeyParameters(y, dhParams),
|
||||
new DHPrivateKeyParameters(x, dhParams));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
78
iTechSharp/srcbc/crypto/generators/DHKeyGeneratorHelper.cs
Normal file
78
iTechSharp/srcbc/crypto/generators/DHKeyGeneratorHelper.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
class DHKeyGeneratorHelper
|
||||
{
|
||||
private const int MAX_ITERATIONS = 1000;
|
||||
|
||||
internal static readonly DHKeyGeneratorHelper Instance = new DHKeyGeneratorHelper();
|
||||
|
||||
private DHKeyGeneratorHelper()
|
||||
{
|
||||
}
|
||||
|
||||
internal BigInteger CalculatePrivate(
|
||||
BigInteger p,
|
||||
SecureRandom random,
|
||||
int limit)
|
||||
{
|
||||
//
|
||||
// calculate the private key
|
||||
//
|
||||
BigInteger pSub2 = p.Subtract(BigInteger.Two);
|
||||
BigInteger x;
|
||||
|
||||
if (limit == 0)
|
||||
{
|
||||
x = createInRange(pSub2, random);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
// TODO Check this (should the generated numbers always be odd,
|
||||
// and length 'limit'?)
|
||||
x = new BigInteger(limit, 0, random);
|
||||
}
|
||||
while (x.SignValue == 0);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
private BigInteger createInRange(
|
||||
BigInteger max,
|
||||
SecureRandom random)
|
||||
{
|
||||
BigInteger x;
|
||||
int maxLength = max.BitLength;
|
||||
int count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
x = new BigInteger(maxLength, random);
|
||||
count++;
|
||||
}
|
||||
while ((x.SignValue == 0 || x.CompareTo(max) > 0) && count != MAX_ITERATIONS);
|
||||
|
||||
if (count == MAX_ITERATIONS) // fall back to a faster (restricted) method
|
||||
{
|
||||
return new BigInteger(maxLength - 1, random).SetBit(0);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
internal BigInteger CalculatePublic(
|
||||
BigInteger p,
|
||||
BigInteger g,
|
||||
BigInteger x)
|
||||
{
|
||||
return g.ModPow(x, p);
|
||||
}
|
||||
}
|
||||
}
|
40
iTechSharp/srcbc/crypto/generators/DHKeyPairGenerator.cs
Normal file
40
iTechSharp/srcbc/crypto/generators/DHKeyPairGenerator.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* a Diffie-Helman key pair generator.
|
||||
*
|
||||
* This Generates keys consistent for use in the MTI/A0 key agreement protocol
|
||||
* as described in "Handbook of Applied Cryptography", Pages 516-519.
|
||||
*/
|
||||
public class DHKeyPairGenerator
|
||||
: IAsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private DHKeyGenerationParameters param;
|
||||
|
||||
public virtual void Init(
|
||||
KeyGenerationParameters parameters)
|
||||
{
|
||||
this.param = (DHKeyGenerationParameters) parameters;
|
||||
}
|
||||
|
||||
public virtual AsymmetricCipherKeyPair GenerateKeyPair()
|
||||
{
|
||||
DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
|
||||
DHParameters dhParams = param.Parameters;
|
||||
|
||||
BigInteger p = dhParams.P;
|
||||
BigInteger x = helper.CalculatePrivate(p, param.Random, dhParams.L);
|
||||
BigInteger y = helper.CalculatePublic(p, dhParams.G, x);
|
||||
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new DHPublicKeyParameters(y, dhParams),
|
||||
new DHPrivateKeyParameters(x, dhParams));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
45
iTechSharp/srcbc/crypto/generators/DHParametersGenerator.cs
Normal file
45
iTechSharp/srcbc/crypto/generators/DHParametersGenerator.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
public class DHParametersGenerator
|
||||
{
|
||||
private int size;
|
||||
private int certainty;
|
||||
private SecureRandom random;
|
||||
|
||||
public virtual void Init(
|
||||
int size,
|
||||
int certainty,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.size = size;
|
||||
this.certainty = certainty;
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
/**
|
||||
* which Generates the p and g values from the given parameters,
|
||||
* returning the DHParameters object.
|
||||
* <p>
|
||||
* Note: can take a while...</p>
|
||||
*/
|
||||
public virtual DHParameters GenerateParameters()
|
||||
{
|
||||
//
|
||||
// find a safe prime p where p = 2*q + 1, where p and q are prime.
|
||||
//
|
||||
BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random);
|
||||
|
||||
BigInteger p = safePrimes[0];
|
||||
BigInteger q = safePrimes[1];
|
||||
BigInteger g = DHParametersHelper.SelectGenerator(p, q, random);
|
||||
|
||||
return new DHParameters(p, g, q, BigInteger.Two, null);
|
||||
}
|
||||
}
|
||||
}
|
244
iTechSharp/srcbc/crypto/generators/DHParametersHelper.cs
Normal file
244
iTechSharp/srcbc/crypto/generators/DHParametersHelper.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
internal class DHParametersHelper
|
||||
{
|
||||
// The primes b/w 2 and ~2^10
|
||||
/*
|
||||
3 5 7 11 13 17 19 23 29
|
||||
31 37 41 43 47 53 59 61 67 71
|
||||
73 79 83 89 97 101 103 107 109 113
|
||||
127 131 137 139 149 151 157 163 167 173
|
||||
179 181 191 193 197 199 211 223 227 229
|
||||
233 239 241 251 257 263 269 271 277 281
|
||||
283 293 307 311 313 317 331 337 347 349
|
||||
353 359 367 373 379 383 389 397 401 409
|
||||
419 421 431 433 439 443 449 457 461 463
|
||||
467 479 487 491 499 503 509 521 523 541
|
||||
547 557 563 569 571 577 587 593 599 601
|
||||
607 613 617 619 631 641 643 647 653 659
|
||||
661 673 677 683 691 701 709 719 727 733
|
||||
739 743 751 757 761 769 773 787 797 809
|
||||
811 821 823 827 829 839 853 857 859 863
|
||||
877 881 883 887 907 911 919 929 937 941
|
||||
947 953 967 971 977 983 991 997
|
||||
1009 1013 1019 1021 1031
|
||||
*/
|
||||
|
||||
// Each list has a product < 2^31
|
||||
private static readonly int[][] primeLists = new int[][]
|
||||
{
|
||||
new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
|
||||
new int[]{ 29, 31, 37, 41, 43 },
|
||||
new int[]{ 47, 53, 59, 61, 67 },
|
||||
new int[]{ 71, 73, 79, 83 },
|
||||
new int[]{ 89, 97, 101, 103 },
|
||||
|
||||
new int[]{ 107, 109, 113, 127 },
|
||||
new int[]{ 131, 137, 139, 149 },
|
||||
new int[]{ 151, 157, 163, 167 },
|
||||
new int[]{ 173, 179, 181, 191 },
|
||||
new int[]{ 193, 197, 199, 211 },
|
||||
|
||||
new int[]{ 223, 227, 229 },
|
||||
new int[]{ 233, 239, 241 },
|
||||
new int[]{ 251, 257, 263 },
|
||||
new int[]{ 269, 271, 277 },
|
||||
new int[]{ 281, 283, 293 },
|
||||
|
||||
new int[]{ 307, 311, 313 },
|
||||
new int[]{ 317, 331, 337 },
|
||||
new int[]{ 347, 349, 353 },
|
||||
new int[]{ 359, 367, 373 },
|
||||
new int[]{ 379, 383, 389 },
|
||||
|
||||
new int[]{ 397, 401, 409 },
|
||||
new int[]{ 419, 421, 431 },
|
||||
new int[]{ 433, 439, 443 },
|
||||
new int[]{ 449, 457, 461 },
|
||||
new int[]{ 463, 467, 479 },
|
||||
|
||||
new int[]{ 487, 491, 499 },
|
||||
new int[]{ 503, 509, 521 },
|
||||
new int[]{ 523, 541, 547 },
|
||||
new int[]{ 557, 563, 569 },
|
||||
new int[]{ 571, 577, 587 },
|
||||
|
||||
new int[]{ 593, 599, 601 },
|
||||
new int[]{ 607, 613, 617 },
|
||||
new int[]{ 619, 631, 641 },
|
||||
new int[]{ 643, 647, 653 },
|
||||
new int[]{ 659, 661, 673 },
|
||||
|
||||
new int[]{ 677, 683, 691 },
|
||||
new int[]{ 701, 709, 719 },
|
||||
new int[]{ 727, 733, 739 },
|
||||
new int[]{ 743, 751, 757 },
|
||||
new int[]{ 761, 769, 773 },
|
||||
|
||||
new int[]{ 787, 797, 809 },
|
||||
new int[]{ 811, 821, 823 },
|
||||
new int[]{ 827, 829, 839 },
|
||||
new int[]{ 853, 857, 859 },
|
||||
new int[]{ 863, 877, 881 },
|
||||
|
||||
new int[]{ 883, 887, 907 },
|
||||
new int[]{ 911, 919, 929 },
|
||||
new int[]{ 937, 941, 947 },
|
||||
new int[]{ 953, 967, 971 },
|
||||
new int[]{ 977, 983, 991 },
|
||||
|
||||
new int[]{ 997, 1009, 1013 },
|
||||
new int[]{ 1019, 1021, 1031 },
|
||||
};
|
||||
|
||||
private static readonly BigInteger Six = BigInteger.ValueOf(6);
|
||||
|
||||
private static readonly int[] primeProducts;
|
||||
private static readonly BigInteger[] PrimeProducts;
|
||||
|
||||
static DHParametersHelper()
|
||||
{
|
||||
primeProducts = new int[primeLists.Length];
|
||||
PrimeProducts = new BigInteger[primeLists.Length];
|
||||
|
||||
for (int i = 0; i < primeLists.Length; ++i)
|
||||
{
|
||||
int[] primeList = primeLists[i];
|
||||
int product = 1;
|
||||
for (int j = 0; j < primeList.Length; ++j)
|
||||
{
|
||||
product *= primeList[j];
|
||||
}
|
||||
primeProducts[i] = product;
|
||||
PrimeProducts[i] = BigInteger.ValueOf(product);
|
||||
}
|
||||
}
|
||||
|
||||
// Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
|
||||
internal static BigInteger[] GenerateSafePrimes(
|
||||
int size,
|
||||
int certainty,
|
||||
SecureRandom random)
|
||||
{
|
||||
BigInteger p, q;
|
||||
int qLength = size - 1;
|
||||
|
||||
if (size <= 32)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
q = new BigInteger(qLength, 2, random);
|
||||
|
||||
p = q.ShiftLeft(1).Add(BigInteger.One);
|
||||
|
||||
if (p.IsProbablePrime(certainty)
|
||||
&& (certainty <= 2 || q.IsProbablePrime(certainty)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: Modified from Java version for speed
|
||||
for (;;)
|
||||
{
|
||||
q = new BigInteger(qLength, 0, random);
|
||||
|
||||
retry:
|
||||
for (int i = 0; i < primeLists.Length; ++i)
|
||||
{
|
||||
int test = q.Remainder(PrimeProducts[i]).IntValue;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
int rem3 = test % 3;
|
||||
if (rem3 != 2)
|
||||
{
|
||||
int diff = 2 * rem3 + 2;
|
||||
q = q.Add(BigInteger.ValueOf(diff));
|
||||
test = (test + diff) % primeProducts[i];
|
||||
}
|
||||
}
|
||||
|
||||
int[] primeList = primeLists[i];
|
||||
for (int j = 0; j < primeList.Length; ++j)
|
||||
{
|
||||
int prime = primeList[j];
|
||||
int qRem = test % prime;
|
||||
if (qRem == 0 || qRem == (prime >> 1))
|
||||
{
|
||||
q = q.Add(Six);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (q.BitLength != qLength)
|
||||
continue;
|
||||
|
||||
if (!q.RabinMillerTest(2, random))
|
||||
continue;
|
||||
|
||||
p = q.ShiftLeft(1).Add(BigInteger.One);
|
||||
|
||||
if (p.RabinMillerTest(certainty, random)
|
||||
&& (certainty <= 2 || q.RabinMillerTest(certainty - 2, random)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new BigInteger[] { p, q };
|
||||
}
|
||||
|
||||
// Select a high order element of the multiplicative group Zp*
|
||||
// p and q must be s.t. p = 2*q + 1, where p and q are prime
|
||||
internal static BigInteger SelectGenerator(
|
||||
BigInteger p,
|
||||
BigInteger q,
|
||||
SecureRandom random)
|
||||
{
|
||||
BigInteger pMinusTwo = p.Subtract(BigInteger.Two);
|
||||
BigInteger g;
|
||||
|
||||
// Handbook of Applied Cryptography 4.86
|
||||
do
|
||||
{
|
||||
g = CreateInRange(BigInteger.Two, pMinusTwo, random);
|
||||
}
|
||||
while (g.ModPow(BigInteger.Two, p).Equals(BigInteger.One)
|
||||
|| g.ModPow(q, p).Equals(BigInteger.One));
|
||||
|
||||
/*
|
||||
// RFC 2631 2.1.1 (and see Handbook of Applied Cryptography 4.81)
|
||||
do
|
||||
{
|
||||
BigInteger h = CreateInRange(BigInteger.Two, pMinusTwo, random);
|
||||
|
||||
g = h.ModPow(BigInteger.Two, p);
|
||||
}
|
||||
while (g.Equals(BigInteger.One));
|
||||
*/
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
private static BigInteger CreateInRange(
|
||||
BigInteger min,
|
||||
BigInteger max,
|
||||
SecureRandom random)
|
||||
{
|
||||
BigInteger x;
|
||||
do
|
||||
{
|
||||
x = new BigInteger(max.BitLength, random);
|
||||
}
|
||||
while (x.CompareTo(min) < 0 || x.CompareTo(max) > 0);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
66
iTechSharp/srcbc/crypto/generators/DesEdeKeyGenerator.cs
Normal file
66
iTechSharp/srcbc/crypto/generators/DesEdeKeyGenerator.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
public class DesEdeKeyGenerator
|
||||
: DesKeyGenerator
|
||||
{
|
||||
public DesEdeKeyGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
internal DesEdeKeyGenerator(
|
||||
int defaultStrength)
|
||||
: base(defaultStrength)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise the key generator - if strength is set to zero
|
||||
* the key Generated will be 192 bits in size, otherwise
|
||||
* strength can be 128 or 192 (or 112 or 168 if you don't count
|
||||
* parity bits), depending on whether you wish to do 2-key or 3-key
|
||||
* triple DES.
|
||||
*
|
||||
* @param param the parameters to be used for key generation
|
||||
*/
|
||||
protected override void engineInit(
|
||||
KeyGenerationParameters parameters)
|
||||
{
|
||||
base.engineInit(parameters);
|
||||
|
||||
if (strength == 0 || strength == (168 / 8))
|
||||
{
|
||||
strength = DesEdeParameters.DesEdeKeyLength;
|
||||
}
|
||||
else if (strength == (112 / 8))
|
||||
{
|
||||
strength = 2 * DesEdeParameters.DesKeyLength;
|
||||
}
|
||||
else if (strength != DesEdeParameters.DesEdeKeyLength
|
||||
&& strength != (2 * DesEdeParameters.DesKeyLength))
|
||||
{
|
||||
throw new ArgumentException("DESede key must be "
|
||||
+ (DesEdeParameters.DesEdeKeyLength * 8) + " or "
|
||||
+ (2 * 8 * DesEdeParameters.DesKeyLength)
|
||||
+ " bits long.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override byte[] engineGenerateKey()
|
||||
{
|
||||
byte[] newKey;
|
||||
|
||||
do
|
||||
{
|
||||
newKey = random.GenerateSeed(strength);
|
||||
DesEdeParameters.SetOddParity(newKey);
|
||||
}
|
||||
while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length));
|
||||
|
||||
return newKey;
|
||||
}
|
||||
}
|
||||
}
|
34
iTechSharp/srcbc/crypto/generators/DesKeyGenerator.cs
Normal file
34
iTechSharp/srcbc/crypto/generators/DesKeyGenerator.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
public class DesKeyGenerator
|
||||
: CipherKeyGenerator
|
||||
{
|
||||
public DesKeyGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
internal DesKeyGenerator(
|
||||
int defaultStrength)
|
||||
: base(defaultStrength)
|
||||
{
|
||||
}
|
||||
|
||||
protected override byte[] engineGenerateKey()
|
||||
{
|
||||
byte[] newKey;
|
||||
|
||||
do
|
||||
{
|
||||
newKey = random.GenerateSeed(DesParameters.DesKeyLength);
|
||||
DesParameters.SetOddParity(newKey);
|
||||
}
|
||||
while (DesParameters.IsWeakKey(newKey, 0));
|
||||
|
||||
return newKey;
|
||||
}
|
||||
}
|
||||
}
|
56
iTechSharp/srcbc/crypto/generators/DsaKeyPairGenerator.cs
Normal file
56
iTechSharp/srcbc/crypto/generators/DsaKeyPairGenerator.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* a DSA key pair generator.
|
||||
*
|
||||
* This Generates DSA keys in line with the method described
|
||||
* in FIPS 186-2.
|
||||
*/
|
||||
public class DsaKeyPairGenerator
|
||||
: IAsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private DsaKeyGenerationParameters param;
|
||||
|
||||
public void Init(
|
||||
KeyGenerationParameters parameters)
|
||||
{
|
||||
if (parameters == null)
|
||||
throw new ArgumentNullException("parameters");
|
||||
|
||||
// Note: If we start accepting instances of KeyGenerationParameters,
|
||||
// must apply constraint checking on strength (see DsaParametersGenerator.Init)
|
||||
|
||||
this.param = (DsaKeyGenerationParameters) parameters;
|
||||
}
|
||||
|
||||
public AsymmetricCipherKeyPair GenerateKeyPair()
|
||||
{
|
||||
DsaParameters dsaParams = param.Parameters;
|
||||
SecureRandom random = param.Random;
|
||||
|
||||
BigInteger q = dsaParams.Q;
|
||||
BigInteger x;
|
||||
|
||||
do
|
||||
{
|
||||
x = new BigInteger(160, random);
|
||||
}
|
||||
while (x.SignValue == 0 || x.CompareTo(q) >= 0);
|
||||
|
||||
//
|
||||
// calculate the public key.
|
||||
//
|
||||
BigInteger y = dsaParams.G.ModPow(x, dsaParams.P);
|
||||
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new DsaPublicKeyParameters(y, dsaParams),
|
||||
new DsaPrivateKeyParameters(x, dsaParams));
|
||||
}
|
||||
}
|
||||
}
|
184
iTechSharp/srcbc/crypto/generators/DsaParametersGenerator.cs
Normal file
184
iTechSharp/srcbc/crypto/generators/DsaParametersGenerator.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Generate suitable parameters for DSA, in line with FIPS 186-2.
|
||||
*/
|
||||
public class DsaParametersGenerator
|
||||
{
|
||||
private int size;
|
||||
private int certainty;
|
||||
private SecureRandom random;
|
||||
|
||||
/**
|
||||
* initialise the key generator.
|
||||
*
|
||||
* @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
|
||||
* @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
|
||||
* @param random random byte source.
|
||||
*/
|
||||
public void Init(
|
||||
int size,
|
||||
int certainty,
|
||||
SecureRandom random)
|
||||
{
|
||||
if (!IsValidDsaStrength(size))
|
||||
throw new ArgumentException("size must be from 512 - 1024 and a multiple of 64", "size");
|
||||
|
||||
this.size = size;
|
||||
this.certainty = certainty;
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
/**
|
||||
* add value to b, returning the result in a. The a value is treated
|
||||
* as a BigInteger of length (a.Length * 8) bits. The result is
|
||||
* modulo 2^a.Length in case of overflow.
|
||||
*/
|
||||
private static void Add(
|
||||
byte[] a,
|
||||
byte[] b,
|
||||
int value)
|
||||
{
|
||||
int x = (b[b.Length - 1] & 0xff) + value;
|
||||
|
||||
a[b.Length - 1] = (byte)x;
|
||||
x = (int) ((uint) x >>8);
|
||||
|
||||
for (int i = b.Length - 2; i >= 0; i--)
|
||||
{
|
||||
x += (b[i] & 0xff);
|
||||
a[i] = (byte)x;
|
||||
x = (int) ((uint) x >>8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* which Generates the p and g values from the given parameters,
|
||||
* returning the DsaParameters object.
|
||||
* <p>
|
||||
* Note: can take a while...</p>
|
||||
*/
|
||||
public DsaParameters GenerateParameters()
|
||||
{
|
||||
byte[] seed = new byte[20];
|
||||
byte[] part1 = new byte[20];
|
||||
byte[] part2 = new byte[20];
|
||||
byte[] u = new byte[20];
|
||||
Sha1Digest sha1 = new Sha1Digest();
|
||||
int n = (size - 1) / 160;
|
||||
byte[] w = new byte[size / 8];
|
||||
|
||||
BigInteger q = null, p = null, g = null;
|
||||
int counter = 0;
|
||||
bool primesFound = false;
|
||||
|
||||
while (!primesFound)
|
||||
{
|
||||
do
|
||||
{
|
||||
random.NextBytes(seed);
|
||||
|
||||
sha1.BlockUpdate(seed, 0, seed.Length);
|
||||
|
||||
sha1.DoFinal(part1, 0);
|
||||
|
||||
Array.Copy(seed, 0, part2, 0, seed.Length);
|
||||
|
||||
Add(part2, seed, 1);
|
||||
|
||||
sha1.BlockUpdate(part2, 0, part2.Length);
|
||||
|
||||
sha1.DoFinal(part2, 0);
|
||||
|
||||
for (int i = 0; i != u.Length; i++)
|
||||
{
|
||||
u[i] = (byte)(part1[i] ^ part2[i]);
|
||||
}
|
||||
|
||||
u[0] |= (byte)0x80;
|
||||
u[19] |= (byte)0x01;
|
||||
|
||||
q = new BigInteger(1, u);
|
||||
}
|
||||
while (!q.IsProbablePrime(certainty));
|
||||
|
||||
counter = 0;
|
||||
|
||||
int offset = 2;
|
||||
|
||||
while (counter < 4096)
|
||||
{
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
Add(part1, seed, offset + k);
|
||||
sha1.BlockUpdate(part1, 0, part1.Length);
|
||||
sha1.DoFinal(part1, 0);
|
||||
Array.Copy(part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length);
|
||||
}
|
||||
|
||||
Add(part1, seed, offset + n);
|
||||
sha1.BlockUpdate(part1, 0, part1.Length);
|
||||
sha1.DoFinal(part1, 0);
|
||||
Array.Copy(part1, part1.Length - ((w.Length - (n) * part1.Length)), w, 0, w.Length - n * part1.Length);
|
||||
|
||||
w[0] |= (byte)0x80;
|
||||
|
||||
BigInteger x = new BigInteger(1, w);
|
||||
|
||||
BigInteger c = x.Mod(q.ShiftLeft(1));
|
||||
|
||||
p = x.Subtract(c.Subtract(BigInteger.One));
|
||||
|
||||
if (p.TestBit(size - 1))
|
||||
{
|
||||
if (p.IsProbablePrime(certainty))
|
||||
{
|
||||
primesFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
counter += 1;
|
||||
offset += n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// calculate the generator g
|
||||
//
|
||||
BigInteger pMinusOneOverQ = p.Subtract(BigInteger.One).Divide(q);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
BigInteger h = new BigInteger(size, random);
|
||||
if (h.CompareTo(BigInteger.One) <= 0 || h.CompareTo(p.Subtract(BigInteger.One)) >= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
g = h.ModPow(pMinusOneOverQ, p);
|
||||
if (g.CompareTo(BigInteger.One) <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
|
||||
}
|
||||
|
||||
private static bool IsValidDsaStrength(
|
||||
int strength)
|
||||
{
|
||||
return strength >= 512 && strength <= 1024 && strength % 64 == 0;
|
||||
}
|
||||
}
|
||||
}
|
130
iTechSharp/srcbc/crypto/generators/ECKeyPairGenerator.cs
Normal file
130
iTechSharp/srcbc/crypto/generators/ECKeyPairGenerator.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.X9;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
public class ECKeyPairGenerator
|
||||
: IAsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private readonly string algorithm;
|
||||
|
||||
private ECDomainParameters parameters;
|
||||
private DerObjectIdentifier publicKeyParamSet;
|
||||
private SecureRandom random;
|
||||
|
||||
public ECKeyPairGenerator()
|
||||
: this("EC")
|
||||
{
|
||||
}
|
||||
|
||||
public ECKeyPairGenerator(
|
||||
string algorithm)
|
||||
{
|
||||
if (algorithm == null)
|
||||
throw new ArgumentNullException("algorithm");
|
||||
|
||||
this.algorithm = VerifyAlgorithmName(algorithm);
|
||||
}
|
||||
|
||||
public void Init(
|
||||
KeyGenerationParameters parameters)
|
||||
{
|
||||
if (parameters is ECKeyGenerationParameters)
|
||||
{
|
||||
ECKeyGenerationParameters ecP = (ECKeyGenerationParameters) parameters;
|
||||
|
||||
if (ecP.PublicKeyParamSet != null)
|
||||
{
|
||||
if (algorithm != "ECGOST3410")
|
||||
throw new ArgumentException("parameters invalid for algorithm: " + algorithm, "parameters");
|
||||
|
||||
this.publicKeyParamSet = ecP.PublicKeyParamSet;
|
||||
}
|
||||
|
||||
this.parameters = ecP.DomainParameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
DerObjectIdentifier oid;
|
||||
switch (parameters.Strength)
|
||||
{
|
||||
case 192:
|
||||
oid = X9ObjectIdentifiers.Prime192v1;
|
||||
break;
|
||||
case 239:
|
||||
oid = X9ObjectIdentifiers.Prime239v1;
|
||||
break;
|
||||
case 256:
|
||||
oid = X9ObjectIdentifiers.Prime256v1;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidParameterException("unknown key size.");
|
||||
}
|
||||
|
||||
X9ECParameters ecps = X962NamedCurves.GetByOid(oid);
|
||||
|
||||
this.parameters = new ECDomainParameters(
|
||||
ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
|
||||
}
|
||||
|
||||
this.random = parameters.Random;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the domain parameters this routine Generates an EC key
|
||||
* pair in accordance with X9.62 section 5.2.1 pages 26, 27.
|
||||
*/
|
||||
public AsymmetricCipherKeyPair GenerateKeyPair()
|
||||
{
|
||||
BigInteger n = parameters.N;
|
||||
BigInteger d;
|
||||
|
||||
do
|
||||
{
|
||||
d = new BigInteger(n.BitLength, random);
|
||||
}
|
||||
while (d.SignValue == 0 || (d.CompareTo(n) >= 0));
|
||||
|
||||
ECPoint q = parameters.G.Multiply(d);
|
||||
|
||||
if (publicKeyParamSet != null)
|
||||
{
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new ECPublicKeyParameters(q, publicKeyParamSet),
|
||||
new ECPrivateKeyParameters(d, publicKeyParamSet));
|
||||
}
|
||||
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new ECPublicKeyParameters(algorithm, q, parameters),
|
||||
new ECPrivateKeyParameters(algorithm, d, parameters));
|
||||
}
|
||||
|
||||
private string VerifyAlgorithmName(
|
||||
string algorithm)
|
||||
{
|
||||
string upper = algorithm.ToUpper(CultureInfo.InvariantCulture);
|
||||
|
||||
switch (upper)
|
||||
{
|
||||
case "EC":
|
||||
case "ECDSA":
|
||||
case "ECGOST3410":
|
||||
case "ECDH":
|
||||
case "ECDHC":
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm");
|
||||
}
|
||||
|
||||
return upper;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* a ElGamal key pair generator.
|
||||
* <p>
|
||||
* This Generates keys consistent for use with ElGamal as described in
|
||||
* page 164 of "Handbook of Applied Cryptography".</p>
|
||||
*/
|
||||
public class ElGamalKeyPairGenerator
|
||||
: IAsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private ElGamalKeyGenerationParameters param;
|
||||
|
||||
public void Init(
|
||||
KeyGenerationParameters parameters)
|
||||
{
|
||||
this.param = (ElGamalKeyGenerationParameters) parameters;
|
||||
}
|
||||
|
||||
public AsymmetricCipherKeyPair GenerateKeyPair()
|
||||
{
|
||||
DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
|
||||
ElGamalParameters elParams = param.Parameters;
|
||||
|
||||
BigInteger p = elParams.P;
|
||||
BigInteger x = helper.CalculatePrivate(p, param.Random, elParams.L);
|
||||
BigInteger y = helper.CalculatePublic(p, elParams.G, x);
|
||||
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new ElGamalPublicKeyParameters(y, elParams),
|
||||
new ElGamalPrivateKeyParameters(x, elParams));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
public class ElGamalParametersGenerator
|
||||
{
|
||||
private int size;
|
||||
private int certainty;
|
||||
private SecureRandom random;
|
||||
|
||||
public void Init(
|
||||
int size,
|
||||
int certainty,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.size = size;
|
||||
this.certainty = certainty;
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
/**
|
||||
* which Generates the p and g values from the given parameters,
|
||||
* returning the ElGamalParameters object.
|
||||
* <p>
|
||||
* Note: can take a while...
|
||||
* </p>
|
||||
*/
|
||||
public ElGamalParameters GenerateParameters()
|
||||
{
|
||||
//
|
||||
// find a safe prime p where p = 2*q + 1, where p and q are prime.
|
||||
//
|
||||
BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random);
|
||||
|
||||
BigInteger p = safePrimes[0];
|
||||
BigInteger q = safePrimes[1];
|
||||
BigInteger g = DHParametersHelper.SelectGenerator(p, q, random);
|
||||
|
||||
return new ElGamalParameters(p, g);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Asn1.CryptoPro;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* a GOST3410 key pair generator.
|
||||
* This generates GOST3410 keys in line with the method described
|
||||
* in GOST R 34.10-94.
|
||||
*/
|
||||
public class Gost3410KeyPairGenerator
|
||||
: IAsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private Gost3410KeyGenerationParameters param;
|
||||
|
||||
public void Init(
|
||||
KeyGenerationParameters parameters)
|
||||
{
|
||||
if (parameters is Gost3410KeyGenerationParameters)
|
||||
{
|
||||
this.param = (Gost3410KeyGenerationParameters) parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters(
|
||||
parameters.Random,
|
||||
CryptoProObjectIdentifiers.GostR3410x94CryptoProA);
|
||||
|
||||
if (parameters.Strength != kgp.Parameters.P.BitLength - 1)
|
||||
{
|
||||
// TODO Should we complain?
|
||||
}
|
||||
|
||||
this.param = kgp;
|
||||
}
|
||||
}
|
||||
|
||||
public AsymmetricCipherKeyPair GenerateKeyPair()
|
||||
{
|
||||
SecureRandom random = param.Random;
|
||||
Gost3410Parameters gost3410Params = param.Parameters;
|
||||
|
||||
BigInteger q = gost3410Params.Q;
|
||||
BigInteger x;
|
||||
do
|
||||
{
|
||||
x = new BigInteger(256, random);
|
||||
}
|
||||
while (x.SignValue < 1 || x.CompareTo(q) >= 0);
|
||||
|
||||
BigInteger p = gost3410Params.P;
|
||||
BigInteger a = gost3410Params.A;
|
||||
|
||||
// calculate the public key.
|
||||
BigInteger y = a.ModPow(x, p);
|
||||
|
||||
if (param.PublicKeyParamSet != null)
|
||||
{
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet),
|
||||
new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet));
|
||||
}
|
||||
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new Gost3410PublicKeyParameters(y, gost3410Params),
|
||||
new Gost3410PrivateKeyParameters(x, gost3410Params));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,530 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* generate suitable parameters for GOST3410.
|
||||
*/
|
||||
public class Gost3410ParametersGenerator
|
||||
{
|
||||
private int size;
|
||||
private int typeproc;
|
||||
private SecureRandom init_random;
|
||||
|
||||
/**
|
||||
* initialise the key generator.
|
||||
*
|
||||
* @param size size of the key
|
||||
* @param typeProcedure type procedure A,B = 1; A',B' - else
|
||||
* @param random random byte source.
|
||||
*/
|
||||
public void Init(
|
||||
int size,
|
||||
int typeProcedure,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.size = size;
|
||||
this.typeproc = typeProcedure;
|
||||
this.init_random = random;
|
||||
}
|
||||
|
||||
//Procedure A
|
||||
private int procedure_A(int x0, int c, BigInteger[] pq, int size)
|
||||
{
|
||||
//Verify and perform condition: 0<x<2^16; 0<c<2^16; c - odd.
|
||||
while(x0<0 || x0>65536)
|
||||
{
|
||||
x0 = init_random.NextInt()/32768;
|
||||
}
|
||||
|
||||
while((c<0 || c>65536) || (c/2==0))
|
||||
{
|
||||
c = init_random.NextInt()/32768 + 1;
|
||||
}
|
||||
|
||||
BigInteger C = BigInteger.ValueOf(c);
|
||||
BigInteger constA16 = BigInteger.ValueOf(19381);
|
||||
|
||||
//step1
|
||||
BigInteger[] y = new BigInteger[1]; // begin length = 1
|
||||
y[0] = BigInteger.ValueOf(x0);
|
||||
|
||||
//step 2
|
||||
int[] t = new int[1]; // t - orders; begin length = 1
|
||||
t[0] = size;
|
||||
int s = 0;
|
||||
for (int i=0; t[i]>=17; i++)
|
||||
{
|
||||
// extension array t
|
||||
int[] tmp_t = new int[t.Length + 1]; ///////////////
|
||||
Array.Copy(t,0,tmp_t,0,t.Length); // extension
|
||||
t = new int[tmp_t.Length]; // array t
|
||||
Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); ///////////////
|
||||
|
||||
t[i+1] = t[i]/2;
|
||||
s = i+1;
|
||||
}
|
||||
|
||||
//step3
|
||||
BigInteger[] p = new BigInteger[s+1];
|
||||
p[s] = new BigInteger("8003",16); //set min prime number length 16 bit
|
||||
|
||||
int m = s-1; //step4
|
||||
|
||||
for (int i=0; i<s; i++)
|
||||
{
|
||||
int rm = t[m]/16; //step5
|
||||
|
||||
step6: for(;;)
|
||||
{
|
||||
//step 6
|
||||
BigInteger[] tmp_y = new BigInteger[y.Length]; ////////////////
|
||||
Array.Copy(y,0,tmp_y,0,y.Length); // extension
|
||||
y = new BigInteger[rm+1]; // array y
|
||||
Array.Copy(tmp_y,0,y,0,tmp_y.Length); ////////////////
|
||||
|
||||
for (int j=0; j<rm; j++)
|
||||
{
|
||||
y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16));
|
||||
}
|
||||
|
||||
//step 7
|
||||
BigInteger Ym = BigInteger.Zero;
|
||||
for (int j=0; j<rm; j++)
|
||||
{
|
||||
Ym = Ym.Add(y[j].ShiftLeft(16*j));
|
||||
}
|
||||
|
||||
y[0] = y[rm]; //step 8
|
||||
|
||||
//step 9
|
||||
BigInteger N = BigInteger.One.ShiftLeft(t[m]-1).Divide(p[m+1]).Add(
|
||||
Ym.ShiftLeft(t[m]-1).Divide(p[m+1].ShiftLeft(16*rm)));
|
||||
|
||||
if (N.TestBit(0))
|
||||
{
|
||||
N = N.Add(BigInteger.One);
|
||||
}
|
||||
|
||||
//step 10
|
||||
|
||||
for(;;)
|
||||
{
|
||||
//step 11
|
||||
BigInteger NByLastP = N.Multiply(p[m+1]);
|
||||
|
||||
if (NByLastP.BitLength > t[m])
|
||||
{
|
||||
goto step6; //step 12
|
||||
}
|
||||
|
||||
p[m] = NByLastP.Add(BigInteger.One);
|
||||
|
||||
//step13
|
||||
if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
|
||||
&& BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
N = N.Add(BigInteger.Two);
|
||||
}
|
||||
|
||||
if (--m < 0)
|
||||
{
|
||||
pq[0] = p[0];
|
||||
pq[1] = p[1];
|
||||
return y[0].IntValue; //return for procedure B step 2
|
||||
}
|
||||
|
||||
break; //step 14
|
||||
}
|
||||
}
|
||||
return y[0].IntValue;
|
||||
}
|
||||
|
||||
//Procedure A'
|
||||
private long procedure_Aa(long x0, long c, BigInteger[] pq, int size)
|
||||
{
|
||||
//Verify and perform condition: 0<x<2^32; 0<c<2^32; c - odd.
|
||||
while(x0<0 || x0>4294967296L)
|
||||
{
|
||||
x0 = init_random.NextInt()*2;
|
||||
}
|
||||
|
||||
while((c<0 || c>4294967296L) || (c/2==0))
|
||||
{
|
||||
c = init_random.NextInt()*2+1;
|
||||
}
|
||||
|
||||
BigInteger C = BigInteger.ValueOf(c);
|
||||
BigInteger constA32 = BigInteger.ValueOf(97781173);
|
||||
|
||||
//step1
|
||||
BigInteger[] y = new BigInteger[1]; // begin length = 1
|
||||
y[0] = BigInteger.ValueOf(x0);
|
||||
|
||||
//step 2
|
||||
int[] t = new int[1]; // t - orders; begin length = 1
|
||||
t[0] = size;
|
||||
int s = 0;
|
||||
for (int i=0; t[i]>=33; i++)
|
||||
{
|
||||
// extension array t
|
||||
int[] tmp_t = new int[t.Length + 1]; ///////////////
|
||||
Array.Copy(t,0,tmp_t,0,t.Length); // extension
|
||||
t = new int[tmp_t.Length]; // array t
|
||||
Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); ///////////////
|
||||
|
||||
t[i+1] = t[i]/2;
|
||||
s = i+1;
|
||||
}
|
||||
|
||||
//step3
|
||||
BigInteger[] p = new BigInteger[s+1];
|
||||
p[s] = new BigInteger("8000000B",16); //set min prime number length 32 bit
|
||||
|
||||
int m = s-1; //step4
|
||||
|
||||
for (int i=0; i<s; i++)
|
||||
{
|
||||
int rm = t[m]/32; //step5
|
||||
|
||||
step6: for(;;)
|
||||
{
|
||||
//step 6
|
||||
BigInteger[] tmp_y = new BigInteger[y.Length]; ////////////////
|
||||
Array.Copy(y,0,tmp_y,0,y.Length); // extension
|
||||
y = new BigInteger[rm+1]; // array y
|
||||
Array.Copy(tmp_y,0,y,0,tmp_y.Length); ////////////////
|
||||
|
||||
for (int j=0; j<rm; j++)
|
||||
{
|
||||
y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32));
|
||||
}
|
||||
|
||||
//step 7
|
||||
BigInteger Ym = BigInteger.Zero;
|
||||
for (int j=0; j<rm; j++)
|
||||
{
|
||||
Ym = Ym.Add(y[j].ShiftLeft(32*j));
|
||||
}
|
||||
|
||||
y[0] = y[rm]; //step 8
|
||||
|
||||
//step 9
|
||||
BigInteger N = BigInteger.One.ShiftLeft(t[m]-1).Divide(p[m+1]).Add(
|
||||
Ym.ShiftLeft(t[m]-1).Divide(p[m+1].ShiftLeft(32*rm)));
|
||||
|
||||
if (N.TestBit(0))
|
||||
{
|
||||
N = N.Add(BigInteger.One);
|
||||
}
|
||||
|
||||
//step 10
|
||||
|
||||
for(;;)
|
||||
{
|
||||
//step 11
|
||||
BigInteger NByLastP = N.Multiply(p[m+1]);
|
||||
|
||||
if (NByLastP.BitLength > t[m])
|
||||
{
|
||||
goto step6; //step 12
|
||||
}
|
||||
|
||||
p[m] = NByLastP.Add(BigInteger.One);
|
||||
|
||||
//step13
|
||||
if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
|
||||
&& BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
N = N.Add(BigInteger.Two);
|
||||
}
|
||||
|
||||
if (--m < 0)
|
||||
{
|
||||
pq[0] = p[0];
|
||||
pq[1] = p[1];
|
||||
return y[0].LongValue; //return for procedure B' step 2
|
||||
}
|
||||
|
||||
break; //step 14
|
||||
}
|
||||
}
|
||||
return y[0].LongValue;
|
||||
}
|
||||
|
||||
//Procedure B
|
||||
private void procedure_B(int x0, int c, BigInteger[] pq)
|
||||
{
|
||||
//Verify and perform condition: 0<x<2^16; 0<c<2^16; c - odd.
|
||||
while(x0<0 || x0>65536)
|
||||
{
|
||||
x0 = init_random.NextInt()/32768;
|
||||
}
|
||||
|
||||
while((c<0 || c>65536) || (c/2==0))
|
||||
{
|
||||
c = init_random.NextInt()/32768 + 1;
|
||||
}
|
||||
|
||||
BigInteger [] qp = new BigInteger[2];
|
||||
BigInteger q = null, Q = null, p = null;
|
||||
BigInteger C = BigInteger.ValueOf(c);
|
||||
BigInteger constA16 = BigInteger.ValueOf(19381);
|
||||
|
||||
//step1
|
||||
x0 = procedure_A(x0, c, qp, 256);
|
||||
q = qp[0];
|
||||
|
||||
//step2
|
||||
x0 = procedure_A(x0, c, qp, 512);
|
||||
Q = qp[0];
|
||||
|
||||
BigInteger[] y = new BigInteger[65];
|
||||
y[0] = BigInteger.ValueOf(x0);
|
||||
|
||||
const int tp = 1024;
|
||||
|
||||
BigInteger qQ = q.Multiply(Q);
|
||||
|
||||
step3:
|
||||
for(;;)
|
||||
{
|
||||
//step 3
|
||||
for (int j=0; j<64; j++)
|
||||
{
|
||||
y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16));
|
||||
}
|
||||
|
||||
//step 4
|
||||
BigInteger Y = BigInteger.Zero;
|
||||
|
||||
for (int j=0; j<64; j++)
|
||||
{
|
||||
Y = Y.Add(y[j].ShiftLeft(16*j));
|
||||
}
|
||||
|
||||
y[0] = y[64]; //step 5
|
||||
|
||||
//step 6
|
||||
BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
|
||||
Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
|
||||
|
||||
if (N.TestBit(0))
|
||||
{
|
||||
N = N.Add(BigInteger.One);
|
||||
}
|
||||
|
||||
//step 7
|
||||
|
||||
for(;;)
|
||||
{
|
||||
//step 11
|
||||
BigInteger qQN = qQ.Multiply(N);
|
||||
|
||||
if (qQN.BitLength > tp)
|
||||
{
|
||||
goto step3; //step 9
|
||||
}
|
||||
|
||||
p = qQN.Add(BigInteger.One);
|
||||
|
||||
//step10
|
||||
if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
|
||||
&& BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
|
||||
{
|
||||
pq[0] = p;
|
||||
pq[1] = q;
|
||||
return;
|
||||
}
|
||||
|
||||
N = N.Add(BigInteger.Two);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Procedure B'
|
||||
private void procedure_Bb(long x0, long c, BigInteger[] pq)
|
||||
{
|
||||
//Verify and perform condition: 0<x<2^32; 0<c<2^32; c - odd.
|
||||
while(x0<0 || x0>4294967296L)
|
||||
{
|
||||
x0 = init_random.NextInt()*2;
|
||||
}
|
||||
|
||||
while((c<0 || c>4294967296L) || (c/2==0))
|
||||
{
|
||||
c = init_random.NextInt()*2+1;
|
||||
}
|
||||
|
||||
BigInteger [] qp = new BigInteger[2];
|
||||
BigInteger q = null, Q = null, p = null;
|
||||
BigInteger C = BigInteger.ValueOf(c);
|
||||
BigInteger constA32 = BigInteger.ValueOf(97781173);
|
||||
|
||||
//step1
|
||||
x0 = procedure_Aa(x0, c, qp, 256);
|
||||
q = qp[0];
|
||||
|
||||
//step2
|
||||
x0 = procedure_Aa(x0, c, qp, 512);
|
||||
Q = qp[0];
|
||||
|
||||
BigInteger[] y = new BigInteger[33];
|
||||
y[0] = BigInteger.ValueOf(x0);
|
||||
|
||||
const int tp = 1024;
|
||||
|
||||
BigInteger qQ = q.Multiply(Q);
|
||||
|
||||
step3:
|
||||
for(;;)
|
||||
{
|
||||
//step 3
|
||||
for (int j=0; j<32; j++)
|
||||
{
|
||||
y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32));
|
||||
}
|
||||
|
||||
//step 4
|
||||
BigInteger Y = BigInteger.Zero;
|
||||
for (int j=0; j<32; j++)
|
||||
{
|
||||
Y = Y.Add(y[j].ShiftLeft(32*j));
|
||||
}
|
||||
|
||||
y[0] = y[32]; //step 5
|
||||
|
||||
//step 6
|
||||
BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
|
||||
Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
|
||||
|
||||
if (N.TestBit(0))
|
||||
{
|
||||
N = N.Add(BigInteger.One);
|
||||
}
|
||||
|
||||
//step 7
|
||||
|
||||
for(;;)
|
||||
{
|
||||
//step 11
|
||||
BigInteger qQN = qQ.Multiply(N);
|
||||
|
||||
if (qQN.BitLength > tp)
|
||||
{
|
||||
goto step3; //step 9
|
||||
}
|
||||
|
||||
p = qQN.Add(BigInteger.One);
|
||||
|
||||
//step10
|
||||
if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
|
||||
&& BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
|
||||
{
|
||||
pq[0] = p;
|
||||
pq[1] = q;
|
||||
return;
|
||||
}
|
||||
|
||||
N = N.Add(BigInteger.Two);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Procedure C
|
||||
* procedure generates the a value from the given p,q,
|
||||
* returning the a value.
|
||||
*/
|
||||
private BigInteger procedure_C(BigInteger p, BigInteger q)
|
||||
{
|
||||
BigInteger pSub1 = p.Subtract(BigInteger.One);
|
||||
BigInteger pSub1Divq = pSub1.Divide(q);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
BigInteger d = new BigInteger(p.BitLength, init_random);
|
||||
|
||||
// 1 < d < p-1
|
||||
if (d.CompareTo(BigInteger.One) > 0 && d.CompareTo(pSub1) < 0)
|
||||
{
|
||||
BigInteger a = d.ModPow(pSub1Divq, p);
|
||||
|
||||
if (a.CompareTo(BigInteger.One) != 0)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* which generates the p , q and a values from the given parameters,
|
||||
* returning the Gost3410Parameters object.
|
||||
*/
|
||||
public Gost3410Parameters GenerateParameters()
|
||||
{
|
||||
BigInteger [] pq = new BigInteger[2];
|
||||
BigInteger q = null, p = null, a = null;
|
||||
|
||||
int x0, c;
|
||||
long x0L, cL;
|
||||
|
||||
if (typeproc==1)
|
||||
{
|
||||
x0 = init_random.NextInt();
|
||||
c = init_random.NextInt();
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case 512:
|
||||
procedure_A(x0, c, pq, 512);
|
||||
break;
|
||||
case 1024:
|
||||
procedure_B(x0, c, pq);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Ooops! key size 512 or 1024 bit.");
|
||||
}
|
||||
p = pq[0]; q = pq[1];
|
||||
a = procedure_C(p, q);
|
||||
//System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
|
||||
//System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
|
||||
return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0, c));
|
||||
}
|
||||
else
|
||||
{
|
||||
x0L = init_random.NextLong();
|
||||
cL = init_random.NextLong();
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case 512:
|
||||
procedure_Aa(x0L, cL, pq, 512);
|
||||
break;
|
||||
case 1024:
|
||||
procedure_Bb(x0L, cL, pq);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Ooops! key size 512 or 1024 bit.");
|
||||
}
|
||||
p = pq[0]; q = pq[1];
|
||||
a = procedure_C(p, q);
|
||||
//System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
|
||||
//System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
|
||||
return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0L, cL));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
iTechSharp/srcbc/crypto/generators/Kdf1BytesGenerator.cs
Normal file
27
iTechSharp/srcbc/crypto/generators/Kdf1BytesGenerator.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
|
||||
* <br/>
|
||||
* This implementation is based on IEEE P1363/ISO 18033.
|
||||
*/
|
||||
public class Kdf1BytesGenerator
|
||||
: BaseKdfBytesGenerator
|
||||
{
|
||||
/**
|
||||
* Construct a KDF1 byte generator.
|
||||
*
|
||||
* @param digest the digest to be used as the source of derived keys.
|
||||
*/
|
||||
public Kdf1BytesGenerator(
|
||||
IDigest digest)
|
||||
: base(0, digest)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
28
iTechSharp/srcbc/crypto/generators/Kdf2BytesGenerator.cs
Normal file
28
iTechSharp/srcbc/crypto/generators/Kdf2BytesGenerator.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
|
||||
* <br/>
|
||||
* This implementation is based on IEEE P1363/ISO 18033.
|
||||
*/
|
||||
public class Kdf2BytesGenerator
|
||||
: BaseKdfBytesGenerator
|
||||
{
|
||||
/**
|
||||
* Construct a KDF2 bytes generator. Generates key material
|
||||
* according to IEEE P1363 or ISO 18033 depending on the initialisation.
|
||||
*
|
||||
* @param digest the digest to be used as the source of derived keys.
|
||||
*/
|
||||
public Kdf2BytesGenerator(
|
||||
IDigest digest)
|
||||
: base(1, digest)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
117
iTechSharp/srcbc/crypto/generators/Mgf1BytesGenerator.cs
Normal file
117
iTechSharp/srcbc/crypto/generators/Mgf1BytesGenerator.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
//using Org.BouncyCastle.Math;
|
||||
//using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Generator for MGF1 as defined in Pkcs 1v2
|
||||
*/
|
||||
public class Mgf1BytesGenerator : IDerivationFunction
|
||||
{
|
||||
private IDigest digest;
|
||||
private byte[] seed;
|
||||
private int hLen;
|
||||
|
||||
/**
|
||||
* @param digest the digest to be used as the source of Generated bytes
|
||||
*/
|
||||
public Mgf1BytesGenerator(
|
||||
IDigest digest)
|
||||
{
|
||||
this.digest = digest;
|
||||
this.hLen = digest.GetDigestSize();
|
||||
}
|
||||
|
||||
public void Init(
|
||||
IDerivationParameters parameters)
|
||||
{
|
||||
if (!(typeof(MgfParameters).IsInstanceOfType(parameters)))
|
||||
{
|
||||
throw new ArgumentException("MGF parameters required for MGF1Generator");
|
||||
}
|
||||
|
||||
MgfParameters p = (MgfParameters)parameters;
|
||||
|
||||
seed = p.GetSeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying digest.
|
||||
*/
|
||||
public IDigest Digest
|
||||
{
|
||||
get
|
||||
{
|
||||
return digest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* int to octet string.
|
||||
*/
|
||||
private void ItoOSP(
|
||||
int i,
|
||||
byte[] sp)
|
||||
{
|
||||
sp[0] = (byte)((uint) i >> 24);
|
||||
sp[1] = (byte)((uint) i >> 16);
|
||||
sp[2] = (byte)((uint) i >> 8);
|
||||
sp[3] = (byte)((uint) i >> 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* fill len bytes of the output buffer with bytes Generated from
|
||||
* the derivation function.
|
||||
*
|
||||
* @throws DataLengthException if the out buffer is too small.
|
||||
*/
|
||||
public int GenerateBytes(
|
||||
byte[] output,
|
||||
int outOff,
|
||||
int length)
|
||||
{
|
||||
if ((output.Length - length) < outOff)
|
||||
{
|
||||
throw new DataLengthException("output buffer too small");
|
||||
}
|
||||
|
||||
byte[] hashBuf = new byte[hLen];
|
||||
byte[] C = new byte[4];
|
||||
int counter = 0;
|
||||
|
||||
digest.Reset();
|
||||
|
||||
if (length > hLen)
|
||||
{
|
||||
do
|
||||
{
|
||||
ItoOSP(counter, C);
|
||||
|
||||
digest.BlockUpdate(seed, 0, seed.Length);
|
||||
digest.BlockUpdate(C, 0, C.Length);
|
||||
digest.DoFinal(hashBuf, 0);
|
||||
|
||||
Array.Copy(hashBuf, 0, output, outOff + counter * hLen, hLen);
|
||||
}
|
||||
while (++counter < (length / hLen));
|
||||
}
|
||||
|
||||
if ((counter * hLen) < length)
|
||||
{
|
||||
ItoOSP(counter, C);
|
||||
|
||||
digest.BlockUpdate(seed, 0, seed.Length);
|
||||
digest.BlockUpdate(C, 0, C.Length);
|
||||
digest.DoFinal(hashBuf, 0);
|
||||
|
||||
Array.Copy(hashBuf, 0, output, outOff + counter * hLen, length - (counter * hLen));
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,330 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Key generation parameters for NaccacheStern cipher. For details on this cipher, please see
|
||||
*
|
||||
* http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
|
||||
*/
|
||||
public class NaccacheSternKeyPairGenerator
|
||||
: IAsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private static readonly int[] smallPrimes =
|
||||
{
|
||||
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
|
||||
71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
|
||||
151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
|
||||
239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331,
|
||||
337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431,
|
||||
433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523,
|
||||
541, 547, 557
|
||||
};
|
||||
|
||||
private NaccacheSternKeyGenerationParameters param;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#init(org.bouncycastle.crypto.KeyGenerationParameters)
|
||||
*/
|
||||
public void Init(KeyGenerationParameters parameters)
|
||||
{
|
||||
this.param = (NaccacheSternKeyGenerationParameters)parameters;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#generateKeyPair()
|
||||
*/
|
||||
public AsymmetricCipherKeyPair GenerateKeyPair()
|
||||
{
|
||||
int strength = param.Strength;
|
||||
SecureRandom rand = param.Random;
|
||||
int certainty = param.Certainty;
|
||||
bool debug = param.IsDebug;
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("Fetching first " + param.CountSmallPrimes + " primes.");
|
||||
}
|
||||
|
||||
ArrayList smallPrimes = findFirstPrimes(param.CountSmallPrimes);
|
||||
|
||||
smallPrimes = permuteList(smallPrimes, rand);
|
||||
|
||||
BigInteger u = BigInteger.One;
|
||||
BigInteger v = BigInteger.One;
|
||||
|
||||
for (int i = 0; i < smallPrimes.Count / 2; i++)
|
||||
{
|
||||
u = u.Multiply((BigInteger)smallPrimes[i]);
|
||||
}
|
||||
for (int i = smallPrimes.Count / 2; i < smallPrimes.Count; i++)
|
||||
{
|
||||
v = v.Multiply((BigInteger)smallPrimes[i]);
|
||||
}
|
||||
|
||||
BigInteger sigma = u.Multiply(v);
|
||||
|
||||
// n = (2 a u p_ + 1 ) ( 2 b v q_ + 1)
|
||||
// -> |n| = strength
|
||||
// |2| = 1 in bits
|
||||
// -> |a| * |b| = |n| - |u| - |v| - |p_| - |q_| - |2| -|2|
|
||||
// remainingStrength = strength - sigma.bitLength() - p_.bitLength() -
|
||||
// q_.bitLength() - 1 -1
|
||||
int remainingStrength = strength - sigma.BitLength - 48;
|
||||
BigInteger a = generatePrime(remainingStrength / 2 + 1, certainty, rand);
|
||||
BigInteger b = generatePrime(remainingStrength / 2 + 1, certainty, rand);
|
||||
|
||||
BigInteger p_;
|
||||
BigInteger q_;
|
||||
BigInteger p;
|
||||
BigInteger q;
|
||||
|
||||
long tries = 0;
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("generating p and q");
|
||||
}
|
||||
|
||||
BigInteger _2au = a.Multiply(u).ShiftLeft(1);
|
||||
BigInteger _2bv = b.Multiply(v).ShiftLeft(1);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
tries++;
|
||||
|
||||
p_ = generatePrime(24, certainty, rand);
|
||||
|
||||
p = p_.Multiply(_2au).Add(BigInteger.One);
|
||||
|
||||
if (!p.IsProbablePrime(certainty))
|
||||
continue;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
q_ = generatePrime(24, certainty, rand);
|
||||
|
||||
if (p_.Equals(q_))
|
||||
continue;
|
||||
|
||||
q = q_.Multiply(_2bv).Add(BigInteger.One);
|
||||
|
||||
if (q.IsProbablePrime(certainty))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sigma.Gcd(p_.Multiply(q_)).Equals(BigInteger.One))
|
||||
{
|
||||
Console.WriteLine("sigma.gcd(p_.mult(q_)) != 1!\n p_: " + p_ +"\n q_: "+ q_ );
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p.Multiply(q).BitLength < strength)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("key size too small. Should be " + strength + " but is actually "
|
||||
+ p.Multiply(q).BitLength);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("needed " + tries + " tries to generate p and q.");
|
||||
}
|
||||
|
||||
BigInteger n = p.Multiply(q);
|
||||
BigInteger phi_n = p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One));
|
||||
BigInteger g;
|
||||
tries = 0;
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("generating g");
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
// TODO After the first loop, just regenerate one randomly-selected gPart each time?
|
||||
ArrayList gParts = new ArrayList();
|
||||
for (int ind = 0; ind != smallPrimes.Count; ind++)
|
||||
{
|
||||
BigInteger i = (BigInteger)smallPrimes[ind];
|
||||
BigInteger e = phi_n.Divide(i);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
tries++;
|
||||
|
||||
g = generatePrime(strength, certainty, rand);
|
||||
|
||||
if (!g.ModPow(e, n).Equals(BigInteger.One))
|
||||
{
|
||||
gParts.Add(g);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
g = BigInteger.One;
|
||||
for (int i = 0; i < smallPrimes.Count; i++)
|
||||
{
|
||||
BigInteger gPart = (BigInteger) gParts[i];
|
||||
BigInteger smallPrime = (BigInteger) smallPrimes[i];
|
||||
g = g.Multiply(gPart.ModPow(sigma.Divide(smallPrime), n)).Mod(n);
|
||||
}
|
||||
|
||||
// make sure that g is not divisible by p_i or q_i
|
||||
bool divisible = false;
|
||||
for (int i = 0; i < smallPrimes.Count; i++)
|
||||
{
|
||||
if (g.ModPow(phi_n.Divide((BigInteger)smallPrimes[i]), n).Equals(BigInteger.One))
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("g has order phi(n)/" + smallPrimes[i] + "\n g: " + g);
|
||||
}
|
||||
divisible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (divisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// make sure that g has order > phi_n/4
|
||||
|
||||
//if (g.ModPow(phi_n.Divide(BigInteger.ValueOf(4)), n).Equals(BigInteger.One))
|
||||
if (g.ModPow(phi_n.ShiftRight(2), n).Equals(BigInteger.One))
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("g has order phi(n)/4\n g:" + g);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g.ModPow(phi_n.Divide(p_), n).Equals(BigInteger.One))
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("g has order phi(n)/p'\n g: " + g);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (g.ModPow(phi_n.Divide(q_), n).Equals(BigInteger.One))
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("g has order phi(n)/q'\n g: " + g);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (g.ModPow(phi_n.Divide(a), n).Equals(BigInteger.One))
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("g has order phi(n)/a\n g: " + g);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (g.ModPow(phi_n.Divide(b), n).Equals(BigInteger.One))
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("g has order phi(n)/b\n g: " + g);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine("needed " + tries + " tries to generate g");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("found new NaccacheStern cipher variables:");
|
||||
Console.WriteLine("smallPrimes: " + Arrays.ToString(smallPrimes.ToArray()));
|
||||
Console.WriteLine("sigma:...... " + sigma + " (" + sigma.BitLength + " bits)");
|
||||
Console.WriteLine("a:.......... " + a);
|
||||
Console.WriteLine("b:.......... " + b);
|
||||
Console.WriteLine("p':......... " + p_);
|
||||
Console.WriteLine("q':......... " + q_);
|
||||
Console.WriteLine("p:.......... " + p);
|
||||
Console.WriteLine("q:.......... " + q);
|
||||
Console.WriteLine("n:.......... " + n);
|
||||
Console.WriteLine("phi(n):..... " + phi_n);
|
||||
Console.WriteLine("g:.......... " + g);
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
return new AsymmetricCipherKeyPair(new NaccacheSternKeyParameters(false, g, n, sigma.BitLength),
|
||||
new NaccacheSternPrivateKeyParameters(g, n, sigma.BitLength, smallPrimes, phi_n));
|
||||
}
|
||||
|
||||
private static BigInteger generatePrime(
|
||||
int bitLength,
|
||||
int certainty,
|
||||
SecureRandom rand)
|
||||
{
|
||||
return new BigInteger(bitLength, certainty, rand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a permuted ArrayList from the original one. The original List
|
||||
* is not modified
|
||||
*
|
||||
* @param arr
|
||||
* the ArrayList to be permuted
|
||||
* @param rand
|
||||
* the source of Randomness for permutation
|
||||
* @return a new ArrayList with the permuted elements.
|
||||
*/
|
||||
private static ArrayList permuteList(
|
||||
ArrayList arr,
|
||||
SecureRandom rand)
|
||||
{
|
||||
ArrayList retval = new ArrayList(arr.Count);
|
||||
|
||||
foreach (object element in arr)
|
||||
{
|
||||
int index = rand.Next(retval.Count + 1);
|
||||
retval.Insert(index, element);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first 'count' primes starting with 3
|
||||
*
|
||||
* @param count
|
||||
* the number of primes to find
|
||||
* @return a vector containing the found primes as Integer
|
||||
*/
|
||||
private static ArrayList findFirstPrimes(
|
||||
int count)
|
||||
{
|
||||
ArrayList primes = new ArrayList(count);
|
||||
|
||||
for (int i = 0; i != count; i++)
|
||||
{
|
||||
primes.Add(BigInteger.ValueOf(smallPrimes[i]));
|
||||
}
|
||||
|
||||
return primes;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Generator for PBE derived keys and ivs as usd by OpenSSL.
|
||||
* <p>
|
||||
* The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
|
||||
* iteration count of 1.
|
||||
* </p>
|
||||
*/
|
||||
public class OpenSslPbeParametersGenerator
|
||||
: PbeParametersGenerator
|
||||
{
|
||||
private readonly IDigest digest = new MD5Digest();
|
||||
|
||||
/**
|
||||
* Construct a OpenSSL Parameters generator.
|
||||
*/
|
||||
public OpenSslPbeParametersGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Init(
|
||||
byte[] password,
|
||||
byte[] salt,
|
||||
int iterationCount)
|
||||
{
|
||||
// Ignore the provided iterationCount
|
||||
base.Init(password, salt, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise - note the iteration count for this algorithm is fixed at 1.
|
||||
*
|
||||
* @param password password to use.
|
||||
* @param salt salt to use.
|
||||
*/
|
||||
public virtual void Init(
|
||||
byte[] password,
|
||||
byte[] salt)
|
||||
{
|
||||
base.Init(password, salt, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* the derived key function, the ith hash of the password and the salt.
|
||||
*/
|
||||
private byte[] GenerateDerivedKey(
|
||||
int bytesNeeded)
|
||||
{
|
||||
byte[] buf = new byte[digest.GetDigestSize()];
|
||||
byte[] key = new byte[bytesNeeded];
|
||||
int offset = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
digest.BlockUpdate(mPassword, 0, mPassword.Length);
|
||||
digest.BlockUpdate(mSalt, 0, mSalt.Length);
|
||||
|
||||
digest.DoFinal(buf, 0);
|
||||
|
||||
int len = (bytesNeeded > buf.Length) ? buf.Length : bytesNeeded;
|
||||
Array.Copy(buf, 0, key, offset, len);
|
||||
offset += len;
|
||||
|
||||
// check if we need any more
|
||||
bytesNeeded -= len;
|
||||
if (bytesNeeded == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// do another round
|
||||
digest.Reset();
|
||||
digest.BlockUpdate(buf, 0, buf.Length);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter derived from the password, salt, and iteration
|
||||
* count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
* @exception ArgumentException if the key length larger than the base hash size.
|
||||
*/
|
||||
[Obsolete("Use version with 'algorithm' parameter")]
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
int keySize)
|
||||
{
|
||||
return GenerateDerivedMacParameters(keySize);
|
||||
}
|
||||
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
string algorithm,
|
||||
int keySize)
|
||||
{
|
||||
keySize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(keySize);
|
||||
|
||||
return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key with initialisation vector parameter derived from
|
||||
* the password, salt, and iteration count we are currently initialised
|
||||
* with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @param ivSize the size of the iv we want (in bits)
|
||||
* @return a ParametersWithIV object.
|
||||
* @exception ArgumentException if keySize + ivSize is larger than the base hash size.
|
||||
*/
|
||||
[Obsolete("Use version with 'algorithm' parameter")]
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize = keySize / 8;
|
||||
ivSize = ivSize / 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(keySize + ivSize);
|
||||
|
||||
return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
|
||||
}
|
||||
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
string algorithm,
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize /= 8;
|
||||
ivSize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(keySize + ivSize);
|
||||
KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
|
||||
|
||||
return new ParametersWithIV(key, dKey, keySize, ivSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter for use with a MAC derived from the password,
|
||||
* salt, and iteration count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
* @exception ArgumentException if the key length larger than the base hash size.
|
||||
*/
|
||||
public override ICipherParameters GenerateDerivedMacParameters(
|
||||
int keySize)
|
||||
{
|
||||
keySize = keySize / 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(keySize);
|
||||
|
||||
return new KeyParameter(dKey, 0, keySize);
|
||||
}
|
||||
}
|
||||
}
|
245
iTechSharp/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs
Normal file
245
iTechSharp/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Generator for Pbe derived keys and ivs as defined by Pkcs 12 V1.0.
|
||||
* <p>
|
||||
* The document this implementation is based on can be found at
|
||||
* <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html">
|
||||
* RSA's Pkcs12 Page</a>
|
||||
* </p>
|
||||
*/
|
||||
public class Pkcs12ParametersGenerator
|
||||
: PbeParametersGenerator
|
||||
{
|
||||
public const int KeyMaterial = 1;
|
||||
public const int IVMaterial = 2;
|
||||
public const int MacMaterial = 3;
|
||||
|
||||
private readonly IDigest digest;
|
||||
|
||||
private readonly int u;
|
||||
private readonly int v;
|
||||
|
||||
/**
|
||||
* Construct a Pkcs 12 Parameters generator.
|
||||
*
|
||||
* @param digest the digest to be used as the source of derived keys.
|
||||
* @exception ArgumentException if an unknown digest is passed in.
|
||||
*/
|
||||
public Pkcs12ParametersGenerator(
|
||||
IDigest digest)
|
||||
{
|
||||
this.digest = digest;
|
||||
|
||||
u = digest.GetDigestSize();
|
||||
v = digest.GetByteLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* add a + b + 1, returning the result in a. The a value is treated
|
||||
* as a BigInteger of length (b.Length * 8) bits. The result is
|
||||
* modulo 2^b.Length in case of overflow.
|
||||
*/
|
||||
private void Adjust(
|
||||
byte[] a,
|
||||
int aOff,
|
||||
byte[] b)
|
||||
{
|
||||
int x = (b[b.Length - 1] & 0xff) + (a[aOff + b.Length - 1] & 0xff) + 1;
|
||||
|
||||
a[aOff + b.Length - 1] = (byte)x;
|
||||
x = (int) ((uint) x >> 8);
|
||||
|
||||
for (int i = b.Length - 2; i >= 0; i--)
|
||||
{
|
||||
x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
|
||||
a[aOff + i] = (byte)x;
|
||||
x = (int) ((uint) x >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generation of a derived key ala Pkcs12 V1.0.
|
||||
*/
|
||||
private byte[] GenerateDerivedKey(
|
||||
int idByte,
|
||||
int n)
|
||||
{
|
||||
byte[] D = new byte[v];
|
||||
byte[] dKey = new byte[n];
|
||||
|
||||
for (int i = 0; i != D.Length; i++)
|
||||
{
|
||||
D[i] = (byte)idByte;
|
||||
}
|
||||
|
||||
byte[] S;
|
||||
|
||||
if ((mSalt != null) && (mSalt.Length != 0))
|
||||
{
|
||||
S = new byte[v * ((mSalt.Length + v - 1) / v)];
|
||||
|
||||
for (int i = 0; i != S.Length; i++)
|
||||
{
|
||||
S[i] = mSalt[i % mSalt.Length];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
S = new byte[0];
|
||||
}
|
||||
|
||||
byte[] P;
|
||||
|
||||
if ((mPassword != null) && (mPassword.Length != 0))
|
||||
{
|
||||
P = new byte[v * ((mPassword.Length + v - 1) / v)];
|
||||
|
||||
for (int i = 0; i != P.Length; i++)
|
||||
{
|
||||
P[i] = mPassword[i % mPassword.Length];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P = new byte[0];
|
||||
}
|
||||
|
||||
byte[] I = new byte[S.Length + P.Length];
|
||||
|
||||
Array.Copy(S, 0, I, 0, S.Length);
|
||||
Array.Copy(P, 0, I, S.Length, P.Length);
|
||||
|
||||
byte[] B = new byte[v];
|
||||
int c = (n + u - 1) / u;
|
||||
|
||||
for (int i = 1; i <= c; i++)
|
||||
{
|
||||
byte[] A = new byte[u];
|
||||
|
||||
digest.BlockUpdate(D, 0, D.Length);
|
||||
digest.BlockUpdate(I, 0, I.Length);
|
||||
digest.DoFinal(A, 0);
|
||||
for (int j = 1; j != mIterationCount; j++)
|
||||
{
|
||||
digest.BlockUpdate(A, 0, A.Length);
|
||||
digest.DoFinal(A, 0);
|
||||
}
|
||||
|
||||
for (int j = 0; j != B.Length; j++)
|
||||
{
|
||||
B[j] = A[j % A.Length];
|
||||
}
|
||||
|
||||
for (int j = 0; j != I.Length / v; j++)
|
||||
{
|
||||
Adjust(I, j * v, B);
|
||||
}
|
||||
|
||||
if (i == c)
|
||||
{
|
||||
Array.Copy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(A, 0, dKey, (i - 1) * u, A.Length);
|
||||
}
|
||||
}
|
||||
|
||||
return dKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter derived from the password, salt, and iteration
|
||||
* count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
*/
|
||||
[Obsolete("Use version with 'algorithm' parameter")]
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
int keySize)
|
||||
{
|
||||
keySize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
|
||||
|
||||
return new KeyParameter(dKey, 0, keySize);
|
||||
}
|
||||
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
string algorithm,
|
||||
int keySize)
|
||||
{
|
||||
keySize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
|
||||
|
||||
return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key with initialisation vector parameter derived from
|
||||
* the password, salt, and iteration count we are currently initialised
|
||||
* with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @param ivSize the size of the iv we want (in bits)
|
||||
* @return a ParametersWithIV object.
|
||||
*/
|
||||
[Obsolete("Use version with 'algorithm' parameter")]
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize /= 8;
|
||||
ivSize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
|
||||
|
||||
byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
|
||||
|
||||
return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
|
||||
}
|
||||
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
string algorithm,
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize /= 8;
|
||||
ivSize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
|
||||
KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
|
||||
|
||||
byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
|
||||
|
||||
return new ParametersWithIV(key, iv, 0, ivSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter for use with a MAC derived from the password,
|
||||
* salt, and iteration count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
*/
|
||||
public override ICipherParameters GenerateDerivedMacParameters(
|
||||
int keySize)
|
||||
{
|
||||
keySize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(MacMaterial, keySize);
|
||||
|
||||
return new KeyParameter(dKey, 0, keySize);
|
||||
}
|
||||
}
|
||||
}
|
162
iTechSharp/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs
Normal file
162
iTechSharp/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 1.
|
||||
* Note this generator is limited to the size of the hash produced by the
|
||||
* digest used to drive it.
|
||||
* <p>
|
||||
* The document this implementation is based on can be found at
|
||||
* <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html">
|
||||
* RSA's Pkcs5 Page</a>
|
||||
* </p>
|
||||
*/
|
||||
public class Pkcs5S1ParametersGenerator
|
||||
: PbeParametersGenerator
|
||||
{
|
||||
private readonly IDigest digest;
|
||||
|
||||
/**
|
||||
* Construct a Pkcs 5 Scheme 1 Parameters generator.
|
||||
*
|
||||
* @param digest the digest to be used as the source of derived keys.
|
||||
*/
|
||||
public Pkcs5S1ParametersGenerator(
|
||||
IDigest digest)
|
||||
{
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* the derived key function, the ith hash of the mPassword and the mSalt.
|
||||
*/
|
||||
private byte[] GenerateDerivedKey()
|
||||
{
|
||||
byte[] digestBytes = new byte[digest.GetDigestSize()];
|
||||
|
||||
digest.BlockUpdate(mPassword, 0, mPassword.Length);
|
||||
digest.BlockUpdate(mSalt, 0, mSalt.Length);
|
||||
|
||||
digest.DoFinal(digestBytes, 0);
|
||||
for (int i = 1; i < mIterationCount; i++)
|
||||
{
|
||||
digest.BlockUpdate(digestBytes, 0, digestBytes.Length);
|
||||
digest.DoFinal(digestBytes, 0);
|
||||
}
|
||||
|
||||
return digestBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter derived from the mPassword, mSalt, and iteration
|
||||
* count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
* @exception ArgumentException if the key length larger than the base hash size.
|
||||
*/
|
||||
[Obsolete("Use version with 'algorithm' parameter")]
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
int keySize)
|
||||
{
|
||||
return GenerateDerivedMacParameters(keySize);
|
||||
}
|
||||
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
string algorithm,
|
||||
int keySize)
|
||||
{
|
||||
keySize /= 8;
|
||||
|
||||
if (keySize > digest.GetDigestSize())
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Can't Generate a derived key " + keySize + " bytes long.");
|
||||
}
|
||||
|
||||
byte[] dKey = GenerateDerivedKey();
|
||||
|
||||
return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key with initialisation vector parameter derived from
|
||||
* the mPassword, mSalt, and iteration count we are currently initialised
|
||||
* with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @param ivSize the size of the iv we want (in bits)
|
||||
* @return a ParametersWithIV object.
|
||||
* @exception ArgumentException if keySize + ivSize is larger than the base hash size.
|
||||
*/
|
||||
[Obsolete("Use version with 'algorithm' parameter")]
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize /= 8;
|
||||
ivSize /= 8;
|
||||
|
||||
if ((keySize + ivSize) > digest.GetDigestSize())
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
|
||||
}
|
||||
|
||||
byte[] dKey = GenerateDerivedKey();
|
||||
|
||||
return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
|
||||
}
|
||||
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
string algorithm,
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize /= 8;
|
||||
ivSize /= 8;
|
||||
|
||||
if ((keySize + ivSize) > digest.GetDigestSize())
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
|
||||
}
|
||||
|
||||
byte[] dKey = GenerateDerivedKey();
|
||||
KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
|
||||
|
||||
return new ParametersWithIV(key, dKey, keySize, ivSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter for use with a MAC derived from the mPassword,
|
||||
* mSalt, and iteration count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
* @exception ArgumentException if the key length larger than the base hash size.
|
||||
*/
|
||||
public override ICipherParameters GenerateDerivedMacParameters(
|
||||
int keySize)
|
||||
{
|
||||
keySize /= 8;
|
||||
|
||||
if (keySize > digest.GetDigestSize())
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Can't Generate a derived key " + keySize + " bytes long.");
|
||||
}
|
||||
|
||||
byte[] dKey = GenerateDerivedKey();
|
||||
|
||||
return new KeyParameter(dKey, 0, keySize);
|
||||
}
|
||||
}
|
||||
}
|
175
iTechSharp/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs
Normal file
175
iTechSharp/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using Org.BouncyCastle.Crypto.Macs;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 2.
|
||||
* This generator uses a SHA-1 HMac as the calculation function.
|
||||
* <p>
|
||||
* The document this implementation is based on can be found at
|
||||
* <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html">
|
||||
* RSA's Pkcs5 Page</a></p>
|
||||
*/
|
||||
public class Pkcs5S2ParametersGenerator
|
||||
: PbeParametersGenerator
|
||||
{
|
||||
private readonly IMac hMac = new HMac(new Sha1Digest());
|
||||
|
||||
/**
|
||||
* construct a Pkcs5 Scheme 2 Parameters generator.
|
||||
*/
|
||||
public Pkcs5S2ParametersGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private void F(
|
||||
byte[] P,
|
||||
byte[] S,
|
||||
int c,
|
||||
byte[] iBuf,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
byte[] state = new byte[hMac.GetMacSize()];
|
||||
ICipherParameters param = new KeyParameter(P);
|
||||
|
||||
hMac.Init(param);
|
||||
|
||||
if (S != null)
|
||||
{
|
||||
hMac.BlockUpdate(S, 0, S.Length);
|
||||
}
|
||||
|
||||
hMac.BlockUpdate(iBuf, 0, iBuf.Length);
|
||||
|
||||
hMac.DoFinal(state, 0);
|
||||
|
||||
Array.Copy(state, 0, outBytes, outOff, state.Length);
|
||||
|
||||
for (int count = 1; count != c; count++)
|
||||
{
|
||||
hMac.Init(param);
|
||||
hMac.BlockUpdate(state, 0, state.Length);
|
||||
hMac.DoFinal(state, 0);
|
||||
|
||||
for (int j = 0; j != state.Length; j++)
|
||||
{
|
||||
outBytes[outOff + j] ^= state[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void IntToOctet(
|
||||
byte[] Buffer,
|
||||
int i)
|
||||
{
|
||||
Buffer[0] = (byte)((uint) i >> 24);
|
||||
Buffer[1] = (byte)((uint) i >> 16);
|
||||
Buffer[2] = (byte)((uint) i >> 8);
|
||||
Buffer[3] = (byte)i;
|
||||
}
|
||||
|
||||
private byte[] GenerateDerivedKey(
|
||||
int dkLen)
|
||||
{
|
||||
int hLen = hMac.GetMacSize();
|
||||
int l = (dkLen + hLen - 1) / hLen;
|
||||
byte[] iBuf = new byte[4];
|
||||
byte[] outBytes = new byte[l * hLen];
|
||||
|
||||
for (int i = 1; i <= l; i++)
|
||||
{
|
||||
IntToOctet(iBuf, i);
|
||||
|
||||
F(mPassword, mSalt, mIterationCount, iBuf, outBytes, (i - 1) * hLen);
|
||||
}
|
||||
|
||||
return outBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter derived from the password, salt, and iteration
|
||||
* count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
*/
|
||||
[Obsolete("Use version with 'algorithm' parameter")]
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
int keySize)
|
||||
{
|
||||
return GenerateDerivedMacParameters(keySize);
|
||||
}
|
||||
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
string algorithm,
|
||||
int keySize)
|
||||
{
|
||||
keySize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(keySize);
|
||||
|
||||
return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key with initialisation vector parameter derived from
|
||||
* the password, salt, and iteration count we are currently initialised
|
||||
* with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @param ivSize the size of the iv we want (in bits)
|
||||
* @return a ParametersWithIV object.
|
||||
*/
|
||||
[Obsolete("Use version with 'algorithm' parameter")]
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize /= 8;
|
||||
ivSize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(keySize + ivSize);
|
||||
|
||||
return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
|
||||
}
|
||||
|
||||
public override ICipherParameters GenerateDerivedParameters(
|
||||
string algorithm,
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize /= 8;
|
||||
ivSize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(keySize + ivSize);
|
||||
KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
|
||||
|
||||
return new ParametersWithIV(key, dKey, keySize, ivSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter for use with a MAC derived from the password,
|
||||
* salt, and iteration count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
*/
|
||||
public override ICipherParameters GenerateDerivedMacParameters(
|
||||
int keySize)
|
||||
{
|
||||
keySize /= 8;
|
||||
|
||||
byte[] dKey = GenerateDerivedKey(keySize);
|
||||
|
||||
return new KeyParameter(dKey, 0, keySize);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* Generate a random factor suitable for use with RSA blind signatures
|
||||
* as outlined in Chaum's blinding and unblinding as outlined in
|
||||
* "Handbook of Applied Cryptography", page 475.
|
||||
*/
|
||||
public class RsaBlindingFactorGenerator
|
||||
{
|
||||
private RsaKeyParameters key;
|
||||
private SecureRandom random;
|
||||
|
||||
/**
|
||||
* Initialise the factor generator
|
||||
*
|
||||
* @param param the necessary RSA key parameters.
|
||||
*/
|
||||
public void Init(
|
||||
ICipherParameters param)
|
||||
{
|
||||
if (param is ParametersWithRandom)
|
||||
{
|
||||
ParametersWithRandom rParam = (ParametersWithRandom)param;
|
||||
|
||||
key = (RsaKeyParameters)rParam.Parameters;
|
||||
random = rParam.Random;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = (RsaKeyParameters)param;
|
||||
random = new SecureRandom();
|
||||
}
|
||||
|
||||
if (key.IsPrivate)
|
||||
throw new ArgumentException("generator requires RSA public key");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a suitable blind factor for the public key the generator was initialised with.
|
||||
*
|
||||
* @return a random blind factor
|
||||
*/
|
||||
public BigInteger GenerateBlindingFactor()
|
||||
{
|
||||
if (key == null)
|
||||
throw new InvalidOperationException("generator not initialised");
|
||||
|
||||
BigInteger m = key.Modulus;
|
||||
int length = m.BitLength - 1; // must be less than m.BitLength
|
||||
BigInteger factor;
|
||||
BigInteger gcd;
|
||||
|
||||
do
|
||||
{
|
||||
factor = new BigInteger(length, random);
|
||||
gcd = factor.Gcd(m);
|
||||
}
|
||||
while (factor.SignValue == 0 || factor.Equals(BigInteger.One) || !gcd.Equals(BigInteger.One));
|
||||
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
}
|
139
iTechSharp/srcbc/crypto/generators/RsaKeyPairGenerator.cs
Normal file
139
iTechSharp/srcbc/crypto/generators/RsaKeyPairGenerator.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Generators
|
||||
{
|
||||
/**
|
||||
* an RSA key pair generator.
|
||||
*/
|
||||
public class RsaKeyPairGenerator
|
||||
: IAsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
|
||||
private const int DefaultTests = 12;
|
||||
|
||||
private RsaKeyGenerationParameters param;
|
||||
|
||||
public void Init(
|
||||
KeyGenerationParameters parameters)
|
||||
{
|
||||
if (parameters is RsaKeyGenerationParameters)
|
||||
{
|
||||
this.param = (RsaKeyGenerationParameters)parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.param = new RsaKeyGenerationParameters(
|
||||
DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
|
||||
}
|
||||
}
|
||||
|
||||
public AsymmetricCipherKeyPair GenerateKeyPair()
|
||||
{
|
||||
BigInteger p, q, n, d, e, pSub1, qSub1, phi;
|
||||
|
||||
//
|
||||
// p and q values should have a length of half the strength in bits
|
||||
//
|
||||
int strength = param.Strength;
|
||||
int pbitlength = (strength + 1) / 2;
|
||||
int qbitlength = (strength - pbitlength);
|
||||
int mindiffbits = strength / 3;
|
||||
|
||||
e = param.PublicExponent;
|
||||
|
||||
// TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
|
||||
// (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
|
||||
|
||||
//
|
||||
// Generate p, prime and (p-1) relatively prime to e
|
||||
//
|
||||
for (;;)
|
||||
{
|
||||
p = new BigInteger(pbitlength, 1, param.Random);
|
||||
|
||||
if (p.Mod(e).Equals(BigInteger.One))
|
||||
continue;
|
||||
|
||||
if (!p.IsProbablePrime(param.Certainty))
|
||||
continue;
|
||||
|
||||
if (e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One))
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Generate a modulus of the required length
|
||||
//
|
||||
for (;;)
|
||||
{
|
||||
// Generate q, prime and (q-1) relatively prime to e,
|
||||
// and not equal to p
|
||||
//
|
||||
for (;;)
|
||||
{
|
||||
q = new BigInteger(qbitlength, 1, param.Random);
|
||||
|
||||
if (q.Subtract(p).Abs().BitLength < mindiffbits)
|
||||
continue;
|
||||
|
||||
if (q.Mod(e).Equals(BigInteger.One))
|
||||
continue;
|
||||
|
||||
if (!q.IsProbablePrime(param.Certainty))
|
||||
continue;
|
||||
|
||||
if (e.Gcd(q.Subtract(BigInteger.One)).Equals(BigInteger.One))
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// calculate the modulus
|
||||
//
|
||||
n = p.Multiply(q);
|
||||
|
||||
if (n.BitLength == param.Strength)
|
||||
break;
|
||||
|
||||
//
|
||||
// if we Get here our primes aren't big enough, make the largest
|
||||
// of the two p and try again
|
||||
//
|
||||
p = p.Max(q);
|
||||
}
|
||||
|
||||
if (p.CompareTo(q) < 0)
|
||||
{
|
||||
phi = p;
|
||||
p = q;
|
||||
q = phi;
|
||||
}
|
||||
|
||||
pSub1 = p.Subtract(BigInteger.One);
|
||||
qSub1 = q.Subtract(BigInteger.One);
|
||||
phi = pSub1.Multiply(qSub1);
|
||||
|
||||
//
|
||||
// calculate the private exponent
|
||||
//
|
||||
d = e.ModInverse(phi);
|
||||
|
||||
//
|
||||
// calculate the CRT factors
|
||||
//
|
||||
BigInteger dP, dQ, qInv;
|
||||
|
||||
dP = d.Remainder(pSub1);
|
||||
dQ = d.Remainder(qSub1);
|
||||
qInv = q.ModInverse(p);
|
||||
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new RsaKeyParameters(false, n, e),
|
||||
new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user