Initial Commit

This commit is contained in:
2023-06-21 12:46:23 -04:00
commit c70248a520
1352 changed files with 336780 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
using System;
using System.Diagnostics;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Agreement
{
/**
* a Diffie-Hellman key exchange engine.
* <p>
* note: This uses MTI/A0 key agreement in order to make the key agreement
* secure against passive attacks. If you're doing Diffie-Hellman and both
* parties have long term public keys you should look at using this. For
* further information have a look at RFC 2631.</p>
* <p>
* It's possible to extend this to more than two parties as well, for the moment
* that is left as an exercise for the reader.</p>
*/
public class DHAgreement
{
private DHPrivateKeyParameters key;
private DHParameters dhParams;
private BigInteger privateValue;
private SecureRandom random;
public void Init(
ICipherParameters parameters)
{
AsymmetricKeyParameter kParam;
if (parameters is ParametersWithRandom)
{
ParametersWithRandom rParam = (ParametersWithRandom)parameters;
this.random = rParam.Random;
kParam = (AsymmetricKeyParameter)rParam.Parameters;
}
else
{
this.random = new SecureRandom();
kParam = (AsymmetricKeyParameter)parameters;
}
if (!(kParam is DHPrivateKeyParameters))
{
throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
}
this.key = (DHPrivateKeyParameters)kParam;
this.dhParams = key.Parameters;
}
/**
* calculate our initial message.
*/
public BigInteger CalculateMessage()
{
int bits = dhParams.P.BitLength - 1;
// TODO Should the generated numbers always have length 'P.BitLength - 1'?
this.privateValue = new BigInteger(bits, random).SetBit(bits - 1);
return dhParams.G.ModPow(privateValue, dhParams.P);
}
/**
* given a message from a given party and the corresponding public key
* calculate the next message in the agreement sequence. In this case
* this will represent the shared secret.
*/
public BigInteger CalculateAgreement(
DHPublicKeyParameters pub,
BigInteger message)
{
if (pub == null)
throw new ArgumentNullException("pub");
if (message == null)
throw new ArgumentNullException("message");
if (!pub.Parameters.Equals(dhParams))
{
throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
}
return message.ModPow(key.X, dhParams.P).Multiply(pub.Y.ModPow(privateValue, dhParams.P)).Mod(dhParams.P);
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Agreement
{
/**
* a Diffie-Hellman key agreement class.
* <p>
* note: This is only the basic algorithm, it doesn't take advantage of
* long term public keys if they are available. See the DHAgreement class
* for a "better" implementation.</p>
*/
public class DHBasicAgreement
: IBasicAgreement
{
private DHPrivateKeyParameters key;
private DHParameters dhParams;
public void Init(
ICipherParameters parameters)
{
if (parameters is ParametersWithRandom)
{
parameters = ((ParametersWithRandom) parameters).Parameters;
}
if (!(parameters is DHPrivateKeyParameters))
{
throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
}
this.key = (DHPrivateKeyParameters) parameters;
this.dhParams = key.Parameters;
}
/**
* given a short term public key from a given party calculate the next
* message in the agreement sequence.
*/
public BigInteger CalculateAgreement(
ICipherParameters pubKey)
{
if (this.key == null)
throw new InvalidOperationException("Agreement algorithm not initialised");
DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey;
if (!pub.Parameters.Equals(dhParams))
{
throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
}
return pub.Y.ModPow(key.X, dhParams.P);
}
}
}

View File

@@ -0,0 +1,50 @@
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Agreement
{
/**
* P1363 7.2.1 ECSVDP-DH
*
* ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
* Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
* and [Kob87]. This primitive derives a shared secret value from one
* party's private key and another party's public key, where both have
* the same set of EC domain parameters. If two parties correctly
* execute this primitive, they will produce the same output. This
* primitive can be invoked by a scheme to derive a shared secret key;
* specifically, it may be used with the schemes ECKAS-DH1 and
* DL/ECKAS-DH2. It assumes that the input keys are valid (see also
* Section 7.2.2).
*/
public class ECDHBasicAgreement
: IBasicAgreement
{
private ECPrivateKeyParameters key;
public void Init(
ICipherParameters parameters)
{
if (parameters is ParametersWithRandom)
{
parameters = ((ParametersWithRandom) parameters).Parameters;
}
this.key = (ECPrivateKeyParameters) parameters;
}
public virtual BigInteger CalculateAgreement(
ICipherParameters pubKey)
{
ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
ECPoint P = pub.Q.Multiply(key.D);
// if ( p.IsInfinity ) throw new Exception("d*Q == infinity");
return P.X.ToBigInteger();
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Agreement
{
/**
* P1363 7.2.2 ECSVDP-DHC
*
* ECSVDP-DHC is Elliptic Curve Secret Value Derivation Primitive,
* Diffie-Hellman version with cofactor multiplication. It is based on
* the work of [DH76], [Mil86], [Kob87], [LMQ98] and [Kal98a]. This
* primitive derives a shared secret value from one party's private key
* and another party's public key, where both have the same set of EC
* domain parameters. If two parties correctly execute this primitive,
* they will produce the same output. This primitive can be invoked by a
* scheme to derive a shared secret key; specifically, it may be used
* with the schemes ECKAS-DH1 and DL/ECKAS-DH2. It does not assume the
* validity of the input public key (see also Section 7.2.1).
* <p>
* Note: As stated P1363 compatibility mode with ECDH can be preset, and
* in this case the implementation doesn't have a ECDH compatibility mode
* (if you want that just use ECDHBasicAgreement and note they both implement
* BasicAgreement!).</p>
*/
public class ECDHCBasicAgreement
: IBasicAgreement
{
private ECPrivateKeyParameters key;
public void Init(
ICipherParameters parameters)
{
if (parameters is ParametersWithRandom)
{
parameters = ((ParametersWithRandom) parameters).Parameters;
}
this.key = (ECPrivateKeyParameters)parameters;
}
public BigInteger CalculateAgreement(
ICipherParameters pubKey)
{
ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
ECDomainParameters parameters = pub.Parameters;
ECPoint P = pub.Q.Multiply(parameters.H.Multiply(key.D));
// if ( p.IsInfinity ) throw new Exception("Invalid public key");
return P.X.ToBigInteger();
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Crypto.Agreement.Kdf;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Crypto.Agreement
{
public class ECDHWithKdfBasicAgreement
: ECDHBasicAgreement
{
private static readonly Hashtable algorithms = new Hashtable();
static ECDHWithKdfBasicAgreement()
{
algorithms.Add(NistObjectIdentifiers.IdAes128Cbc.Id, 128);
algorithms.Add(NistObjectIdentifiers.IdAes192Cbc.Id, 192);
algorithms.Add(NistObjectIdentifiers.IdAes256Cbc.Id, 256);
algorithms.Add(NistObjectIdentifiers.IdAes128Wrap.Id, 128);
algorithms.Add(NistObjectIdentifiers.IdAes192Wrap.Id, 192);
algorithms.Add(NistObjectIdentifiers.IdAes256Wrap.Id, 256);
algorithms.Add(PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id, 192);
}
private readonly string algorithm;
private readonly IDerivationFunction kdf;
public ECDHWithKdfBasicAgreement(
string algorithm,
IDerivationFunction kdf)
{
if (algorithm == null)
throw new ArgumentNullException("algorithm");
if (!algorithms.Contains(algorithm))
throw new ArgumentException("Unknown algorithm", "algorithm");
if (kdf == null)
throw new ArgumentNullException("kdf");
this.algorithm = algorithm;
this.kdf = kdf;
}
public override BigInteger CalculateAgreement(
ICipherParameters pubKey)
{
BigInteger result = base.CalculateAgreement(pubKey);
int keySize = (int) algorithms[algorithm];
DHKdfParameters dhKdfParams = new DHKdfParameters(
new DerObjectIdentifier(algorithm),
keySize,
// TODO Fix the way bytes are derived from the secret
result.ToByteArrayUnsigned());
kdf.Init(dhKdfParams);
byte[] keyBytes = new byte[keySize / 8];
kdf.GenerateBytes(keyBytes, 0, keyBytes.Length);
return new BigInteger(1, keyBytes);
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using Org.BouncyCastle.Asn1;
namespace Org.BouncyCastle.Crypto.Agreement.Kdf
{
public class DHKdfParameters
: IDerivationParameters
{
private readonly DerObjectIdentifier algorithm;
private readonly int keySize;
private readonly byte[] z;
private readonly byte[] extraInfo;
public DHKdfParameters(
DerObjectIdentifier algorithm,
int keySize,
byte[] z)
: this(algorithm, keySize, z, null)
{
}
public DHKdfParameters(
DerObjectIdentifier algorithm,
int keySize,
byte[] z,
byte[] extraInfo)
{
this.algorithm = algorithm;
this.keySize = keySize;
this.z = z; // TODO Clone?
this.extraInfo = extraInfo;
}
public DerObjectIdentifier Algorithm
{
get { return algorithm; }
}
public int KeySize
{
get { return keySize; }
}
public byte[] GetZ()
{
// TODO Clone?
return z;
}
public byte[] GetExtraInfo()
{
// TODO Clone?
return extraInfo;
}
}
}

View File

@@ -0,0 +1,129 @@
using System;
using Org.BouncyCastle.Asn1;
namespace Org.BouncyCastle.Crypto.Agreement.Kdf
{
/**
* RFC 2631 Diffie-hellman KEK derivation function.
*/
public class DHKekGenerator
: IDerivationFunction
{
private readonly IDigest digest;
private DerObjectIdentifier algorithm;
private int keySize;
private byte[] z;
private byte[] partyAInfo;
public DHKekGenerator(
IDigest digest)
{
this.digest = digest;
}
public void Init(
IDerivationParameters param)
{
DHKdfParameters parameters = (DHKdfParameters)param;
this.algorithm = parameters.Algorithm;
this.keySize = parameters.KeySize;
this.z = parameters.GetZ(); // TODO Clone?
this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone?
}
public IDigest Digest
{
get { return digest; }
}
public int GenerateBytes(
byte[] outBytes,
int outOff,
int len)
{
if ((outBytes.Length - len) < outOff)
{
throw new DataLengthException("output buffer too small");
}
long oBytes = len;
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 = 1;
for (int i = 0; i < cThreshold; i++)
{
digest.BlockUpdate(z, 0, z.Length);
// KeySpecificInfo
DerSequence keyInfo = new DerSequence(
algorithm,
new DerOctetString(integerToBytes(counter)));
// OtherInfo
Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo);
if (partyAInfo != null)
{
v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo)));
}
v1.Add(new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize))));
byte[] other = new DerSequence(v1).GetDerEncoded();
digest.BlockUpdate(other, 0, other.Length);
digest.DoFinal(dig, 0);
if (len > outLen)
{
Array.Copy(dig, 0, outBytes, outOff, outLen);
outOff += outLen;
len -= outLen;
}
else
{
Array.Copy(dig, 0, outBytes, outOff, len);
}
counter++;
}
digest.Reset();
return len;
}
private byte[] integerToBytes(
int keySize)
{
byte[] val = new byte[4];
val[0] = (byte)(keySize >> 24);
val[1] = (byte)(keySize >> 16);
val[2] = (byte)(keySize >> 8);
val[3] = (byte)keySize;
return val;
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Agreement.Kdf
{
/**
* X9.63 based key derivation function for ECDH CMS.
*/
public class ECDHKekGenerator
: IDerivationFunction
{
private readonly IDerivationFunction kdf;
private DerObjectIdentifier algorithm;
private int keySize;
private byte[] z;
public ECDHKekGenerator(
IDigest digest)
{
this.kdf = new Kdf2BytesGenerator(digest);
}
public void Init(
IDerivationParameters param)
{
DHKdfParameters parameters = (DHKdfParameters)param;
this.algorithm = parameters.Algorithm;
this.keySize = parameters.KeySize;
this.z = parameters.GetZ(); // TODO Clone?
}
public IDigest Digest
{
get { return kdf.Digest; }
}
public int GenerateBytes(
byte[] outBytes,
int outOff,
int len)
{
// ECC-CMS-SharedInfo
DerSequence s = new DerSequence(
new AlgorithmIdentifier(algorithm, DerNull.Instance),
new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize))));
kdf.Init(new KdfParameters(z, s.GetDerEncoded()));
return kdf.GenerateBytes(outBytes, outOff, len);
}
private byte[] integerToBytes(int keySize)
{
byte[] val = new byte[4];
val[0] = (byte)(keySize >> 24);
val[1] = (byte)(keySize >> 16);
val[2] = (byte)(keySize >> 8);
val[3] = (byte)keySize;
return val;
}
}
}