summary refs log tree commit diff
path: root/crypto/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/crypto')
-rw-r--r--crypto/src/crypto/CipherKeyGenerator.cs4
-rw-r--r--crypto/src/crypto/IEntropySource.cs29
-rw-r--r--crypto/src/crypto/IEntropySourceProvider.cs17
-rw-r--r--crypto/src/crypto/digests/NonMemoableDigest.cs62
-rw-r--r--crypto/src/crypto/digests/SkeinEngine.cs2
-rw-r--r--crypto/src/crypto/ec/CustomNamedCurves.cs10
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs2
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs4
-rw-r--r--crypto/src/crypto/engines/AesFastEngine.cs4
-rw-r--r--crypto/src/crypto/engines/AesLightEngine.cs4
-rw-r--r--crypto/src/crypto/engines/BlowfishEngine.cs3
-rw-r--r--crypto/src/crypto/engines/Cast5Engine.cs3
-rw-r--r--crypto/src/crypto/engines/DesEdeEngine.cs3
-rw-r--r--crypto/src/crypto/engines/DesEngine.cs3
-rw-r--r--crypto/src/crypto/engines/GOST28147Engine.cs3
-rw-r--r--crypto/src/crypto/engines/HC128Engine.cs3
-rw-r--r--crypto/src/crypto/engines/HC256Engine.cs3
-rw-r--r--crypto/src/crypto/engines/ISAACEngine.cs3
-rw-r--r--crypto/src/crypto/engines/IdeaEngine.cs3
-rw-r--r--crypto/src/crypto/engines/IesEngine.cs4
-rw-r--r--crypto/src/crypto/engines/NoekeonEngine.cs4
-rw-r--r--crypto/src/crypto/engines/RC2Engine.cs3
-rw-r--r--crypto/src/crypto/engines/RC4Engine.cs3
-rw-r--r--crypto/src/crypto/engines/RC532Engine.cs3
-rw-r--r--crypto/src/crypto/engines/RC564Engine.cs3
-rw-r--r--crypto/src/crypto/engines/RC6Engine.cs3
-rw-r--r--crypto/src/crypto/engines/RSACoreEngine.cs2
-rw-r--r--crypto/src/crypto/engines/RijndaelEngine.cs3
-rw-r--r--crypto/src/crypto/engines/SerpentEngine.cs565
-rw-r--r--crypto/src/crypto/engines/SerpentEngineBase.cs468
-rw-r--r--crypto/src/crypto/engines/SkipjackEngine.cs3
-rw-r--r--crypto/src/crypto/engines/TEAEngine.cs3
-rw-r--r--crypto/src/crypto/engines/ThreefishEngine.cs3
-rw-r--r--crypto/src/crypto/engines/TnepresEngine.cs299
-rw-r--r--crypto/src/crypto/engines/TwofishEngine.cs3
-rw-r--r--crypto/src/crypto/engines/XTEAEngine.cs3
-rw-r--r--crypto/src/crypto/generators/DesEdeKeyGenerator.cs8
-rw-r--r--crypto/src/crypto/generators/DesKeyGenerator.cs8
-rw-r--r--crypto/src/crypto/macs/GOST28147Mac.cs3
-rw-r--r--crypto/src/crypto/macs/SkeinMac.cs3
-rw-r--r--crypto/src/crypto/modes/SicBlockCipher.cs8
-rw-r--r--crypto/src/crypto/operators/Asn1Signature.cs8
-rw-r--r--crypto/src/crypto/parameters/DesEdeParameters.cs45
-rw-r--r--crypto/src/crypto/parameters/DesParameters.cs35
-rw-r--r--crypto/src/crypto/prng/BasicEntropySourceProvider.cs71
-rw-r--r--crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs70
-rw-r--r--crypto/src/crypto/prng/DigestRandomGenerator.cs12
-rw-r--r--crypto/src/crypto/prng/EntropyUtilities.cs30
-rw-r--r--crypto/src/crypto/prng/IDrbgProvider.cs11
-rw-r--r--crypto/src/crypto/prng/SP800SecureRandom.cs80
-rw-r--r--crypto/src/crypto/prng/SP800SecureRandomBuilder.cs208
-rw-r--r--crypto/src/crypto/prng/X931Rng.cs146
-rw-r--r--crypto/src/crypto/prng/X931SecureRandom.cs70
-rw-r--r--crypto/src/crypto/prng/X931SecureRandomBuilder.cs87
-rw-r--r--crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs466
-rw-r--r--crypto/src/crypto/prng/drbg/DrbgUtilities.cs103
-rw-r--r--crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs186
-rw-r--r--crypto/src/crypto/prng/drbg/HashSP800Drbg.cs287
-rw-r--r--crypto/src/crypto/prng/drbg/ISP80090Drbg.cs35
-rw-r--r--crypto/src/crypto/signers/ECDsaSigner.cs59
-rw-r--r--crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs2
-rw-r--r--crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs3
-rw-r--r--crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs3
-rw-r--r--crypto/src/crypto/tls/ServerName.cs12
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs5
65 files changed, 2995 insertions, 609 deletions
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; }