From eb261258c070decc949f07829ab7c942818167ed Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 16 Sep 2017 09:25:49 +0700 Subject: Use Arrays.CopyOfRange --- crypto/src/crypto/parameters/ParametersWithIV.cs | 41 +++++++++++------------- 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/parameters/ParametersWithIV.cs b/crypto/src/crypto/parameters/ParametersWithIV.cs index 11a8b77a0..4b2eb930f 100644 --- a/crypto/src/crypto/parameters/ParametersWithIV.cs +++ b/crypto/src/crypto/parameters/ParametersWithIV.cs @@ -1,41 +1,38 @@ using System; +using Org.BouncyCastle.Utilities; + namespace Org.BouncyCastle.Crypto.Parameters { public class ParametersWithIV - : ICipherParameters + : ICipherParameters { - private readonly ICipherParameters parameters; - private readonly byte[] iv; + private readonly ICipherParameters parameters; + private readonly byte[] iv; - public ParametersWithIV( - ICipherParameters parameters, - byte[] iv) - : this(parameters, iv, 0, iv.Length) - { - } + public ParametersWithIV(ICipherParameters parameters, + byte[] iv) + : this(parameters, iv, 0, iv.Length) + { + } - public ParametersWithIV( - ICipherParameters parameters, - byte[] iv, - int ivOff, - int ivLen) + public ParametersWithIV(ICipherParameters parameters, + byte[] iv, int ivOff, int ivLen) { // NOTE: 'parameters' may be null to imply key re-use - if (iv == null) - throw new ArgumentNullException("iv"); + if (iv == null) + throw new ArgumentNullException("iv"); - this.parameters = parameters; - this.iv = new byte[ivLen]; - Array.Copy(iv, ivOff, this.iv, 0, ivLen); + this.parameters = parameters; + this.iv = Arrays.CopyOfRange(iv, ivOff, ivOff + ivLen); } - public byte[] GetIV() + public byte[] GetIV() { - return (byte[]) iv.Clone(); + return (byte[])iv.Clone(); } - public ICipherParameters Parameters + public ICipherParameters Parameters { get { return parameters; } } -- cgit 1.5.1 From c2aa15d6ed73998d59901082f4f754934ee8aa5e Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 16 Sep 2017 09:42:27 +0700 Subject: Use RandomNumberGenerator.Create --- crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs | 2 +- crypto/src/crypto/prng/CryptoApiRandomGenerator.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs index 68579aaf4..459d3a740 100644 --- a/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs +++ b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs @@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Prng private readonly bool mPredictionResistant; public CryptoApiEntropySourceProvider() - : this(new RNGCryptoServiceProvider(), true) + : this(RandomNumberGenerator.Create(), true) { } diff --git a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs index fa5f523d3..0b6592025 100644 --- a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs +++ b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs @@ -6,7 +6,7 @@ using System.Security.Cryptography; namespace Org.BouncyCastle.Crypto.Prng { /// - /// Uses Microsoft's RNGCryptoServiceProvider + /// Uses RandomNumberGenerator.Create() to get randomness generator /// public class CryptoApiRandomGenerator : IRandomGenerator @@ -14,7 +14,7 @@ namespace Org.BouncyCastle.Crypto.Prng private readonly RandomNumberGenerator rndProv; public CryptoApiRandomGenerator() - : this(new RNGCryptoServiceProvider()) + : this(RandomNumberGenerator.Create()) { } -- cgit 1.5.1 From 67403751cdd80fd9b2b17489909c6178bbef1cc4 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 16 Sep 2017 11:39:55 +0700 Subject: Port of SM2Signer from Java --- crypto/BouncyCastle.Android.csproj | 2 + crypto/BouncyCastle.csproj | 2 + crypto/BouncyCastle.iOS.csproj | 2 + crypto/crypto.csproj | 20 ++ crypto/src/crypto/parameters/ParametersWithID.cs | 36 +++ crypto/src/crypto/signers/SM2Signer.cs | 258 ++++++++++++++++++++++ crypto/test/UnitTests.csproj | 2 + crypto/test/src/crypto/test/RegressionTest.cs | 1 + crypto/test/src/crypto/test/SM2SignerTest.cs | 194 ++++++++++++++++ crypto/test/src/util/test/FixedSecureRandom.cs | 236 +++++++++++++++++++- crypto/test/src/util/test/SimpleTest.cs | 6 + crypto/test/src/util/test/TestRandomBigInteger.cs | 55 +++++ 12 files changed, 813 insertions(+), 1 deletion(-) create mode 100644 crypto/src/crypto/parameters/ParametersWithID.cs create mode 100644 crypto/src/crypto/signers/SM2Signer.cs create mode 100644 crypto/test/src/crypto/test/SM2SignerTest.cs create mode 100644 crypto/test/src/util/test/TestRandomBigInteger.cs (limited to 'crypto/src') diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index ef931731d..926e0fd94 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -916,6 +916,7 @@ + @@ -951,6 +952,7 @@ + diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index c30056db8..463ba2a1c 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -910,6 +910,7 @@ + @@ -945,6 +946,7 @@ + diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index 1b004957b..783009d38 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -911,6 +911,7 @@ + @@ -946,6 +947,7 @@ + diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index a80ac39ea..509638ff1 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -4368,6 +4368,11 @@ SubType = "Code" BuildAction = "Compile" /> + + + + The SM2 Digital Signature algorithm. + public class SM2Signer + : ISigner + { + private readonly IDsaKCalculator kCalculator = new RandomDsaKCalculator(); + private readonly SM3Digest digest = new SM3Digest(); + + private ECDomainParameters ecParams; + private ECPoint pubPoint; + private ECKeyParameters ecKey; + private byte[] z; + + public virtual string AlgorithmName + { + get { return "SM2"; } + } + + public virtual void Init(bool forSigning, ICipherParameters parameters) + { + ICipherParameters baseParam; + byte[] userID; + + if (parameters is ParametersWithID) + { + baseParam = ((ParametersWithID)parameters).Parameters; + userID = ((ParametersWithID)parameters).GetID(); + } + else + { + baseParam = parameters; + userID = Hex.Decode("31323334353637383132333435363738"); // the default value (ASCII "1234567812345678") + } + + if (forSigning) + { + if (baseParam is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)baseParam; + + ecKey = (ECKeyParameters)rParam.Parameters; + ecParams = ecKey.Parameters; + kCalculator.Init(ecParams.N, rParam.Random); + } + else + { + ecKey = (ECKeyParameters)baseParam; + ecParams = ecKey.Parameters; + kCalculator.Init(ecParams.N, new SecureRandom()); + } + pubPoint = CreateBasePointMultiplier().Multiply(ecParams.G, ((ECPrivateKeyParameters)ecKey).D).Normalize(); + } + else + { + ecKey = (ECKeyParameters)baseParam; + ecParams = ecKey.Parameters; + pubPoint = ((ECPublicKeyParameters)ecKey).Q; + } + + digest.Reset(); + z = GetZ(userID); + + digest.BlockUpdate(z, 0, z.Length); + } + + public virtual void Update(byte b) + { + digest.Update(b); + } + + public virtual void BlockUpdate(byte[] buf, int off, int len) + { + digest.BlockUpdate(buf, off, len); + } + + public virtual bool VerifySignature(byte[] signature) + { + try + { + BigInteger[] rs = DerDecode(signature); + if (rs != null) + { + return VerifySignature(rs[0], rs[1]); + } + } + catch (IOException e) + { + } + + return false; + } + + public virtual void Reset() + { + if (z != null) + { + digest.Reset(); + digest.BlockUpdate(z, 0, z.Length); + } + } + + public virtual byte[] GenerateSignature() + { + byte[] eHash = DigestUtilities.DoFinal(digest); + + BigInteger n = ecParams.N; + BigInteger e = CalculateE(eHash); + BigInteger d = ((ECPrivateKeyParameters)ecKey).D; + + BigInteger r, s; + + ECMultiplier basePointMultiplier = CreateBasePointMultiplier(); + + // 5.2.1 Draft RFC: SM2 Public Key Algorithms + do // generate s + { + BigInteger k; + do // generate r + { + // A3 + k = kCalculator.NextK(); + + // A4 + ECPoint p = basePointMultiplier.Multiply(ecParams.G, k).Normalize(); + + // A5 + r = e.Add(p.AffineXCoord.ToBigInteger()).Mod(n); + } + while (r.SignValue == 0 || r.Add(k).Equals(n)); + + // A6 + BigInteger dPlus1ModN = d.Add(BigInteger.One).ModInverse(n); + + s = k.Subtract(r.Multiply(d)).Mod(n); + s = dPlus1ModN.Multiply(s).Mod(n); + } + while (s.SignValue == 0); + + // A7 + try + { + return DerEncode(r, s); + } + catch (IOException ex) + { + throw new CryptoException("unable to encode signature: " + ex.Message, ex); + } + } + + private bool VerifySignature(BigInteger r, BigInteger s) + { + BigInteger n = ecParams.N; + + // 5.3.1 Draft RFC: SM2 Public Key Algorithms + // B1 + if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0) + return false; + + // B2 + if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0) + return false; + + // B3 + byte[] eHash = DigestUtilities.DoFinal(digest); + + // B4 + BigInteger e = CalculateE(eHash); + + // B5 + BigInteger t = r.Add(s).Mod(n); + if (t.SignValue == 0) + return false; + + // B6 + ECPoint q = ((ECPublicKeyParameters)ecKey).Q; + ECPoint x1y1 = ECAlgorithms.SumOfTwoMultiplies(ecParams.G, s, q, t).Normalize(); + if (x1y1.IsInfinity) + return false; + + // B7 + return r.Equals(e.Add(x1y1.AffineXCoord.ToBigInteger()).Mod(n)); + } + + private byte[] GetZ(byte[] userID) + { + AddUserID(digest, userID); + + AddFieldElement(digest, ecParams.Curve.A); + AddFieldElement(digest, ecParams.Curve.B); + AddFieldElement(digest, ecParams.G.AffineXCoord); + AddFieldElement(digest, ecParams.G.AffineYCoord); + AddFieldElement(digest, pubPoint.AffineXCoord); + AddFieldElement(digest, pubPoint.AffineYCoord); + + return DigestUtilities.DoFinal(digest); + } + + private void AddUserID(IDigest digest, byte[] userID) + { + int len = userID.Length * 8; + digest.Update((byte)(len >> 8)); + digest.Update((byte)len); + digest.BlockUpdate(userID, 0, userID.Length); + } + + private void AddFieldElement(IDigest digest, ECFieldElement v) + { + byte[] p = v.GetEncoded(); + digest.BlockUpdate(p, 0, p.Length); + } + + protected virtual BigInteger CalculateE(byte[] message) + { + return new BigInteger(1, message); + } + + protected virtual ECMultiplier CreateBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } + + protected virtual BigInteger[] DerDecode(byte[] encoding) + { + Asn1Sequence seq = Asn1Sequence.GetInstance(Asn1Object.FromByteArray(encoding)); + if (seq.Count != 2) + return null; + + BigInteger r = DerInteger.GetInstance(seq[0]).Value; + BigInteger s = DerInteger.GetInstance(seq[1]).Value; + + byte[] expectedEncoding = DerEncode(r, s); + if (!Arrays.ConstantTimeAreEqual(expectedEncoding, encoding)) + return null; + + return new BigInteger[]{ r, s }; + } + + protected virtual byte[] DerEncode(BigInteger r, BigInteger s) + { + return new DerSequence(new DerInteger(r), new DerInteger(s)).GetEncoded(Asn1Encodable.Der); + } + } +} diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj index e33b47464..f875c22b1 100644 --- a/crypto/test/UnitTests.csproj +++ b/crypto/test/UnitTests.csproj @@ -256,6 +256,7 @@ + @@ -440,6 +441,7 @@ + diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs index ba6c341d4..f2a92fab3 100644 --- a/crypto/test/src/crypto/test/RegressionTest.cs +++ b/crypto/test/src/crypto/test/RegressionTest.cs @@ -128,6 +128,7 @@ namespace Org.BouncyCastle.Crypto.Tests new X931SignerTest(), new KeccakDigestTest(), new ShakeDigestTest(), + new SM2SignerTest(), }; public static void Main(string[] args) diff --git a/crypto/test/src/crypto/test/SM2SignerTest.cs b/crypto/test/src/crypto/test/SM2SignerTest.cs new file mode 100644 index 000000000..a79793016 --- /dev/null +++ b/crypto/test/src/crypto/test/SM2SignerTest.cs @@ -0,0 +1,194 @@ +using System; +using System.IO; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class SM2SignerTest + : SimpleTest + { + public override string Name + { + get { return "SM2Signer"; } + } + + private void DoSignerTestFp() + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263", 16)); + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + keyPairGenerator.Init(keyGenerationParams); + AsymmetricCipherKeyPair kp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters ecPub = (ECPublicKeyParameters)kp.Public; + ECPrivateKeyParameters ecPriv = (ECPrivateKeyParameters)kp.Private; + + SM2Signer signer = new SM2Signer(); + + signer.Init(true, + new ParametersWithID(new ParametersWithRandom(ecPriv, + new TestRandomBigInteger("6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F", 16)), + Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[] msg = Strings.ToByteArray("message digest"); + + signer.BlockUpdate(msg, 0, msg.Length); + + byte[] sig = signer.GenerateSignature(); + + BigInteger[] rs = Decode(sig); + + IsTrue("r wrong", rs[0].Equals(new BigInteger("40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1", 16))); + IsTrue("s wrong", rs[1].Equals(new BigInteger("6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7", 16))); + + signer.Init(false, new ParametersWithID(ecPub, Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + signer.BlockUpdate(msg, 0, msg.Length); + + IsTrue("verification failed", signer.VerifySignature(sig)); + } + + private void DoSignerTestF2m() + { + BigInteger SM2_ECC_A = new BigInteger("00", 16); + BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); + BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); + BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); + + ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("771EF3DBFF5F1CDC32B9C572930476191998B2BF7CB981D7F5B39202645F0931", 16)); + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + keyPairGenerator.Init(keyGenerationParams); + AsymmetricCipherKeyPair kp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters ecPub = (ECPublicKeyParameters)kp.Public; + ECPrivateKeyParameters ecPriv = (ECPrivateKeyParameters)kp.Private; + + SM2Signer signer = new SM2Signer(); + + signer.Init(true, + new ParametersWithID(new ParametersWithRandom(ecPriv, + new TestRandomBigInteger("36CD79FC8E24B7357A8A7B4A46D454C397703D6498158C605399B341ADA186D6", 16)), + Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[] msg = Strings.ToByteArray("message digest"); + + signer.BlockUpdate(msg, 0, msg.Length); + + byte[] sig = signer.GenerateSignature(); + + BigInteger[] rs = Decode(sig); + + IsTrue("F2m r wrong", rs[0].Equals(new BigInteger("6D3FBA26EAB2A1054F5D198332E335817C8AC453ED26D3391CD4439D825BF25B", 16))); + IsTrue("F2m s wrong", rs[1].Equals(new BigInteger("3124C5688D95F0A10252A9BED033BEC84439DA384621B6D6FAD77F94B74A9556", 16))); + + signer.Init(false, new ParametersWithID(ecPub, Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + signer.BlockUpdate(msg, 0, msg.Length); + + IsTrue("verification failed", signer.VerifySignature(sig)); + } + + private void DoVerifyBoundsCheck() + { + BigInteger SM2_ECC_A = new BigInteger("00", 16); + BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); + BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); + BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); + + ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("771EF3DBFF5F1CDC32B9C572930476191998B2BF7CB981D7F5B39202645F0931", 16)); + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + keyPairGenerator.Init(keyGenerationParams); + AsymmetricCipherKeyPair kp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters ecPub = (ECPublicKeyParameters)kp.Public; + + SM2Signer signer = new SM2Signer(); + + signer.Init(false, ecPub); + + signer.BlockUpdate(new byte[20], 0, 20); + IsTrue(!signer.VerifySignature(Encode(BigInteger.Zero, BigInteger.ValueOf(8)))); + + signer.BlockUpdate(new byte[20], 0, 20); + IsTrue(!signer.VerifySignature(Encode(BigInteger.ValueOf(8), BigInteger.Zero))); + + signer.BlockUpdate(new byte[20], 0, 20); + IsTrue(!signer.VerifySignature(Encode(SM2_ECC_N, BigInteger.ValueOf(8)))); + + signer.BlockUpdate(new byte[20], 0, 20); + IsTrue(!signer.VerifySignature(Encode(BigInteger.ValueOf(8), SM2_ECC_N))); + } + + public override void PerformTest() + { + DoSignerTestFp(); + DoSignerTestF2m(); + DoVerifyBoundsCheck(); + } + + private static BigInteger[] Decode(byte[] sig) + { + Asn1Sequence s = Asn1Sequence.GetInstance(sig); + + return new BigInteger[] { DerInteger.GetInstance(s[0]).Value, + DerInteger.GetInstance(s[1]).Value }; + } + + private static byte[] Encode(BigInteger r, BigInteger s) + { + return new DerSequence(new DerInteger(r), new DerInteger(s)).GetEncoded(); + } + + public static void Main( + string[] args) + { + RunTest(new SM2SignerTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} diff --git a/crypto/test/src/util/test/FixedSecureRandom.cs b/crypto/test/src/util/test/FixedSecureRandom.cs index d8598ac24..1368aa231 100644 --- a/crypto/test/src/util/test/FixedSecureRandom.cs +++ b/crypto/test/src/util/test/FixedSecureRandom.cs @@ -2,16 +2,90 @@ using System; using System.IO; using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Encoders; + +using M = Org.BouncyCastle.Math; namespace Org.BouncyCastle.Utilities.Test { public class FixedSecureRandom : SecureRandom { + private static readonly M.BigInteger REGULAR = new M.BigInteger("01020304ffffffff0506070811111111", 16); + private static readonly M.BigInteger ANDROID = new M.BigInteger("1111111105060708ffffffff01020304", 16); + private static readonly M.BigInteger CLASSPATH = new M.BigInteger("3020104ffffffff05060708111111", 16); + + private static readonly bool isAndroidStyle; + private static readonly bool isClasspathStyle; + private static readonly bool isRegularStyle; + + static FixedSecureRandom() + { + M.BigInteger check1 = new M.BigInteger(128, new RandomChecker()); + M.BigInteger check2 = new M.BigInteger(120, new RandomChecker()); + + isAndroidStyle = check1.Equals(ANDROID); + isRegularStyle = check1.Equals(REGULAR); + isClasspathStyle = check2.Equals(CLASSPATH); + } + private byte[] _data; private int _index; - protected FixedSecureRandom( + /** + * Base class for sources of fixed "Randomness" + */ + public class Source + { + internal byte[] data; + + internal Source(byte[] data) + { + this.data = data; + } + } + + /** + * Data Source - in this case we just expect requests for byte arrays. + */ + public class Data + : Source + { + public Data(byte[] data) + : base(data) + { + } + } + + /** + * BigInteger Source - in this case we expect requests for data that will be used + * for BigIntegers. The FixedSecureRandom will attempt to compensate for platform differences here. + */ + public class BigInteger + : Source + { + public BigInteger(byte[] data) + : base(data) + { + } + + public BigInteger(int bitLength, byte[] data) + : base(ExpandToBitLength(bitLength, data)) + { + } + + public BigInteger(string hexData) + : this(Hex.Decode(hexData)) + { + } + + public BigInteger(int bitLength, string hexData) + : base(ExpandToBitLength(bitLength, Hex.Decode(hexData))) + { + } + } + + protected FixedSecureRandom( byte[] data) { _data = data; @@ -38,6 +112,103 @@ namespace Org.BouncyCastle.Utilities.Test return new FixedSecureRandom(bOut.ToArray()); } + public FixedSecureRandom( + Source[] sources) + { + MemoryStream bOut = new MemoryStream(); + + if (isRegularStyle) + { + if (isClasspathStyle) + { + for (int i = 0; i != sources.Length; i++) + { + try + { + if (sources[i] is BigInteger) + { + byte[] data = sources[i].data; + int len = data.Length - (data.Length % 4); + for (int w = data.Length - len - 1; w >= 0; w--) + { + bOut.WriteByte(data[w]); + } + for (int w = data.Length - len; w < data.Length; w += 4) + { + bOut.Write(data, w, 4); + } + } + else + { + bOut.Write(sources[i].data, 0, sources[i].data.Length); + } + } + catch (IOException e) + { + throw new ArgumentException("can't save value source."); + } + } + } + else + { + for (int i = 0; i != sources.Length; i++) + { + try + { + bOut.Write(sources[i].data, 0, sources[i].data.Length); + } + catch (IOException e) + { + throw new ArgumentException("can't save value source."); + } + } + } + } + else if (isAndroidStyle) + { + for (int i = 0; i != sources.Length; i++) + { + try + { + if (sources[i] is BigInteger) + { + byte[] data = sources[i].data; + int len = data.Length - (data.Length % 4); + for (int w = 0; w < len; w += 4) + { + bOut.Write(data, data.Length - (w + 4), 4); + } + if (data.Length - len != 0) + { + for (int w = 0; w != 4 - (data.Length - len); w++) + { + bOut.WriteByte(0); + } + } + for (int w = 0; w != data.Length - len; w++) + { + bOut.WriteByte(data[len + w]); + } + } + else + { + bOut.Write(sources[i].data, 0, sources[i].data.Length); + } + } + catch (IOException e) + { + throw new ArgumentException("can't save value source."); + } + } + } + else + { + throw new InvalidOperationException("Unrecognized BigInteger implementation"); + } + + _data = bOut.ToArray(); + } + public override byte[] GenerateSeed(int numBytes) { return SecureRandom.GetNextBytes(this, numBytes); @@ -65,5 +236,68 @@ namespace Org.BouncyCastle.Utilities.Test { get { return _index == _data.Length; } } + + private class RandomChecker + : SecureRandom + { + byte[] data = Hex.Decode("01020304ffffffff0506070811111111"); + int index = 0; + + public override void NextBytes(byte[] bytes) + { + Array.Copy(data, index, bytes, 0, bytes.Length); + + index += bytes.Length; + } + } + + private static byte[] ExpandToBitLength(int bitLength, byte[] v) + { + if ((bitLength + 7) / 8 > v.Length) + { + byte[] tmp = new byte[(bitLength + 7) / 8]; + + Array.Copy(v, 0, tmp, tmp.Length - v.Length, v.Length); + if (isAndroidStyle) + { + if (bitLength % 8 != 0) + { + uint i = BE_To_UInt32(tmp, 0); + UInt32_To_BE(i << (8 - (bitLength % 8)), tmp, 0); + } + } + + return tmp; + } + else + { + if (isAndroidStyle && bitLength < (v.Length * 8)) + { + if (bitLength % 8 != 0) + { + uint i = BE_To_UInt32(v, 0); + UInt32_To_BE(i << (8 - (bitLength % 8)), v, 0); + } + } + } + + return v; + } + + internal static uint BE_To_UInt32(byte[] bs, int off) + { + return (uint)bs[off] << 24 + | (uint)bs[off + 1] << 16 + | (uint)bs[off + 2] << 8 + | (uint)bs[off + 3]; + } + + internal static void UInt32_To_BE(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n >> 24); + bs[off + 1] = (byte)(n >> 16); + bs[off + 2] = (byte)(n >> 8); + bs[off + 3] = (byte)(n); + } } } diff --git a/crypto/test/src/util/test/SimpleTest.cs b/crypto/test/src/util/test/SimpleTest.cs index fea680832..154da27f4 100644 --- a/crypto/test/src/util/test/SimpleTest.cs +++ b/crypto/test/src/util/test/SimpleTest.cs @@ -27,6 +27,12 @@ namespace Org.BouncyCastle.Utilities.Test throw new TestFailedException(SimpleTestResult.Failed(this, message)); } + internal void IsTrue(bool value) + { + if (!value) + throw new TestFailedException(SimpleTestResult.Failed(this, "no message")); + } + internal void IsTrue(string message, bool value) { if (!value) diff --git a/crypto/test/src/util/test/TestRandomBigInteger.cs b/crypto/test/src/util/test/TestRandomBigInteger.cs new file mode 100644 index 000000000..ef38293b9 --- /dev/null +++ b/crypto/test/src/util/test/TestRandomBigInteger.cs @@ -0,0 +1,55 @@ +using System; + +using M = Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Utilities.Test +{ + /** + * A fixed secure random designed to return data for someone needing to create a single BigInteger. + */ + public class TestRandomBigInteger + : FixedSecureRandom + { + /** + * Constructor from a base 10 represention of a BigInteger. + * + * @param encoding a base 10 represention of a BigInteger. + */ + public TestRandomBigInteger(string encoding) + : this(encoding, 10) + { + } + + /** + * Constructor from a base radix represention of a BigInteger. + * + * @param encoding a String BigInteger of base radix. + * @param radix the radix to use. + */ + public TestRandomBigInteger(string encoding, int radix) + : base(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(BigIntegers.AsUnsignedByteArray(new M.BigInteger(encoding, radix))) }) + { + } + + /** + * Constructor based on a byte array. + * + * @param encoding a 2's complement representation of the BigInteger. + */ + public TestRandomBigInteger(byte[] encoding) + : base(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(encoding) }) + { + } + + /** + * Constructor which ensures encoding will produce a BigInteger from a request from the passed in bitLength. + * + * @param bitLength bit length for the BigInteger data request. + * @param encoding bytes making up the encoding. + */ + public TestRandomBigInteger(int bitLength, byte[] encoding) + : base(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(bitLength, encoding) }) + { + } + } +} -- cgit 1.5.1 From 65aabb84f67f3f726a6b7e08c73bdd58aa6b8425 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 16 Sep 2017 15:12:49 +0700 Subject: SM2 signing cleanup --- crypto/src/crypto/signers/SM2Signer.cs | 2 +- crypto/test/src/crypto/test/SM2SignerTest.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/signers/SM2Signer.cs b/crypto/src/crypto/signers/SM2Signer.cs index c5a5981d8..8151e6be0 100644 --- a/crypto/src/crypto/signers/SM2Signer.cs +++ b/crypto/src/crypto/signers/SM2Signer.cs @@ -28,7 +28,7 @@ namespace Org.BouncyCastle.Crypto.Signers public virtual string AlgorithmName { - get { return "SM2"; } + get { return "SM2Sign"; } } public virtual void Init(bool forSigning, ICipherParameters parameters) diff --git a/crypto/test/src/crypto/test/SM2SignerTest.cs b/crypto/test/src/crypto/test/SM2SignerTest.cs index a79793016..5904c95a7 100644 --- a/crypto/test/src/crypto/test/SM2SignerTest.cs +++ b/crypto/test/src/crypto/test/SM2SignerTest.cs @@ -4,7 +4,6 @@ using System.IO; using NUnit.Framework; using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Signers; -- cgit 1.5.1 From 574dbc0875687377c607a92765463986caa3da7a Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 16 Sep 2017 15:21:21 +0700 Subject: Port of SM2KeyExchange from Java --- crypto/BouncyCastle.Android.csproj | 3 + crypto/BouncyCastle.csproj | 3 + crypto/BouncyCastle.iOS.csproj | 3 + crypto/crypto.csproj | 20 ++ crypto/src/crypto/agreement/SM2KeyExchange.cs | 272 +++++++++++++++++++++ .../parameters/SM2KeyExchangePrivateParameters.cs | 64 +++++ .../parameters/SM2KeyExchangePublicParameters.cs | 40 +++ crypto/test/UnitTests.csproj | 1 + crypto/test/src/crypto/test/RegressionTest.cs | 1 + crypto/test/src/crypto/test/SM2KeyExchangeTest.cs | 229 +++++++++++++++++ 10 files changed, 636 insertions(+) create mode 100644 crypto/src/crypto/agreement/SM2KeyExchange.cs create mode 100644 crypto/src/crypto/parameters/SM2KeyExchangePrivateParameters.cs create mode 100644 crypto/src/crypto/parameters/SM2KeyExchangePublicParameters.cs create mode 100644 crypto/test/src/crypto/test/SM2KeyExchangeTest.cs (limited to 'crypto/src') diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index 926e0fd94..3a716e52e 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -696,6 +696,7 @@ + @@ -928,6 +929,8 @@ + + diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index 463ba2a1c..346092b76 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -690,6 +690,7 @@ + @@ -922,6 +923,8 @@ + + diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index 783009d38..53597e3dd 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -691,6 +691,7 @@ + @@ -923,6 +924,8 @@ + + diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 509638ff1..f9d38edd5 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -3233,6 +3233,11 @@ SubType = "Code" BuildAction = "Compile" /> + + + + + /// SM2 Key Exchange protocol - based on https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02 + /// + public class SM2KeyExchange + { + private readonly IDigest mDigest; + + private byte[] mUserID; + private ECPrivateKeyParameters mStaticKey; + private ECPoint mStaticPubPoint; + private ECPoint mEphemeralPubPoint; + private ECDomainParameters mECParams; + private int mW; + private ECPrivateKeyParameters mEphemeralKey; + private bool mInitiator; + + public SM2KeyExchange() + : this(new SM3Digest()) + { + } + + public SM2KeyExchange(IDigest digest) + { + this.mDigest = digest; + } + + public virtual void Init(ICipherParameters privParam) + { + SM2KeyExchangePrivateParameters baseParam; + + if (privParam is ParametersWithID) + { + baseParam = (SM2KeyExchangePrivateParameters)((ParametersWithID)privParam).Parameters; + mUserID = ((ParametersWithID)privParam).GetID(); + } + else + { + baseParam = (SM2KeyExchangePrivateParameters)privParam; + mUserID = new byte[0]; + } + + mInitiator = baseParam.IsInitiator; + mStaticKey = baseParam.StaticPrivateKey; + mEphemeralKey = baseParam.EphemeralPrivateKey; + mECParams = mStaticKey.Parameters; + mStaticPubPoint = baseParam.StaticPublicPoint; + mEphemeralPubPoint = baseParam.EphemeralPublicPoint; + mW = mECParams.Curve.FieldSize / 2 - 1; + } + + public virtual byte[] CalculateKey(int kLen, ICipherParameters pubParam) + { + SM2KeyExchangePublicParameters otherPub; + byte[] otherUserID; + + if (pubParam is ParametersWithID) + { + otherPub = (SM2KeyExchangePublicParameters)((ParametersWithID)pubParam).Parameters; + otherUserID = ((ParametersWithID)pubParam).GetID(); + } + else + { + otherPub = (SM2KeyExchangePublicParameters)pubParam; + otherUserID = new byte[0]; + } + + byte[] za = GetZ(mDigest, mUserID, mStaticPubPoint); + byte[] zb = GetZ(mDigest, otherUserID, otherPub.StaticPublicKey.Q); + + ECPoint U = CalculateU(otherPub); + + byte[] rv; + if (mInitiator) + { + rv = Kdf(U, za, zb, kLen); + } + else + { + rv = Kdf(U, zb, za, kLen); + } + + return rv; + } + + public virtual byte[][] CalculateKeyWithConfirmation(int kLen, byte[] confirmationTag, ICipherParameters pubParam) + { + SM2KeyExchangePublicParameters otherPub; + byte[] otherUserID; + + if (pubParam is ParametersWithID) + { + otherPub = (SM2KeyExchangePublicParameters)((ParametersWithID)pubParam).Parameters; + otherUserID = ((ParametersWithID)pubParam).GetID(); + } + else + { + otherPub = (SM2KeyExchangePublicParameters)pubParam; + otherUserID = new byte[0]; + } + + if (mInitiator && confirmationTag == null) + throw new ArgumentException("if initiating, confirmationTag must be set"); + + byte[] za = GetZ(mDigest, mUserID, mStaticPubPoint); + byte[] zb = GetZ(mDigest, otherUserID, otherPub.StaticPublicKey.Q); + + ECPoint U = CalculateU(otherPub); + + byte[] rv; + if (mInitiator) + { + rv = Kdf(U, za, zb, kLen); + + byte[] inner = CalculateInnerHash(mDigest, U, za, zb, mEphemeralPubPoint, otherPub.EphemeralPublicKey.Q); + + byte[] s1 = S1(mDigest, U, inner); + + if (!Arrays.ConstantTimeAreEqual(s1, confirmationTag)) + throw new InvalidOperationException("confirmation tag mismatch"); + + return new byte[][] { rv, S2(mDigest, U, inner)}; + } + else + { + rv = Kdf(U, zb, za, kLen); + + byte[] inner = CalculateInnerHash(mDigest, U, zb, za, otherPub.EphemeralPublicKey.Q, mEphemeralPubPoint); + + return new byte[][] { rv, S1(mDigest, U, inner), S2(mDigest, U, inner) }; + } + } + + protected virtual ECPoint CalculateU(SM2KeyExchangePublicParameters otherPub) + { + ECPoint p1 = otherPub.StaticPublicKey.Q; + ECPoint p2 = otherPub.EphemeralPublicKey.Q; + + BigInteger x1 = Reduce(mEphemeralPubPoint.AffineXCoord.ToBigInteger()); + BigInteger x2 = Reduce(p2.AffineXCoord.ToBigInteger()); + BigInteger tA = mStaticKey.D.Add(x1.Multiply(mEphemeralKey.D)); + BigInteger k1 = mECParams.H.Multiply(tA).Mod(mECParams.N); + BigInteger k2 = k1.Multiply(x2).Mod(mECParams.N); + + return ECAlgorithms.SumOfTwoMultiplies(p1, k1, p2, k2).Normalize(); + } + + protected virtual byte[] Kdf(ECPoint u, byte[] za, byte[] zb, int klen) + { + int digestSize = mDigest.GetDigestSize(); + byte[] buf = new byte[System.Math.Max(4, digestSize)]; + byte[] rv = new byte[(klen + 7) / 8]; + int off = 0; + + IMemoable memo = mDigest as IMemoable; + IMemoable copy = null; + + if (memo != null) + { + AddFieldElement(mDigest, u.AffineXCoord); + AddFieldElement(mDigest, u.AffineYCoord); + mDigest.BlockUpdate(za, 0, za.Length); + mDigest.BlockUpdate(zb, 0, zb.Length); + copy = memo.Copy(); + } + + uint ct = 0; + + while (off < rv.Length) + { + if (memo != null) + { + memo.Reset(copy); + } + else + { + AddFieldElement(mDigest, u.AffineXCoord); + AddFieldElement(mDigest, u.AffineYCoord); + mDigest.BlockUpdate(za, 0, za.Length); + mDigest.BlockUpdate(zb, 0, zb.Length); + } + + Pack.UInt32_To_BE(++ct, buf, 0); + mDigest.BlockUpdate(buf, 0, 4); + mDigest.DoFinal(buf, 0); + + int copyLen = System.Math.Min(digestSize, rv.Length - off); + Array.Copy(buf, 0, rv, off, copyLen); + off += copyLen; + } + + return rv; + } + + //x1~=2^w+(x1 AND (2^w-1)) + private BigInteger Reduce(BigInteger x) + { + return x.And(BigInteger.One.ShiftLeft(mW).Subtract(BigInteger.One)).SetBit(mW); + } + + private byte[] S1(IDigest digest, ECPoint u, byte[] inner) + { + digest.Update((byte)0x02); + AddFieldElement(digest, u.AffineYCoord); + digest.BlockUpdate(inner, 0, inner.Length); + + return DigestUtilities.DoFinal(digest); + } + + private byte[] CalculateInnerHash(IDigest digest, ECPoint u, byte[] za, byte[] zb, ECPoint p1, ECPoint p2) + { + AddFieldElement(digest, u.AffineXCoord); + digest.BlockUpdate(za, 0, za.Length); + digest.BlockUpdate(zb, 0, zb.Length); + AddFieldElement(digest, p1.AffineXCoord); + AddFieldElement(digest, p1.AffineYCoord); + AddFieldElement(digest, p2.AffineXCoord); + AddFieldElement(digest, p2.AffineYCoord); + + return DigestUtilities.DoFinal(digest); + } + + private byte[] S2(IDigest digest, ECPoint u, byte[] inner) + { + digest.Update((byte)0x03); + AddFieldElement(digest, u.AffineYCoord); + digest.BlockUpdate(inner, 0, inner.Length); + + return DigestUtilities.DoFinal(digest); + } + + private byte[] GetZ(IDigest digest, byte[] userID, ECPoint pubPoint) + { + AddUserID(digest, userID); + + AddFieldElement(digest, mECParams.Curve.A); + AddFieldElement(digest, mECParams.Curve.B); + AddFieldElement(digest, mECParams.G.AffineXCoord); + AddFieldElement(digest, mECParams.G.AffineYCoord); + AddFieldElement(digest, pubPoint.AffineXCoord); + AddFieldElement(digest, pubPoint.AffineYCoord); + + return DigestUtilities.DoFinal(digest); + } + + private void AddUserID(IDigest digest, byte[] userID) + { + uint len = (uint)(userID.Length * 8); + + digest.Update((byte)(len >> 8)); + digest.Update((byte)len); + digest.BlockUpdate(userID, 0, userID.Length); + } + + private void AddFieldElement(IDigest digest, ECFieldElement v) + { + byte[] p = v.GetEncoded(); + digest.BlockUpdate(p, 0, p.Length); + } + } +} diff --git a/crypto/src/crypto/parameters/SM2KeyExchangePrivateParameters.cs b/crypto/src/crypto/parameters/SM2KeyExchangePrivateParameters.cs new file mode 100644 index 000000000..8afb61544 --- /dev/null +++ b/crypto/src/crypto/parameters/SM2KeyExchangePrivateParameters.cs @@ -0,0 +1,64 @@ +using System; + +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /// Private parameters for an SM2 key exchange. + /// The ephemeralPrivateKey is used to calculate the random point used in the algorithm. + public class SM2KeyExchangePrivateParameters + : ICipherParameters + { + private readonly bool mInitiator; + private readonly ECPrivateKeyParameters mStaticPrivateKey; + private readonly ECPoint mStaticPublicPoint; + private readonly ECPrivateKeyParameters mEphemeralPrivateKey; + private readonly ECPoint mEphemeralPublicPoint; + + public SM2KeyExchangePrivateParameters( + bool initiator, + ECPrivateKeyParameters staticPrivateKey, + ECPrivateKeyParameters ephemeralPrivateKey) + { + if (staticPrivateKey == null) + throw new ArgumentNullException("staticPrivateKey"); + if (ephemeralPrivateKey == null) + throw new ArgumentNullException("ephemeralPrivateKey"); + + ECDomainParameters parameters = staticPrivateKey.Parameters; + if (!parameters.Equals(ephemeralPrivateKey.Parameters)) + throw new ArgumentException("Static and ephemeral private keys have different domain parameters"); + + this.mInitiator = initiator; + this.mStaticPrivateKey = staticPrivateKey; + this.mStaticPublicPoint = parameters.G.Multiply(staticPrivateKey.D).Normalize(); + this.mEphemeralPrivateKey = ephemeralPrivateKey; + this.mEphemeralPublicPoint = parameters.G.Multiply(ephemeralPrivateKey.D).Normalize(); + } + + public virtual bool IsInitiator + { + get { return mInitiator; } + } + + public virtual ECPrivateKeyParameters StaticPrivateKey + { + get { return mStaticPrivateKey; } + } + + public virtual ECPoint StaticPublicPoint + { + get { return mStaticPublicPoint; } + } + + public virtual ECPrivateKeyParameters EphemeralPrivateKey + { + get { return mEphemeralPrivateKey; } + } + + public virtual ECPoint EphemeralPublicPoint + { + get { return mEphemeralPublicPoint; } + } + } +} diff --git a/crypto/src/crypto/parameters/SM2KeyExchangePublicParameters.cs b/crypto/src/crypto/parameters/SM2KeyExchangePublicParameters.cs new file mode 100644 index 000000000..5c213159e --- /dev/null +++ b/crypto/src/crypto/parameters/SM2KeyExchangePublicParameters.cs @@ -0,0 +1,40 @@ +using System; + +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /// Public parameters for an SM2 key exchange. + /// In this case the ephemeralPublicKey provides the random point used in the algorithm. + public class SM2KeyExchangePublicParameters + : ICipherParameters + { + private readonly ECPublicKeyParameters mStaticPublicKey; + private readonly ECPublicKeyParameters mEphemeralPublicKey; + + public SM2KeyExchangePublicParameters( + ECPublicKeyParameters staticPublicKey, + ECPublicKeyParameters ephemeralPublicKey) + { + if (staticPublicKey == null) + throw new ArgumentNullException("staticPublicKey"); + if (ephemeralPublicKey == null) + throw new ArgumentNullException("ephemeralPublicKey"); + if (!staticPublicKey.Parameters.Equals(ephemeralPublicKey.Parameters)) + throw new ArgumentException("Static and ephemeral public keys have different domain parameters"); + + this.mStaticPublicKey = staticPublicKey; + this.mEphemeralPublicKey = ephemeralPublicKey; + } + + public virtual ECPublicKeyParameters StaticPublicKey + { + get { return mStaticPublicKey; } + } + + public virtual ECPublicKeyParameters EphemeralPublicKey + { + get { return mEphemeralPublicKey; } + } + } +} diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj index f875c22b1..bd7ad5787 100644 --- a/crypto/test/UnitTests.csproj +++ b/crypto/test/UnitTests.csproj @@ -256,6 +256,7 @@ + diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs index f2a92fab3..bc857b5d0 100644 --- a/crypto/test/src/crypto/test/RegressionTest.cs +++ b/crypto/test/src/crypto/test/RegressionTest.cs @@ -128,6 +128,7 @@ namespace Org.BouncyCastle.Crypto.Tests new X931SignerTest(), new KeccakDigestTest(), new ShakeDigestTest(), + new SM2KeyExchangeTest(), new SM2SignerTest(), }; diff --git a/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs b/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs new file mode 100644 index 000000000..d7a2650eb --- /dev/null +++ b/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs @@ -0,0 +1,229 @@ +using System; +using System.IO; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class SM2KeyExchangeTest + : SimpleTest + { + public override string Name + { + get { return "SM2KeyExchange"; } + } + + private void DoKeyExchangeTestFp() + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE", 16)); + + keyPairGenerator.Init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.Public; + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.Private; + + ECKeyGenerationParameters aeKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563", 16)); + + keyPairGenerator.Init(aeKeyGenParams); + + AsymmetricCipherKeyPair aeKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aePub = (ECPublicKeyParameters)aeKp.Public; + ECPrivateKeyParameters aePriv = (ECPrivateKeyParameters)aeKp.Private; + + ECKeyGenerationParameters bKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53", 16)); + + keyPairGenerator.Init(bKeyGenParams); + + AsymmetricCipherKeyPair bKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters bPub = (ECPublicKeyParameters)bKp.Public; + ECPrivateKeyParameters bPriv = (ECPrivateKeyParameters)bKp.Private; + + ECKeyGenerationParameters beKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80", 16)); + + keyPairGenerator.Init(beKeyGenParams); + + AsymmetricCipherKeyPair beKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters bePub = (ECPublicKeyParameters)beKp.Public; + ECPrivateKeyParameters bePriv = (ECPrivateKeyParameters)beKp.Private; + + SM2KeyExchange exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[] k1 = exch.CalculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + IsTrue("key 1 wrong", Arrays.AreEqual(Hex.Decode("55b0ac62a6b927ba23703832c853ded4"), k1)); + + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + byte[] k2 = exch.CalculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + IsTrue("key 2 wrong", Arrays.AreEqual(Hex.Decode("55b0ac62a6b927ba23703832c853ded4"), k2)); + + // with key confirmation + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + byte[][] vals2 = exch.CalculateKeyWithConfirmation(128, null, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + IsTrue("key 2 wrong", Arrays.AreEqual(Hex.Decode("55b0ac62a6b927ba23703832c853ded4"), k2)); + + IsTrue("conf a tag 2 wrong", Arrays.AreEqual(Hex.Decode("284C8F198F141B502E81250F1581C7E9EEB4CA6990F9E02DF388B45471F5BC5C"), vals2[1])); + IsTrue("conf b tag 2 wrong", Arrays.AreEqual(Hex.Decode("23444DAF8ED7534366CB901C84B3BDBB63504F4065C1116C91A4C00697E6CF7A"), vals2[2])); + + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[][] vals1 = exch.CalculateKeyWithConfirmation(128, vals2[1], new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + IsTrue("conf key 1 wrong", Arrays.AreEqual(Hex.Decode("55b0ac62a6b927ba23703832c853ded4"), vals1[0])); + IsTrue("conf tag 1 wrong", Arrays.AreEqual(Hex.Decode("23444DAF8ED7534366CB901C84B3BDBB63504F4065C1116C91A4C00697E6CF7A"), vals1[1])); + } + + private void DoKeyExchangeTestF2m() + { + BigInteger SM2_ECC_A = new BigInteger("00", 16); + BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); + BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); + BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); + BigInteger SM2_ECC_H = BigInteger.ValueOf(4); + + ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("4813903D254F2C20A94BC5704238496954BB5279F861952EF2C5298E84D2CEAA", 16)); + + keyPairGenerator.Init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.Public; + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.Private; + + ECKeyGenerationParameters aeKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("54A3D6673FF3A6BD6B02EBB164C2A3AF6D4A4906229D9BFCE68CC366A2E64BA4", 16)); + + keyPairGenerator.Init(aeKeyGenParams); + + AsymmetricCipherKeyPair aeKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aePub = (ECPublicKeyParameters)aeKp.Public; + ECPrivateKeyParameters aePriv = (ECPrivateKeyParameters)aeKp.Private; + + ECKeyGenerationParameters bKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("08F41BAE0922F47C212803FE681AD52B9BF28A35E1CD0EC273A2CF813E8FD1DC", 16)); + + keyPairGenerator.Init(bKeyGenParams); + + AsymmetricCipherKeyPair bKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters bPub = (ECPublicKeyParameters)bKp.Public; + ECPrivateKeyParameters bPriv = (ECPrivateKeyParameters)bKp.Private; + + ECKeyGenerationParameters beKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("1F21933387BEF781D0A8F7FD708C5AE0A56EE3F423DBC2FE5BDF6F068C53F7AD", 16)); + + keyPairGenerator.Init(beKeyGenParams); + + AsymmetricCipherKeyPair beKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters bePub = (ECPublicKeyParameters)beKp.Public; + ECPrivateKeyParameters bePriv = (ECPrivateKeyParameters)beKp.Private; + + SM2KeyExchange exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[] k1 = exch.CalculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + // there appears to be typo for ZA in the draft + //IsTrue("F2m key 1 wrong", Arrays.AreEqual(Hex.Decode("4E587E5C66634F22D973A7D98BF8BE23"), k1)); + IsTrue("F2m key 1 wrong", Arrays.AreEqual(Hex.Decode("8c2b03289aa7126555dc660cfc29fd74"), k1)); + + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + byte[] k2 = exch.CalculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + //IsTrue("F2m key 2 wrong", Arrays.AreEqual(Hex.Decode("4E587E5C66634F22D973A7D98BF8BE23"), k2)); + IsTrue("F2m key 2 wrong", Arrays.AreEqual(Hex.Decode("8c2b03289aa7126555dc660cfc29fd74"), k2)); + + // with key confirmation + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + byte[][] vals2 = exch.CalculateKeyWithConfirmation(128, null, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + IsTrue("key 2 wrong", Arrays.AreEqual(Hex.Decode("8c2b03289aa7126555dc660cfc29fd74"), k2)); + + IsTrue("conf a tag 2 wrong", Arrays.AreEqual(Hex.Decode("d8294c4c0f0ac180feac95e8a0d786638c9e915b9a684b2348809af03a0de2a5"), vals2[1])); + IsTrue("conf b tag 2 wrong", Arrays.AreEqual(Hex.Decode("52089e706911b58fd5e7c7b2ab5cf32bb61e481ef1e114a1e33d99eec84b5a4f"), vals2[2])); + + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[][] vals1 = exch.CalculateKeyWithConfirmation(128, vals2[1], new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + IsTrue("conf key 1 wrong", Arrays.AreEqual(Hex.Decode("8c2b03289aa7126555dc660cfc29fd74"), vals1[0])); + IsTrue("conf tag 1 wrong", Arrays.AreEqual(Hex.Decode("52089e706911b58fd5e7c7b2ab5cf32bb61e481ef1e114a1e33d99eec84b5a4f"), vals1[1])); + } + + public override void PerformTest() + { + DoKeyExchangeTestFp(); + DoKeyExchangeTestF2m(); + } + + public static void Main(string[] args) + { + RunTest(new SM2KeyExchangeTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} -- cgit 1.5.1 From 2b0b26630f78a64835e8f71b29c7f973a0fe05fd Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 16 Sep 2017 18:12:04 +0700 Subject: Port of SM2Engine from Java --- crypto/BouncyCastle.Android.csproj | 1 + crypto/BouncyCastle.csproj | 1 + crypto/BouncyCastle.iOS.csproj | 1 + crypto/crypto.csproj | 10 ++ crypto/src/crypto/engines/SM2Engine.cs | 238 ++++++++++++++++++++++++++ crypto/test/UnitTests.csproj | 1 + crypto/test/src/crypto/test/RegressionTest.cs | 1 + crypto/test/src/crypto/test/SM2EngineTest.cs | 167 ++++++++++++++++++ 8 files changed, 420 insertions(+) create mode 100644 crypto/src/crypto/engines/SM2Engine.cs create mode 100644 crypto/test/src/crypto/test/SM2EngineTest.cs (limited to 'crypto/src') diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index 3a716e52e..1c7463c3b 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -791,6 +791,7 @@ + diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index 346092b76..d5840b942 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -785,6 +785,7 @@ + diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index 53597e3dd..5e2ced2ad 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -786,6 +786,7 @@ + diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index f9d38edd5..f872911e1 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -3718,6 +3718,11 @@ SubType = "Code" BuildAction = "Compile" /> + + + /// SM2 public key encryption engine - based on https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02. + /// + public class SM2Engine + { + private readonly IDigest mDigest; + + private bool mForEncryption; + private ECKeyParameters mECKey; + private ECDomainParameters mECParams; + private int mCurveLength; + private SecureRandom mRandom; + + public SM2Engine() + : this(new SM3Digest()) + { + } + + public SM2Engine(IDigest digest) + { + this.mDigest = digest; + } + + public virtual void Init(bool forEncryption, ICipherParameters param) + { + this.mForEncryption = forEncryption; + + if (forEncryption) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + mECKey = (ECKeyParameters)rParam.Parameters; + mECParams = mECKey.Parameters; + + ECPoint s = ((ECPublicKeyParameters)mECKey).Q.Multiply(mECParams.H); + if (s.IsInfinity) + throw new ArgumentException("invalid key: [h]Q at infinity"); + + mRandom = rParam.Random; + } + else + { + mECKey = (ECKeyParameters)param; + mECParams = mECKey.Parameters; + } + + mCurveLength = (mECParams.Curve.FieldSize + 7) / 8; + } + + public virtual byte[] ProcessBlock(byte[] input, int inOff, int inLen) + { + if (mForEncryption) + { + return Encrypt(input, inOff, inLen); + } + else + { + return Decrypt(input, inOff, inLen); + } + } + + protected virtual ECMultiplier CreateBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } + + private byte[] Encrypt(byte[] input, int inOff, int inLen) + { + byte[] c2 = new byte[inLen]; + + Array.Copy(input, inOff, c2, 0, c2.Length); + + ECMultiplier multiplier = CreateBasePointMultiplier(); + + byte[] c1; + ECPoint kPB; + do + { + BigInteger k = NextK(); + + ECPoint c1P = multiplier.Multiply(mECParams.G, k).Normalize(); + + c1 = c1P.GetEncoded(false); + + kPB = ((ECPublicKeyParameters)mECKey).Q.Multiply(k).Normalize(); + + Kdf(mDigest, kPB, c2); + } + while (NotEncrypted(c2, input, inOff)); + + AddFieldElement(mDigest, kPB.AffineXCoord); + mDigest.BlockUpdate(input, inOff, inLen); + AddFieldElement(mDigest, kPB.AffineYCoord); + + byte[] c3 = DigestUtilities.DoFinal(mDigest); + + return Arrays.ConcatenateAll(c1, c2, c3); + } + + private byte[] Decrypt(byte[] input, int inOff, int inLen) + { + byte[] c1 = new byte[mCurveLength * 2 + 1]; + + Array.Copy(input, inOff, c1, 0, c1.Length); + + ECPoint c1P = mECParams.Curve.DecodePoint(c1); + + ECPoint s = c1P.Multiply(mECParams.H); + if (s.IsInfinity) + throw new InvalidCipherTextException("[h]C1 at infinity"); + + c1P = c1P.Multiply(((ECPrivateKeyParameters)mECKey).D).Normalize(); + + byte[] c2 = new byte[inLen - c1.Length - mDigest.GetDigestSize()]; + + Array.Copy(input, inOff + c1.Length, c2, 0, c2.Length); + + Kdf(mDigest, c1P, c2); + + AddFieldElement(mDigest, c1P.AffineXCoord); + mDigest.BlockUpdate(c2, 0, c2.Length); + AddFieldElement(mDigest, c1P.AffineYCoord); + + byte[] c3 = DigestUtilities.DoFinal(mDigest); + + int check = 0; + for (int i = 0; i != c3.Length; i++) + { + check |= c3[i] ^ input[c1.Length + c2.Length + i]; + } + + Arrays.Fill(c1, 0); + Arrays.Fill(c3, 0); + + if (check != 0) + { + Arrays.Fill(c2, 0); + throw new InvalidCipherTextException("invalid cipher text"); + } + + return c2; + } + + private bool NotEncrypted(byte[] encData, byte[] input, int inOff) + { + for (int i = 0; i != encData.Length; i++) + { + if (encData[i] != input[inOff]) + { + return false; + } + } + + return true; + } + + private void Kdf(IDigest digest, ECPoint c1, byte[] encData) + { + int digestSize = digest.GetDigestSize(); + byte[] buf = new byte[System.Math.Max(4, digestSize)]; + int off = 0; + + IMemoable memo = digest as IMemoable; + IMemoable copy = null; + + if (memo != null) + { + AddFieldElement(digest, c1.AffineXCoord); + AddFieldElement(digest, c1.AffineYCoord); + copy = memo.Copy(); + } + + uint ct = 0; + + while (off < encData.Length) + { + if (memo != null) + { + memo.Reset(copy); + } + else + { + AddFieldElement(digest, c1.AffineXCoord); + AddFieldElement(digest, c1.AffineYCoord); + } + + Pack.UInt32_To_BE(++ct, buf, 0); + digest.BlockUpdate(buf, 0, 4); + digest.DoFinal(buf, 0); + + int xorLen = System.Math.Min(digestSize, encData.Length - off); + Xor(encData, buf, off, xorLen); + off += xorLen; + } + } + + private void Xor(byte[] data, byte[] kdfOut, int dOff, int dRemaining) + { + for (int i = 0; i != dRemaining; i++) + { + data[dOff + i] ^= kdfOut[i]; + } + } + + private BigInteger NextK() + { + int qBitLength = mECParams.N.BitLength; + + BigInteger k; + do + { + k = new BigInteger(qBitLength, mRandom); + } + while (k.SignValue == 0 || k.CompareTo(mECParams.N) >= 0); + + return k; + } + + private void AddFieldElement(IDigest digest, ECFieldElement v) + { + byte[] p = v.GetEncoded(); + digest.BlockUpdate(p, 0, p.Length); + } + } +} diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj index bd7ad5787..e9e0b3f4e 100644 --- a/crypto/test/UnitTests.csproj +++ b/crypto/test/UnitTests.csproj @@ -256,6 +256,7 @@ + diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs index bc857b5d0..c065a1320 100644 --- a/crypto/test/src/crypto/test/RegressionTest.cs +++ b/crypto/test/src/crypto/test/RegressionTest.cs @@ -128,6 +128,7 @@ namespace Org.BouncyCastle.Crypto.Tests new X931SignerTest(), new KeccakDigestTest(), new ShakeDigestTest(), + new SM2EngineTest(), new SM2KeyExchangeTest(), new SM2SignerTest(), }; diff --git a/crypto/test/src/crypto/test/SM2EngineTest.cs b/crypto/test/src/crypto/test/SM2EngineTest.cs new file mode 100644 index 000000000..8a1987d52 --- /dev/null +++ b/crypto/test/src/crypto/test/SM2EngineTest.cs @@ -0,0 +1,167 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class SM2EngineTest + : SimpleTest + { + public override string Name + { + get { return "SM2Engine"; } + } + + private void DoEngineTestFp() + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0", 16)); + + keyPairGenerator.Init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.Public; + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.Private; + + SM2Engine sm2Engine = new SM2Engine(); + + byte[] m = Strings.ToByteArray("encryption standard"); + + sm2Engine.Init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16))); + + byte[] enc = sm2Engine.ProcessBlock(m, 0, m.Length); + + IsTrue("enc wrong", Arrays.AreEqual(Hex.Decode( + "04245C26 FB68B1DD DDB12C4B 6BF9F2B6 D5FE60A3 83B0D18D 1C4144AB F17F6252" + + "E776CB92 64C2A7E8 8E52B199 03FDC473 78F605E3 6811F5C0 7423A24B 84400F01" + + "B8650053 A89B41C4 18B0C3AA D00D886C 00286467 9C3D7360 C30156FA B7C80A02" + + "76712DA9 D8094A63 4B766D3A 285E0748 0653426D"), enc)); + + sm2Engine.Init(false, aPriv); + + byte[] dec = sm2Engine.ProcessBlock(enc, 0, enc.Length); + + IsTrue("dec wrong", Arrays.AreEqual(m, dec)); + + enc[80] = (byte)(enc[80] + 1); + + try + { + sm2Engine.ProcessBlock(enc, 0, enc.Length); + Fail("no exception"); + } + catch (InvalidCipherTextException e) + { + IsTrue("wrong exception", "invalid cipher text".Equals(e.Message)); + } + + // long message + sm2Engine = new SM2Engine(); + + m = new byte[4097]; + for (int i = 0; i != m.Length; i++) + { + m[i] = (byte)i; + } + + sm2Engine.Init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16))); + + enc = sm2Engine.ProcessBlock(m, 0, m.Length); + + sm2Engine.Init(false, aPriv); + + dec = sm2Engine.ProcessBlock(enc, 0, enc.Length); + + IsTrue("dec wrong", Arrays.AreEqual(m, dec)); + } + + private void DoEngineTestF2m() + { + BigInteger SM2_ECC_A = new BigInteger("00", 16); + BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); + BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); + BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); + BigInteger SM2_ECC_H = BigInteger.ValueOf(4); + + ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("56A270D17377AA9A367CFA82E46FA5267713A9B91101D0777B07FCE018C757EB", 16)); + + keyPairGenerator.Init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.Public; + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.Private; + + SM2Engine sm2Engine = new SM2Engine(); + + byte[] m = Strings.ToByteArray("encryption standard"); + + sm2Engine.Init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("6D3B497153E3E92524E5C122682DBDC8705062E20B917A5F8FCDB8EE4C66663D", 16))); + + byte[] enc = sm2Engine.ProcessBlock(m, 0, m.Length); + + IsTrue("f2m enc wrong", Arrays.AreEqual(Hex.Decode( + "04019D23 6DDB3050 09AD52C5 1BB93270 9BD534D4 76FBB7B0 DF9542A8 A4D890A3" + + "F2E100B2 3B938DC0 A94D1DF8 F42CF45D 2D6601BF 638C3D7D E75A29F0 2AFB7E45" + + "E91771FD 55AC6213 C2A8A040 E4CAB5B2 6A9CFCDA 737373A4 8625D375 8FA37B3E" + + "AB80E9CF CABA665E 3199EA15 A1FA8189 D96F5791 25E4"), enc)); + + sm2Engine.Init(false, aPriv); + + byte[] dec = sm2Engine.ProcessBlock(enc, 0, enc.Length); + + IsTrue("f2m dec wrong", Arrays.AreEqual(m, dec)); + } + + public override void PerformTest() + { + DoEngineTestFp(); + DoEngineTestF2m(); + } + + public static void Main(string[] args) + { + RunTest(new SM2EngineTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} -- cgit 1.5.1 From 86a7490aaf8f0d9b35cc2fb094efae8409c095a6 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 16 Sep 2017 18:32:37 +0700 Subject: Port of ConcatenationKdfGenerator from Java --- crypto/BouncyCastle.Android.csproj | 1 + crypto/BouncyCastle.csproj | 1 + crypto/BouncyCastle.iOS.csproj | 1 + crypto/crypto.csproj | 5 ++ .../agreement/kdf/ConcatenationKdfGenerator.cs | 100 +++++++++++++++++++++ 5 files changed, 108 insertions(+) create mode 100644 crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs (limited to 'crypto/src') diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index 1c7463c3b..9c05a5df4 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -704,6 +704,7 @@ + diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index d5840b942..f1de777c6 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -698,6 +698,7 @@ + diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index 5e2ced2ad..e655422b8 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -699,6 +699,7 @@ + diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index f872911e1..85af6ef1a 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -3273,6 +3273,11 @@ SubType = "Code" BuildAction = "Compile" /> + mHLen) + { + do + { + Pack.UInt32_To_BE(counter, C); + + mDigest.BlockUpdate(C, 0, C.Length); + mDigest.BlockUpdate(mShared, 0, mShared.Length); + mDigest.BlockUpdate(mOtherInfo, 0, mOtherInfo.Length); + + mDigest.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, outBytes, outOff + outputLen, mHLen); + outputLen += mHLen; + } + while ((counter++) < (len / mHLen)); + } + + if (outputLen < len) + { + Pack.UInt32_To_BE(counter, C); + + mDigest.BlockUpdate(C, 0, C.Length); + mDigest.BlockUpdate(mShared, 0, mShared.Length); + mDigest.BlockUpdate(mOtherInfo, 0, mOtherInfo.Length); + + mDigest.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, outBytes, outOff + outputLen, len - outputLen); + } + + return len; + } + } +} -- cgit 1.5.1 From 3b9aaf9221bc63a32c96be074bb505a86b389121 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 16 Sep 2017 19:09:28 +0700 Subject: Add GOST34.10 2012 parameter sets --- crypto/BouncyCastle.Android.csproj | 1 + crypto/BouncyCastle.csproj | 1 + crypto/BouncyCastle.iOS.csproj | 1 + crypto/crypto.csproj | 5 ++ crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs | 89 +++++++++++++++++++++- .../rosstandart/RosstandartObjectIdentifiers.cs | 47 ++++++++++++ crypto/src/asn1/x9/ECNamedCurveTable.cs | 24 ++++++ 7 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 crypto/src/asn1/rosstandart/RosstandartObjectIdentifiers.cs (limited to 'crypto/src') diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index 9c05a5df4..7a69c92cb 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -371,6 +371,7 @@ + diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index f1de777c6..a5f149620 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -365,6 +365,7 @@ + diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index e655422b8..56dd59ea7 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -366,6 +366,7 @@ + diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 85af6ef1a..d48b2db5b 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -1713,6 +1713,11 @@ SubType = "Code" BuildAction = "Compile" /> + + /// Table of the available named parameters for GOST 3410-2001 / 2012. + /// public sealed class ECGost3410NamedCurves { private ECGost3410NamedCurves() @@ -119,17 +119,98 @@ namespace Org.BouncyCastle.Asn1.CryptoPro parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams; + //GOST34.10 2012 + mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); //p + mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); //q + curve = new FpCurve( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a + new BigInteger("166"), // b + mod_q, + BigInteger.One); + + ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + new BigInteger("1"), // x + new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y + mod_q); // q + + parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA] = ecParams; + + mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",16); //p + mod_q = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",16); //q + curve = new FpCurve( + mod_p, // p + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",16), // a + new BigInteger("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",16), // b + mod_q, + BigInteger.One); + + ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"), // x + new BigInteger("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",16)), // y + mod_q); // q + + parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA] = ecParams; + + mod_p = new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F",16); //p + mod_q = new BigInteger("800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD",16); //q + curve = new FpCurve( + mod_p, // p + new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",16), // a + new BigInteger("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",16), // b + mod_q, + BigInteger.One); + + ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"), // x + new BigInteger("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD",16)), // y + mod_q); // q + + parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetB] = ecParams; + + mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",16); //p + mod_q = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED",16); //q + curve = new FpCurve( + mod_p, // p + new BigInteger("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3",16), // a + new BigInteger("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1",16), // b + mod_q, + BigInteger.One); + + ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + new BigInteger("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148", 16), // x + new BigInteger("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F",16)), // y + mod_q); // q + + parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetC] = ecParams; + objIds["GostR3410-2001-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProA; objIds["GostR3410-2001-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProB; objIds["GostR3410-2001-CryptoPro-C"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProC; objIds["GostR3410-2001-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA; objIds["GostR3410-2001-CryptoPro-XchB"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB; + objIds["Tc26-Gost-3410-12-256-paramSetA"] = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA; + objIds["Tc26-Gost-3410-12-512-paramSetA"] = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA; + objIds["Tc26-Gost-3410-12-512-paramSetB"] = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetB; + objIds["Tc26-Gost-3410-12-512-paramSetC"] = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetC; names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = "GostR3410-2001-CryptoPro-A"; names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = "GostR3410-2001-CryptoPro-B"; names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = "GostR3410-2001-CryptoPro-C"; names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = "GostR3410-2001-CryptoPro-XchA"; names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = "GostR3410-2001-CryptoPro-XchB"; + names[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA] = "Tc26-Gost-3410-12-256-paramSetA"; + names[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA] = "Tc26-Gost-3410-12-512-paramSetA"; + names[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetB] = "Tc26-Gost-3410-12-512-paramSetB"; + names[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetC] = "Tc26-Gost-3410-12-512-paramSetC"; } /** diff --git a/crypto/src/asn1/rosstandart/RosstandartObjectIdentifiers.cs b/crypto/src/asn1/rosstandart/RosstandartObjectIdentifiers.cs new file mode 100644 index 000000000..86fedb7bb --- /dev/null +++ b/crypto/src/asn1/rosstandart/RosstandartObjectIdentifiers.cs @@ -0,0 +1,47 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Rosstandart +{ + public abstract class RosstandartObjectIdentifiers + { + public static readonly DerObjectIdentifier rosstandart = new DerObjectIdentifier("1.2.643.7"); + + public static readonly DerObjectIdentifier id_tc26 = rosstandart.Branch("1"); + + public static readonly DerObjectIdentifier id_tc26_gost_3411_12_256 = id_tc26.Branch("1.2.2"); + + public static readonly DerObjectIdentifier id_tc26_gost_3411_12_512 = id_tc26.Branch("1.2.3"); + + public static readonly DerObjectIdentifier id_tc26_hmac_gost_3411_12_256 = id_tc26.Branch("1.4.1"); + + public static readonly DerObjectIdentifier id_tc26_hmac_gost_3411_12_512 = id_tc26.Branch("1.4.2"); + + public static readonly DerObjectIdentifier id_tc26_gost_3410_12_256 = id_tc26.Branch("1.1.1"); + + public static readonly DerObjectIdentifier id_tc26_gost_3410_12_512 = id_tc26.Branch("1.1.2"); + + public static readonly DerObjectIdentifier id_tc26_signwithdigest_gost_3410_12_256 = id_tc26.Branch("1.3.2"); + + public static readonly DerObjectIdentifier id_tc26_signwithdigest_gost_3410_12_512 = id_tc26.Branch("1.3.3"); + + public static readonly DerObjectIdentifier id_tc26_agreement = id_tc26.Branch("1.6"); + + public static readonly DerObjectIdentifier id_tc26_agreement_gost_3410_12_256 = id_tc26_agreement.Branch("1"); + + public static readonly DerObjectIdentifier id_tc26_agreement_gost_3410_12_512 = id_tc26_agreement.Branch("2"); + + public static readonly DerObjectIdentifier id_tc26_gost_3410_12_256_paramSet = id_tc26.Branch("2.1.1"); + + public static readonly DerObjectIdentifier id_tc26_gost_3410_12_256_paramSetA = id_tc26_gost_3410_12_256_paramSet.Branch("1"); + + public static readonly DerObjectIdentifier id_tc26_gost_3410_12_512_paramSet = id_tc26.Branch("2.1.2"); + + public static readonly DerObjectIdentifier id_tc26_gost_3410_12_512_paramSetA = id_tc26_gost_3410_12_512_paramSet.Branch("1"); + + public static readonly DerObjectIdentifier id_tc26_gost_3410_12_512_paramSetB = id_tc26_gost_3410_12_512_paramSet.Branch("2"); + + public static readonly DerObjectIdentifier id_tc26_gost_3410_12_512_paramSetC = id_tc26_gost_3410_12_512_paramSet.Branch("3"); + + public static readonly DerObjectIdentifier id_tc26_gost_28147_param_Z = id_tc26.Branch("2.5.1.1"); + } +} diff --git a/crypto/src/asn1/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs index 317ef17b4..f91bded18 100644 --- a/crypto/src/asn1/x9/ECNamedCurveTable.cs +++ b/crypto/src/asn1/x9/ECNamedCurveTable.cs @@ -2,10 +2,12 @@ using System.Collections; using Org.BouncyCastle.Asn1.Anssi; +using Org.BouncyCastle.Asn1.CryptoPro; using Org.BouncyCastle.Asn1.GM; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Collections; @@ -43,6 +45,10 @@ namespace Org.BouncyCastle.Asn1.X9 ecP = AnssiNamedCurves.GetByName(name); } if (ecP == null) + { + ecP = FromDomainParameters(ECGost3410NamedCurves.GetByName(name)); + } + if (ecP == null) { ecP = GMNamedCurves.GetByName(name); } @@ -69,6 +75,10 @@ namespace Org.BouncyCastle.Asn1.X9 name = AnssiNamedCurves.GetName(oid); } if (name == null) + { + name = ECGost3410NamedCurves.GetName(oid); + } + if (name == null) { name = GMNamedCurves.GetName(oid); } @@ -101,6 +111,10 @@ namespace Org.BouncyCastle.Asn1.X9 oid = AnssiNamedCurves.GetOid(name); } if (oid == null) + { + oid = ECGost3410NamedCurves.GetOid(name); + } + if (oid == null) { oid = GMNamedCurves.GetOid(name); } @@ -133,6 +147,10 @@ namespace Org.BouncyCastle.Asn1.X9 ecP = AnssiNamedCurves.GetByOid(oid); } if (ecP == null) + { + ecP = FromDomainParameters(ECGost3410NamedCurves.GetByOid(oid)); + } + if (ecP == null) { ecP = GMNamedCurves.GetByOid(oid); } @@ -154,9 +172,15 @@ namespace Org.BouncyCastle.Asn1.X9 CollectionUtilities.AddRange(v, NistNamedCurves.Names); CollectionUtilities.AddRange(v, TeleTrusTNamedCurves.Names); CollectionUtilities.AddRange(v, AnssiNamedCurves.Names); + CollectionUtilities.AddRange(v, ECGost3410NamedCurves.Names); CollectionUtilities.AddRange(v, GMNamedCurves.Names); return v; } } + + private static X9ECParameters FromDomainParameters(ECDomainParameters dp) + { + return dp == null ? null : new X9ECParameters(dp.Curve, dp.G, dp.N, dp.H, dp.GetSeed()); + } } } -- cgit 1.5.1 From 73f71ddda7ebd2b57281c7c546138408c8a289ee Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 17 Sep 2017 11:23:40 +0700 Subject: Check final padding character in Base64 data. --- crypto/src/util/encoders/Base64Encoder.cs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'crypto/src') diff --git a/crypto/src/util/encoders/Base64Encoder.cs b/crypto/src/util/encoders/Base64Encoder.cs index 7b53df25a..07294c9a6 100644 --- a/crypto/src/util/encoders/Base64Encoder.cs +++ b/crypto/src/util/encoders/Base64Encoder.cs @@ -269,6 +269,9 @@ namespace Org.BouncyCastle.Utilities.Encoders { if (c3 == padding) { + if (c4 != padding) + throw new IOException("invalid characters encountered at end of base64 data"); + byte b1 = decodingTable[c1]; byte b2 = decodingTable[c2]; -- cgit 1.5.1 From 992f73598ec5b8325286616515536a5f6f40fa51 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 17 Sep 2017 11:53:45 +0700 Subject: Avoid infinity appearing in lookup table for FixedPointCombMultiplier --- crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs | 2 +- crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs | 10 +++++++++- crypto/src/math/ec/multiplier/FixedPointUtilities.cs | 10 +++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs index a8ef5a77a..05bb4000b 100644 --- a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs +++ b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs @@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier R = R.TwicePlus(lookupTable[index]); } - return R; + return R.Add(info.Offset); } protected virtual int GetWidthForCombSize(int combSize) diff --git a/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs b/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs index 56a6326a1..11bdadc6f 100644 --- a/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs +++ b/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs @@ -6,11 +6,13 @@ public class FixedPointPreCompInfo : PreCompInfo { + protected ECPoint m_offset = null; + /** * Array holding the precomputed ECPoints used for a fixed * point multiplication. */ - protected ECPoint[] m_preComp = null; + protected ECPoint[] m_preComp = null; /** * The width used for the precomputation. If a larger width precomputation @@ -19,6 +21,12 @@ */ protected int m_width = -1; + public virtual ECPoint Offset + { + get { return m_offset; } + set { this.m_offset = value; } + } + public virtual ECPoint[] PreComp { get { return m_preComp; } diff --git a/crypto/src/math/ec/multiplier/FixedPointUtilities.cs b/crypto/src/math/ec/multiplier/FixedPointUtilities.cs index d927d010b..8e129a8f3 100644 --- a/crypto/src/math/ec/multiplier/FixedPointUtilities.cs +++ b/crypto/src/math/ec/multiplier/FixedPointUtilities.cs @@ -35,17 +35,20 @@ namespace Org.BouncyCastle.Math.EC.Multiplier int bits = GetCombSize(c); int d = (bits + minWidth - 1) / minWidth; - ECPoint[] pow2Table = new ECPoint[minWidth]; + ECPoint[] pow2Table = new ECPoint[minWidth + 1]; pow2Table[0] = p; for (int i = 1; i < minWidth; ++i) { pow2Table[i] = pow2Table[i - 1].TimesPow2(d); } - + + // This will be the 'offset' value + pow2Table[minWidth] = pow2Table[0].Subtract(pow2Table[1]); + c.NormalizeAll(pow2Table); lookupTable = new ECPoint[n]; - lookupTable[0] = c.Infinity; + lookupTable[0] = pow2Table[0]; for (int bit = minWidth - 1; bit >= 0; --bit) { @@ -60,6 +63,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier c.NormalizeAll(lookupTable); + info.Offset = pow2Table[minWidth]; info.PreComp = lookupTable; info.Width = minWidth; -- cgit 1.5.1 From 48a6d119371426cc80fecd4f4e82981397bbb1d0 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 17 Sep 2017 16:59:02 +0700 Subject: Remove redundant Init call --- crypto/src/crypto/generators/HKDFBytesGenerator.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/generators/HKDFBytesGenerator.cs b/crypto/src/crypto/generators/HKDFBytesGenerator.cs index c2e667c95..6f36a6faa 100644 --- a/crypto/src/crypto/generators/HKDFBytesGenerator.cs +++ b/crypto/src/crypto/generators/HKDFBytesGenerator.cs @@ -66,7 +66,6 @@ namespace Org.BouncyCastle.Crypto.Generators */ private KeyParameter Extract(byte[] salt, byte[] ikm) { - hMacHash.Init(new KeyParameter(ikm)); if (salt == null) { // TODO check if hashLen is indeed same as HMAC size -- cgit 1.5.1 From de8e5c63b7886c07530d830755145d530e5475e6 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 17 Sep 2017 17:45:28 +0700 Subject: Improve exception messages --- crypto/src/crypto/tls/CertificateStatus.cs | 2 +- crypto/src/crypto/tls/CertificateStatusRequest.cs | 2 +- crypto/src/crypto/tls/ServerName.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/tls/CertificateStatus.cs b/crypto/src/crypto/tls/CertificateStatus.cs index 0f95475b9..bc4128722 100644 --- a/crypto/src/crypto/tls/CertificateStatus.cs +++ b/crypto/src/crypto/tls/CertificateStatus.cs @@ -95,7 +95,7 @@ namespace Org.BouncyCastle.Crypto.Tls case CertificateStatusType.ocsp: return response is OcspResponse; default: - throw new ArgumentException("unsupported value", "statusType"); + throw new ArgumentException("unsupported CertificateStatusType", "statusType"); } } } diff --git a/crypto/src/crypto/tls/CertificateStatusRequest.cs b/crypto/src/crypto/tls/CertificateStatusRequest.cs index 9587d7df8..24ce37655 100644 --- a/crypto/src/crypto/tls/CertificateStatusRequest.cs +++ b/crypto/src/crypto/tls/CertificateStatusRequest.cs @@ -88,7 +88,7 @@ namespace Org.BouncyCastle.Crypto.Tls case CertificateStatusType.ocsp: return request is OcspStatusRequest; default: - throw new ArgumentException("unsupported value", "statusType"); + throw new ArgumentException("unsupported CertificateStatusType", "statusType"); } } } diff --git a/crypto/src/crypto/tls/ServerName.cs b/crypto/src/crypto/tls/ServerName.cs index 508c2ddbc..45d18b79b 100644 --- a/crypto/src/crypto/tls/ServerName.cs +++ b/crypto/src/crypto/tls/ServerName.cs @@ -98,7 +98,7 @@ namespace Org.BouncyCastle.Crypto.Tls case Tls.NameType.host_name: return name is string; default: - throw new ArgumentException("unsupported value", "name"); + throw new ArgumentException("unsupported NameType", "nameType"); } } } -- cgit 1.5.1 From b30a73590e054908e41231dfd200881dcaea0907 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 17 Sep 2017 18:47:43 +0700 Subject: Update SignerLocation to use DirectoryString - obsolete old UTF8-based methods. --- crypto/src/asn1/esf/SignerLocation.cs | 106 +++++++++++++-------- crypto/src/asn1/x500/DirectoryString.cs | 9 +- .../test/src/asn1/test/SignerLocationUnitTest.cs | 24 ++--- 3 files changed, 82 insertions(+), 57 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/asn1/esf/SignerLocation.cs b/crypto/src/asn1/esf/SignerLocation.cs index d2cef51bb..16dbcd01f 100644 --- a/crypto/src/asn1/esf/SignerLocation.cs +++ b/crypto/src/asn1/esf/SignerLocation.cs @@ -1,7 +1,7 @@ using System; using System.Collections; -using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X500; namespace Org.BouncyCastle.Asn1.Esf { @@ -20,10 +20,9 @@ namespace Org.BouncyCastle.Asn1.Esf public class SignerLocation : Asn1Encodable { - // TODO Should these be using DirectoryString? - private DerUtf8String countryName; - private DerUtf8String localityName; - private Asn1Sequence postalAddress; + private DirectoryString countryName; + private DirectoryString localityName; + private Asn1Sequence postalAddress; public SignerLocation( Asn1Sequence seq) @@ -33,10 +32,10 @@ namespace Org.BouncyCastle.Asn1.Esf switch (obj.TagNo) { case 0: - this.countryName = DerUtf8String.GetInstance(obj, true); + this.countryName = DirectoryString.GetInstance(obj, true); break; case 1: - this.localityName = DerUtf8String.GetInstance(obj, true); + this.localityName = DirectoryString.GetInstance(obj, true); break; case 2: bool isExplicit = obj.IsExplicit(); // handle erroneous implicitly tagged sequences @@ -50,33 +49,36 @@ namespace Org.BouncyCastle.Asn1.Esf } } - public SignerLocation( - DerUtf8String countryName, - DerUtf8String localityName, - Asn1Sequence postalAddress) - { - if (postalAddress != null && postalAddress.Count > 6) - { - throw new ArgumentException("postal address must contain less than 6 strings"); - } - - if (countryName != null) - { - this.countryName = DerUtf8String.GetInstance(countryName.ToAsn1Object()); - } - - if (localityName != null) - { - this.localityName = DerUtf8String.GetInstance(localityName.ToAsn1Object()); - } - - if (postalAddress != null) - { - this.postalAddress = (Asn1Sequence) postalAddress.ToAsn1Object(); - } - } - - public static SignerLocation GetInstance( + private SignerLocation( + DirectoryString countryName, + DirectoryString localityName, + Asn1Sequence postalAddress) + { + if (postalAddress != null && postalAddress.Count > 6) + throw new ArgumentException("postal address must contain less than 6 strings"); + + this.countryName = countryName; + this.localityName = localityName; + this.postalAddress = postalAddress; + } + + public SignerLocation( + DirectoryString countryName, + DirectoryString localityName, + DirectoryString[] postalAddress) + : this(countryName, localityName, new DerSequence(postalAddress)) + { + } + + public SignerLocation( + DerUtf8String countryName, + DerUtf8String localityName, + Asn1Sequence postalAddress) + : this(DirectoryString.GetInstance(countryName), DirectoryString.GetInstance(localityName), postalAddress) + { + } + + public static SignerLocation GetInstance( object obj) { if (obj == null || obj is SignerLocation) @@ -87,15 +89,41 @@ namespace Org.BouncyCastle.Asn1.Esf return new SignerLocation(Asn1Sequence.GetInstance(obj)); } + public DirectoryString Country + { + get { return countryName; } + } + + public DirectoryString Locality + { + get { return localityName; } + } + + public DirectoryString[] GetPostal() + { + if (postalAddress == null) + return null; + + DirectoryString[] dirStrings = new DirectoryString[postalAddress.Count]; + for (int i = 0; i != dirStrings.Length; i++) + { + dirStrings[i] = DirectoryString.GetInstance(postalAddress[i]); + } + + return dirStrings; + } + + [Obsolete("Use 'Country' property instead")] public DerUtf8String CountryName { - get { return countryName; } + get { return countryName == null ? null : new DerUtf8String(countryName.GetString()); } } - public DerUtf8String LocalityName - { - get { return localityName; } - } + [Obsolete("Use 'Locality' property instead")] + public DerUtf8String LocalityName + { + get { return localityName == null ? null : new DerUtf8String(localityName.GetString()); } + } public Asn1Sequence PostalAddress { diff --git a/crypto/src/asn1/x500/DirectoryString.cs b/crypto/src/asn1/x500/DirectoryString.cs index d907c6456..6585fcdf5 100644 --- a/crypto/src/asn1/x500/DirectoryString.cs +++ b/crypto/src/asn1/x500/DirectoryString.cs @@ -9,15 +9,12 @@ namespace Org.BouncyCastle.Asn1.X500 { private readonly DerStringBase str; - public static DirectoryString GetInstance( - object obj) + public static DirectoryString GetInstance(object obj) { - if (obj is DirectoryString) - { + if (obj == null || obj is DirectoryString) return (DirectoryString) obj; - } - if (obj is DerStringBase) + if (obj is DerStringBase) { if (obj is DerT61String || obj is DerPrintableString diff --git a/crypto/test/src/asn1/test/SignerLocationUnitTest.cs b/crypto/test/src/asn1/test/SignerLocationUnitTest.cs index bf20f1fda..650e2fcfd 100644 --- a/crypto/test/src/asn1/test/SignerLocationUnitTest.cs +++ b/crypto/test/src/asn1/test/SignerLocationUnitTest.cs @@ -2,8 +2,8 @@ using System; using NUnit.Framework; -using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Esf; +using Org.BouncyCastle.Asn1.X500; using Org.BouncyCastle.Utilities.Test; namespace Org.BouncyCastle.Asn1.Tests @@ -23,17 +23,17 @@ namespace Org.BouncyCastle.Asn1.Tests SignerLocation sl = new SignerLocation(countryName, null, null); - CheckConstruction(sl, countryName, null, null); + CheckConstruction(sl, DirectoryString.GetInstance(countryName), null, null); DerUtf8String localityName = new DerUtf8String("Melbourne"); sl = new SignerLocation(null, localityName, null); - CheckConstruction(sl, null, localityName, null); + CheckConstruction(sl, null, DirectoryString.GetInstance(localityName), null); sl = new SignerLocation(countryName, localityName, null); - CheckConstruction(sl, countryName, localityName, null); + CheckConstruction(sl, DirectoryString.GetInstance(countryName), DirectoryString.GetInstance(localityName), null); Asn1Sequence postalAddress = new DerSequence( new DerUtf8String("line 1"), @@ -45,11 +45,11 @@ namespace Org.BouncyCastle.Asn1.Tests sl = new SignerLocation(countryName, null, postalAddress); - CheckConstruction(sl, countryName, null, postalAddress); + CheckConstruction(sl, DirectoryString.GetInstance(countryName), null, postalAddress); sl = new SignerLocation(countryName, localityName, postalAddress); - CheckConstruction(sl, countryName, localityName, postalAddress); + CheckConstruction(sl, DirectoryString.GetInstance(countryName), DirectoryString.GetInstance(localityName), postalAddress); sl = SignerLocation.GetInstance(null); @@ -117,9 +117,9 @@ namespace Org.BouncyCastle.Asn1.Tests private void CheckConstruction( SignerLocation sl, - DerUtf8String countryName, - DerUtf8String localityName, - Asn1Sequence postalAddress) + DirectoryString countryName, + DirectoryString localityName, + Asn1Sequence postalAddress) { CheckValues(sl, countryName, localityName, postalAddress); @@ -137,9 +137,9 @@ namespace Org.BouncyCastle.Asn1.Tests private void CheckValues( SignerLocation sl, - DerUtf8String countryName, - DerUtf8String localityName, - Asn1Sequence postalAddress) + DirectoryString countryName, + DirectoryString localityName, + Asn1Sequence postalAddress) { if (countryName != null) { -- cgit 1.5.1 From f43bed554a8f5fd60e7c81fe5a37a75890988b85 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 17 Sep 2017 21:21:06 +0700 Subject: Update Copyright year --- crypto/src/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crypto/src') diff --git a/crypto/src/AssemblyInfo.cs b/crypto/src/AssemblyInfo.cs index bb9811d83..4887b00b0 100644 --- a/crypto/src/AssemblyInfo.cs +++ b/crypto/src/AssemblyInfo.cs @@ -18,7 +18,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("The Legion of the Bouncy Castle Inc.")] [assembly: AssemblyProduct("Bouncy Castle for .NET")] -[assembly: AssemblyCopyright("Copyright (C) 2000-2015")] +[assembly: AssemblyCopyright("Copyright (C) 2000-2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -- cgit 1.5.1 From 50d6d0e0b6cf9c840d59574e0374196e94bbc95b Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Mon, 18 Sep 2017 09:01:01 +0700 Subject: Fix method qualifiers and refactor --- crypto/src/crypto/digests/DSTU7564Digest.cs | 773 +++++++++++++--------------- crypto/test/src/crypto/test/DSTU7564Test.cs | 487 +++++++++--------- 2 files changed, 601 insertions(+), 659 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/digests/DSTU7564Digest.cs b/crypto/src/crypto/digests/DSTU7564Digest.cs index 9de41dd6b..3531bf589 100644 --- a/crypto/src/crypto/digests/DSTU7564Digest.cs +++ b/crypto/src/crypto/digests/DSTU7564Digest.cs @@ -11,48 +11,40 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Digests { - /** - * implementation of Ukrainian DSTU 7564 hash function - */ - public class Dstu7564Digest : IDigest, IMemoable - { - private const int ROWS = 8; - private const int REDUCTION_POLYNOMIAL = 0x011d; - private const int BITS_IN_BYTE = 8; - - - private const int NB_512 = 8; //Number of 8-byte words in state for <=256-bit hash code. - private const int NB_1024 = 16; //Number of 8-byte words in state for <=512-bit hash code. - - private const int NR_512 = 10; //Number of rounds for 512-bit state. - private const int NR_1024 = 14; //Number of rounds for 1024-bit state. - - private const int STATE_BYTE_SIZE_512 = ROWS * NB_512; - private const int STATE_BYTE_SIZE_1024 = ROWS * NB_1024; - - private int hashSize; - private int blockSize; - - - - private int columns; - private int rounds; - - - private byte[] padded_; - - private byte[][] state_; - + /** + * implementation of Ukrainian DSTU 7564 hash function + */ + public class Dstu7564Digest : IDigest, IMemoable + { + private const int ROWS = 8; + private const int REDUCTION_POLYNOMIAL = 0x011d; + private const int BITS_IN_BYTE = 8; + + private const int NB_512 = 8; //Number of 8-byte words in state for <=256-bit hash code. + private const int NB_1024 = 16; //Number of 8-byte words in state for <=512-bit hash code. + + private const int NR_512 = 10; //Number of rounds for 512-bit state. + private const int NR_1024 = 14; //Number of rounds for 1024-bit state. + + private const int STATE_BYTE_SIZE_512 = ROWS * NB_512; + private const int STATE_BYTE_SIZE_1024 = ROWS * NB_1024; + + private int hashSize; + private int blockSize; + private int columns; + private int rounds; + private byte[] padded_; + private byte[][] state_; private ulong inputLength; private int bufOff; private byte[] buf; public Dstu7564Digest(Dstu7564Digest digest) { - copyIn(digest); + CopyIn(digest); } - private void copyIn(Dstu7564Digest digest) + private void CopyIn(Dstu7564Digest digest) { this.hashSize = digest.hashSize; this.blockSize = digest.blockSize; @@ -62,6 +54,7 @@ namespace Org.BouncyCastle.Crypto.Digests this.padded_ = Arrays.Clone(digest.padded_); this.state_ = new byte[digest.state_.Length][]; + for (int i = 0; i != this.state_.Length; i++) { this.state_[i] = Arrays.Clone(digest.state_[i]); @@ -73,56 +66,51 @@ namespace Org.BouncyCastle.Crypto.Digests } public Dstu7564Digest(int hashSizeBits) - { - if (hashSizeBits == 256 || hashSizeBits == 384 || hashSizeBits == 512) - { - this.hashSize = hashSizeBits / 8; - } - else - { - throw new ArgumentException("Hash size is not recommended. Use 256 or 384 or 512 size"); - } - - if (hashSizeBits > 256) - { - this.blockSize = 1024 / 8; - this.columns = NB_1024; - this.rounds = NR_1024; - this.state_ = new byte[STATE_BYTE_SIZE_1024][]; - - } - else - { - this.blockSize = 512 / 8; - this.columns = NB_512; - this.rounds = NR_512; - this.state_ = new byte[STATE_BYTE_SIZE_512][]; - - } - - //Console.WriteLine("length: " + state_.Length); - - for (int i = 0; i < state_.Length; i++) - { - this.state_[i] = new byte[columns]; - } - - this.state_[0][0] = (byte)state_.Length; - - this.hashSize = hashSizeBits / 8; - - this.padded_ = null; - this.buf = new byte[blockSize]; - } + { + if (hashSizeBits == 256 || hashSizeBits == 384 || hashSizeBits == 512) + { + this.hashSize = hashSizeBits / 8; + } + else + { + throw new ArgumentException("Hash size is not recommended. Use 256 or 384 or 512 size"); + } - public string AlgorithmName - { - get { return "DSTU7564"; } - } + if (hashSizeBits > 256) + { + this.blockSize = 1024 / 8; + this.columns = NB_1024; + this.rounds = NR_1024; + this.state_ = new byte[STATE_BYTE_SIZE_1024][]; + } + else + { + this.blockSize = 512 / 8; + this.columns = NB_512; + this.rounds = NR_512; + this.state_ = new byte[STATE_BYTE_SIZE_512][]; + } + + for (int i = 0; i < state_.Length; i++) + { + this.state_[i] = new byte[columns]; + } + + this.state_[0][0] = (byte)state_.Length; + + this.hashSize = hashSizeBits / 8; + + this.padded_ = null; + this.buf = new byte[blockSize]; + } + public virtual string AlgorithmName + { + get { return "DSTU7564"; } + } - public virtual void BlockUpdate(byte[] input, int inOff, int length) - { + public virtual void BlockUpdate(byte[] input, int inOff, int length) + { while (bufOff != 0 && length > 0) { Update(input[inOff++]); @@ -147,10 +135,8 @@ namespace Org.BouncyCastle.Crypto.Digests } } - protected byte[] Pad(byte[] input, int inOff, int length) - { - //Console.WriteLine(length); - + protected virtual byte[] Pad(byte[] input, int inOff, int length) + { byte[] padded; if (blockSize - length < 13) // terminator byte + 96 bits of length { @@ -161,55 +147,47 @@ namespace Org.BouncyCastle.Crypto.Digests padded = new byte[blockSize]; } + Array.Copy(input, inOff, padded, 0, length); + padded[length] = 0x80; + Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12); - Array.Copy(input, inOff, padded, 0, length); - padded[length] = 0x80; - Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12); - - return padded; - } - - protected void ProcessBlock(byte[] input, int inOff) - { - byte[][] temp1 = new byte[STATE_BYTE_SIZE_1024][]; - byte[][] temp2 = new byte[STATE_BYTE_SIZE_1024][]; - - for (int i = 0; i < state_.Length; i++) - { - temp1[i] = new byte[ROWS]; - temp2[i] = new byte[ROWS]; - } - - for (int i = 0; i < ROWS; ++i) - { - for (int j = 0; j < columns; ++j) - { - //Console.WriteLine("row = {0}, column = {1}", i, j); - - temp1[j][i] = (byte)(state_[j][i] ^ input[j * ROWS + i + inOff]); - temp2[j][i] = input[j * ROWS + i + inOff]; + return padded; + } - } - - } + protected virtual void ProcessBlock(byte[] input, int inOff) + { + byte[][] temp1 = new byte[STATE_BYTE_SIZE_1024][]; + byte[][] temp2 = new byte[STATE_BYTE_SIZE_1024][]; - P(temp1); + for (int i = 0; i < state_.Length; i++) + { + temp1[i] = new byte[ROWS]; + temp2[i] = new byte[ROWS]; + } - Q(temp2); + for (int i = 0; i < ROWS; ++i) + { + for (int j = 0; j < columns; ++j) + { + temp1[j][i] = (byte)(state_[j][i] ^ input[j * ROWS + i + inOff]); + temp2[j][i] = input[j * ROWS + i + inOff]; + } + } - for (int i = 0; i < ROWS; ++i) - { - for (int j = 0; j < columns; ++j) - { - state_[j][i] ^= (byte)(temp1[j][i] ^ temp2[j][i]); + P(temp1); + Q(temp2); - } - - } - } + for (int i = 0; i < ROWS; ++i) + { + for (int j = 0; j < columns; ++j) + { + state_[j][i] ^= (byte)(temp1[j][i] ^ temp2[j][i]); + } + } + } - public int DoFinal(byte[] output, int outOff) - { + public virtual int DoFinal(byte[] output, int outOff) + { padded_ = Pad(buf, 0, bufOff); int paddedLen = padded_.Length; @@ -222,55 +200,43 @@ namespace Org.BouncyCastle.Crypto.Digests paddedLen -= blockSize; } - - //Console.WriteLine(stateLine.Length); - byte[][] temp = new byte[STATE_BYTE_SIZE_1024][]; - for (int i = 0; i < state_.Length; i++) - { - temp[i] = new byte[ROWS]; - Array.Copy(state_[i], temp[i], ROWS); - } + for (int i = 0; i < state_.Length; i++) + { + temp[i] = new byte[ROWS]; + Array.Copy(state_[i], temp[i], ROWS); + } P(temp); for (int i = 0; i < ROWS; ++i) { - for (int j = 0; j < columns; ++j) - { - state_[j][i] ^= temp[j][i]; - //Console.Write("{0:x} ", state_[j][i]); - } - //Console.WriteLine(); + for (int j = 0; j < columns; ++j) + { + state_[j][i] ^= temp[j][i]; + } } byte[] stateLine = new byte[ROWS * columns]; int stateLineIndex = 0; - for (int j = 0; j < columns; ++j) - { - for (int i = 0; i < ROWS; ++i) - { - - stateLine[stateLineIndex] = state_[j][i]; - stateLineIndex++; - - //Console.WriteLine("index = {0}, row = {1}, column = {2}", stateLineIndex, i, j); + for (int j = 0; j < columns; ++j) + { + for (int i = 0; i < ROWS; ++i) + { + stateLine[stateLineIndex] = state_[j][i]; + stateLineIndex++; + } + } - } - } - - //Console.WriteLine("final: " + Hex.ToHexString(stateLine)); - //Console.WriteLine(stateLine.Length); - - Array.Copy(stateLine, stateLine.Length - hashSize, output, outOff, hashSize); + Array.Copy(stateLine, stateLine.Length - hashSize, output, outOff, hashSize); - Reset(); + Reset(); - return hashSize; - } + return hashSize; + } - public void Reset() - { + public virtual void Reset() + { for (int bufferIndex = 0; bufferIndex < state_.Length; bufferIndex++) { state_[bufferIndex] = new byte[columns]; @@ -289,18 +255,18 @@ namespace Org.BouncyCastle.Crypto.Digests } } - public int GetDigestSize() - { - return hashSize; - } + public virtual int GetDigestSize() + { + return hashSize; + } - public int GetByteLength() - { - return blockSize; - } + public virtual int GetByteLength() + { + return blockSize; + } - public void Update(byte input) - { + public virtual void Update(byte input) + { buf[bufOff++] = input; if (bufOff == blockSize) { @@ -308,255 +274,246 @@ namespace Org.BouncyCastle.Crypto.Digests bufOff = 0; } inputLength++; - } - - void SubBytes(byte[][] state) - { - int i, j; - for (i = 0; i < ROWS; ++i) - { - for (j = 0; j < columns; ++j) - { - state[j][i] = sBoxes[i % 4][state[j][i]]; - } - } - } - - void ShiftBytes(byte[][] state) - { - int i, j; - byte[] temp = new byte[NB_1024]; - int shift = -1; - for (i = 0; i < ROWS; ++i) - { - if ((i == ROWS - 1) && (columns == NB_1024)) - { - shift = 11; - } - else - { - ++shift; - } - for (j = 0; j < columns; ++j) - { - temp[(j + shift) % columns] = state[j][i]; - } - for (j = 0; j < columns; ++j) - { - state[j][i] = temp[j]; - } - } - } - - byte MultiplyGF(byte x, byte y) - { - int i; - byte r = 0; - byte hbit = 0; - for (i = 0; i < BITS_IN_BYTE; ++i) - { - if ((y & 0x1) == 1) - { - r ^= x; - } + } - hbit = (byte)(x & 0x80); + private void SubBytes(byte[][] state) + { + int i, j; + for (i = 0; i < ROWS; ++i) + { + for (j = 0; j < columns; ++j) + { + state[j][i] = sBoxes[i % 4][state[j][i]]; + } + } + } - x <<= 1; + private void ShiftBytes(byte[][] state) + { + int i, j; + byte[] temp = new byte[NB_1024]; + int shift = -1; + for (i = 0; i < ROWS; ++i) + { + if ((i == ROWS - 1) && (columns == NB_1024)) + { + shift = 11; + } + else + { + ++shift; + } + for (j = 0; j < columns; ++j) + { + temp[(j + shift) % columns] = state[j][i]; + } + for (j = 0; j < columns; ++j) + { + state[j][i] = temp[j]; + } + } + } - if (hbit == 0x80) - { - x = (byte)((int)x ^ REDUCTION_POLYNOMIAL); - } + private static byte MultiplyGF(byte x, byte y) + { + int i; + byte r = 0; + byte hbit = 0; + for (i = 0; i < BITS_IN_BYTE; ++i) + { + if ((y & 0x1) == 1) + { + r ^= x; + } - y >>= 1; - } - return r; - } - - private void MixColumns(byte[][] state) - { - int i, row, col, b; - byte product; - byte[] result = new byte[ROWS]; - - for (col = 0; col < columns; ++col) - { - Array.Clear(result, 0, ROWS); - for (row = ROWS - 1; row >= 0; --row) - { - product = 0; - for (b = ROWS - 1; b >= 0; --b) - { - product ^= MultiplyGF(state[col][b], mds_matrix[row][b]); - } - result[row] = product; - } - for (i = 0; i < ROWS; ++i) + hbit = (byte)(x & 0x80); + + x <<= 1; + + if (hbit == 0x80) + { + x = (byte)((int)x ^ REDUCTION_POLYNOMIAL); + } + + y >>= 1; + } + return r; + } + + private void MixColumns(byte[][] state) + { + int i, row, col, b; + byte product; + byte[] result = new byte[ROWS]; + + for (col = 0; col < columns; ++col) + { + Array.Clear(result, 0, ROWS); + for (row = ROWS - 1; row >= 0; --row) + { + product = 0; + for (b = ROWS - 1; b >= 0; --b) { - state[col][i] = result[i]; + product ^= MultiplyGF(state[col][b], mds_matrix[row][b]); } - } - } - - void AddRoundConstantP(byte[][] state, int round) - { - int i; - for (i = 0; i < columns; ++i) - { - state[i][0] ^= (byte)((i * 0x10) ^ round); - } - } - - void AddRoundConstantQ(byte[][] state, int round) - { - int j; - UInt64[] s = new UInt64[columns]; - - for (j = 0; j < columns; j++) - { - s[j] = Pack.LE_To_UInt64(state[j]); - - s[j] = s[j] + (0x00F0F0F0F0F0F0F3UL ^ ((((UInt64)(columns - j - 1) * 0x10UL) ^ (UInt64)round) << (7 * 8))); - - state[j] = Pack.UInt64_To_LE(s[j]); - } - } - - void P(byte[][] state) - { - int i; - for (i = 0; i < rounds; ++i) - { - AddRoundConstantP(state, i); - SubBytes(state); - ShiftBytes(state); - MixColumns(state); - } - } - - void Q(byte[][] state) - { - int i; - for (i = 0; i < rounds; ++i) - { - AddRoundConstantQ(state, i); - SubBytes(state); - ShiftBytes(state); - MixColumns(state); - } - } - - public IMemoable Copy() + result[row] = product; + } + for (i = 0; i < ROWS; ++i) + { + state[col][i] = result[i]; + } + } + } + + private void AddRoundConstantP(byte[][] state, int round) + { + int i; + for (i = 0; i < columns; ++i) + { + state[i][0] ^= (byte)((i * 0x10) ^ round); + } + } + + private void AddRoundConstantQ(byte[][] state, int round) + { + int j; + UInt64[] s = new UInt64[columns]; + + for (j = 0; j < columns; j++) + { + s[j] = Pack.LE_To_UInt64(state[j]); + + s[j] = s[j] + (0x00F0F0F0F0F0F0F3UL ^ ((((UInt64)(columns - j - 1) * 0x10UL) ^ (UInt64)round) << (7 * 8))); + + state[j] = Pack.UInt64_To_LE(s[j]); + } + } + + private void P(byte[][] state) + { + int i; + for (i = 0; i < rounds; ++i) + { + AddRoundConstantP(state, i); + SubBytes(state); + ShiftBytes(state); + MixColumns(state); + } + } + + private void Q(byte[][] state) + { + int i; + for (i = 0; i < rounds; ++i) + { + AddRoundConstantQ(state, i); + SubBytes(state); + ShiftBytes(state); + MixColumns(state); + } + } + + public virtual IMemoable Copy() { return new Dstu7564Digest(this); } - public void Reset(IMemoable other) + public virtual void Reset(IMemoable other) { Dstu7564Digest d = (Dstu7564Digest)other; - copyIn(d); + CopyIn(d); } - private readonly byte[][] mds_matrix = new byte[][] - { - new byte[] {0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04}, - new byte[] {0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07}, - new byte[] {0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06}, - new byte[] {0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08}, - new byte[] {0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01}, - new byte[] {0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05}, - new byte[] {0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01}, - new byte[] {0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01} - }; - - - - - private readonly byte[][] sBoxes = new byte[][] - { - new byte[] - { - 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09, - 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39, - 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6, - 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1, - 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27, - 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41, - 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e, - 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55, - 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff, - 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1, - 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76, - 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26, - 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82, - 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8, - 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d, - 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80 - }, - - new byte[] - { - 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8, - 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d, - 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d, - 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc, - 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee, - 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca, - 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20, - 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f, - 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51, - 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98, - 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9, - 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05, - 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82, - 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad, - 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59, - 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7 - }, - - new byte[] - { - 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59, - 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1, - 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72, - 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90, - 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35, - 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48, - 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38, - 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33, - 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29, - 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83, - 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2, - 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43, - 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82, - 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91, - 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44, - 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67 - }, - - new byte[] - { - 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f, - 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd, - 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66, - 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf, - 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99, - 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71, - 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60, - 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b, - 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09, - 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2, - 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7, - 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a, - 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39, - 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef, - 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36, - 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61 - } - }; - - - } + private static readonly byte[][] mds_matrix = new byte[][] + { + new byte[] { 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04 }, + new byte[] { 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07 }, + new byte[] { 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06 }, + new byte[] { 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08 }, + new byte[] { 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01 }, + new byte[] { 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05 }, + new byte[] { 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01 }, + new byte[] { 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01 } + }; + + private static readonly byte[][] sBoxes = new byte[][] + { + new byte[] { + 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09, + 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39, + 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6, + 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1, + 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27, + 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41, + 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e, + 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55, + 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff, + 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1, + 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76, + 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26, + 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82, + 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8, + 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d, + 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80 + }, + + new byte[] { + 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8, + 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d, + 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d, + 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc, + 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee, + 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca, + 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20, + 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f, + 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51, + 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98, + 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9, + 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05, + 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82, + 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad, + 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59, + 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7 + }, + + new byte[]{ + 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59, + 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1, + 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72, + 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90, + 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35, + 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48, + 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38, + 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33, + 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29, + 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83, + 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2, + 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43, + 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82, + 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91, + 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44, + 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67 + }, + + new byte[]{ + 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f, + 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd, + 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66, + 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf, + 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99, + 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71, + 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60, + 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b, + 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09, + 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2, + 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7, + 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a, + 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39, + 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef, + 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36, + 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61 + } + }; + } } diff --git a/crypto/test/src/crypto/test/DSTU7564Test.cs b/crypto/test/src/crypto/test/DSTU7564Test.cs index 98f0bbdea..805d3c8ab 100644 --- a/crypto/test/src/crypto/test/DSTU7564Test.cs +++ b/crypto/test/src/crypto/test/DSTU7564Test.cs @@ -46,16 +46,16 @@ namespace Org.BouncyCastle.Crypto.Tests public override void PerformTest() { base.PerformTest(); - - hash256Tests(); - hash384Tests(); - hash512Tests(); - macTests(); - overflowTest(); - } - private void overflowTest() - { + hash256Tests(); + hash384Tests(); + hash512Tests(); + macTests(); + overflowTest(); + } + + private void overflowTest() + { int macBitSize = 256; byte[] input = new byte[1024]; for (int i = 0; i != input.Length; i++) @@ -300,29 +300,28 @@ namespace Org.BouncyCastle.Crypto.Tests } } - private void macTests() - { - - //test1 - int macBitSize = 256; - byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); - byte[] key = Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); + private void macTests() + { + //test1 + int macBitSize = 256; + byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); + byte[] key = Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); - byte[] expectedMac = Hex.Decode("B60594D56FA79BA210314C72C2495087CCD0A99FC04ACFE2A39EF669925D98EE"); - byte[] mac = new byte[macBitSize / 8]; + byte[] expectedMac = Hex.Decode("B60594D56FA79BA210314C72C2495087CCD0A99FC04ACFE2A39EF669925D98EE"); + byte[] mac = new byte[macBitSize / 8]; - Dstu7564Mac dstu7564mac = new Dstu7564Mac(macBitSize); + Dstu7564Mac dstu7564mac = new Dstu7564Mac(macBitSize); - dstu7564mac.Init(new KeyParameter(key)); - dstu7564mac.BlockUpdate(input, 0, input.Length); - dstu7564mac.DoFinal(mac, 0); + dstu7564mac.Init(new KeyParameter(key)); + dstu7564mac.BlockUpdate(input, 0, input.Length); + dstu7564mac.DoFinal(mac, 0); - if (!Arrays.AreEqual(expectedMac, mac)) - { - Fail("Failed mac test 1 - expected " - + Hex.ToHexString(expectedMac) - + " got " + Hex.ToHexString(mac)); - } + if (!Arrays.AreEqual(expectedMac, mac)) + { + Fail("Failed mac test 1 - expected " + + Hex.ToHexString(expectedMac) + + " got " + Hex.ToHexString(mac)); + } //test1a input = Hex.Decode("0001020304050607"); @@ -346,290 +345,276 @@ namespace Org.BouncyCastle.Crypto.Tests //test 2 macBitSize = 384; - input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); - key = Hex.Decode("2F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); + input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); + key = Hex.Decode("2F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); - expectedMac = Hex.Decode("BEBFD8D730336F043ABACB41829E79A4D320AEDDD8D14024D5B805DA70C396FA295C281A38B30AE728A304B3F5AE490E"); - mac = new byte[macBitSize / 8]; + expectedMac = Hex.Decode("BEBFD8D730336F043ABACB41829E79A4D320AEDDD8D14024D5B805DA70C396FA295C281A38B30AE728A304B3F5AE490E"); + mac = new byte[macBitSize / 8]; - dstu7564mac = new Dstu7564Mac(macBitSize); + dstu7564mac = new Dstu7564Mac(macBitSize); - dstu7564mac.Init(new KeyParameter(key)); - dstu7564mac.BlockUpdate(input, 0, input.Length); - dstu7564mac.DoFinal(mac, 0); + dstu7564mac.Init(new KeyParameter(key)); + dstu7564mac.BlockUpdate(input, 0, input.Length); + dstu7564mac.DoFinal(mac, 0); - if (!Arrays.AreEqual(expectedMac, mac)) - { - Fail("Failed mac test 2 - expected " - + Hex.ToHexString(expectedMac) - + " got " + Hex.ToHexString(mac)); - } + if (!Arrays.AreEqual(expectedMac, mac)) + { + Fail("Failed mac test 2 - expected " + + Hex.ToHexString(expectedMac) + + " got " + Hex.ToHexString(mac)); + } - //test 3 - macBitSize = 512; - input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); - key = Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); + //test 3 + macBitSize = 512; + input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); + key = Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); - expectedMac = Hex.Decode("F270043C06A5C37E65D9D791C5FBFB966E5EE709F8F54019C9A55B76CA40B70100579F269CEC24E347A9D864614CF3ABBF6610742E4DB3BD2ABC000387C49D24"); - mac = new byte[macBitSize / 8]; + expectedMac = Hex.Decode("F270043C06A5C37E65D9D791C5FBFB966E5EE709F8F54019C9A55B76CA40B70100579F269CEC24E347A9D864614CF3ABBF6610742E4DB3BD2ABC000387C49D24"); + mac = new byte[macBitSize / 8]; - dstu7564mac = new Dstu7564Mac(macBitSize); + dstu7564mac = new Dstu7564Mac(macBitSize); - dstu7564mac.Init(new KeyParameter(key)); - dstu7564mac.BlockUpdate(input, 0, input.Length); - dstu7564mac.DoFinal(mac, 0); + dstu7564mac.Init(new KeyParameter(key)); + dstu7564mac.BlockUpdate(input, 0, input.Length); + dstu7564mac.DoFinal(mac, 0); - if (!Arrays.AreEqual(expectedMac, mac)) - { - Fail("Failed mac test 3 - expected " - + Hex.ToHexString(expectedMac) - + " got " + Hex.ToHexString(mac)); + if (!Arrays.AreEqual(expectedMac, mac)) + { + Fail("Failed mac test 3 - expected " + + Hex.ToHexString(expectedMac) + + " got " + Hex.ToHexString(mac)); + } } - } - - private void hash512Tests() - { - - int hashBitSize = 512; - - //test 1 - byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); - byte[] expectedHash = Hex.Decode("3813E2109118CDFB5A6D5E72F7208DCCC80A2DFB3AFDFB02F46992B5EDBE536B3560DD1D7E29C6F53978AF58B444E37BA685C0DD910533BA5D78EFFFC13DE62A"); - byte[] hash = new byte[hashBitSize / 8]; - - - Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); - if (!Arrays.AreEqual(expectedHash, hash)) + private void hash512Tests() { - Fail("Failed hash-512 test 1 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } - - //test 2 - input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); - expectedHash = Hex.Decode("76ED1AC28B1D0143013FFA87213B4090B356441263C13E03FA060A8CADA32B979635657F256B15D5FCA4A174DE029F0B1B4387C878FCC1C00E8705D783FD7FFE"); - hash = new byte[hashBitSize / 8]; + int hashBitSize = 512; + //test 1 + byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + byte[] expectedHash = Hex.Decode("3813E2109118CDFB5A6D5E72F7208DCCC80A2DFB3AFDFB02F46992B5EDBE536B3560DD1D7E29C6F53978AF58B444E37BA685C0DD910533BA5D78EFFFC13DE62A"); + byte[] hash = new byte[hashBitSize / 8]; - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); - - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-512 test 2 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } - - //test 3 - input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); - expectedHash = Hex.Decode("0DD03D7350C409CB3C29C25893A0724F6B133FA8B9EB90A64D1A8FA93B56556611EB187D715A956B107E3BFC76482298133A9CE8CBC0BD5E1436A5B197284F7E"); - hash = new byte[hashBitSize / 8]; + Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-512 test 1 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + //test 2 + input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + expectedHash = Hex.Decode("76ED1AC28B1D0143013FFA87213B4090B356441263C13E03FA060A8CADA32B979635657F256B15D5FCA4A174DE029F0B1B4387C878FCC1C00E8705D783FD7FFE"); + hash = new byte[hashBitSize / 8]; - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-512 test 3 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - //test 4 - input = Hex.Decode("FF"); - expectedHash = Hex.Decode("871B18CF754B72740307A97B449ABEB32B64444CC0D5A4D65830AE5456837A72D8458F12C8F06C98C616ABE11897F86263B5CB77C420FB375374BEC52B6D0292"); - hash = new byte[hashBitSize / 8]; + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-512 test 2 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } + //test 3 + input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); + expectedHash = Hex.Decode("0DD03D7350C409CB3C29C25893A0724F6B133FA8B9EB90A64D1A8FA93B56556611EB187D715A956B107E3BFC76482298133A9CE8CBC0BD5E1436A5B197284F7E"); + hash = new byte[hashBitSize / 8]; - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-512 test 4 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-512 test 3 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } - //test 5 - input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); - expectedHash = Hex.Decode("B189BFE987F682F5F167F0D7FA565330E126B6E592B1C55D44299064EF95B1A57F3C2D0ECF17869D1D199EBBD02E8857FB8ADD67A8C31F56CD82C016CF743121"); - hash = new byte[hashBitSize / 8]; + //test 4 + input = Hex.Decode("FF"); + expectedHash = Hex.Decode("871B18CF754B72740307A97B449ABEB32B64444CC0D5A4D65830AE5456837A72D8458F12C8F06C98C616ABE11897F86263B5CB77C420FB375374BEC52B6D0292"); + hash = new byte[hashBitSize / 8]; + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-512 test 4 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-512 test 5 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } + //test 5 + input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + expectedHash = Hex.Decode("B189BFE987F682F5F167F0D7FA565330E126B6E592B1C55D44299064EF95B1A57F3C2D0ECF17869D1D199EBBD02E8857FB8ADD67A8C31F56CD82C016CF743121"); + hash = new byte[hashBitSize / 8]; + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - //test 6 - input = Hex.Decode(""); - expectedHash = Hex.Decode("656B2F4CD71462388B64A37043EA55DBE445D452AECD46C3298343314EF04019BCFA3F04265A9857F91BE91FCE197096187CEDA78C9C1C021C294A0689198538"); - hash = new byte[hashBitSize / 8]; + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-512 test 5 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } + //test 6 + input = Hex.Decode(""); + expectedHash = Hex.Decode("656B2F4CD71462388B64A37043EA55DBE445D452AECD46C3298343314EF04019BCFA3F04265A9857F91BE91FCE197096187CEDA78C9C1C021C294A0689198538"); + hash = new byte[hashBitSize / 8]; - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-512 test 6 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-512 test 6 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } } - } - - private void hash384Tests() - { - int hashBitSize = 384; - - //test 1 - byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E"); - byte[] expectedHash = Hex.Decode("D9021692D84E5175735654846BA751E6D0ED0FAC36DFBC0841287DCB0B5584C75016C3DECC2A6E47C50B2F3811E351B8"); - byte[] hash = new byte[hashBitSize / 8]; - - - Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); - - if (!Arrays.AreEqual(expectedHash, hash)) + private void hash384Tests() { - Fail("Failed hash-384 test 1 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } - } + int hashBitSize = 384; - private void hash256Tests() - { + //test 1 + byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E"); + byte[] expectedHash = Hex.Decode("D9021692D84E5175735654846BA751E6D0ED0FAC36DFBC0841287DCB0B5584C75016C3DECC2A6E47C50B2F3811E351B8"); + byte[] hash = new byte[hashBitSize / 8]; - int hashBitSize = 256; + Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - //test 1 - byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); - byte[] expectedHash = Hex.Decode("08F4EE6F1BE6903B324C4E27990CB24EF69DD58DBE84813EE0A52F6631239875"); - byte[] hash = new byte[hashBitSize / 8]; + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-384 test 1 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } + } + private void hash256Tests() + { + int hashBitSize = 256; - Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + //test 1 + byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + byte[] expectedHash = Hex.Decode("08F4EE6F1BE6903B324C4E27990CB24EF69DD58DBE84813EE0A52F6631239875"); + byte[] hash = new byte[hashBitSize / 8]; - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-256 test 1 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } + Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - //test 2 - input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); - expectedHash = Hex.Decode("0A9474E645A7D25E255E9E89FFF42EC7EB31349007059284F0B182E452BDA882"); - hash = new byte[hashBitSize / 8]; + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-256 test 1 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } + //test 2 + input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + expectedHash = Hex.Decode("0A9474E645A7D25E255E9E89FFF42EC7EB31349007059284F0B182E452BDA882"); + hash = new byte[hashBitSize / 8]; - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-256 test 2 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-256 test 2 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } - //test 3 - input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); - expectedHash = Hex.Decode("D305A32B963D149DC765F68594505D4077024F836C1BF03806E1624CE176C08F"); - hash = new byte[hashBitSize / 8]; + //test 3 + input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); + expectedHash = Hex.Decode("D305A32B963D149DC765F68594505D4077024F836C1BF03806E1624CE176C08F"); + hash = new byte[hashBitSize / 8]; - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-256 test 3 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-256 test 3 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } - //test 4 - input = Hex.Decode("FF"); - expectedHash = Hex.Decode("EA7677CA4526555680441C117982EA14059EA6D0D7124D6ECDB3DEEC49E890F4"); - hash = new byte[hashBitSize / 8]; + //test 4 + input = Hex.Decode("FF"); + expectedHash = Hex.Decode("EA7677CA4526555680441C117982EA14059EA6D0D7124D6ECDB3DEEC49E890F4"); + hash = new byte[hashBitSize / 8]; - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-256 test 4 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-256 test 4 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } - //test 5 - input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E"); - expectedHash = Hex.Decode("1075C8B0CB910F116BDA5FA1F19C29CF8ECC75CAFF7208BA2994B68FC56E8D16"); - hash = new byte[hashBitSize / 8]; + //test 5 + input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E"); + expectedHash = Hex.Decode("1075C8B0CB910F116BDA5FA1F19C29CF8ECC75CAFF7208BA2994B68FC56E8D16"); + hash = new byte[hashBitSize / 8]; - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-256 test 5 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); - } + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-256 test 5 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } - //test 6 - input = Hex.Decode(""); - expectedHash = Hex.Decode("CD5101D1CCDF0D1D1F4ADA56E888CD724CA1A0838A3521E7131D4FB78D0F5EB6"); - hash = new byte[hashBitSize / 8]; + //test 6 + input = Hex.Decode(""); + expectedHash = Hex.Decode("CD5101D1CCDF0D1D1F4ADA56E888CD724CA1A0838A3521E7131D4FB78D0F5EB6"); + hash = new byte[hashBitSize / 8]; - dstu7564 = new Dstu7564Digest(hashBitSize); - dstu7564.BlockUpdate(input, 0, input.Length); - dstu7564.DoFinal(hash, 0); + dstu7564 = new Dstu7564Digest(hashBitSize); + dstu7564.BlockUpdate(input, 0, input.Length); + dstu7564.DoFinal(hash, 0); - if (!Arrays.AreEqual(expectedHash, hash)) - { - Fail("Failed hash-256 test 6 - expected " - + Hex.ToHexString(expectedHash) - + " got " + Hex.ToHexString(hash)); + if (!Arrays.AreEqual(expectedHash, hash)) + { + Fail("Failed hash-256 test 6 - expected " + + Hex.ToHexString(expectedHash) + + " got " + Hex.ToHexString(hash)); + } } - } - protected override IDigest CloneDigest(IDigest digest) + protected override IDigest CloneDigest(IDigest digest) { return new Dstu7564Digest((Dstu7564Digest)digest); } - public static void Main( - string[] args) + public static void Main(string[] args) { RunTest(new Dstu7564Test()); } -- cgit 1.5.1 From 6cc4a1614564fdc14b2cccb295b9081c62086122 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Mon, 18 Sep 2017 09:22:18 +0700 Subject: Constant-time GF multiplication --- crypto/src/crypto/digests/DSTU7564Digest.cs | 33 ++++++++++++--------------- crypto/src/crypto/engines/Dstu7624Engine.cs | 35 +++++++++++++---------------- 2 files changed, 29 insertions(+), 39 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/digests/DSTU7564Digest.cs b/crypto/src/crypto/digests/DSTU7564Digest.cs index 3531bf589..c3b027a17 100644 --- a/crypto/src/crypto/digests/DSTU7564Digest.cs +++ b/crypto/src/crypto/digests/DSTU7564Digest.cs @@ -17,7 +17,6 @@ namespace Org.BouncyCastle.Crypto.Digests public class Dstu7564Digest : IDigest, IMemoable { private const int ROWS = 8; - private const int REDUCTION_POLYNOMIAL = 0x011d; private const int BITS_IN_BYTE = 8; private const int NB_512 = 8; //Number of 8-byte words in state for <=256-bit hash code. @@ -316,28 +315,24 @@ namespace Org.BouncyCastle.Crypto.Digests private static byte MultiplyGF(byte x, byte y) { - int i; - byte r = 0; - byte hbit = 0; - for (i = 0; i < BITS_IN_BYTE; ++i) - { - if ((y & 0x1) == 1) - { - r ^= x; - } + // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ - hbit = (byte)(x & 0x80); + uint u = x, v = y; + uint r = u & (0U - (v & 1)); - x <<= 1; + for (int i = 1; i < BITS_IN_BYTE; i++) + { + u <<= 1; + v >>= 1; + r ^= u & (0U - (v & 1)); + } - if (hbit == 0x80) - { - x = (byte)((int)x ^ REDUCTION_POLYNOMIAL); - } + uint hi = r & 0xFF00U; + r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); + hi = r & 0x0F00U; + r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - y >>= 1; - } - return r; + return (byte)r; } private void MixColumns(byte[][] state) diff --git a/crypto/src/crypto/engines/Dstu7624Engine.cs b/crypto/src/crypto/engines/Dstu7624Engine.cs index cdb0f50e0..3ae3ef3f8 100644 --- a/crypto/src/crypto/engines/Dstu7624Engine.cs +++ b/crypto/src/crypto/engines/Dstu7624Engine.cs @@ -16,8 +16,6 @@ namespace Org.BouncyCastle.Crypto.Engines private static readonly int BITS_IN_WORD = 64; private static readonly int BITS_IN_BYTE = 8; - private static readonly int REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ - private ulong[] internalState; private ulong[] workingKey; private ulong[][] roundKeys; @@ -495,29 +493,26 @@ namespace Org.BouncyCastle.Crypto.Engines } } - private byte MultiplyGF(byte x, byte y) + private static byte MultiplyGF(byte x, byte y) { - byte r = 0; - byte hbit = 0; + // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ - for (int i = 0; i < BITS_IN_BYTE; i++) - { - if ((y & 0x01) == 1) - { - r ^= x; - } + uint u = x, v = y; + uint r = u & (0U - (v & 1)); - hbit = (byte)(x & 0x80); + for (int i = 1; i < BITS_IN_BYTE; i++) + { + u <<= 1; + v >>= 1; + r ^= u & (0U - (v & 1)); + } - x <<= 1; + uint hi = r & 0xFF00U; + r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); + hi = r & 0x0F00U; + r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - if (hbit == 0x80) - { - x = (byte)((int)x ^ REDUCTION_POLYNOMIAL); - } - y >>= 1; - } - return r; + return (byte)r; } private void SubBytes() -- cgit 1.5.1 From 0801c1543f0cafc79c44b225e53c973bdd1b0a0f Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Mon, 18 Sep 2017 17:14:46 +0700 Subject: Performance optimisation in DSTU algorithms --- crypto/src/crypto/digests/DSTU7564Digest.cs | 103 ++++++++++++++-------------- crypto/src/crypto/engines/Dstu7624Engine.cs | 86 ++++++++++------------- 2 files changed, 87 insertions(+), 102 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/digests/DSTU7564Digest.cs b/crypto/src/crypto/digests/DSTU7564Digest.cs index c3b027a17..e641af6c2 100644 --- a/crypto/src/crypto/digests/DSTU7564Digest.cs +++ b/crypto/src/crypto/digests/DSTU7564Digest.cs @@ -155,32 +155,33 @@ namespace Org.BouncyCastle.Crypto.Digests protected virtual void ProcessBlock(byte[] input, int inOff) { - byte[][] temp1 = new byte[STATE_BYTE_SIZE_1024][]; - byte[][] temp2 = new byte[STATE_BYTE_SIZE_1024][]; + byte[][] temp1 = new byte[columns][]; + byte[][] temp2 = new byte[columns][]; - for (int i = 0; i < state_.Length; i++) + int pos = inOff; + for (int i = 0; i < columns; i++) { - temp1[i] = new byte[ROWS]; - temp2[i] = new byte[ROWS]; - } + byte[] S = state_[i]; + byte[] T1 = temp1[i] = new byte[ROWS]; + byte[] T2 = temp2[i] = new byte[ROWS]; - for (int i = 0; i < ROWS; ++i) - { - for (int j = 0; j < columns; ++j) + for (int j = 0; j < ROWS; ++j) { - temp1[j][i] = (byte)(state_[j][i] ^ input[j * ROWS + i + inOff]); - temp2[j][i] = input[j * ROWS + i + inOff]; + byte inVal = input[pos++]; + T1[j] = (byte)(S[j] ^ inVal); + T2[j] = inVal; } } P(temp1); Q(temp2); - for (int i = 0; i < ROWS; ++i) + for (int i = 0; i < columns; ++i) { - for (int j = 0; j < columns; ++j) + byte[] S = state_[i], T1 = temp1[i], T2 = temp2[i]; + for (int j = 0; j < ROWS; ++j) { - state_[j][i] ^= (byte)(temp1[j][i] ^ temp2[j][i]); + S[j] ^= (byte)(T1[j] ^ T2[j]); } } } @@ -313,50 +314,55 @@ namespace Org.BouncyCastle.Crypto.Digests } } - private static byte MultiplyGF(byte x, byte y) + /* Pair-wise GF multiplication of 4 byte-pairs (at bits 0, 16, 32, 48 within x, y) */ + private static ulong MultiplyGFx4(ulong u, ulong v) { - // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ - - uint u = x, v = y; - uint r = u & (0U - (v & 1)); + ulong r = u & ((v & 0x0001000100010001UL) * 0xFFFFUL); - for (int i = 1; i < BITS_IN_BYTE; i++) + for (int i = 1; i < 8; ++i) { u <<= 1; v >>= 1; - r ^= u & (0U - (v & 1)); + r ^= u & ((v & 0x0001000100010001L) * 0xFFFFL); } - uint hi = r & 0xFF00U; + // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ + + ulong hi = r & 0xFF00FF00FF00FF00UL; r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - hi = r & 0x0F00U; + hi = r & 0x0F000F000F000F00UL; r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - - return (byte)r; + return r; } private void MixColumns(byte[][] state) { - int i, row, col, b; - byte product; - byte[] result = new byte[ROWS]; - - for (col = 0; col < columns; ++col) + for (int col = 0; col < columns; ++col) { - Array.Clear(result, 0, ROWS); - for (row = ROWS - 1; row >= 0; --row) - { - product = 0; - for (b = ROWS - 1; b >= 0; --b) - { - product ^= MultiplyGF(state[col][b], mds_matrix[row][b]); - } - result[row] = product; - } - for (i = 0; i < ROWS; ++i) + ulong colVal = Pack.LE_To_UInt64(state[col]); + ulong colEven = colVal & 0x00FF00FF00FF00FFUL; + ulong colOdd = (colVal >> 8) & 0x00FF00FF00FF00FFUL; + + //ulong rowMatrix = (mdsMatrix >> 8) | (mdsMatrix << 56); + ulong rowMatrix = mdsMatrix; + + ulong result = 0; + for (int row = 7; row >= 0; --row) { - state[col][i] = result[i]; + ulong product = MultiplyGFx4(colEven, rowMatrix & 0x00FF00FF00FF00FFUL); + + rowMatrix = (rowMatrix >> 8) | (rowMatrix << 56); + + product ^= MultiplyGFx4(colOdd, rowMatrix & 0x00FF00FF00FF00FFUL); + + product ^= (product >> 32); + product ^= (product >> 16); + + result <<= 8; + result |= (product & 0xFFUL); } + + Pack.UInt64_To_LE(result, state[col]); } } @@ -420,17 +426,8 @@ namespace Org.BouncyCastle.Crypto.Digests CopyIn(d); } - private static readonly byte[][] mds_matrix = new byte[][] - { - new byte[] { 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04 }, - new byte[] { 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07 }, - new byte[] { 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06 }, - new byte[] { 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08 }, - new byte[] { 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01 }, - new byte[] { 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05 }, - new byte[] { 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01 }, - new byte[] { 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01 } - }; + //private const ulong mdsMatrix = 0x0407060801050101UL; + private const ulong mdsMatrix = 0x0104070608010501UL; private static readonly byte[][] sBoxes = new byte[][] { diff --git a/crypto/src/crypto/engines/Dstu7624Engine.cs b/crypto/src/crypto/engines/Dstu7624Engine.cs index 3ae3ef3f8..534a23bbf 100644 --- a/crypto/src/crypto/engines/Dstu7624Engine.cs +++ b/crypto/src/crypto/engines/Dstu7624Engine.cs @@ -470,49 +470,56 @@ namespace Org.BouncyCastle.Crypto.Engines MatrixMultiply(mdsInvMatrix); } - private void MatrixMultiply(byte[][] matrix) + private void MatrixMultiply(ulong matrix) { - int col, row, b; - byte product; - ulong result; - byte[] stateBytes = Pack.UInt64_To_LE(internalState); - - for (col = 0; col < wordsInBlock; ++col) + for (int col = 0; col < wordsInBlock; ++col) { - result = 0; - for (row = 8 - 1; row >= 0; --row) + ulong colVal = internalState[col]; + ulong colEven = colVal & 0x00FF00FF00FF00FFUL; + ulong colOdd = (colVal >> 8) & 0x00FF00FF00FF00FFUL; + + //ulong rowMatrix = (matrix >> 8) | (matrix << 56); + ulong rowMatrix = matrix; + + ulong result = 0; + for (int row = 7; row >= 0; --row) { - product = 0; - for (b = 8 - 1; b >= 0; --b) - { - product ^= MultiplyGF(stateBytes[b + col * 8], matrix[row][b]); - } - result |= (ulong)product << (row * 8); + ulong product = MultiplyGFx4(colEven, rowMatrix & 0x00FF00FF00FF00FFUL); + + rowMatrix = (rowMatrix >> 8) | (rowMatrix << 56); + + product ^= MultiplyGFx4(colOdd, rowMatrix & 0x00FF00FF00FF00FFUL); + + product ^= (product >> 32); + product ^= (product >> 16); + + result <<= 8; + result |= (product & 0xFFUL); } + internalState[col] = result; } } - private static byte MultiplyGF(byte x, byte y) + /* Pair-wise GF multiplication of 4 byte-pairs (at bits 0, 16, 32, 48 within x, y) */ + private static ulong MultiplyGFx4(ulong u, ulong v) { - // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ - - uint u = x, v = y; - uint r = u & (0U - (v & 1)); + ulong r = u & ((v & 0x0001000100010001UL) * 0xFFFFUL); - for (int i = 1; i < BITS_IN_BYTE; i++) + for (int i = 1; i < 8; ++i) { u <<= 1; v >>= 1; - r ^= u & (0U - (v & 1)); + r ^= u & ((v & 0x0001000100010001L) * 0xFFFFL); } - uint hi = r & 0xFF00U; + // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ + + ulong hi = r & 0xFF00FF00FF00FF00UL; r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - hi = r & 0x0F00U; + hi = r & 0x0F000F000F000F00UL; r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - - return (byte)r; + return r; } private void SubBytes() @@ -547,29 +554,10 @@ namespace Org.BouncyCastle.Crypto.Engines #region TABLES AND S-BOXES - private byte[][] mdsMatrix = - { - new byte[] { 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04 }, - new byte[] { 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07 }, - new byte[] { 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06 }, - new byte[] { 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08 }, - new byte[] { 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01 }, - new byte[] { 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05 }, - new byte[] { 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01 }, - new byte[] { 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01 }, - }; - - private byte[][] mdsInvMatrix = - { - new byte[] { 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA }, - new byte[] { 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7 }, - new byte[] { 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49 }, - new byte[] { 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F }, - new byte[] { 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8 }, - new byte[] { 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76 }, - new byte[] { 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95 }, - new byte[] { 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD }, - }; + //private const ulong mdsMatrix = 0x0407060801050101UL; + //private const ulong mdsInvMatrix = 0xCAD7492FA87695ADUL; + private const ulong mdsMatrix = 0x0104070608010501UL; + private const ulong mdsInvMatrix = 0xADCAD7492FA87695UL; private byte[][] sboxesForEncryption = { -- cgit 1.5.1