diff --git a/crypto/src/crypto/CipherKeyGenerator.cs b/crypto/src/crypto/CipherKeyGenerator.cs
index 5d00d34dd..d8d9b29b5 100644
--- a/crypto/src/crypto/CipherKeyGenerator.cs
+++ b/crypto/src/crypto/CipherKeyGenerator.cs
@@ -75,9 +75,9 @@ namespace Org.BouncyCastle.Crypto
return engineGenerateKey();
}
- protected virtual byte[] engineGenerateKey()
+ protected virtual byte[] engineGenerateKey()
{
- return random.GenerateSeed(strength);
+ return SecureRandom.GetNextBytes(random, strength);
}
}
}
diff --git a/crypto/src/crypto/IEntropySource.cs b/crypto/src/crypto/IEntropySource.cs
new file mode 100644
index 000000000..62e3bc76c
--- /dev/null
+++ b/crypto/src/crypto/IEntropySource.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// <summary>
+ /// Base interface describing an entropy source for a DRBG.
+ /// </summary>
+ public interface IEntropySource
+ {
+ /// <summary>
+ /// Return whether or not this entropy source is regarded as prediction resistant.
+ /// </summary>
+ /// <value><c>true</c> if this instance is prediction resistant; otherwise, <c>false</c>.</value>
+ bool IsPredictionResistant { get; }
+
+ /// <summary>
+ /// Return a byte array of entropy.
+ /// </summary>
+ /// <returns>The entropy bytes.</returns>
+ byte[] GetEntropy();
+
+ /// <summary>
+ /// Return the number of bits of entropy this source can produce.
+ /// </summary>
+ /// <value>The size, in bits, of the return value of getEntropy.</value>
+ int EntropySize { get; }
+ }
+}
+
diff --git a/crypto/src/crypto/IEntropySourceProvider.cs b/crypto/src/crypto/IEntropySourceProvider.cs
new file mode 100644
index 000000000..756414171
--- /dev/null
+++ b/crypto/src/crypto/IEntropySourceProvider.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// <summary>
+ /// Base interface describing a provider of entropy sources.
+ /// </summary>
+ public interface IEntropySourceProvider
+ {
+ /// <summary>
+ /// Return an entropy source providing a block of entropy.
+ /// </summary>
+ /// <param name="bitsRequired">The size of the block of entropy required.</param>
+ /// <returns>An entropy source providing bitsRequired blocks of entropy.</returns>
+ IEntropySource Get(int bitsRequired);
+ }
+}
diff --git a/crypto/src/crypto/digests/NonMemoableDigest.cs b/crypto/src/crypto/digests/NonMemoableDigest.cs
new file mode 100644
index 000000000..02c49b887
--- /dev/null
+++ b/crypto/src/crypto/digests/NonMemoableDigest.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Wrapper removes exposure to the IMemoable interface on an IDigest implementation.
+ */
+ public class NonMemoableDigest
+ : IDigest
+ {
+ protected readonly IDigest mBaseDigest;
+
+ /**
+ * Base constructor.
+ *
+ * @param baseDigest underlying digest to use.
+ * @exception IllegalArgumentException if baseDigest is null
+ */
+ public NonMemoableDigest(IDigest baseDigest)
+ {
+ if (baseDigest == null)
+ throw new ArgumentNullException("baseDigest");
+
+ this.mBaseDigest = baseDigest;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return mBaseDigest.AlgorithmName; }
+ }
+
+ public virtual int GetDigestSize()
+ {
+ return mBaseDigest.GetDigestSize();
+ }
+
+ public virtual void Update(byte input)
+ {
+ mBaseDigest.Update(input);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ mBaseDigest.BlockUpdate(input, inOff, len);
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ return mBaseDigest.DoFinal(output, outOff);
+ }
+
+ public virtual void Reset()
+ {
+ mBaseDigest.Reset();
+ }
+
+ public virtual int GetByteLength()
+ {
+ return mBaseDigest.GetByteLength();
+ }
+ }
+}
diff --git a/crypto/src/crypto/digests/SkeinEngine.cs b/crypto/src/crypto/digests/SkeinEngine.cs
index 7e93138ac..cfedfadf3 100644
--- a/crypto/src/crypto/digests/SkeinEngine.cs
+++ b/crypto/src/crypto/digests/SkeinEngine.cs
@@ -741,7 +741,7 @@ namespace Org.BouncyCastle.Crypto.Digests
CheckInitialised();
if (outBytes.Length < (outOff + outputSizeBytes))
{
- throw new DataLengthException("Output buffer is too short to hold output of " + outputSizeBytes + " bytes");
+ throw new DataLengthException("Output buffer is too short to hold output");
}
// Finalise message block
diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
index 51bb1829a..8a0c50a47 100644
--- a/crypto/src/crypto/ec/CustomNamedCurves.cs
+++ b/crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -756,7 +756,7 @@ namespace Org.BouncyCastle.Crypto.EC
private static void DefineCurve(string name, X9ECParametersHolder holder)
{
names.Add(name);
- name = Platform.ToLowerInvariant(name);
+ name = Platform.ToUpperInvariant(name);
nameToCurve.Add(name, holder);
}
@@ -765,7 +765,7 @@ namespace Org.BouncyCastle.Crypto.EC
names.Add(name);
oidToName.Add(oid, name);
oidToCurve.Add(oid, holder);
- name = Platform.ToLowerInvariant(name);
+ name = Platform.ToUpperInvariant(name);
nameToOid.Add(name, oid);
nameToCurve.Add(name, holder);
}
@@ -776,7 +776,7 @@ namespace Org.BouncyCastle.Crypto.EC
if (curve == null)
throw new InvalidOperationException();
- name = Platform.ToLowerInvariant(name);
+ name = Platform.ToUpperInvariant(name);
nameToOid.Add(name, oid);
nameToCurve.Add(name, curve);
}
@@ -841,7 +841,7 @@ namespace Org.BouncyCastle.Crypto.EC
public static X9ECParameters GetByName(string name)
{
- X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve[Platform.ToLowerInvariant(name)];
+ X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve[Platform.ToUpperInvariant(name)];
return holder == null ? null : holder.Parameters;
}
@@ -865,7 +865,7 @@ namespace Org.BouncyCastle.Crypto.EC
*/
public static DerObjectIdentifier GetOid(string name)
{
- return (DerObjectIdentifier)nameToOid[Platform.ToLowerInvariant(name)];
+ return (DerObjectIdentifier)nameToOid[Platform.ToUpperInvariant(name)];
}
/**
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index a4d2f0e36..95814ef25 100644
--- a/crypto/src/crypto/encodings/OaepEncoding.cs
+++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -161,7 +161,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
//
// generate the seed.
//
- byte[] seed = random.GenerateSeed(defHash.Length);
+ byte[] seed = SecureRandom.GetNextBytes(random, defHash.Length);
//
// mask the message block.
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index c84f4a964..ba62af4da 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -452,7 +453,8 @@ namespace Org.BouncyCastle.Crypto.Engines
KeyParameter keyParameter = parameters as KeyParameter;
if (keyParameter == null)
- throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
+ throw new ArgumentException("invalid parameter passed to AES init - "
+ + Platform.GetTypeName(parameters));
WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs
index 18367a324..3a9c3a89e 100644
--- a/crypto/src/crypto/engines/AesFastEngine.cs
+++ b/crypto/src/crypto/engines/AesFastEngine.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -788,7 +789,8 @@ namespace Org.BouncyCastle.Crypto.Engines
KeyParameter keyParameter = parameters as KeyParameter;
if (keyParameter == null)
- throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
+ throw new ArgumentException("invalid parameter passed to AES init - "
+ + Platform.GetTypeName(parameters));
WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index a48fa5857..9cc9c34a0 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -349,7 +350,8 @@ namespace Org.BouncyCastle.Crypto.Engines
KeyParameter keyParameter = parameters as KeyParameter;
if (keyParameter == null)
- throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
+ throw new ArgumentException("invalid parameter passed to AES init - "
+ + Platform.GetTypeName(parameters));
WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
diff --git a/crypto/src/crypto/engines/BlowfishEngine.cs b/crypto/src/crypto/engines/BlowfishEngine.cs
index 7b50e832f..e38f4e8f6 100644
--- a/crypto/src/crypto/engines/BlowfishEngine.cs
+++ b/crypto/src/crypto/engines/BlowfishEngine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -329,7 +330,7 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("invalid parameter passed to Blowfish init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to Blowfish init - " + Platform.GetTypeName(parameters));
this.encrypting = forEncryption;
this.workingKey = ((KeyParameter)parameters).GetKey();
diff --git a/crypto/src/crypto/engines/Cast5Engine.cs b/crypto/src/crypto/engines/Cast5Engine.cs
index 1af30a335..53836db02 100644
--- a/crypto/src/crypto/engines/Cast5Engine.cs
+++ b/crypto/src/crypto/engines/Cast5Engine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -334,7 +335,7 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("Invalid parameter passed to "+ AlgorithmName +" init - " + parameters.GetType().ToString());
+ throw new ArgumentException("Invalid parameter passed to "+ AlgorithmName +" init - " + Platform.GetTypeName(parameters));
_encrypting = forEncryption;
_workingKey = ((KeyParameter)parameters).GetKey();
diff --git a/crypto/src/crypto/engines/DesEdeEngine.cs b/crypto/src/crypto/engines/DesEdeEngine.cs
index bc40b56a8..2fac24ac0 100644
--- a/crypto/src/crypto/engines/DesEdeEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeEngine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -24,7 +25,7 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("invalid parameter passed to DESede init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to DESede init - " + Platform.GetTypeName(parameters));
byte[] keyMaster = ((KeyParameter)parameters).GetKey();
if (keyMaster.Length != 24 && keyMaster.Length != 16)
diff --git a/crypto/src/crypto/engines/DesEngine.cs b/crypto/src/crypto/engines/DesEngine.cs
index a6d580bb6..cfd50681e 100644
--- a/crypto/src/crypto/engines/DesEngine.cs
+++ b/crypto/src/crypto/engines/DesEngine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -31,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("invalid parameter passed to DES init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to DES init - " + Platform.GetTypeName(parameters));
workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)parameters).GetKey());
}
diff --git a/crypto/src/crypto/engines/GOST28147Engine.cs b/crypto/src/crypto/engines/GOST28147Engine.cs
index e37ddaefd..71e6d9e44 100644
--- a/crypto/src/crypto/engines/GOST28147Engine.cs
+++ b/crypto/src/crypto/engines/GOST28147Engine.cs
@@ -183,7 +183,8 @@ namespace Org.BouncyCastle.Crypto.Engines
}
else if (parameters != null)
{
- throw new ArgumentException("invalid parameter passed to Gost28147 init - " + parameters.GetType().Name);
+ throw new ArgumentException("invalid parameter passed to Gost28147 init - "
+ + Platform.GetTypeName(parameters));
}
}
diff --git a/crypto/src/crypto/engines/HC128Engine.cs b/crypto/src/crypto/engines/HC128Engine.cs
index 40c7a4e17..7bd1a48ed 100644
--- a/crypto/src/crypto/engines/HC128Engine.cs
+++ b/crypto/src/crypto/engines/HC128Engine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -180,7 +181,7 @@ namespace Org.BouncyCastle.Crypto.Engines
else
{
throw new ArgumentException(
- "Invalid parameter passed to HC128 init - " + parameters.GetType().Name,
+ "Invalid parameter passed to HC128 init - " + Platform.GetTypeName(parameters),
"parameters");
}
diff --git a/crypto/src/crypto/engines/HC256Engine.cs b/crypto/src/crypto/engines/HC256Engine.cs
index 6eb360711..b72258a19 100644
--- a/crypto/src/crypto/engines/HC256Engine.cs
+++ b/crypto/src/crypto/engines/HC256Engine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -164,7 +165,7 @@ namespace Org.BouncyCastle.Crypto.Engines
else
{
throw new ArgumentException(
- "Invalid parameter passed to HC256 init - " + parameters.GetType().Name,
+ "Invalid parameter passed to HC256 init - " + Platform.GetTypeName(parameters),
"parameters");
}
diff --git a/crypto/src/crypto/engines/ISAACEngine.cs b/crypto/src/crypto/engines/ISAACEngine.cs
index f25577130..b94ee6ed9 100644
--- a/crypto/src/crypto/engines/ISAACEngine.cs
+++ b/crypto/src/crypto/engines/ISAACEngine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -41,7 +42,7 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!(parameters is KeyParameter))
throw new ArgumentException(
- "invalid parameter passed to ISAAC Init - " + parameters.GetType().Name,
+ "invalid parameter passed to ISAAC Init - " + Platform.GetTypeName(parameters),
"parameters");
/*
diff --git a/crypto/src/crypto/engines/IdeaEngine.cs b/crypto/src/crypto/engines/IdeaEngine.cs
index 4909510ac..18a151c93 100644
--- a/crypto/src/crypto/engines/IdeaEngine.cs
+++ b/crypto/src/crypto/engines/IdeaEngine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -52,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("invalid parameter passed to IDEA init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to IDEA init - " + Platform.GetTypeName(parameters));
workingKey = GenerateWorkingKey(forEncryption,
((KeyParameter)parameters).GetKey());
diff --git a/crypto/src/crypto/engines/IesEngine.cs b/crypto/src/crypto/engines/IesEngine.cs
index a2004a9d6..307cc7a80 100644
--- a/crypto/src/crypto/engines/IesEngine.cs
+++ b/crypto/src/crypto/engines/IesEngine.cs
@@ -97,6 +97,10 @@ namespace Org.BouncyCastle.Crypto.Engines
kdf.Init(kParam);
+ // Ensure that the length of the input is greater than the MAC in bytes
+ if (inLen < mac.GetMacSize())
+ throw new InvalidCipherTextException("Length of input must be greater than the MAC");
+
inLen -= mac.GetMacSize();
if (cipher == null) // stream mode
diff --git a/crypto/src/crypto/engines/NoekeonEngine.cs b/crypto/src/crypto/engines/NoekeonEngine.cs
index dd78a4ea5..f64be50ba 100644
--- a/crypto/src/crypto/engines/NoekeonEngine.cs
+++ b/crypto/src/crypto/engines/NoekeonEngine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -70,7 +71,8 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("Invalid parameters passed to Noekeon init - " + parameters.GetType().Name, "parameters");
+ throw new ArgumentException("Invalid parameters passed to Noekeon init - "
+ + Platform.GetTypeName(parameters), "parameters");
_forEncryption = forEncryption;
_initialised = true;
diff --git a/crypto/src/crypto/engines/RC2Engine.cs b/crypto/src/crypto/engines/RC2Engine.cs
index b56953de5..4aca1894f 100644
--- a/crypto/src/crypto/engines/RC2Engine.cs
+++ b/crypto/src/crypto/engines/RC2Engine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -135,7 +136,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
else
{
- throw new ArgumentException("invalid parameter passed to RC2 init - " + parameters.GetType().Name);
+ throw new ArgumentException("invalid parameter passed to RC2 init - " + Platform.GetTypeName(parameters));
}
}
diff --git a/crypto/src/crypto/engines/RC4Engine.cs b/crypto/src/crypto/engines/RC4Engine.cs
index fd84b7d23..a515bb04e 100644
--- a/crypto/src/crypto/engines/RC4Engine.cs
+++ b/crypto/src/crypto/engines/RC4Engine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -44,7 +45,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return;
}
- throw new ArgumentException("invalid parameter passed to RC4 init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to RC4 init - " + Platform.GetTypeName(parameters));
}
public virtual string AlgorithmName
diff --git a/crypto/src/crypto/engines/RC532Engine.cs b/crypto/src/crypto/engines/RC532Engine.cs
index 169a60b98..d1c29e624 100644
--- a/crypto/src/crypto/engines/RC532Engine.cs
+++ b/crypto/src/crypto/engines/RC532Engine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -91,7 +92,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
else
{
- throw new ArgumentException("invalid parameter passed to RC532 init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to RC532 init - " + Platform.GetTypeName(parameters));
}
this.forEncryption = forEncryption;
diff --git a/crypto/src/crypto/engines/RC564Engine.cs b/crypto/src/crypto/engines/RC564Engine.cs
index ddcce0fa8..097fd60ba 100644
--- a/crypto/src/crypto/engines/RC564Engine.cs
+++ b/crypto/src/crypto/engines/RC564Engine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -80,7 +81,7 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!(typeof(RC5Parameters).IsInstanceOfType(parameters)))
{
- throw new ArgumentException("invalid parameter passed to RC564 init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to RC564 init - " + Platform.GetTypeName(parameters));
}
RC5Parameters p = (RC5Parameters)parameters;
diff --git a/crypto/src/crypto/engines/RC6Engine.cs b/crypto/src/crypto/engines/RC6Engine.cs
index 196bd8394..9aeb1e7cb 100644
--- a/crypto/src/crypto/engines/RC6Engine.cs
+++ b/crypto/src/crypto/engines/RC6Engine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -76,7 +77,7 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("invalid parameter passed to RC6 init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to RC6 init - " + Platform.GetTypeName(parameters));
this.forEncryption = forEncryption;
diff --git a/crypto/src/crypto/engines/RSACoreEngine.cs b/crypto/src/crypto/engines/RSACoreEngine.cs
index 38326371f..fd44e3cc1 100644
--- a/crypto/src/crypto/engines/RSACoreEngine.cs
+++ b/crypto/src/crypto/engines/RSACoreEngine.cs
@@ -124,7 +124,7 @@ namespace Org.BouncyCastle.Crypto.Engines
//
RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key;
- BigInteger p = crtKey.P;;
+ BigInteger p = crtKey.P;
BigInteger q = crtKey.Q;
BigInteger dP = crtKey.DP;
BigInteger dQ = crtKey.DQ;
diff --git a/crypto/src/crypto/engines/RijndaelEngine.cs b/crypto/src/crypto/engines/RijndaelEngine.cs
index 80f522353..7025cb5dc 100644
--- a/crypto/src/crypto/engines/RijndaelEngine.cs
+++ b/crypto/src/crypto/engines/RijndaelEngine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -582,7 +583,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return;
}
- throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to Rijndael init - " + Platform.GetTypeName(parameters));
}
public virtual string AlgorithmName
diff --git a/crypto/src/crypto/engines/SerpentEngine.cs b/crypto/src/crypto/engines/SerpentEngine.cs
index 255c204ab..76799f045 100644
--- a/crypto/src/crypto/engines/SerpentEngine.cs
+++ b/crypto/src/crypto/engines/SerpentEngine.cs
@@ -1,117 +1,32 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
- * Serpent is a 128-bit 32-round block cipher with variable key lengths,
- * including 128, 192 and 256 bit keys conjectured to be at least as
- * secure as three-key triple-DES.
- * <p>
- * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
- * candidate algorithm for the NIST AES Quest.>
- * </p>
- * <p>
- * For full details see the <a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">The Serpent home page</a>
- * </p>
+ * Serpent is a 128-bit 32-round block cipher with variable key lengths,
+ * including 128, 192 and 256 bit keys conjectured to be at least as
+ * secure as three-key triple-DES.
+ * <p>
+ * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
+ * candidate algorithm for the NIST AES Quest.
+ * </p>
+ * <p>
+ * For full details see <a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">The Serpent home page</a>
+ * </p>
*/
- public class SerpentEngine
- : IBlockCipher
+ public sealed class SerpentEngine
+ : SerpentEngineBase
{
- private const int BLOCK_SIZE = 16;
-
- static readonly int ROUNDS = 32;
- static readonly int PHI = unchecked((int)0x9E3779B9); // (Sqrt(5) - 1) * 2**31
-
- private bool encrypting;
- private int[] wKey;
-
- private int X0, X1, X2, X3; // registers
-
- /**
- * initialise a Serpent cipher.
- *
- * @param forEncryption whether or not we are for encryption.
- * @param parameters the parameters required to set up the cipher.
- * @exception ArgumentException if the parameters argument is
- * inappropriate.
- */
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
- {
- if (!(parameters is KeyParameter))
- throw new ArgumentException("invalid parameter passed to Serpent init - " + parameters.GetType().ToString());
-
- this.encrypting = forEncryption;
- this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey());
- }
-
- public virtual string AlgorithmName
- {
- get { return "Serpent"; }
- }
-
- public virtual bool IsPartialBlockOkay
- {
- get { return false; }
- }
-
- public virtual int GetBlockSize()
- {
- return BLOCK_SIZE;
- }
-
- /**
- * Process one block of input from the array in and write it to
- * the out array.
- *
- * @param in the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
- {
- if (wKey == null)
- throw new InvalidOperationException("Serpent not initialised");
-
- Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
- Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
-
- if (encrypting)
- {
- EncryptBlock(input, inOff, output, outOff);
- }
- else
- {
- DecryptBlock(input, inOff, output, outOff);
- }
-
- return BLOCK_SIZE;
- }
-
- public virtual void Reset()
- {
- }
-
/**
* Expand a user-supplied key material into a session key.
*
* @param key The user-key bytes (multiples of 4) to use.
* @exception ArgumentException
*/
- private int[] MakeWorkingKey(
- byte[] key)
+ protected override int[] MakeWorkingKey(byte[] key)
{
//
// pad key to 256 bits
@@ -120,14 +35,14 @@ namespace Org.BouncyCastle.Crypto.Engines
int off = 0;
int length = 0;
- for (off = key.Length - 4; off > 0; off -= 4)
+ for (off = 0; (off + 4) < key.Length; off += 4)
{
- kPad[length++] = BytesToWord(key, off);
+ kPad[length++] = (int)Pack.LE_To_UInt32(key, off);
}
- if (off == 0)
+ if (off % 4 == 0)
{
- kPad[length++] = BytesToWord(key, 0);
+ kPad[length++] = (int)Pack.LE_To_UInt32(key, off);
if (length < 8)
{
kPad[length] = 1;
@@ -235,57 +150,20 @@ namespace Org.BouncyCastle.Crypto.Engines
return w;
}
- private int RotateLeft(
- int x,
- int bits)
- {
- return ((x << bits) | (int) ((uint)x >> (32 - bits)));
- }
-
- private int RotateRight(
- int x,
- int bits)
- {
- return ( (int)((uint)x >> bits) | (x << (32 - bits)));
- }
-
- private int BytesToWord(
- byte[] src,
- int srcOff)
- {
- return (((src[srcOff] & 0xff) << 24) | ((src[srcOff + 1] & 0xff) << 16) |
- ((src[srcOff + 2] & 0xff) << 8) | ((src[srcOff + 3] & 0xff)));
- }
-
- private void WordToBytes(
- int word,
- byte[] dst,
- int dstOff)
- {
- dst[dstOff + 3] = (byte)(word);
- dst[dstOff + 2] = (byte)((uint)word >> 8);
- dst[dstOff + 1] = (byte)((uint)word >> 16);
- dst[dstOff] = (byte)((uint)word >> 24);
- }
-
/**
* Encrypt one block of plaintext.
*
- * @param in the array containing the input data.
+ * @param input the array containing the input data.
* @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
+ * @param output the array the output data will be copied into.
* @param outOff the offset into the out array the output will start at.
*/
- private void EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ protected override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- X3 = BytesToWord(input, inOff);
- X2 = BytesToWord(input, inOff + 4);
- X1 = BytesToWord(input, inOff + 8);
- X0 = BytesToWord(input, inOff + 12);
+ X0 = (int)Pack.LE_To_UInt32(input, inOff);
+ X1 = (int)Pack.LE_To_UInt32(input, inOff + 4);
+ X2 = (int)Pack.LE_To_UInt32(input, inOff + 8);
+ X3 = (int)Pack.LE_To_UInt32(input, inOff + 12);
Sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT();
Sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT();
@@ -320,30 +198,26 @@ namespace Org.BouncyCastle.Crypto.Engines
Sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT();
Sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
- WordToBytes(wKey[131] ^ X3, outBytes, outOff);
- WordToBytes(wKey[130] ^ X2, outBytes, outOff + 4);
- WordToBytes(wKey[129] ^ X1, outBytes, outOff + 8);
- WordToBytes(wKey[128] ^ X0, outBytes, outOff + 12);
+ Pack.UInt32_To_LE((uint)(wKey[128] ^ X0), output, outOff);
+ Pack.UInt32_To_LE((uint)(wKey[129] ^ X1), output, outOff + 4);
+ Pack.UInt32_To_LE((uint)(wKey[130] ^ X2), output, outOff + 8);
+ Pack.UInt32_To_LE((uint)(wKey[131] ^ X3), output, outOff + 12);
}
/**
* Decrypt one block of ciphertext.
*
- * @param in the array containing the input data.
+ * @param input the array containing the input data.
* @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
+ * @param output the array the output data will be copied into.
* @param outOff the offset into the out array the output will start at.
*/
- private void DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ protected override void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- X3 = wKey[131] ^ BytesToWord(input, inOff);
- X2 = wKey[130] ^ BytesToWord(input, inOff + 4);
- X1 = wKey[129] ^ BytesToWord(input, inOff + 8);
- X0 = wKey[128] ^ BytesToWord(input, inOff + 12);
+ X0 = wKey[128] ^ (int)Pack.LE_To_UInt32(input, inOff);
+ X1 = wKey[129] ^ (int)Pack.LE_To_UInt32(input, inOff + 4);
+ X2 = wKey[130] ^ (int)Pack.LE_To_UInt32(input, inOff + 8);
+ X3 = wKey[131] ^ (int)Pack.LE_To_UInt32(input, inOff + 12);
Ib7(X0, X1, X2, X3);
X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127];
@@ -409,369 +283,10 @@ namespace Org.BouncyCastle.Crypto.Engines
X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7];
InverseLT(); Ib0(X0, X1, X2, X3);
- WordToBytes(X3 ^ wKey[3], outBytes, outOff);
- WordToBytes(X2 ^ wKey[2], outBytes, outOff + 4);
- WordToBytes(X1 ^ wKey[1], outBytes, outOff + 8);
- WordToBytes(X0 ^ wKey[0], outBytes, outOff + 12);
- }
-
- /*
- * The sboxes below are based on the work of Brian Gladman and
- * Sam Simpson, whose original notice appears below.
- * <p>
- * For further details see:
- * http://fp.gladman.plus.com/cryptography_technology/serpent/
- * </p>
- */
-
- /* Partially optimised Serpent S Box bool functions derived */
- /* using a recursive descent analyser but without a full search */
- /* of all subtrees. This set of S boxes is the result of work */
- /* by Sam Simpson and Brian Gladman using the spare time on a */
- /* cluster of high capacity servers to search for S boxes with */
- /* this customised search engine. There are now an average of */
- /* 15.375 terms per S box. */
- /* */
- /* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */
- /* and Sam Simpson (s.simpson@mia.co.uk) */
- /* 17th December 1998 */
- /* */
- /* We hereby give permission for information in this file to be */
- /* used freely subject only to acknowledgement of its origin. */
-
- /**
- * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
- */
- private void Sb0(int a, int b, int c, int d)
- {
- int t1 = a ^ d;
- int t3 = c ^ t1;
- int t4 = b ^ t3;
- X3 = (a & d) ^ t4;
- int t7 = a ^ (b & t1);
- X2 = t4 ^ (c | t7);
- int t12 = X3 & (t3 ^ t7);
- X1 = (~t3) ^ t12;
- X0 = t12 ^ (~t7);
- }
-
- /**
- * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
- */
- private void Ib0(int a, int b, int c, int d)
- {
- int t1 = ~a;
- int t2 = a ^ b;
- int t4 = d ^ (t1 | t2);
- int t5 = c ^ t4;
- X2 = t2 ^ t5;
- int t8 = t1 ^ (d & t2);
- X1 = t4 ^ (X2 & t8);
- X3 = (a & t4) ^ (t5 | X1);
- X0 = X3 ^ (t5 ^ t8);
- }
-
- /**
- * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
- */
- private void Sb1(int a, int b, int c, int d)
- {
- int t2 = b ^ (~a);
- int t5 = c ^ (a | t2);
- X2 = d ^ t5;
- int t7 = b ^ (d | t2);
- int t8 = t2 ^ X2;
- X3 = t8 ^ (t5 & t7);
- int t11 = t5 ^ t7;
- X1 = X3 ^ t11;
- X0 = t5 ^ (t8 & t11);
- }
-
- /**
- * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
- */
- private void Ib1(int a, int b, int c, int d)
- {
- int t1 = b ^ d;
- int t3 = a ^ (b & t1);
- int t4 = t1 ^ t3;
- X3 = c ^ t4;
- int t7 = b ^ (t1 & t3);
- int t8 = X3 | t7;
- X1 = t3 ^ t8;
- int t10 = ~X1;
- int t11 = X3 ^ t7;
- X0 = t10 ^ t11;
- X2 = t4 ^ (t10 | t11);
- }
-
- /**
- * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
- */
- private void Sb2(int a, int b, int c, int d)
- {
- int t1 = ~a;
- int t2 = b ^ d;
- int t3 = c & t1;
- X0 = t2 ^ t3;
- int t5 = c ^ t1;
- int t6 = c ^ X0;
- int t7 = b & t6;
- X3 = t5 ^ t7;
- X2 = a ^ ((d | t7) & (X0 | t5));
- X1 = (t2 ^ X3) ^ (X2 ^ (d | t1));
- }
-
- /**
- * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
- */
- private void Ib2(int a, int b, int c, int d)
- {
- int t1 = b ^ d;
- int t2 = ~t1;
- int t3 = a ^ c;
- int t4 = c ^ t1;
- int t5 = b & t4;
- X0 = t3 ^ t5;
- int t7 = a | t2;
- int t8 = d ^ t7;
- int t9 = t3 | t8;
- X3 = t1 ^ t9;
- int t11 = ~t4;
- int t12 = X0 | X3;
- X1 = t11 ^ t12;
- X2 = (d & t11) ^ (t3 ^ t12);
- }
-
- /**
- * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
- */
- private void Sb3(int a, int b, int c, int d)
- {
- int t1 = a ^ b;
- int t2 = a & c;
- int t3 = a | d;
- int t4 = c ^ d;
- int t5 = t1 & t3;
- int t6 = t2 | t5;
- X2 = t4 ^ t6;
- int t8 = b ^ t3;
- int t9 = t6 ^ t8;
- int t10 = t4 & t9;
- X0 = t1 ^ t10;
- int t12 = X2 & X0;
- X1 = t9 ^ t12;
- X3 = (b | d) ^ (t4 ^ t12);
- }
-
- /**
- * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
- */
- private void Ib3(int a, int b, int c, int d)
- {
- int t1 = a | b;
- int t2 = b ^ c;
- int t3 = b & t2;
- int t4 = a ^ t3;
- int t5 = c ^ t4;
- int t6 = d | t4;
- X0 = t2 ^ t6;
- int t8 = t2 | t6;
- int t9 = d ^ t8;
- X2 = t5 ^ t9;
- int t11 = t1 ^ t9;
- int t12 = X0 & t11;
- X3 = t4 ^ t12;
- X1 = X3 ^ (X0 ^ t11);
- }
-
- /**
- * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
- */
- private void Sb4(int a, int b, int c, int d)
- {
- int t1 = a ^ d;
- int t2 = d & t1;
- int t3 = c ^ t2;
- int t4 = b | t3;
- X3 = t1 ^ t4;
- int t6 = ~b;
- int t7 = t1 | t6;
- X0 = t3 ^ t7;
- int t9 = a & X0;
- int t10 = t1 ^ t6;
- int t11 = t4 & t10;
- X2 = t9 ^ t11;
- X1 = (a ^ t3) ^ (t10 & X2);
- }
-
- /**
- * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
- */
- private void Ib4(int a, int b, int c, int d)
- {
- int t1 = c | d;
- int t2 = a & t1;
- int t3 = b ^ t2;
- int t4 = a & t3;
- int t5 = c ^ t4;
- X1 = d ^ t5;
- int t7 = ~a;
- int t8 = t5 & X1;
- X3 = t3 ^ t8;
- int t10 = X1 | t7;
- int t11 = d ^ t10;
- X0 = X3 ^ t11;
- X2 = (t3 & t11) ^ (X1 ^ t7);
- }
-
- /**
- * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
- */
- private void Sb5(int a, int b, int c, int d)
- {
- int t1 = ~a;
- int t2 = a ^ b;
- int t3 = a ^ d;
- int t4 = c ^ t1;
- int t5 = t2 | t3;
- X0 = t4 ^ t5;
- int t7 = d & X0;
- int t8 = t2 ^ X0;
- X1 = t7 ^ t8;
- int t10 = t1 | X0;
- int t11 = t2 | t7;
- int t12 = t3 ^ t10;
- X2 = t11 ^ t12;
- X3 = (b ^ t7) ^ (X1 & t12);
- }
-
- /**
- * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
- */
- private void Ib5(int a, int b, int c, int d)
- {
- int t1 = ~c;
- int t2 = b & t1;
- int t3 = d ^ t2;
- int t4 = a & t3;
- int t5 = b ^ t1;
- X3 = t4 ^ t5;
- int t7 = b | X3;
- int t8 = a & t7;
- X1 = t3 ^ t8;
- int t10 = a | d;
- int t11 = t1 ^ t7;
- X0 = t10 ^ t11;
- X2 = (b & t10) ^ (t4 | (a ^ c));
- }
-
- /**
- * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
- */
- private void Sb6(int a, int b, int c, int d)
- {
- int t1 = ~a;
- int t2 = a ^ d;
- int t3 = b ^ t2;
- int t4 = t1 | t2;
- int t5 = c ^ t4;
- X1 = b ^ t5;
- int t7 = t2 | X1;
- int t8 = d ^ t7;
- int t9 = t5 & t8;
- X2 = t3 ^ t9;
- int t11 = t5 ^ t8;
- X0 = X2 ^ t11;
- X3 = (~t5) ^ (t3 & t11);
- }
-
- /**
- * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
- */
- private void Ib6(int a, int b, int c, int d)
- {
- int t1 = ~a;
- int t2 = a ^ b;
- int t3 = c ^ t2;
- int t4 = c | t1;
- int t5 = d ^ t4;
- X1 = t3 ^ t5;
- int t7 = t3 & t5;
- int t8 = t2 ^ t7;
- int t9 = b | t8;
- X3 = t5 ^ t9;
- int t11 = b | X3;
- X0 = t8 ^ t11;
- X2 = (d & t1) ^ (t3 ^ t11);
- }
-
- /**
- * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
- */
- private void Sb7(int a, int b, int c, int d)
- {
- int t1 = b ^ c;
- int t2 = c & t1;
- int t3 = d ^ t2;
- int t4 = a ^ t3;
- int t5 = d | t1;
- int t6 = t4 & t5;
- X1 = b ^ t6;
- int t8 = t3 | X1;
- int t9 = a & t4;
- X3 = t1 ^ t9;
- int t11 = t4 ^ t8;
- int t12 = X3 & t11;
- X2 = t3 ^ t12;
- X0 = (~t11) ^ (X3 & X2);
- }
-
- /**
- * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
- */
- private void Ib7(int a, int b, int c, int d)
- {
- int t3 = c | (a & b);
- int t4 = d & (a | b);
- X3 = t3 ^ t4;
- int t6 = ~d;
- int t7 = b ^ t4;
- int t9 = t7 | (X3 ^ t6);
- X1 = a ^ t9;
- X0 = (c ^ t7) ^ (d | X1);
- X2 = (t3 ^ X1) ^ (X0 ^ (a & X3));
- }
-
- /**
- * Apply the linear transformation to the register set.
- */
- private void LT()
- {
- int x0 = RotateLeft(X0, 13);
- int x2 = RotateLeft(X2, 3);
- int x1 = X1 ^ x0 ^ x2 ;
- int x3 = X3 ^ x2 ^ x0 << 3;
-
- X1 = RotateLeft(x1, 1);
- X3 = RotateLeft(x3, 7);
- X0 = RotateLeft(x0 ^ X1 ^ X3, 5);
- X2 = RotateLeft(x2 ^ X3 ^ (X1 << 7), 22);
- }
-
- /**
- * Apply the inverse of the linear transformation to the register set.
- */
- private void InverseLT()
- {
- int x2 = RotateRight(X2, 22) ^ X3 ^ (X1 << 7);
- int x0 = RotateRight(X0, 5) ^ X1 ^ X3;
- int x3 = RotateRight(X3, 7);
- int x1 = RotateRight(X1, 1);
- X3 = x3 ^ x2 ^ x0 << 3;
- X1 = x1 ^ x0 ^ x2;
- X2 = RotateRight(x2, 3);
- X0 = RotateRight(x0, 13);
+ Pack.UInt32_To_LE((uint)(X0 ^ wKey[0]), output, outOff);
+ Pack.UInt32_To_LE((uint)(X1 ^ wKey[1]), output, outOff + 4);
+ Pack.UInt32_To_LE((uint)(X2 ^ wKey[2]), output, outOff + 8);
+ Pack.UInt32_To_LE((uint)(X3 ^ wKey[3]), output, outOff + 12);
}
}
}
diff --git a/crypto/src/crypto/engines/SerpentEngineBase.cs b/crypto/src/crypto/engines/SerpentEngineBase.cs
new file mode 100644
index 000000000..a5d91b3be
--- /dev/null
+++ b/crypto/src/crypto/engines/SerpentEngineBase.cs
@@ -0,0 +1,468 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public abstract class SerpentEngineBase
+ : IBlockCipher
+ {
+ protected static readonly int BlockSize = 16;
+
+ internal const int ROUNDS = 32;
+ internal const int PHI = unchecked((int)0x9E3779B9); // (sqrt(5) - 1) * 2**31
+
+ protected bool encrypting;
+ protected int[] wKey;
+
+ protected int X0, X1, X2, X3; // registers
+
+ protected SerpentEngineBase()
+ {
+ }
+
+ /**
+ * initialise a Serpent cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @throws IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public virtual void Init(bool encrypting, ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to " + AlgorithmName + " init - " + Platform.GetTypeName(parameters));
+
+ this.encrypting = encrypting;
+ this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey());
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Serpent"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @return the number of bytes processed and produced.
+ * @throws DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @throws IllegalStateException if the cipher isn't initialised.
+ */
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ if (wKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BlockSize;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ protected static int RotateLeft(int x, int bits)
+ {
+ return ((x << bits) | (int) ((uint)x >> (32 - bits)));
+ }
+
+ private static int RotateRight(int x, int bits)
+ {
+ return ( (int)((uint)x >> bits) | (x << (32 - bits)));
+ }
+
+ /**
+ * The sboxes below are based on the work of Brian Gladman and
+ * Sam Simpson, whose original notice appears below.
+ * <p>
+ * For further details see:
+ * http://fp.gladman.plus.com/cryptography_technology/serpent/
+ */
+
+ /* Partially optimised Serpent S Box boolean functions derived */
+ /* using a recursive descent analyser but without a full search */
+ /* of all subtrees. This set of S boxes is the result of work */
+ /* by Sam Simpson and Brian Gladman using the spare time on a */
+ /* cluster of high capacity servers to search for S boxes with */
+ /* this customised search engine. There are now an average of */
+ /* 15.375 terms per S box. */
+ /* */
+ /* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */
+ /* and Sam Simpson (s.simpson@mia.co.uk) */
+ /* 17th December 1998 */
+ /* */
+ /* We hereby give permission for information in this file to be */
+ /* used freely subject only to acknowledgement of its origin. */
+
+ /**
+ * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
+ */
+ protected void Sb0(int a, int b, int c, int d)
+ {
+ int t1 = a ^ d;
+ int t3 = c ^ t1;
+ int t4 = b ^ t3;
+ X3 = (a & d) ^ t4;
+ int t7 = a ^ (b & t1);
+ X2 = t4 ^ (c | t7);
+ int t12 = X3 & (t3 ^ t7);
+ X1 = (~t3) ^ t12;
+ X0 = t12 ^ (~t7);
+ }
+
+ /**
+ * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
+ */
+ protected void Ib0(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t4 = d ^ (t1 | t2);
+ int t5 = c ^ t4;
+ X2 = t2 ^ t5;
+ int t8 = t1 ^ (d & t2);
+ X1 = t4 ^ (X2 & t8);
+ X3 = (a & t4) ^ (t5 | X1);
+ X0 = X3 ^ (t5 ^ t8);
+ }
+
+ /**
+ * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
+ */
+ protected void Sb1(int a, int b, int c, int d)
+ {
+ int t2 = b ^ (~a);
+ int t5 = c ^ (a | t2);
+ X2 = d ^ t5;
+ int t7 = b ^ (d | t2);
+ int t8 = t2 ^ X2;
+ X3 = t8 ^ (t5 & t7);
+ int t11 = t5 ^ t7;
+ X1 = X3 ^ t11;
+ X0 = t5 ^ (t8 & t11);
+ }
+
+ /**
+ * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
+ */
+ protected void Ib1(int a, int b, int c, int d)
+ {
+ int t1 = b ^ d;
+ int t3 = a ^ (b & t1);
+ int t4 = t1 ^ t3;
+ X3 = c ^ t4;
+ int t7 = b ^ (t1 & t3);
+ int t8 = X3 | t7;
+ X1 = t3 ^ t8;
+ int t10 = ~X1;
+ int t11 = X3 ^ t7;
+ X0 = t10 ^ t11;
+ X2 = t4 ^ (t10 | t11);
+ }
+
+ /**
+ * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
+ */
+ protected void Sb2(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = b ^ d;
+ int t3 = c & t1;
+ X0 = t2 ^ t3;
+ int t5 = c ^ t1;
+ int t6 = c ^ X0;
+ int t7 = b & t6;
+ X3 = t5 ^ t7;
+ X2 = a ^ ((d | t7) & (X0 | t5));
+ X1 = (t2 ^ X3) ^ (X2 ^ (d | t1));
+ }
+
+ /**
+ * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
+ */
+ protected void Ib2(int a, int b, int c, int d)
+ {
+ int t1 = b ^ d;
+ int t2 = ~t1;
+ int t3 = a ^ c;
+ int t4 = c ^ t1;
+ int t5 = b & t4;
+ X0 = t3 ^ t5;
+ int t7 = a | t2;
+ int t8 = d ^ t7;
+ int t9 = t3 | t8;
+ X3 = t1 ^ t9;
+ int t11 = ~t4;
+ int t12 = X0 | X3;
+ X1 = t11 ^ t12;
+ X2 = (d & t11) ^ (t3 ^ t12);
+ }
+
+ /**
+ * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
+ */
+ protected void Sb3(int a, int b, int c, int d)
+ {
+ int t1 = a ^ b;
+ int t2 = a & c;
+ int t3 = a | d;
+ int t4 = c ^ d;
+ int t5 = t1 & t3;
+ int t6 = t2 | t5;
+ X2 = t4 ^ t6;
+ int t8 = b ^ t3;
+ int t9 = t6 ^ t8;
+ int t10 = t4 & t9;
+ X0 = t1 ^ t10;
+ int t12 = X2 & X0;
+ X1 = t9 ^ t12;
+ X3 = (b | d) ^ (t4 ^ t12);
+ }
+
+ /**
+ * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
+ */
+ protected void Ib3(int a, int b, int c, int d)
+ {
+ int t1 = a | b;
+ int t2 = b ^ c;
+ int t3 = b & t2;
+ int t4 = a ^ t3;
+ int t5 = c ^ t4;
+ int t6 = d | t4;
+ X0 = t2 ^ t6;
+ int t8 = t2 | t6;
+ int t9 = d ^ t8;
+ X2 = t5 ^ t9;
+ int t11 = t1 ^ t9;
+ int t12 = X0 & t11;
+ X3 = t4 ^ t12;
+ X1 = X3 ^ (X0 ^ t11);
+ }
+
+ /**
+ * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
+ */
+ protected void Sb4(int a, int b, int c, int d)
+ {
+ int t1 = a ^ d;
+ int t2 = d & t1;
+ int t3 = c ^ t2;
+ int t4 = b | t3;
+ X3 = t1 ^ t4;
+ int t6 = ~b;
+ int t7 = t1 | t6;
+ X0 = t3 ^ t7;
+ int t9 = a & X0;
+ int t10 = t1 ^ t6;
+ int t11 = t4 & t10;
+ X2 = t9 ^ t11;
+ X1 = (a ^ t3) ^ (t10 & X2);
+ }
+
+ /**
+ * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
+ */
+ protected void Ib4(int a, int b, int c, int d)
+ {
+ int t1 = c | d;
+ int t2 = a & t1;
+ int t3 = b ^ t2;
+ int t4 = a & t3;
+ int t5 = c ^ t4;
+ X1 = d ^ t5;
+ int t7 = ~a;
+ int t8 = t5 & X1;
+ X3 = t3 ^ t8;
+ int t10 = X1 | t7;
+ int t11 = d ^ t10;
+ X0 = X3 ^ t11;
+ X2 = (t3 & t11) ^ (X1 ^ t7);
+ }
+
+ /**
+ * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
+ */
+ protected void Sb5(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t3 = a ^ d;
+ int t4 = c ^ t1;
+ int t5 = t2 | t3;
+ X0 = t4 ^ t5;
+ int t7 = d & X0;
+ int t8 = t2 ^ X0;
+ X1 = t7 ^ t8;
+ int t10 = t1 | X0;
+ int t11 = t2 | t7;
+ int t12 = t3 ^ t10;
+ X2 = t11 ^ t12;
+ X3 = (b ^ t7) ^ (X1 & t12);
+ }
+
+ /**
+ * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
+ */
+ protected void Ib5(int a, int b, int c, int d)
+ {
+ int t1 = ~c;
+ int t2 = b & t1;
+ int t3 = d ^ t2;
+ int t4 = a & t3;
+ int t5 = b ^ t1;
+ X3 = t4 ^ t5;
+ int t7 = b | X3;
+ int t8 = a & t7;
+ X1 = t3 ^ t8;
+ int t10 = a | d;
+ int t11 = t1 ^ t7;
+ X0 = t10 ^ t11;
+ X2 = (b & t10) ^ (t4 | (a ^ c));
+ }
+
+ /**
+ * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
+ */
+ protected void Sb6(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ d;
+ int t3 = b ^ t2;
+ int t4 = t1 | t2;
+ int t5 = c ^ t4;
+ X1 = b ^ t5;
+ int t7 = t2 | X1;
+ int t8 = d ^ t7;
+ int t9 = t5 & t8;
+ X2 = t3 ^ t9;
+ int t11 = t5 ^ t8;
+ X0 = X2 ^ t11;
+ X3 = (~t5) ^ (t3 & t11);
+ }
+
+ /**
+ * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
+ */
+ protected void Ib6(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t3 = c ^ t2;
+ int t4 = c | t1;
+ int t5 = d ^ t4;
+ X1 = t3 ^ t5;
+ int t7 = t3 & t5;
+ int t8 = t2 ^ t7;
+ int t9 = b | t8;
+ X3 = t5 ^ t9;
+ int t11 = b | X3;
+ X0 = t8 ^ t11;
+ X2 = (d & t1) ^ (t3 ^ t11);
+ }
+
+ /**
+ * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
+ */
+ protected void Sb7(int a, int b, int c, int d)
+ {
+ int t1 = b ^ c;
+ int t2 = c & t1;
+ int t3 = d ^ t2;
+ int t4 = a ^ t3;
+ int t5 = d | t1;
+ int t6 = t4 & t5;
+ X1 = b ^ t6;
+ int t8 = t3 | X1;
+ int t9 = a & t4;
+ X3 = t1 ^ t9;
+ int t11 = t4 ^ t8;
+ int t12 = X3 & t11;
+ X2 = t3 ^ t12;
+ X0 = (~t11) ^ (X3 & X2);
+ }
+
+ /**
+ * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
+ */
+ protected void Ib7(int a, int b, int c, int d)
+ {
+ int t3 = c | (a & b);
+ int t4 = d & (a | b);
+ X3 = t3 ^ t4;
+ int t6 = ~d;
+ int t7 = b ^ t4;
+ int t9 = t7 | (X3 ^ t6);
+ X1 = a ^ t9;
+ X0 = (c ^ t7) ^ (d | X1);
+ X2 = (t3 ^ X1) ^ (X0 ^ (a & X3));
+ }
+
+ /**
+ * Apply the linear transformation to the register set.
+ */
+ protected void LT()
+ {
+ int x0 = RotateLeft(X0, 13);
+ int x2 = RotateLeft(X2, 3);
+ int x1 = X1 ^ x0 ^ x2;
+ int x3 = X3 ^ x2 ^ x0 << 3;
+
+ X1 = RotateLeft(x1, 1);
+ X3 = RotateLeft(x3, 7);
+ X0 = RotateLeft(x0 ^ X1 ^ X3, 5);
+ X2 = RotateLeft(x2 ^ X3 ^ (X1 << 7), 22);
+ }
+
+ /**
+ * Apply the inverse of the linear transformation to the register set.
+ */
+ protected void InverseLT()
+ {
+ int x2 = RotateRight(X2, 22) ^ X3 ^ (X1 << 7);
+ int x0 = RotateRight(X0, 5) ^ X1 ^ X3;
+ int x3 = RotateRight(X3, 7);
+ int x1 = RotateRight(X1, 1);
+ X3 = x3 ^ x2 ^ x0 << 3;
+ X1 = x1 ^ x0 ^ x2;
+ X2 = RotateRight(x2, 3);
+ X0 = RotateRight(x0, 13);
+ }
+
+ protected abstract int[] MakeWorkingKey(byte[] key);
+
+ protected abstract void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff);
+
+ protected abstract void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff);
+ }
+}
diff --git a/crypto/src/crypto/engines/SkipjackEngine.cs b/crypto/src/crypto/engines/SkipjackEngine.cs
index a45dc9b24..c90646cc4 100644
--- a/crypto/src/crypto/engines/SkipjackEngine.cs
+++ b/crypto/src/crypto/engines/SkipjackEngine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -48,7 +49,7 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + Platform.GetTypeName(parameters));
byte[] keyBytes = ((KeyParameter)parameters).GetKey();
diff --git a/crypto/src/crypto/engines/TEAEngine.cs b/crypto/src/crypto/engines/TEAEngine.cs
index 2e1a7002b..7b700145e 100644
--- a/crypto/src/crypto/engines/TEAEngine.cs
+++ b/crypto/src/crypto/engines/TEAEngine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -66,7 +67,7 @@ namespace Org.BouncyCastle.Crypto.Engines
if (!(parameters is KeyParameter))
{
throw new ArgumentException("invalid parameter passed to TEA init - "
- + parameters.GetType().FullName);
+ + Platform.GetTypeName(parameters));
}
_forEncryption = forEncryption;
diff --git a/crypto/src/crypto/engines/ThreefishEngine.cs b/crypto/src/crypto/engines/ThreefishEngine.cs
index 33ff3a421..eade3cc72 100644
--- a/crypto/src/crypto/engines/ThreefishEngine.cs
+++ b/crypto/src/crypto/engines/ThreefishEngine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Crypto.Engines
@@ -174,7 +175,7 @@ namespace Org.BouncyCastle.Crypto.Engines
else
{
throw new ArgumentException("Invalid parameter passed to Threefish init - "
- + parameters.GetType().Name);
+ + Platform.GetTypeName(parameters));
}
ulong[] keyWords = null;
diff --git a/crypto/src/crypto/engines/TnepresEngine.cs b/crypto/src/crypto/engines/TnepresEngine.cs
new file mode 100644
index 000000000..ce687d1e5
--- /dev/null
+++ b/crypto/src/crypto/engines/TnepresEngine.cs
@@ -0,0 +1,299 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Tnepres is a 128-bit 32-round block cipher with variable key lengths,
+ * including 128, 192 and 256 bit keys conjectured to be at least as
+ * secure as three-key triple-DES.
+ * <p>
+ * Tnepres is based on Serpent which was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
+ * candidate algorithm for the NIST AES Quest. Unfortunately there was an endianness issue
+ * with test vectors in the AES submission and the resulting confusion lead to the Tnepres cipher
+ * as well, which is a byte swapped version of Serpent.
+ * </p>
+ * <p>
+ * For full details see <a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">The Serpent home page</a>
+ * </p>
+ */
+ public sealed class TnepresEngine
+ : SerpentEngineBase
+ {
+ public override string AlgorithmName
+ {
+ get { return "Tnepres"; }
+ }
+
+ /**
+ * Expand a user-supplied key material into a session key.
+ *
+ * @param key The user-key bytes (multiples of 4) to use.
+ * @exception ArgumentException
+ */
+ protected override int[] MakeWorkingKey(byte[] key)
+ {
+ //
+ // pad key to 256 bits
+ //
+ int[] kPad = new int[16];
+ int off = 0;
+ int length = 0;
+
+ for (off = key.Length - 4; off > 0; off -= 4)
+ {
+ kPad[length++] = (int)Pack.BE_To_UInt32(key, off);
+ }
+
+ if (off == 0)
+ {
+ kPad[length++] = (int)Pack.BE_To_UInt32(key, 0);
+ if (length < 8)
+ {
+ kPad[length] = 1;
+ }
+ }
+ else
+ {
+ throw new ArgumentException("key must be a multiple of 4 bytes");
+ }
+
+ //
+ // expand the padded key up to 33 x 128 bits of key material
+ //
+ int amount = (ROUNDS + 1) * 4;
+ int[] w = new int[amount];
+
+ //
+ // compute w0 to w7 from w-8 to w-1
+ //
+ for (int i = 8; i < 16; i++)
+ {
+ kPad[i] = RotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11);
+ }
+
+ Array.Copy(kPad, 8, w, 0, 8);
+
+ //
+ // compute w8 to w136
+ //
+ for (int i = 8; i < amount; i++)
+ {
+ w[i] = RotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
+ }
+
+ //
+ // create the working keys by processing w with the Sbox and IP
+ //
+ Sb3(w[0], w[1], w[2], w[3]);
+ w[0] = X0; w[1] = X1; w[2] = X2; w[3] = X3;
+ Sb2(w[4], w[5], w[6], w[7]);
+ w[4] = X0; w[5] = X1; w[6] = X2; w[7] = X3;
+ Sb1(w[8], w[9], w[10], w[11]);
+ w[8] = X0; w[9] = X1; w[10] = X2; w[11] = X3;
+ Sb0(w[12], w[13], w[14], w[15]);
+ w[12] = X0; w[13] = X1; w[14] = X2; w[15] = X3;
+ Sb7(w[16], w[17], w[18], w[19]);
+ w[16] = X0; w[17] = X1; w[18] = X2; w[19] = X3;
+ Sb6(w[20], w[21], w[22], w[23]);
+ w[20] = X0; w[21] = X1; w[22] = X2; w[23] = X3;
+ Sb5(w[24], w[25], w[26], w[27]);
+ w[24] = X0; w[25] = X1; w[26] = X2; w[27] = X3;
+ Sb4(w[28], w[29], w[30], w[31]);
+ w[28] = X0; w[29] = X1; w[30] = X2; w[31] = X3;
+ Sb3(w[32], w[33], w[34], w[35]);
+ w[32] = X0; w[33] = X1; w[34] = X2; w[35] = X3;
+ Sb2(w[36], w[37], w[38], w[39]);
+ w[36] = X0; w[37] = X1; w[38] = X2; w[39] = X3;
+ Sb1(w[40], w[41], w[42], w[43]);
+ w[40] = X0; w[41] = X1; w[42] = X2; w[43] = X3;
+ Sb0(w[44], w[45], w[46], w[47]);
+ w[44] = X0; w[45] = X1; w[46] = X2; w[47] = X3;
+ Sb7(w[48], w[49], w[50], w[51]);
+ w[48] = X0; w[49] = X1; w[50] = X2; w[51] = X3;
+ Sb6(w[52], w[53], w[54], w[55]);
+ w[52] = X0; w[53] = X1; w[54] = X2; w[55] = X3;
+ Sb5(w[56], w[57], w[58], w[59]);
+ w[56] = X0; w[57] = X1; w[58] = X2; w[59] = X3;
+ Sb4(w[60], w[61], w[62], w[63]);
+ w[60] = X0; w[61] = X1; w[62] = X2; w[63] = X3;
+ Sb3(w[64], w[65], w[66], w[67]);
+ w[64] = X0; w[65] = X1; w[66] = X2; w[67] = X3;
+ Sb2(w[68], w[69], w[70], w[71]);
+ w[68] = X0; w[69] = X1; w[70] = X2; w[71] = X3;
+ Sb1(w[72], w[73], w[74], w[75]);
+ w[72] = X0; w[73] = X1; w[74] = X2; w[75] = X3;
+ Sb0(w[76], w[77], w[78], w[79]);
+ w[76] = X0; w[77] = X1; w[78] = X2; w[79] = X3;
+ Sb7(w[80], w[81], w[82], w[83]);
+ w[80] = X0; w[81] = X1; w[82] = X2; w[83] = X3;
+ Sb6(w[84], w[85], w[86], w[87]);
+ w[84] = X0; w[85] = X1; w[86] = X2; w[87] = X3;
+ Sb5(w[88], w[89], w[90], w[91]);
+ w[88] = X0; w[89] = X1; w[90] = X2; w[91] = X3;
+ Sb4(w[92], w[93], w[94], w[95]);
+ w[92] = X0; w[93] = X1; w[94] = X2; w[95] = X3;
+ Sb3(w[96], w[97], w[98], w[99]);
+ w[96] = X0; w[97] = X1; w[98] = X2; w[99] = X3;
+ Sb2(w[100], w[101], w[102], w[103]);
+ w[100] = X0; w[101] = X1; w[102] = X2; w[103] = X3;
+ Sb1(w[104], w[105], w[106], w[107]);
+ w[104] = X0; w[105] = X1; w[106] = X2; w[107] = X3;
+ Sb0(w[108], w[109], w[110], w[111]);
+ w[108] = X0; w[109] = X1; w[110] = X2; w[111] = X3;
+ Sb7(w[112], w[113], w[114], w[115]);
+ w[112] = X0; w[113] = X1; w[114] = X2; w[115] = X3;
+ Sb6(w[116], w[117], w[118], w[119]);
+ w[116] = X0; w[117] = X1; w[118] = X2; w[119] = X3;
+ Sb5(w[120], w[121], w[122], w[123]);
+ w[120] = X0; w[121] = X1; w[122] = X2; w[123] = X3;
+ Sb4(w[124], w[125], w[126], w[127]);
+ w[124] = X0; w[125] = X1; w[126] = X2; w[127] = X3;
+ Sb3(w[128], w[129], w[130], w[131]);
+ w[128] = X0; w[129] = X1; w[130] = X2; w[131] = X3;
+
+ return w;
+ }
+
+ /**
+ * Encrypt one block of plaintext.
+ *
+ * @param input the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param output the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ */
+ protected override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ X3 = (int)Pack.BE_To_UInt32(input, inOff);
+ X2 = (int)Pack.BE_To_UInt32(input, inOff + 4);
+ X1 = (int)Pack.BE_To_UInt32(input, inOff + 8);
+ X0 = (int)Pack.BE_To_UInt32(input, inOff + 12);
+
+ Sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT();
+ Sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT();
+ Sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); LT();
+ Sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); LT();
+ Sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); LT();
+ Sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); LT();
+ Sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); LT();
+ Sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); LT();
+ Sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); LT();
+ Sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); LT();
+ Sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); LT();
+ Sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); LT();
+ Sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); LT();
+ Sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); LT();
+ Sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); LT();
+ Sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); LT();
+ Sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); LT();
+ Sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); LT();
+ Sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); LT();
+ Sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); LT();
+ Sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); LT();
+ Sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); LT();
+ Sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); LT();
+ Sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); LT();
+ Sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); LT();
+ Sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); LT();
+ Sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); LT();
+ Sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); LT();
+ Sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); LT();
+ Sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); LT();
+ Sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT();
+ Sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
+
+ Pack.UInt32_To_BE((uint)(wKey[131] ^ X3), output, outOff);
+ Pack.UInt32_To_BE((uint)(wKey[130] ^ X2), output, outOff + 4);
+ Pack.UInt32_To_BE((uint)(wKey[129] ^ X1), output, outOff + 8);
+ Pack.UInt32_To_BE((uint)(wKey[128] ^ X0), output, outOff + 12);
+ }
+
+ /**
+ * Decrypt one block of ciphertext.
+ *
+ * @param input the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param output the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ */
+ protected override void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ X3 = wKey[131] ^ (int)Pack.BE_To_UInt32(input, inOff);
+ X2 = wKey[130] ^ (int)Pack.BE_To_UInt32(input, inOff + 4);
+ X1 = wKey[129] ^ (int)Pack.BE_To_UInt32(input, inOff + 8);
+ X0 = wKey[128] ^ (int)Pack.BE_To_UInt32(input, inOff + 12);
+
+ Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[120]; X1 ^= wKey[121]; X2 ^= wKey[122]; X3 ^= wKey[123];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[116]; X1 ^= wKey[117]; X2 ^= wKey[118]; X3 ^= wKey[119];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[112]; X1 ^= wKey[113]; X2 ^= wKey[114]; X3 ^= wKey[115];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[108]; X1 ^= wKey[109]; X2 ^= wKey[110]; X3 ^= wKey[111];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[104]; X1 ^= wKey[105]; X2 ^= wKey[106]; X3 ^= wKey[107];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[100]; X1 ^= wKey[101]; X2 ^= wKey[102]; X3 ^= wKey[103];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[96]; X1 ^= wKey[97]; X2 ^= wKey[98]; X3 ^= wKey[99];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[92]; X1 ^= wKey[93]; X2 ^= wKey[94]; X3 ^= wKey[95];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[88]; X1 ^= wKey[89]; X2 ^= wKey[90]; X3 ^= wKey[91];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[84]; X1 ^= wKey[85]; X2 ^= wKey[86]; X3 ^= wKey[87];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[80]; X1 ^= wKey[81]; X2 ^= wKey[82]; X3 ^= wKey[83];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[76]; X1 ^= wKey[77]; X2 ^= wKey[78]; X3 ^= wKey[79];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[72]; X1 ^= wKey[73]; X2 ^= wKey[74]; X3 ^= wKey[75];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[68]; X1 ^= wKey[69]; X2 ^= wKey[70]; X3 ^= wKey[71];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[64]; X1 ^= wKey[65]; X2 ^= wKey[66]; X3 ^= wKey[67];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[60]; X1 ^= wKey[61]; X2 ^= wKey[62]; X3 ^= wKey[63];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[56]; X1 ^= wKey[57]; X2 ^= wKey[58]; X3 ^= wKey[59];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[52]; X1 ^= wKey[53]; X2 ^= wKey[54]; X3 ^= wKey[55];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[48]; X1 ^= wKey[49]; X2 ^= wKey[50]; X3 ^= wKey[51];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[44]; X1 ^= wKey[45]; X2 ^= wKey[46]; X3 ^= wKey[47];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[40]; X1 ^= wKey[41]; X2 ^= wKey[42]; X3 ^= wKey[43];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[36]; X1 ^= wKey[37]; X2 ^= wKey[38]; X3 ^= wKey[39];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[32]; X1 ^= wKey[33]; X2 ^= wKey[34]; X3 ^= wKey[35];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[28]; X1 ^= wKey[29]; X2 ^= wKey[30]; X3 ^= wKey[31];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[24]; X1 ^= wKey[25]; X2 ^= wKey[26]; X3 ^= wKey[27];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[20]; X1 ^= wKey[21]; X2 ^= wKey[22]; X3 ^= wKey[23];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[16]; X1 ^= wKey[17]; X2 ^= wKey[18]; X3 ^= wKey[19];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[12]; X1 ^= wKey[13]; X2 ^= wKey[14]; X3 ^= wKey[15];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[8]; X1 ^= wKey[9]; X2 ^= wKey[10]; X3 ^= wKey[11];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+
+ Pack.UInt32_To_BE((uint)(X3 ^ wKey[3]), output, outOff);
+ Pack.UInt32_To_BE((uint)(X2 ^ wKey[2]), output, outOff + 4);
+ Pack.UInt32_To_BE((uint)(X1 ^ wKey[1]), output, outOff + 8);
+ Pack.UInt32_To_BE((uint)(X0 ^ wKey[0]), output, outOff + 12);
+ }
+ }
+}
diff --git a/crypto/src/crypto/engines/TwofishEngine.cs b/crypto/src/crypto/engines/TwofishEngine.cs
index 04a579ced..71c246594 100644
--- a/crypto/src/crypto/engines/TwofishEngine.cs
+++ b/crypto/src/crypto/engines/TwofishEngine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -267,7 +268,7 @@ namespace Org.BouncyCastle.Crypto.Engines
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
- throw new ArgumentException("invalid parameter passed to Twofish init - " + parameters.GetType().ToString());
+ throw new ArgumentException("invalid parameter passed to Twofish init - " + Platform.GetTypeName(parameters));
this.encrypting = forEncryption;
this.workingKey = ((KeyParameter)parameters).GetKey();
diff --git a/crypto/src/crypto/engines/XTEAEngine.cs b/crypto/src/crypto/engines/XTEAEngine.cs
index 40d81fbe6..5fcfa4a57 100644
--- a/crypto/src/crypto/engines/XTEAEngine.cs
+++ b/crypto/src/crypto/engines/XTEAEngine.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -64,7 +65,7 @@ namespace Org.BouncyCastle.Crypto.Engines
if (!(parameters is KeyParameter))
{
throw new ArgumentException("invalid parameter passed to TEA init - "
- + parameters.GetType().FullName);
+ + Platform.GetTypeName(parameters));
}
_forEncryption = forEncryption;
diff --git a/crypto/src/crypto/generators/DesEdeKeyGenerator.cs b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
index 5902643fd..904cc71f1 100644
--- a/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
+++ b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
@@ -52,14 +52,14 @@ namespace Org.BouncyCastle.Crypto.Generators
protected override byte[] engineGenerateKey()
{
- byte[] newKey;
+ byte[] newKey = new byte[strength];
- do
+ do
{
- newKey = random.GenerateSeed(strength);
+ random.NextBytes(newKey);
DesEdeParameters.SetOddParity(newKey);
}
- while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length));
+ while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length) || !DesEdeParameters.IsRealEdeKey(newKey, 0));
return newKey;
}
diff --git a/crypto/src/crypto/generators/DesKeyGenerator.cs b/crypto/src/crypto/generators/DesKeyGenerator.cs
index 154e3471a..4c2051d89 100644
--- a/crypto/src/crypto/generators/DesKeyGenerator.cs
+++ b/crypto/src/crypto/generators/DesKeyGenerator.cs
@@ -42,12 +42,12 @@ namespace Org.BouncyCastle.Crypto.Generators
protected override byte[] engineGenerateKey()
{
- byte[] newKey;
+ byte[] newKey = new byte[DesParameters.DesKeyLength];
- do
+ do
{
- newKey = random.GenerateSeed(DesParameters.DesKeyLength);
- DesParameters.SetOddParity(newKey);
+ random.NextBytes(newKey);
+ DesParameters.SetOddParity(newKey);
}
while (DesParameters.IsWeakKey(newKey, 0));
diff --git a/crypto/src/crypto/macs/GOST28147Mac.cs b/crypto/src/crypto/macs/GOST28147Mac.cs
index 9a8f1b730..cc6b723d6 100644
--- a/crypto/src/crypto/macs/GOST28147Mac.cs
+++ b/crypto/src/crypto/macs/GOST28147Mac.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Macs
{
@@ -83,7 +84,7 @@ namespace Org.BouncyCastle.Crypto.Macs
else
{
throw new ArgumentException("invalid parameter passed to Gost28147 init - "
- + parameters.GetType().Name);
+ + Platform.GetTypeName(parameters));
}
}
diff --git a/crypto/src/crypto/macs/SkeinMac.cs b/crypto/src/crypto/macs/SkeinMac.cs
index 1d61a41ca..07eff24f4 100644
--- a/crypto/src/crypto/macs/SkeinMac.cs
+++ b/crypto/src/crypto/macs/SkeinMac.cs
@@ -3,6 +3,7 @@ using System;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Macs
{
@@ -79,7 +80,7 @@ namespace Org.BouncyCastle.Crypto.Macs
else
{
throw new ArgumentException("Invalid parameter passed to Skein MAC init - "
- + parameters.GetType().Name);
+ + Platform.GetTypeName(parameters));
}
if (skeinParameters.GetKey() == null)
{
diff --git a/crypto/src/crypto/modes/SicBlockCipher.cs b/crypto/src/crypto/modes/SicBlockCipher.cs
index 239f99478..0bea4a455 100644
--- a/crypto/src/crypto/modes/SicBlockCipher.cs
+++ b/crypto/src/crypto/modes/SicBlockCipher.cs
@@ -56,16 +56,18 @@ namespace Org.BouncyCastle.Crypto.Modes
if (blockSize < IV.Length)
throw new ArgumentException("CTR/SIC mode requires IV no greater than: " + blockSize + " bytes.");
- if (blockSize - IV.Length > 8)
- throw new ArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - 8) + " bytes.");
- Reset();
+ int maxCounterSize = System.Math.Min(8, blockSize / 2);
+ if (blockSize - IV.Length > maxCounterSize)
+ throw new ArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
// if null it's an IV changed only.
if (ivParam.Parameters != null)
{
cipher.Init(true, ivParam.Parameters);
}
+
+ Reset();
}
public virtual string AlgorithmName
diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs
index 3a20e4bff..e023c1d18 100644
--- a/crypto/src/crypto/operators/Asn1Signature.cs
+++ b/crypto/src/crypto/operators/Asn1Signature.cs
@@ -170,13 +170,13 @@ namespace Org.BouncyCastle.Crypto.Operators
if (parameters != null && !derNull.Equals(parameters))
{
- if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ if (sigAlgId.Algorithm.Equals(PkcsObjectIdentifiers.IdRsassaPss))
{
RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters);
- return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1";
+ return GetDigestAlgName(rsaParams.HashAlgorithm.Algorithm) + "withRSAandMGF1";
}
- if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
+ if (sigAlgId.Algorithm.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
{
Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters);
@@ -184,7 +184,7 @@ namespace Org.BouncyCastle.Crypto.Operators
}
}
- return sigAlgId.ObjectID.Id;
+ return sigAlgId.Algorithm.Id;
}
private static RsassaPssParameters CreatePssParams(
diff --git a/crypto/src/crypto/parameters/DesEdeParameters.cs b/crypto/src/crypto/parameters/DesEdeParameters.cs
index 420aaecea..6be56fb2c 100644
--- a/crypto/src/crypto/parameters/DesEdeParameters.cs
+++ b/crypto/src/crypto/parameters/DesEdeParameters.cs
@@ -91,5 +91,50 @@ namespace Org.BouncyCastle.Crypto.Parameters
{
return IsWeakKey(key, 0, key.Length);
}
+
+ /**
+ * return true if the passed in key is a real 2/3 part DES-EDE key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static bool IsRealEdeKey(byte[] key, int offset)
+ {
+ return key.Length == 16 ? IsReal2Key(key, offset) : IsReal3Key(key, offset);
+ }
+
+ /**
+ * return true if the passed in key is a real 2 part DES-EDE key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static bool IsReal2Key(byte[] key, int offset)
+ {
+ bool isValid = false;
+ for (int i = offset; i != offset + 8; i++)
+ {
+ isValid |= (key[i] != key[i + 8]);
+ }
+ return isValid;
+ }
+
+ /**
+ * return true if the passed in key is a real 3 part DES-EDE key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static bool IsReal3Key(byte[] key, int offset)
+ {
+ bool diff12 = false, diff13 = false, diff23 = false;
+ for (int i = offset; i != offset + 8; i++)
+ {
+ diff12 |= (key[i] != key[i + 8]);
+ diff13 |= (key[i] != key[i + 16]);
+ diff23 |= (key[i + 8] != key[i + 16]);
+ }
+ return diff12 && diff13 && diff23;
+ }
}
}
diff --git a/crypto/src/crypto/parameters/DesParameters.cs b/crypto/src/crypto/parameters/DesParameters.cs
index ee37cd861..a1f67e2b1 100644
--- a/crypto/src/crypto/parameters/DesParameters.cs
+++ b/crypto/src/crypto/parameters/DesParameters.cs
@@ -103,28 +103,37 @@ namespace Org.BouncyCastle.Crypto.Parameters
return IsWeakKey(key, 0);
}
- /**
+ public static byte SetOddParity(byte b)
+ {
+ uint parity = b ^ 1U;
+ parity ^= (parity >> 4);
+ parity ^= (parity >> 2);
+ parity ^= (parity >> 1);
+ parity &= 1U;
+
+ return (byte)(b ^ parity);
+ }
+
+ /**
* DES Keys use the LSB as the odd parity bit. This can
* be used to check for corrupt keys.
*
* @param bytes the byte array to set the parity on.
*/
- public static void SetOddParity(
- byte[] bytes)
+ public static void SetOddParity(byte[] bytes)
{
for (int i = 0; i < bytes.Length; i++)
{
- int b = bytes[i];
- bytes[i] = (byte)((b & 0xfe) |
- ((((b >> 1) ^
- (b >> 2) ^
- (b >> 3) ^
- (b >> 4) ^
- (b >> 5) ^
- (b >> 6) ^
- (b >> 7)) ^ 0x01) & 0x01));
+ bytes[i] = SetOddParity(bytes[i]);
}
}
- }
+ public static void SetOddParity(byte[] bytes, int off, int len)
+ {
+ for (int i = 0; i < len; i++)
+ {
+ bytes[off + i] = SetOddParity(bytes[off + i]);
+ }
+ }
+ }
}
diff --git a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
new file mode 100644
index 000000000..31a8461f0
--- /dev/null
+++ b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * An EntropySourceProvider where entropy generation is based on a SecureRandom output using SecureRandom.generateSeed().
+ */
+ public class BasicEntropySourceProvider
+ : IEntropySourceProvider
+ {
+ private readonly SecureRandom mSecureRandom;
+ private readonly bool mPredictionResistant;
+
+ /**
+ * Create a entropy source provider based on the passed in SecureRandom.
+ *
+ * @param secureRandom the SecureRandom to base EntropySource construction on.
+ * @param isPredictionResistant boolean indicating if the SecureRandom is based on prediction resistant entropy or not (true if it is).
+ */
+ public BasicEntropySourceProvider(SecureRandom secureRandom, bool isPredictionResistant)
+ {
+ mSecureRandom = secureRandom;
+ mPredictionResistant = isPredictionResistant;
+ }
+
+ /**
+ * Return an entropy source that will create bitsRequired bits of entropy on
+ * each invocation of getEntropy().
+ *
+ * @param bitsRequired size (in bits) of entropy to be created by the provided source.
+ * @return an EntropySource that generates bitsRequired bits of entropy on each call to its getEntropy() method.
+ */
+ public IEntropySource Get(int bitsRequired)
+ {
+ return new BasicEntropySource(mSecureRandom, mPredictionResistant, bitsRequired);
+ }
+
+ private class BasicEntropySource
+ : IEntropySource
+ {
+ private readonly SecureRandom mSecureRandom;
+ private readonly bool mPredictionResistant;
+ private readonly int mEntropySize;
+
+ internal BasicEntropySource(SecureRandom secureRandom, bool predictionResistant, int entropySize)
+ {
+ this.mSecureRandom = secureRandom;
+ this.mPredictionResistant = predictionResistant;
+ this.mEntropySize = entropySize;
+ }
+
+ bool IEntropySource.IsPredictionResistant
+ {
+ get { return mPredictionResistant; }
+ }
+
+ byte[] IEntropySource.GetEntropy()
+ {
+ // TODO[FIPS] Not all SecureRandom implementations are considered valid entropy sources
+ return SecureRandom.GetNextBytes(mSecureRandom, (mEntropySize + 7) / 8);
+ }
+
+ int IEntropySource.EntropySize
+ {
+ get { return mEntropySize; }
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
new file mode 100644
index 000000000..68579aaf4
--- /dev/null
+++ b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
@@ -0,0 +1,70 @@
+#if !(NETCF_1_0 || PORTABLE)
+using System;
+using System.Security.Cryptography;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class CryptoApiEntropySourceProvider
+ : IEntropySourceProvider
+ {
+ private readonly RandomNumberGenerator mRng;
+ private readonly bool mPredictionResistant;
+
+ public CryptoApiEntropySourceProvider()
+ : this(new RNGCryptoServiceProvider(), true)
+ {
+ }
+
+ public CryptoApiEntropySourceProvider(RandomNumberGenerator rng, bool isPredictionResistant)
+ {
+ if (rng == null)
+ throw new ArgumentNullException("rng");
+
+ mRng = rng;
+ mPredictionResistant = isPredictionResistant;
+ }
+
+ public IEntropySource Get(int bitsRequired)
+ {
+ return new CryptoApiEntropySource(mRng, mPredictionResistant, bitsRequired);
+ }
+
+ private class CryptoApiEntropySource
+ : IEntropySource
+ {
+ private readonly RandomNumberGenerator mRng;
+ private readonly bool mPredictionResistant;
+ private readonly int mEntropySize;
+
+ internal CryptoApiEntropySource(RandomNumberGenerator rng, bool predictionResistant, int entropySize)
+ {
+ this.mRng = rng;
+ this.mPredictionResistant = predictionResistant;
+ this.mEntropySize = entropySize;
+ }
+
+ #region IEntropySource Members
+
+ bool IEntropySource.IsPredictionResistant
+ {
+ get { return mPredictionResistant; }
+ }
+
+ byte[] IEntropySource.GetEntropy()
+ {
+ byte[] result = new byte[(mEntropySize + 7) / 8];
+ mRng.GetBytes(result);
+ return result;
+ }
+
+ int IEntropySource.EntropySize
+ {
+ get { return mEntropySize; }
+ }
+
+ #endregion
+ }
+ }
+}
+
+#endif
diff --git a/crypto/src/crypto/prng/DigestRandomGenerator.cs b/crypto/src/crypto/prng/DigestRandomGenerator.cs
index cbd2ef060..f5a29952a 100644
--- a/crypto/src/crypto/prng/DigestRandomGenerator.cs
+++ b/crypto/src/crypto/prng/DigestRandomGenerator.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Prng
{
@@ -108,15 +109,12 @@ namespace Org.BouncyCastle.Crypto.Prng
private void DigestAddCounter(long seedVal)
{
- ulong seed = (ulong)seedVal;
- for (int i = 0; i != 8; i++)
- {
- digest.Update((byte)seed);
- seed >>= 8;
- }
+ byte[] bytes = new byte[8];
+ Pack.UInt64_To_LE((ulong)seedVal, bytes);
+ digest.BlockUpdate(bytes, 0, bytes.Length);
}
- private void DigestUpdate(byte[] inSeed)
+ private void DigestUpdate(byte[] inSeed)
{
digest.BlockUpdate(inSeed, 0, inSeed.Length);
}
diff --git a/crypto/src/crypto/prng/EntropyUtilities.cs b/crypto/src/crypto/prng/EntropyUtilities.cs
new file mode 100644
index 000000000..58c8703f4
--- /dev/null
+++ b/crypto/src/crypto/prng/EntropyUtilities.cs
@@ -0,0 +1,30 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public abstract class EntropyUtilities
+ {
+ /**
+ * Generate numBytes worth of entropy from the passed in entropy source.
+ *
+ * @param entropySource the entropy source to request the data from.
+ * @param numBytes the number of bytes of entropy requested.
+ * @return a byte array populated with the random data.
+ */
+ public static byte[] GenerateSeed(IEntropySource entropySource, int numBytes)
+ {
+ byte[] bytes = new byte[numBytes];
+ int count = 0;
+ while (count < numBytes)
+ {
+ byte[] entropy = entropySource.GetEntropy();
+ int toCopy = System.Math.Min(bytes.Length, numBytes - count);
+ Array.Copy(entropy, 0, bytes, count, toCopy);
+ count += toCopy;
+ }
+ return bytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/IDrbgProvider.cs b/crypto/src/crypto/prng/IDrbgProvider.cs
new file mode 100644
index 000000000..5ebf5fd8d
--- /dev/null
+++ b/crypto/src/crypto/prng/IDrbgProvider.cs
@@ -0,0 +1,11 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ internal interface IDrbgProvider
+ {
+ ISP80090Drbg Get(IEntropySource entropySource);
+ }
+}
diff --git a/crypto/src/crypto/prng/SP800SecureRandom.cs b/crypto/src/crypto/prng/SP800SecureRandom.cs
new file mode 100644
index 000000000..5c5bda399
--- /dev/null
+++ b/crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class SP800SecureRandom
+ : SecureRandom
+ {
+ private readonly IDrbgProvider mDrbgProvider;
+ private readonly bool mPredictionResistant;
+ private readonly SecureRandom mRandomSource;
+ private readonly IEntropySource mEntropySource;
+
+ private ISP80090Drbg mDrbg;
+
+ internal SP800SecureRandom(SecureRandom randomSource, IEntropySource entropySource, IDrbgProvider drbgProvider, bool predictionResistant)
+ : base((IRandomGenerator)null)
+ {
+ this.mRandomSource = randomSource;
+ this.mEntropySource = entropySource;
+ this.mDrbgProvider = drbgProvider;
+ this.mPredictionResistant = predictionResistant;
+ }
+
+ public override void SetSeed(byte[] seed)
+ {
+ lock (this)
+ {
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void SetSeed(long seed)
+ {
+ lock (this)
+ {
+ // this will happen when SecureRandom() is created
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] bytes)
+ {
+ lock (this)
+ {
+ if (mDrbg == null)
+ {
+ mDrbg = mDrbgProvider.Get(mEntropySource);
+ }
+
+ // check if a reseed is required...
+ if (mDrbg.Generate(bytes, null, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed(null);
+ mDrbg.Generate(bytes, null, mPredictionResistant);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] buf, int off, int len)
+ {
+ byte[] bytes = new byte[len];
+ NextBytes(bytes);
+ Array.Copy(bytes, 0, buf, off, len);
+ }
+
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ return EntropyUtilities.GenerateSeed(mEntropySource, numBytes);
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs b/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
new file mode 100644
index 000000000..7199f1ae7
--- /dev/null
+++ b/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
@@ -0,0 +1,208 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * Builder class for making SecureRandom objects based on SP 800-90A Deterministic Random Bit Generators (DRBG).
+ */
+ public class SP800SecureRandomBuilder
+ {
+ private readonly SecureRandom mRandom;
+ private readonly IEntropySourceProvider mEntropySourceProvider;
+
+ private byte[] mPersonalizationString = null;
+ private int mSecurityStrength = 256;
+ private int mEntropyBitsRequired = 256;
+
+ /**
+ * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with
+ * predictionResistant set to false.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the default SecureRandom does for its generateSeed() call.
+ * </p>
+ */
+ public SP800SecureRandomBuilder()
+ : this(new SecureRandom(), false)
+ {
+ }
+
+ /**
+ * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value
+ * for prediction resistance.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the passed in SecureRandom does for its generateSeed() call.
+ * </p>
+ * @param entropySource
+ * @param predictionResistant
+ */
+ public SP800SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
+ {
+ this.mRandom = entropySource;
+ this.mEntropySourceProvider = new BasicEntropySourceProvider(entropySource, predictionResistant);
+ }
+
+ /**
+ * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider.
+ * <p>
+ * <b>Note:</b> If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored.
+ * </p>
+ * @param entropySourceProvider a provider of EntropySource objects.
+ */
+ public SP800SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
+ {
+ this.mRandom = null;
+ this.mEntropySourceProvider = entropySourceProvider;
+ }
+
+ /**
+ * Set the personalization string for DRBG SecureRandoms created by this builder
+ * @param personalizationString the personalisation string for the underlying DRBG.
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetPersonalizationString(byte[] personalizationString)
+ {
+ this.mPersonalizationString = personalizationString;
+ return this;
+ }
+
+ /**
+ * Set the security strength required for DRBGs used in building SecureRandom objects.
+ *
+ * @param securityStrength the security strength (in bits)
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetSecurityStrength(int securityStrength)
+ {
+ this.mSecurityStrength = securityStrength;
+ return this;
+ }
+
+ /**
+ * Set the amount of entropy bits required for seeding and reseeding DRBGs used in building SecureRandom objects.
+ *
+ * @param entropyBitsRequired the number of bits of entropy to be requested from the entropy source on each seed/reseed.
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetEntropyBitsRequired(int entropyBitsRequired)
+ {
+ this.mEntropyBitsRequired = entropyBitsRequired;
+ return this;
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A Hash DRBG.
+ *
+ * @param digest digest algorithm to use in the DRBG underneath the SecureRandom.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a Hash DRBG.
+ */
+ public SP800SecureRandom BuildHash(IDigest digest, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new HashDrbgProvider(digest, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A CTR DRBG.
+ *
+ * @param cipher the block cipher to base the DRBG on.
+ * @param keySizeInBits key size in bits to be used with the block cipher.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a CTR DRBG.
+ */
+ public SP800SecureRandom BuildCtr(IBlockCipher cipher, int keySizeInBits, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new CtrDrbgProvider(cipher, keySizeInBits, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A HMAC DRBG.
+ *
+ * @param hMac HMAC algorithm to use in the DRBG underneath the SecureRandom.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a HMAC DRBG.
+ */
+ public SP800SecureRandom BuildHMac(IMac hMac, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new HMacDrbgProvider(hMac, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ private class HashDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IDigest mDigest;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public HashDrbgProvider(IDigest digest, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mDigest = digest;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new HashSP800Drbg(mDigest, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+
+ private class HMacDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IMac mHMac;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public HMacDrbgProvider(IMac hMac, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mHMac = hMac;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new HMacSP800Drbg(mHMac, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+
+ private class CtrDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IBlockCipher mBlockCipher;
+ private readonly int mKeySizeInBits;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public CtrDrbgProvider(IBlockCipher blockCipher, int keySizeInBits, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mBlockCipher = blockCipher;
+ this.mKeySizeInBits = keySizeInBits;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new CtrSP800Drbg(mBlockCipher, mKeySizeInBits, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931Rng.cs b/crypto/src/crypto/prng/X931Rng.cs
new file mode 100644
index 000000000..2bd8e0c6b
--- /dev/null
+++ b/crypto/src/crypto/prng/X931Rng.cs
@@ -0,0 +1,146 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ internal class X931Rng
+ {
+ private const long BLOCK64_RESEED_MAX = 1L << (16 - 1);
+ private const long BLOCK128_RESEED_MAX = 1L << (24 - 1);
+ private const int BLOCK64_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private const int BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly IBlockCipher mEngine;
+ private readonly IEntropySource mEntropySource;
+
+ private readonly byte[] mDT;
+ private readonly byte[] mI;
+ private readonly byte[] mR;
+
+ private byte[] mV;
+
+ private long mReseedCounter = 1;
+
+ /**
+ *
+ * @param engine
+ * @param entropySource
+ */
+ internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource)
+ {
+ this.mEngine = engine;
+ this.mEntropySource = entropySource;
+
+ this.mDT = new byte[engine.GetBlockSize()];
+
+ Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length);
+
+ this.mI = new byte[engine.GetBlockSize()];
+ this.mR = new byte[engine.GetBlockSize()];
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ internal int Generate(byte[] output, bool predictionResistant)
+ {
+ if (mR.Length == 8) // 64 bit block size
+ {
+ if (mReseedCounter > BLOCK64_RESEED_MAX)
+ return -1;
+
+ if (IsTooLarge(output, BLOCK64_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST, "output");
+ }
+ else
+ {
+ if (mReseedCounter > BLOCK128_RESEED_MAX)
+ return -1;
+
+ if (IsTooLarge(output, BLOCK128_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST, "output");
+ }
+
+ if (predictionResistant || mV == null)
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ }
+
+ int m = output.Length / mR.Length;
+
+ for (int i = 0; i < m; i++)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ Array.Copy(mR, 0, output, i * mR.Length, mR.Length);
+
+ Increment(mDT);
+ }
+
+ int bytesToCopy = (output.Length - m * mR.Length);
+
+ if (bytesToCopy > 0)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ Array.Copy(mR, 0, output, m * mR.Length, bytesToCopy);
+
+ Increment(mDT);
+ }
+
+ mReseedCounter++;
+
+ return output.Length;
+ }
+
+ /**
+ * Reseed the RNG.
+ */
+ internal void Reseed()
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ mReseedCounter = 1;
+ }
+
+ internal IEntropySource EntropySource
+ {
+ get { return mEntropySource; }
+ }
+
+ private void Process(byte[] res, byte[] a, byte[] b)
+ {
+ for (int i = 0; i != res.Length; i++)
+ {
+ res[i] = (byte)(a[i] ^ b[i]);
+ }
+
+ mEngine.ProcessBlock(res, 0, res, 0);
+ }
+
+ private void Increment(byte[] val)
+ {
+ for (int i = val.Length - 1; i >= 0; i--)
+ {
+ if (++val[i] != 0)
+ break;
+ }
+ }
+
+ private static bool IsTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.Length > maxBytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931SecureRandom.cs b/crypto/src/crypto/prng/X931SecureRandom.cs
new file mode 100644
index 000000000..d2e4849c5
--- /dev/null
+++ b/crypto/src/crypto/prng/X931SecureRandom.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class X931SecureRandom
+ : SecureRandom
+ {
+ private readonly bool mPredictionResistant;
+ private readonly SecureRandom mRandomSource;
+ private readonly X931Rng mDrbg;
+
+ internal X931SecureRandom(SecureRandom randomSource, X931Rng drbg, bool predictionResistant)
+ : base((IRandomGenerator)null)
+ {
+ this.mRandomSource = randomSource;
+ this.mDrbg = drbg;
+ this.mPredictionResistant = predictionResistant;
+ }
+
+ public override void SetSeed(byte[] seed)
+ {
+ lock (this)
+ {
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void SetSeed(long seed)
+ {
+ lock (this)
+ {
+ // this will happen when SecureRandom() is created
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] bytes)
+ {
+ lock (this)
+ {
+ // check if a reseed is required...
+ if (mDrbg.Generate(bytes, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed();
+ mDrbg.Generate(bytes, mPredictionResistant);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] buf, int off, int len)
+ {
+ byte[] bytes = new byte[len];
+ NextBytes(bytes);
+ Array.Copy(bytes, 0, buf, off, len);
+ }
+
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ return EntropyUtilities.GenerateSeed(mDrbg.EntropySource, numBytes);
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931SecureRandomBuilder.cs b/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
new file mode 100644
index 000000000..31e94312e
--- /dev/null
+++ b/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class X931SecureRandomBuilder
+ {
+ private readonly SecureRandom mRandom; // JDK 1.1 complains on final.
+
+ private IEntropySourceProvider mEntropySourceProvider;
+ private byte[] mDateTimeVector;
+
+ /**
+ * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with
+ * predictionResistant set to false.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the default SecureRandom does for its generateSeed() call.
+ * </p>
+ */
+ public X931SecureRandomBuilder()
+ : this(new SecureRandom(), false)
+ {
+ }
+
+ /**
+ * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value
+ * for prediction resistance.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the passed in SecureRandom does for its generateSeed() call.
+ * </p>
+ * @param entropySource
+ * @param predictionResistant
+ */
+ public X931SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
+ {
+ this.mRandom = entropySource;
+ this.mEntropySourceProvider = new BasicEntropySourceProvider(mRandom, predictionResistant);
+ }
+
+ /**
+ * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider.
+ * <p>
+ * <b>Note:</b> If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored.
+ * </p>
+ * @param entropySourceProvider a provider of EntropySource objects.
+ */
+ public X931SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
+ {
+ this.mRandom = null;
+ this.mEntropySourceProvider = entropySourceProvider;
+ }
+
+ public X931SecureRandomBuilder SetDateTimeVector(byte[] dateTimeVector)
+ {
+ this.mDateTimeVector = dateTimeVector;
+ return this;
+ }
+
+ /**
+ * Construct a X9.31 secure random generator using the passed in engine and key. If predictionResistant is true the
+ * generator will be reseeded on each request.
+ *
+ * @param engine a block cipher to use as the operator.
+ * @param key the block cipher key to initialise engine with.
+ * @param predictionResistant true if engine to be reseeded on each use, false otherwise.
+ * @return a SecureRandom.
+ */
+ public X931SecureRandom Build(IBlockCipher engine, KeyParameter key, bool predictionResistant)
+ {
+ if (mDateTimeVector == null)
+ {
+ mDateTimeVector = new byte[engine.GetBlockSize()];
+ Pack.UInt64_To_BE((ulong)DateTimeUtilities.CurrentUnixMs(), mDateTimeVector, 0);
+ }
+
+ engine.Init(true, key);
+
+ return new X931SecureRandom(mRandom, new X931Rng(engine, mDateTimeVector, mEntropySourceProvider.Get(engine.GetBlockSize() * 8)), predictionResistant);
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
new file mode 100644
index 000000000..eca1821d3
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
@@ -0,0 +1,466 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A CTR DRBG.
+ */
+ public class CtrSP800Drbg
+ : ISP80090Drbg
+ {
+ private static readonly long TDEA_RESEED_MAX = 1L << (32 - 1);
+ private static readonly long AES_RESEED_MAX = 1L << (48 - 1);
+ private static readonly int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private static readonly int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly IEntropySource mEntropySource;
+ private readonly IBlockCipher mEngine;
+ private readonly int mKeySizeInBits;
+ private readonly int mSeedLength;
+ private readonly int mSecurityStrength;
+
+ // internal state
+ private byte[] mKey;
+ private byte[] mV;
+ private long mReseedCounter = 0;
+ private bool mIsTdea = false;
+
+ /**
+ * Construct a SP800-90A CTR DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param engine underlying block cipher to use to support DRBG
+ * @param keySizeInBits size of the key to use with the block cipher.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public CtrSP800Drbg(IBlockCipher engine, int keySizeInBits, int securityStrength, IEntropySource entropySource,
+ byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > 256)
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (GetMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
+ throw new ArgumentException("Requested security strength is not supported by block cipher and key size");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mEntropySource = entropySource;
+ mEngine = engine;
+
+ mKeySizeInBits = keySizeInBits;
+ mSecurityStrength = securityStrength;
+ mSeedLength = keySizeInBits + engine.GetBlockSize() * 8;
+ mIsTdea = IsTdea(engine);
+
+ byte[] entropy = GetEntropy(); // Get_entropy_input
+
+ CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
+ }
+
+ private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce, byte[] personalisationString)
+ {
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
+ byte[] seed = Block_Cipher_df(seedMaterial, mSeedLength);
+
+ int outlen = mEngine.GetBlockSize();
+
+ mKey = new byte[(mKeySizeInBits + 7) / 8];
+ mV = new byte[outlen];
+
+ // mKey & mV are modified by this call
+ CTR_DRBG_Update(seed, mKey, mV);
+
+ mReseedCounter = 1;
+ }
+
+ private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
+ {
+ byte[] temp = new byte[seed.Length];
+ byte[] outputBlock = new byte[mEngine.GetBlockSize()];
+
+ int i = 0;
+ int outLen = mEngine.GetBlockSize();
+
+ mEngine.Init(true, new KeyParameter(ExpandKey(key)));
+ while (i*outLen < seed.Length)
+ {
+ AddOneTo(v);
+ mEngine.ProcessBlock(v, 0, outputBlock, 0);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen : (temp.Length - i * outLen);
+
+ Array.Copy(outputBlock, 0, temp, i * outLen, bytesToCopy);
+ ++i;
+ }
+
+ XOR(temp, seed, temp, 0);
+
+ Array.Copy(temp, 0, key, 0, key.Length);
+ Array.Copy(temp, key.Length, v, 0, v.Length);
+ }
+
+ private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput)
+ {
+ byte[] seedMaterial = Arrays.Concatenate(GetEntropy(), additionalInput);
+
+ seedMaterial = Block_Cipher_df(seedMaterial, mSeedLength);
+
+ CTR_DRBG_Update(seedMaterial, mKey, mV);
+
+ mReseedCounter = 1;
+ }
+
+ private void XOR(byte[] output, byte[] a, byte[] b, int bOff)
+ {
+ for (int i = 0; i < output.Length; i++)
+ {
+ output[i] = (byte)(a[i] ^ b[bOff + i]);
+ }
+ }
+
+ private void AddOneTo(byte[] longer)
+ {
+ uint carry = 1;
+ int i = longer.Length;
+ while (--i >= 0)
+ {
+ carry += longer[i];
+ longer[i] = (byte)carry;
+ carry >>= 8;
+ }
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+
+ // -- Internal state migration ---
+
+ private static readonly byte[] K_BITS = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ // 1. If (number_of_bits_to_return > max_number_of_bits), then return an
+ // ERROR_FLAG.
+ // 2. L = len (input_string)/8.
+ // 3. N = number_of_bits_to_return/8.
+ // Comment: L is the bitstring represention of
+ // the integer resulting from len (input_string)/8.
+ // L shall be represented as a 32-bit integer.
+ //
+ // Comment : N is the bitstring represention of
+ // the integer resulting from
+ // number_of_bits_to_return/8. N shall be
+ // represented as a 32-bit integer.
+ //
+ // 4. S = L || N || input_string || 0x80.
+ // 5. While (len (S) mod outlen)
+ // Comment : Pad S with zeros, if necessary.
+ // 0, S = S || 0x00.
+ //
+ // Comment : Compute the starting value.
+ // 6. temp = the Null string.
+ // 7. i = 0.
+ // 8. K = Leftmost keylen bits of 0x00010203...1D1E1F.
+ // 9. While len (temp) < keylen + outlen, do
+ //
+ // IV = i || 0outlen - len (i).
+ //
+ // 9.1
+ //
+ // temp = temp || BCC (K, (IV || S)).
+ //
+ // 9.2
+ //
+ // i = i + 1.
+ //
+ // 9.3
+ //
+ // Comment : i shall be represented as a 32-bit
+ // integer, i.e., len (i) = 32.
+ //
+ // Comment: The 32-bit integer represenation of
+ // i is padded with zeros to outlen bits.
+ //
+ // Comment: Compute the requested number of
+ // bits.
+ //
+ // 10. K = Leftmost keylen bits of temp.
+ //
+ // 11. X = Next outlen bits of temp.
+ //
+ // 12. temp = the Null string.
+ //
+ // 13. While len (temp) < number_of_bits_to_return, do
+ //
+ // 13.1 X = Block_Encrypt (K, X).
+ //
+ // 13.2 temp = temp || X.
+ //
+ // 14. requested_bits = Leftmost number_of_bits_to_return of temp.
+ //
+ // 15. Return SUCCESS and requested_bits.
+ private byte[] Block_Cipher_df(byte[] inputString, int bitLength)
+ {
+ int outLen = mEngine.GetBlockSize();
+ int L = inputString.Length; // already in bytes
+ int N = bitLength / 8;
+ // 4 S = L || N || inputstring || 0x80
+ int sLen = 4 + 4 + L + 1;
+ int blockLen = ((sLen + outLen - 1) / outLen) * outLen;
+ byte[] S = new byte[blockLen];
+ copyIntToByteArray(S, L, 0);
+ copyIntToByteArray(S, N, 4);
+ Array.Copy(inputString, 0, S, 8, L);
+ S[8 + L] = (byte)0x80;
+ // S already padded with zeros
+
+ byte[] temp = new byte[mKeySizeInBits / 8 + outLen];
+ byte[] bccOut = new byte[outLen];
+
+ byte[] IV = new byte[outLen];
+
+ int i = 0;
+ byte[] K = new byte[mKeySizeInBits / 8];
+ Array.Copy(K_BITS, 0, K, 0, K.Length);
+
+ while (i*outLen*8 < mKeySizeInBits + outLen *8)
+ {
+ copyIntToByteArray(IV, i, 0);
+ BCC(bccOut, K, IV, S);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen
+ : (temp.Length - i * outLen);
+
+ Array.Copy(bccOut, 0, temp, i * outLen, bytesToCopy);
+ ++i;
+ }
+
+ byte[] X = new byte[outLen];
+ Array.Copy(temp, 0, K, 0, K.Length);
+ Array.Copy(temp, K.Length, X, 0, X.Length);
+
+ temp = new byte[bitLength / 2];
+
+ i = 0;
+ mEngine.Init(true, new KeyParameter(ExpandKey(K)));
+
+ while (i * outLen < temp.Length)
+ {
+ mEngine.ProcessBlock(X, 0, X, 0);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen
+ : (temp.Length - i * outLen);
+
+ Array.Copy(X, 0, temp, i * outLen, bytesToCopy);
+ i++;
+ }
+
+ return temp;
+ }
+
+ /*
+ * 1. chaining_value = 0^outlen
+ * . Comment: Set the first chaining value to outlen zeros.
+ * 2. n = len (data)/outlen.
+ * 3. Starting with the leftmost bits of data, split the data into n blocks of outlen bits
+ * each, forming block(1) to block(n).
+ * 4. For i = 1 to n do
+ * 4.1 input_block = chaining_value ^ block(i) .
+ * 4.2 chaining_value = Block_Encrypt (Key, input_block).
+ * 5. output_block = chaining_value.
+ * 6. Return output_block.
+ */
+ private void BCC(byte[] bccOut, byte[] k, byte[] iV, byte[] data)
+ {
+ int outlen = mEngine.GetBlockSize();
+ byte[] chainingValue = new byte[outlen]; // initial values = 0
+ int n = data.Length / outlen;
+
+ byte[] inputBlock = new byte[outlen];
+
+ mEngine.Init(true, new KeyParameter(ExpandKey(k)));
+
+ mEngine.ProcessBlock(iV, 0, chainingValue, 0);
+
+ for (int i = 0; i < n; i++)
+ {
+ XOR(inputBlock, chainingValue, data, i*outlen);
+ mEngine.ProcessBlock(inputBlock, 0, chainingValue, 0);
+ }
+
+ Array.Copy(chainingValue, 0, bccOut, 0, bccOut.Length);
+ }
+
+ private void copyIntToByteArray(byte[] buf, int value, int offSet)
+ {
+ buf[offSet + 0] = ((byte)(value >> 24));
+ buf[offSet + 1] = ((byte)(value >> 16));
+ buf[offSet + 2] = ((byte)(value >> 8));
+ buf[offSet + 3] = ((byte)(value));
+ }
+
+ /**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each internal round of the DRBG.
+ */
+ public int BlockSize
+ {
+ get { return mV.Length * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ if (mIsTdea)
+ {
+ if (mReseedCounter > TDEA_RESEED_MAX)
+ return -1;
+
+ if (DrbgUtilities.IsTooLarge(output, TDEA_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
+ }
+ else
+ {
+ if (mReseedCounter > AES_RESEED_MAX)
+ return -1;
+
+ if (DrbgUtilities.IsTooLarge(output, AES_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
+ }
+
+ if (predictionResistant)
+ {
+ CTR_DRBG_Reseed_algorithm(additionalInput);
+ additionalInput = null;
+ }
+
+ if (additionalInput != null)
+ {
+ additionalInput = Block_Cipher_df(additionalInput, mSeedLength);
+ CTR_DRBG_Update(additionalInput, mKey, mV);
+ }
+ else
+ {
+ additionalInput = new byte[mSeedLength];
+ }
+
+ byte[] tmp = new byte[mV.Length];
+
+ mEngine.Init(true, new KeyParameter(ExpandKey(mKey)));
+
+ for (int i = 0; i <= output.Length / tmp.Length; i++)
+ {
+ int bytesToCopy = ((output.Length - i * tmp.Length) > tmp.Length)
+ ? tmp.Length
+ : (output.Length - i * mV.Length);
+
+ if (bytesToCopy != 0)
+ {
+ AddOneTo(mV);
+
+ mEngine.ProcessBlock(mV, 0, tmp, 0);
+
+ Array.Copy(tmp, 0, output, i * tmp.Length, bytesToCopy);
+ }
+ }
+
+ CTR_DRBG_Update(additionalInput, mKey, mV);
+
+ mReseedCounter++;
+
+ return output.Length * 8;
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ CTR_DRBG_Reseed_algorithm(additionalInput);
+ }
+
+ private bool IsTdea(IBlockCipher cipher)
+ {
+ return cipher.AlgorithmName.Equals("DESede") || cipher.AlgorithmName.Equals("TDEA");
+ }
+
+ private int GetMaxSecurityStrength(IBlockCipher cipher, int keySizeInBits)
+ {
+ if (IsTdea(cipher) && keySizeInBits == 168)
+ {
+ return 112;
+ }
+ if (cipher.AlgorithmName.Equals("AES"))
+ {
+ return keySizeInBits;
+ }
+
+ return -1;
+ }
+
+ private byte[] ExpandKey(byte[] key)
+ {
+ if (mIsTdea)
+ {
+ // expand key to 192 bits.
+ byte[] tmp = new byte[24];
+
+ PadKey(key, 0, tmp, 0);
+ PadKey(key, 7, tmp, 8);
+ PadKey(key, 14, tmp, 16);
+
+ return tmp;
+ }
+ else
+ {
+ return key;
+ }
+ }
+
+ /**
+ * Pad out a key for TDEA, setting odd parity for each byte.
+ *
+ * @param keyMaster
+ * @param keyOff
+ * @param tmp
+ * @param tmpOff
+ */
+ private void PadKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
+ {
+ tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
+ tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >> 1));
+ tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >> 2));
+ tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >> 3));
+ tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >> 4));
+ tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >> 5));
+ tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >> 6));
+ tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
+
+ DesParameters.SetOddParity(tmp, tmpOff, 8);
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/DrbgUtilities.cs b/crypto/src/crypto/prng/drbg/DrbgUtilities.cs
new file mode 100644
index 000000000..d9a1c439c
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/DrbgUtilities.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ internal class DrbgUtilities
+ {
+ private static readonly IDictionary maxSecurityStrengths = Platform.CreateHashtable();
+
+ static DrbgUtilities()
+ {
+ maxSecurityStrengths.Add("SHA-1", 128);
+
+ maxSecurityStrengths.Add("SHA-224", 192);
+ maxSecurityStrengths.Add("SHA-256", 256);
+ maxSecurityStrengths.Add("SHA-384", 256);
+ maxSecurityStrengths.Add("SHA-512", 256);
+
+ maxSecurityStrengths.Add("SHA-512/224", 192);
+ maxSecurityStrengths.Add("SHA-512/256", 256);
+ }
+
+ internal static int GetMaxSecurityStrength(IDigest d)
+ {
+ return (int)maxSecurityStrengths[d.AlgorithmName];
+ }
+
+ internal static int GetMaxSecurityStrength(IMac m)
+ {
+ string name = m.AlgorithmName;
+
+ return (int)maxSecurityStrengths[name.Substring(0, name.IndexOf("/"))];
+ }
+
+ /**
+ * Used by both Dual EC and Hash.
+ */
+ internal static byte[] HashDF(IDigest digest, byte[] seedMaterial, int seedLength)
+ {
+ // 1. temp = the Null string.
+ // 2. .
+ // 3. counter = an 8-bit binary value representing the integer "1".
+ // 4. For i = 1 to len do
+ // Comment : In step 4.1, no_of_bits_to_return
+ // is used as a 32-bit string.
+ // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
+ // input_string).
+ // 4.2 counter = counter + 1.
+ // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
+ // 6. Return SUCCESS and requested_bits.
+ byte[] temp = new byte[(seedLength + 7) / 8];
+
+ int len = temp.Length / digest.GetDigestSize();
+ int counter = 1;
+
+ byte[] dig = new byte[digest.GetDigestSize()];
+
+ for (int i = 0; i <= len; i++)
+ {
+ digest.Update((byte)counter);
+
+ digest.Update((byte)(seedLength >> 24));
+ digest.Update((byte)(seedLength >> 16));
+ digest.Update((byte)(seedLength >> 8));
+ digest.Update((byte)seedLength);
+
+ digest.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
+
+ digest.DoFinal(dig, 0);
+
+ int bytesToCopy = ((temp.Length - i * dig.Length) > dig.Length)
+ ? dig.Length
+ : (temp.Length - i * dig.Length);
+ Array.Copy(dig, 0, temp, i * dig.Length, bytesToCopy);
+
+ counter++;
+ }
+
+ // do a left shift to get rid of excess bits.
+ if (seedLength % 8 != 0)
+ {
+ int shift = 8 - (seedLength % 8);
+ uint carry = 0;
+
+ for (int i = 0; i != temp.Length; i++)
+ {
+ uint b = temp[i];
+ temp[i] = (byte)((b >> shift) | (carry << (8 - shift)));
+ carry = b;
+ }
+ }
+
+ return temp;
+ }
+
+ internal static bool IsTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.Length > maxBytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs b/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
new file mode 100644
index 000000000..78331705e
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
@@ -0,0 +1,186 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A HMAC DRBG.
+ */
+ public class HMacSP800Drbg
+ : ISP80090Drbg
+ {
+ private readonly static long RESEED_MAX = 1L << (48 - 1);
+ private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly byte[] mK;
+ private readonly byte[] mV;
+ private readonly IEntropySource mEntropySource;
+ private readonly IMac mHMac;
+ private readonly int mSecurityStrength;
+
+ private long mReseedCounter;
+
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param hMac Hash MAC to base the DRBG on.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HMacSP800Drbg(IMac hMac, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(hMac))
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mHMac = hMac;
+ mSecurityStrength = securityStrength;
+ mEntropySource = entropySource;
+
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
+
+ mK = new byte[hMac.GetMacSize()];
+ mV = new byte[mK.Length];
+ Arrays.Fill(mV, (byte)1);
+
+ hmac_DRBG_Update(seedMaterial);
+
+ mReseedCounter = 1;
+ }
+
+ private void hmac_DRBG_Update(byte[] seedMaterial)
+ {
+ hmac_DRBG_Update_Func(seedMaterial, (byte)0x00);
+ if (seedMaterial != null)
+ {
+ hmac_DRBG_Update_Func(seedMaterial, (byte)0x01);
+ }
+ }
+
+ private void hmac_DRBG_Update_Func(byte[] seedMaterial, byte vValue)
+ {
+ mHMac.Init(new KeyParameter(mK));
+
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.Update(vValue);
+
+ if (seedMaterial != null)
+ {
+ mHMac.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
+ }
+
+ mHMac.DoFinal(mK, 0);
+
+ mHMac.Init(new KeyParameter(mK));
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+
+ mHMac.DoFinal(mV, 0);
+ }
+
+ /**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each round of the DRBG.
+ */
+ public int BlockSize
+ {
+ get { return mV.Length * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ int numberOfBits = output.Length * 8;
+
+ if (numberOfBits > MAX_BITS_REQUEST)
+ throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
+
+ if (mReseedCounter > RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (predictionResistant)
+ {
+ Reseed(additionalInput);
+ additionalInput = null;
+ }
+
+ // 2.
+ if (additionalInput != null)
+ {
+ hmac_DRBG_Update(additionalInput);
+ }
+
+ // 3.
+ byte[] rv = new byte[output.Length];
+
+ int m = output.Length / mV.Length;
+
+ mHMac.Init(new KeyParameter(mK));
+
+ for (int i = 0; i < m; i++)
+ {
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.DoFinal(mV, 0);
+
+ Array.Copy(mV, 0, rv, i * mV.Length, mV.Length);
+ }
+
+ if (m * mV.Length < rv.Length)
+ {
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.DoFinal(mV, 0);
+
+ Array.Copy(mV, 0, rv, m * mV.Length, rv.Length - (m * mV.Length));
+ }
+
+ hmac_DRBG_Update(additionalInput);
+
+ mReseedCounter++;
+
+ Array.Copy(rv, 0, output, 0, output.Length);
+
+ return numberOfBits;
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.Concatenate(entropy, additionalInput);
+
+ hmac_DRBG_Update(seedMaterial);
+
+ mReseedCounter = 1;
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs b/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
new file mode 100644
index 000000000..493da5a75
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
@@ -0,0 +1,287 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A Hash DRBG.
+ */
+ public class HashSP800Drbg
+ : ISP80090Drbg
+ {
+ private readonly static byte[] ONE = { 0x01 };
+
+ private readonly static long RESEED_MAX = 1L << (48 - 1);
+ private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private static readonly IDictionary seedlens = Platform.CreateHashtable();
+
+ static HashSP800Drbg()
+ {
+ seedlens.Add("SHA-1", 440);
+ seedlens.Add("SHA-224", 440);
+ seedlens.Add("SHA-256", 440);
+ seedlens.Add("SHA-512/256", 440);
+ seedlens.Add("SHA-512/224", 440);
+ seedlens.Add("SHA-384", 888);
+ seedlens.Add("SHA-512", 888);
+ }
+
+ private readonly IDigest mDigest;
+ private readonly IEntropySource mEntropySource;
+ private readonly int mSecurityStrength;
+ private readonly int mSeedLength;
+
+ private byte[] mV;
+ private byte[] mC;
+ private long mReseedCounter;
+
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param digest source digest to use for DRB stream.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HashSP800Drbg(IDigest digest, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(digest))
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mDigest = digest;
+ mEntropySource = entropySource;
+ mSecurityStrength = securityStrength;
+ mSeedLength = (int)seedlens[digest.AlgorithmName];
+
+ // 1. seed_material = entropy_input || nonce || personalization_string.
+ // 2. seed = Hash_df (seed_material, seedlen).
+ // 3. V = seed.
+ // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed V with a byte
+ // of zeros.
+ // 5. reseed_counter = 1.
+ // 6. Return V, C, and reseed_counter as the initial_working_state
+
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
+ byte[] seed = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
+
+ mV = seed;
+ byte[] subV = new byte[mV.Length + 1];
+ Array.Copy(mV, 0, subV, 1, mV.Length);
+ mC = DrbgUtilities.HashDF(mDigest, subV, mSeedLength);
+
+ mReseedCounter = 1;
+ }
+
+ /**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each internal round of the DRBG.
+ */
+ public int BlockSize
+ {
+ get { return mDigest.GetDigestSize () * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ // 1. If reseed_counter > reseed_interval, then return an indication that a
+ // reseed is required.
+ // 2. If (additional_input != Null), then do
+ // 2.1 w = Hash (0x02 || V || additional_input).
+ // 2.2 V = (V + w) mod 2^seedlen
+ // .
+ // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
+ // 4. H = Hash (0x03 || V).
+ // 5. V = (V + H + C + reseed_counter) mod 2^seedlen
+ // .
+ // 6. reseed_counter = reseed_counter + 1.
+ // 7. Return SUCCESS, returned_bits, and the new values of V, C, and
+ // reseed_counter for the new_working_state.
+ int numberOfBits = output.Length * 8;
+
+ if (numberOfBits > MAX_BITS_REQUEST)
+ throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
+
+ if (mReseedCounter > RESEED_MAX)
+ return -1;
+
+ if (predictionResistant)
+ {
+ Reseed(additionalInput);
+ additionalInput = null;
+ }
+
+ // 2.
+ if (additionalInput != null)
+ {
+ byte[] newInput = new byte[1 + mV.Length + additionalInput.Length];
+ newInput[0] = 0x02;
+ Array.Copy(mV, 0, newInput, 1, mV.Length);
+ // TODO: inOff / inLength
+ Array.Copy(additionalInput, 0, newInput, 1 + mV.Length, additionalInput.Length);
+ byte[] w = Hash(newInput);
+
+ AddTo(mV, w);
+ }
+
+ // 3.
+ byte[] rv = hashgen(mV, numberOfBits);
+
+ // 4.
+ byte[] subH = new byte[mV.Length + 1];
+ Array.Copy(mV, 0, subH, 1, mV.Length);
+ subH[0] = 0x03;
+
+ byte[] H = Hash(subH);
+
+ // 5.
+ AddTo(mV, H);
+ AddTo(mV, mC);
+ byte[] c = new byte[4];
+ c[0] = (byte)(mReseedCounter >> 24);
+ c[1] = (byte)(mReseedCounter >> 16);
+ c[2] = (byte)(mReseedCounter >> 8);
+ c[3] = (byte)mReseedCounter;
+
+ AddTo(mV, c);
+
+ mReseedCounter++;
+
+ Array.Copy(rv, 0, output, 0, output.Length);
+
+ return numberOfBits;
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+
+ // this will always add the shorter length byte array mathematically to the
+ // longer length byte array.
+ // be careful....
+ private void AddTo(byte[] longer, byte[] shorter)
+ {
+ int off = longer.Length - shorter.Length;
+
+ uint carry = 0;
+ int i = shorter.Length;
+ while (--i >= 0)
+ {
+ carry += (uint)longer[off + i] + (uint)shorter[i];
+ longer[off + i] = (byte)carry;
+ carry >>= 8;
+ }
+
+ i = off;
+ while (--i >= 0)
+ {
+ carry += longer[i];
+ longer[i] = (byte)carry;
+ carry >>= 8;
+ }
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ // 1. seed_material = 0x01 || V || entropy_input || additional_input.
+ //
+ // 2. seed = Hash_df (seed_material, seedlen).
+ //
+ // 3. V = seed.
+ //
+ // 4. C = Hash_df ((0x00 || V), seedlen).
+ //
+ // 5. reseed_counter = 1.
+ //
+ // 6. Return V, C, and reseed_counter for the new_working_state.
+ //
+ // Comment: Precede with a byte of all zeros.
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(ONE, mV, entropy, additionalInput);
+ byte[] seed = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
+
+ mV = seed;
+ byte[] subV = new byte[mV.Length + 1];
+ subV[0] = 0x00;
+ Array.Copy(mV, 0, subV, 1, mV.Length);
+ mC = DrbgUtilities.HashDF(mDigest, subV, mSeedLength);
+
+ mReseedCounter = 1;
+ }
+
+ private byte[] Hash(byte[] input)
+ {
+ byte[] hash = new byte[mDigest.GetDigestSize()];
+ DoHash(input, hash);
+ return hash;
+ }
+
+ private void DoHash(byte[] input, byte[] output)
+ {
+ mDigest.BlockUpdate(input, 0, input.Length);
+ mDigest.DoFinal(output, 0);
+ }
+
+ // 1. m = [requested_number_of_bits / outlen]
+ // 2. data = V.
+ // 3. W = the Null string.
+ // 4. For i = 1 to m
+ // 4.1 wi = Hash (data).
+ // 4.2 W = W || wi.
+ // 4.3 data = (data + 1) mod 2^seedlen
+ // .
+ // 5. returned_bits = Leftmost (requested_no_of_bits) bits of W.
+ private byte[] hashgen(byte[] input, int lengthInBits)
+ {
+ int digestSize = mDigest.GetDigestSize();
+ int m = (lengthInBits / 8) / digestSize;
+
+ byte[] data = new byte[input.Length];
+ Array.Copy(input, 0, data, 0, input.Length);
+
+ byte[] W = new byte[lengthInBits / 8];
+
+ byte[] dig = new byte[mDigest.GetDigestSize()];
+ for (int i = 0; i <= m; i++)
+ {
+ DoHash(data, dig);
+
+ int bytesToCopy = ((W.Length - i * dig.Length) > dig.Length)
+ ? dig.Length
+ : (W.Length - i * dig.Length);
+ Array.Copy(dig, 0, W, i * dig.Length, bytesToCopy);
+
+ AddTo(data, ONE);
+ }
+
+ return W;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs b/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
new file mode 100644
index 000000000..0e398209e
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * Interface to SP800-90A deterministic random bit generators.
+ */
+ public interface ISP80090Drbg
+ {
+ /**
+ * Return the block size of the DRBG.
+ *
+ * @return the block size (in bits) produced by each round of the DRBG.
+ */
+ int BlockSize { get; }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ int Generate(byte[] output, byte[] additionalInput, bool predictionResistant);
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ void Reseed(byte[] additionalInput);
+ }
+}
diff --git a/crypto/src/crypto/signers/ECDsaSigner.cs b/crypto/src/crypto/signers/ECDsaSigner.cs
index 9821732c2..520507b8c 100644
--- a/crypto/src/crypto/signers/ECDsaSigner.cs
+++ b/crypto/src/crypto/signers/ECDsaSigner.cs
@@ -15,6 +15,8 @@ namespace Org.BouncyCastle.Crypto.Signers
public class ECDsaSigner
: IDsa
{
+ private static readonly BigInteger Eight = BigInteger.ValueOf(8);
+
protected readonly IDsaKCalculator kCalculator;
protected ECKeyParameters key = null;
@@ -149,13 +151,49 @@ namespace Org.BouncyCastle.Crypto.Signers
ECPoint G = key.Parameters.G;
ECPoint Q = ((ECPublicKeyParameters) key).Q;
- ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2).Normalize();
+ ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2);
if (point.IsInfinity)
return false;
- BigInteger v = point.AffineXCoord.ToBigInteger().Mod(n);
+ /*
+ * If possible, avoid normalizing the point (to save a modular inversion in the curve field).
+ *
+ * There are ~cofactor elements of the curve field that reduce (modulo the group order) to 'r'.
+ * If the cofactor is known and small, we generate those possible field values and project each
+ * of them to the same "denominator" (depending on the particular projective coordinates in use)
+ * as the calculated point.X. If any of the projected values matches point.X, then we have:
+ * (point.X / Denominator mod p) mod n == r
+ * as required, and verification succeeds.
+ *
+ * Based on an original idea by Gregory Maxwell (https://github.com/gmaxwell), as implemented in
+ * the libsecp256k1 project (https://github.com/bitcoin/secp256k1).
+ */
+ ECCurve curve = point.Curve;
+ if (curve != null)
+ {
+ BigInteger cofactor = curve.Cofactor;
+ if (cofactor != null && cofactor.CompareTo(Eight) <= 0)
+ {
+ ECFieldElement D = GetDenominator(curve.CoordinateSystem, point);
+ if (D != null && !D.IsZero)
+ {
+ ECFieldElement X = point.XCoord;
+ while (curve.IsValidFieldElement(r))
+ {
+ ECFieldElement R = curve.FromBigInteger(r).Multiply(D);
+ if (R.Equals(X))
+ {
+ return true;
+ }
+ r = r.Add(n);
+ }
+ return false;
+ }
+ }
+ }
+ BigInteger v = point.Normalize().AffineXCoord.ToBigInteger().Mod(n);
return v.Equals(r);
}
@@ -177,6 +215,23 @@ namespace Org.BouncyCastle.Crypto.Signers
return new FixedPointCombMultiplier();
}
+ protected virtual ECFieldElement GetDenominator(int coordinateSystem, ECPoint p)
+ {
+ switch (coordinateSystem)
+ {
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ case ECCurve.COORD_SKEWED:
+ return p.GetZCoord(0);
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ return p.GetZCoord(0).Square();
+ default:
+ return null;
+ }
+ }
+
protected virtual SecureRandom InitSecureRandom(bool needed, SecureRandom provided)
{
return !needed ? null : (provided != null) ? provided : new SecureRandom();
diff --git a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
index 5147a1990..fab978886 100644
--- a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Crypto.Tls
}
else
{
- throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
+ throw new ArgumentException("type not supported: " + Platform.GetTypeName(privateKey), "privateKey");
}
this.mCertificate = certificate;
diff --git a/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs b/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
index 34d15d146..5348ee88d 100644
--- a/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
@@ -2,6 +2,7 @@
using System.IO;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
@@ -29,7 +30,7 @@ namespace Org.BouncyCastle.Crypto.Tls
}
else
{
- throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
+ throw new ArgumentException("type not supported: " + Platform.GetTypeName(privateKey), "privateKey");
}
this.mContext = context;
diff --git a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
index c7a136573..0ff732a97 100644
--- a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
@@ -2,6 +2,7 @@ using System;
using System.IO;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
@@ -48,7 +49,7 @@ namespace Org.BouncyCastle.Crypto.Tls
}
else
{
- throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
+ throw new ArgumentException("type not supported: " + Platform.GetTypeName(privateKey), "privateKey");
}
this.mSigner.Init(context);
diff --git a/crypto/src/crypto/tls/ServerName.cs b/crypto/src/crypto/tls/ServerName.cs
index 3d1e8f844..508c2ddbc 100644
--- a/crypto/src/crypto/tls/ServerName.cs
+++ b/crypto/src/crypto/tls/ServerName.cs
@@ -51,10 +51,10 @@ namespace Org.BouncyCastle.Crypto.Tls
switch (mNameType)
{
case Tls.NameType.host_name:
- byte[] utf8Encoding = Strings.ToUtf8ByteArray((string)mName);
- if (utf8Encoding.Length < 1)
+ byte[] asciiEncoding = Strings.ToAsciiByteArray((string)mName);
+ if (asciiEncoding.Length < 1)
throw new TlsFatalAlert(AlertDescription.internal_error);
- TlsUtilities.WriteOpaque16(utf8Encoding, output);
+ TlsUtilities.WriteOpaque16(asciiEncoding, output);
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
@@ -78,10 +78,10 @@ namespace Org.BouncyCastle.Crypto.Tls
{
case Tls.NameType.host_name:
{
- byte[] utf8Encoding = TlsUtilities.ReadOpaque16(input);
- if (utf8Encoding.Length < 1)
+ byte[] asciiEncoding = TlsUtilities.ReadOpaque16(input);
+ if (asciiEncoding.Length < 1)
throw new TlsFatalAlert(AlertDescription.decode_error);
- name = Strings.FromUtf8ByteArray(utf8Encoding);
+ name = Strings.FromAsciiByteArray(asciiEncoding);
break;
}
default:
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index a8c8a2b28..26fb0d5e8 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -529,11 +529,12 @@ namespace Org.BouncyCastle.Crypto.Tls
public static Asn1Object ReadAsn1Object(byte[] encoding)
{
- Asn1InputStream asn1 = new Asn1InputStream(encoding);
+ MemoryStream input = new MemoryStream(encoding, false);
+ Asn1InputStream asn1 = new Asn1InputStream(input, encoding.Length);
Asn1Object result = asn1.ReadObject();
if (null == result)
throw new TlsFatalAlert(AlertDescription.decode_error);
- if (null != asn1.ReadObject())
+ if (input.Position != input.Length)
throw new TlsFatalAlert(AlertDescription.decode_error);
return result;
}
|