diff --git a/crypto/src/crypto/signers/DsaSigner.cs b/crypto/src/crypto/signers/DsaSigner.cs
index fc0780a91..bb28addfc 100644
--- a/crypto/src/crypto/signers/DsaSigner.cs
+++ b/crypto/src/crypto/signers/DsaSigner.cs
@@ -1,10 +1,9 @@
using System;
-using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Math.EC;
-using Org.BouncyCastle.Security;
-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.Signers
{
@@ -15,9 +14,29 @@ namespace Org.BouncyCastle.Crypto.Signers
public class DsaSigner
: IDsa
{
+ protected readonly IDsaKCalculator kCalculator;
+
protected DsaKeyParameters key = null;
protected SecureRandom random = null;
+ /**
+ * Default configuration, random K values.
+ */
+ public DsaSigner()
+ {
+ this.kCalculator = new RandomDsaKCalculator();
+ }
+
+ /**
+ * Configuration with an alternate, possibly deterministic calculator of K.
+ *
+ * @param kCalculator a K value calculator.
+ */
+ public DsaSigner(IDsaKCalculator kCalculator)
+ {
+ this.kCalculator = kCalculator;
+ }
+
public virtual string AlgorithmName
{
get { return "DSA"; }
@@ -50,7 +69,7 @@ namespace Org.BouncyCastle.Crypto.Signers
this.key = (DsaPublicKeyParameters)parameters;
}
- this.random = InitSecureRandom(forSigning, providedRandom);
+ this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
}
/**
@@ -65,18 +84,22 @@ namespace Org.BouncyCastle.Crypto.Signers
DsaParameters parameters = key.Parameters;
BigInteger q = parameters.Q;
BigInteger m = CalculateE(q, message);
- BigInteger k;
+ BigInteger x = ((DsaPrivateKeyParameters)key).X;
- do
+ if (kCalculator.IsDeterministic)
{
- k = new BigInteger(q.BitLength, random);
+ kCalculator.Init(q, x, message);
}
- while (k.CompareTo(q) >= 0);
+ else
+ {
+ kCalculator.Init(q, random);
+ }
+
+ BigInteger k = kCalculator.NextK();
BigInteger r = parameters.G.ModPow(k, parameters.P).Mod(q);
- k = k.ModInverse(q).Multiply(
- m.Add(((DsaPrivateKeyParameters)key).X.Multiply(r)));
+ k = k.ModInverse(q).Multiply(m.Add(x.Multiply(r)));
BigInteger s = k.Mod(q);
diff --git a/crypto/src/crypto/signers/ECDsaSigner.cs b/crypto/src/crypto/signers/ECDsaSigner.cs
index 867520535..9821732c2 100644
--- a/crypto/src/crypto/signers/ECDsaSigner.cs
+++ b/crypto/src/crypto/signers/ECDsaSigner.cs
@@ -1,11 +1,11 @@
using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math.EC.Multiplier;
using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Signers
{
@@ -15,9 +15,29 @@ namespace Org.BouncyCastle.Crypto.Signers
public class ECDsaSigner
: IDsa
{
+ protected readonly IDsaKCalculator kCalculator;
+
protected ECKeyParameters key = null;
protected SecureRandom random = null;
+ /**
+ * Default configuration, random K values.
+ */
+ public ECDsaSigner()
+ {
+ this.kCalculator = new RandomDsaKCalculator();
+ }
+
+ /**
+ * Configuration with an alternate, possibly deterministic calculator of K.
+ *
+ * @param kCalculator a K value calculator.
+ */
+ public ECDsaSigner(IDsaKCalculator kCalculator)
+ {
+ this.kCalculator = kCalculator;
+ }
+
public virtual string AlgorithmName
{
get { return "ECDSA"; }
@@ -50,7 +70,7 @@ namespace Org.BouncyCastle.Crypto.Signers
this.key = (ECPublicKeyParameters)parameters;
}
- this.random = InitSecureRandom(forSigning, providedRandom);
+ this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
}
// 5.3 pg 28
@@ -68,6 +88,15 @@ namespace Org.BouncyCastle.Crypto.Signers
BigInteger e = CalculateE(n, message);
BigInteger d = ((ECPrivateKeyParameters)key).D;
+ if (kCalculator.IsDeterministic)
+ {
+ kCalculator.Init(n, d, message);
+ }
+ else
+ {
+ kCalculator.Init(n, random);
+ }
+
BigInteger r, s;
ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
@@ -78,11 +107,7 @@ namespace Org.BouncyCastle.Crypto.Signers
BigInteger k;
do // Generate r
{
- do
- {
- k = new BigInteger(n.BitLength, random);
- }
- while (k.SignValue == 0 || k.CompareTo(n) >= 0);
+ k = kCalculator.NextK();
ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();
diff --git a/crypto/src/crypto/signers/HMacDsaKCalculator.cs b/crypto/src/crypto/signers/HMacDsaKCalculator.cs
new file mode 100644
index 000000000..8231197b9
--- /dev/null
+++ b/crypto/src/crypto/signers/HMacDsaKCalculator.cs
@@ -0,0 +1,150 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * A deterministic K calculator based on the algorithm in section 3.2 of RFC 6979.
+ */
+ public class HMacDsaKCalculator
+ : IDsaKCalculator
+ {
+ private readonly HMac hMac;
+ private readonly byte[] K;
+ private readonly byte[] V;
+
+ private BigInteger n;
+
+ /**
+ * Base constructor.
+ *
+ * @param digest digest to build the HMAC on.
+ */
+ public HMacDsaKCalculator(IDigest digest)
+ {
+ this.hMac = new HMac(digest);
+ this.V = new byte[hMac.GetMacSize()];
+ this.K = new byte[hMac.GetMacSize()];
+ }
+
+ public virtual bool IsDeterministic
+ {
+ get { return true; }
+ }
+
+ public virtual void Init(BigInteger n, SecureRandom random)
+ {
+ throw new InvalidOperationException("Operation not supported");
+ }
+
+ public void Init(BigInteger n, BigInteger d, byte[] message)
+ {
+ this.n = n;
+
+ Arrays.Fill(V, (byte)0x01);
+ Arrays.Fill(K, (byte)0);
+
+ byte[] x = new byte[(n.BitLength + 7) / 8];
+ byte[] dVal = BigIntegers.AsUnsignedByteArray(d);
+
+ Array.Copy(dVal, 0, x, x.Length - dVal.Length, dVal.Length);
+
+ byte[] m = new byte[(n.BitLength + 7) / 8];
+
+ BigInteger mInt = BitsToInt(message);
+
+ if (mInt.CompareTo(n) >= 0)
+ {
+ mInt = mInt.Subtract(n);
+ }
+
+ byte[] mVal = BigIntegers.AsUnsignedByteArray(mInt);
+
+ Array.Copy(mVal, 0, m, m.Length - mVal.Length, mVal.Length);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x00);
+ hMac.BlockUpdate(x, 0, x.Length);
+ hMac.BlockUpdate(m, 0, m.Length);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x01);
+ hMac.BlockUpdate(x, 0, x.Length);
+ hMac.BlockUpdate(m, 0, m.Length);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+ }
+
+ public virtual BigInteger NextK()
+ {
+ byte[] t = new byte[((n.BitLength + 7) / 8)];
+
+ for (;;)
+ {
+ int tOff = 0;
+
+ while (tOff < t.Length)
+ {
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+
+ int len = System.Math.Min(t.Length - tOff, V.Length);
+ Array.Copy(V, 0, t, tOff, len);
+ tOff += len;
+ }
+
+ BigInteger k = BitsToInt(t);
+
+ if (k.SignValue > 0 && k.CompareTo(n) < 0)
+ {
+ return k;
+ }
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x00);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+ }
+ }
+
+ private BigInteger BitsToInt(byte[] t)
+ {
+ BigInteger v = new BigInteger(1, t);
+
+ if (t.Length * 8 > n.BitLength)
+ {
+ v = v.ShiftRight(t.Length * 8 - n.BitLength);
+ }
+
+ return v;
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/IDsaKCalculator.cs b/crypto/src/crypto/signers/IDsaKCalculator.cs
new file mode 100644
index 000000000..645186d41
--- /dev/null
+++ b/crypto/src/crypto/signers/IDsaKCalculator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * Interface define calculators of K values for DSA/ECDSA.
+ */
+ public interface IDsaKCalculator
+ {
+ /**
+ * Return true if this calculator is deterministic, false otherwise.
+ *
+ * @return true if deterministic, otherwise false.
+ */
+ bool IsDeterministic { get; }
+
+ /**
+ * Non-deterministic initialiser.
+ *
+ * @param n the order of the DSA group.
+ * @param random a source of randomness.
+ */
+ void Init(BigInteger n, SecureRandom random);
+
+ /**
+ * Deterministic initialiser.
+ *
+ * @param n the order of the DSA group.
+ * @param d the DSA private value.
+ * @param message the message being signed.
+ */
+ void Init(BigInteger n, BigInteger d, byte[] message);
+
+ /**
+ * Return the next valid value of K.
+ *
+ * @return a K value.
+ */
+ BigInteger NextK();
+ }
+}
diff --git a/crypto/src/crypto/signers/RandomDsaKCalculator.cs b/crypto/src/crypto/signers/RandomDsaKCalculator.cs
new file mode 100644
index 000000000..022cc268d
--- /dev/null
+++ b/crypto/src/crypto/signers/RandomDsaKCalculator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class RandomDsaKCalculator
+ : IDsaKCalculator
+ {
+ private BigInteger q;
+ private SecureRandom random;
+
+ public virtual bool IsDeterministic
+ {
+ get { return false; }
+ }
+
+ public virtual void Init(BigInteger n, SecureRandom random)
+ {
+ this.q = n;
+ this.random = random;
+ }
+
+ public virtual void Init(BigInteger n, BigInteger d, byte[] message)
+ {
+ throw new InvalidOperationException("Operation not supported");
+ }
+
+ public virtual BigInteger NextK()
+ {
+ int qBitLength = q.BitLength;
+
+ BigInteger k;
+ do
+ {
+ k = new BigInteger(qBitLength, random);
+ }
+ while (k.SignValue < 1 || k.CompareTo(q) >= 0);
+
+ return k;
+ }
+ }
+}
|