diff --git a/crypto/src/AssemblyInfo.cs b/crypto/src/AssemblyInfo.cs
index 7dd625878..4a813bc5a 100644
--- a/crypto/src/AssemblyInfo.cs
+++ b/crypto/src/AssemblyInfo.cs
@@ -14,7 +14,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-2014")]
+[assembly: AssemblyCopyright("Copyright (C) 2000-2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index 18d13c32d..501e788a0 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -2,7 +2,6 @@ using System;
using System.Diagnostics;
using System.IO;
-using Org.BouncyCastle.Asn1.Utilities;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Asn1
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index 2e77ca2a9..cf039d7fe 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -278,67 +278,30 @@ namespace Org.BouncyCastle.Asn1
return encObj;
}
- /**
- * return true if a <= b (arrays are assumed padded with zeros).
- */
- private bool LessThanOrEqual(
- byte[] a,
- byte[] b)
+ protected internal void Sort()
{
- int len = System.Math.Min(a.Length, b.Length);
- for (int i = 0; i != len; ++i)
+ if (_set.Count < 2)
+ return;
+
+ Asn1Encodable[] items = new Asn1Encodable[_set.Count];
+ byte[][] keys = new byte[_set.Count][];
+
+ for (int i = 0; i < _set.Count; ++i)
{
- if (a[i] != b[i])
- {
- return a[i] < b[i];
- }
+ Asn1Encodable item = (Asn1Encodable)_set[i];
+ items[i] = item;
+ keys[i] = item.GetEncoded(Asn1Encodable.Der);
}
- return len == a.Length;
- }
- protected internal void Sort()
- {
- if (_set.Count > 1)
- {
- bool swapped = true;
- int lastSwap = _set.Count - 1;
+ Array.Sort(keys, items, new DerComparer());
- while (swapped)
- {
- int index = 0;
- int swapIndex = 0;
- byte[] a = ((Asn1Encodable) _set[0]).GetEncoded();
-
- swapped = false;
-
- while (index != lastSwap)
- {
- byte[] b = ((Asn1Encodable) _set[index + 1]).GetEncoded();
-
- if (LessThanOrEqual(a, b))
- {
- a = b;
- }
- else
- {
- object o = _set[index];
- _set[index] = _set[index + 1];
- _set[index + 1] = o;
-
- swapped = true;
- swapIndex = index;
- }
-
- index++;
- }
-
- lastSwap = swapIndex;
- }
+ for (int i = 0; i < _set.Count; ++i)
+ {
+ _set[i] = items[i];
}
}
- protected internal void AddObject(
- Asn1Encodable obj)
+ protected internal void AddObject(Asn1Encodable obj)
{
_set.Add(obj);
}
@@ -347,5 +310,36 @@ namespace Org.BouncyCastle.Asn1
{
return CollectionUtilities.ToString(_set);
}
+
+ private class DerComparer
+ : IComparer
+ {
+ public int Compare(object x, object y)
+ {
+ byte[] a = (byte[])x, b = (byte[])y;
+ int len = System.Math.Min(a.Length, b.Length);
+ for (int i = 0; i != len; ++i)
+ {
+ byte ai = a[i], bi = b[i];
+ if (ai != bi)
+ return ai < bi ? -1 : 1;
+ }
+ if (a.Length > b.Length)
+ return AllZeroesFrom(a, len) ? 0 : 1;
+ if (a.Length < b.Length)
+ return AllZeroesFrom(b, len) ? 0 : -1;
+ return 0;
+ }
+
+ private bool AllZeroesFrom(byte[] bs, int pos)
+ {
+ while (pos < bs.Length)
+ {
+ if (bs[pos++] != 0)
+ return false;
+ }
+ return true;
+ }
+ }
}
}
diff --git a/crypto/src/asn1/DerOutputStream.cs b/crypto/src/asn1/DerOutputStream.cs
index f95d123f9..c03d9dc11 100644
--- a/crypto/src/asn1/DerOutputStream.cs
+++ b/crypto/src/asn1/DerOutputStream.cs
@@ -1,7 +1,7 @@
using System;
using System.IO;
-using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Asn1
{
diff --git a/crypto/src/asn1/anssi/ANSSINamedCurves.cs b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
new file mode 100644
index 000000000..c7f9545f2
--- /dev/null
+++ b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Anssi
+{
+ public class AnssiNamedCurves
+ {
+ private static ECCurve ConfigureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ /*
+ * FRP256v1
+ */
+ internal class Frp256v1Holder
+ : X9ECParametersHolder
+ {
+ private Frp256v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Frp256v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger p = FromHex("F1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C03");
+ BigInteger a = FromHex("F1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C00");
+ BigInteger b = FromHex("EE353FCA5428A9300D4ABA754A44C00FDFEC0C9AE4B1A1803075ED967B7BB73F");
+ byte[] S = null;
+ BigInteger n = FromHex("F1FD178C0B3AD58F10126DE8CE42435B53DC67E140D2BF941FFDD459C6D655E1");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "B6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF"
+ + "6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+
+ private static readonly IDictionary objIds = Platform.CreateHashtable();
+ private static readonly IDictionary curves = Platform.CreateHashtable();
+ private static readonly IDictionary names = Platform.CreateHashtable();
+
+ private static void DefineCurve(
+ string name,
+ DerObjectIdentifier oid,
+ X9ECParametersHolder holder)
+ {
+ objIds.Add(Platform.ToLowerInvariant(name), oid);
+ names.Add(oid, name);
+ curves.Add(oid, holder);
+ }
+
+ static AnssiNamedCurves()
+ {
+ DefineCurve("FRP256v1", AnssiObjectIdentifiers.FRP256v1, Frp256v1Holder.Instance);
+ }
+
+ public static X9ECParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by
+ * the passed in object identifier. Null if the curve isn't present.
+ *
+ * @param oid an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
+ return holder == null ? null : holder.Parameters;
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)];
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(
+ DerObjectIdentifier oid)
+ {
+ return (string)names[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names.Values); }
+ }
+ }
+}
diff --git a/crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs b/crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs
new file mode 100644
index 000000000..d230832b5
--- /dev/null
+++ b/crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Anssi
+{
+ public sealed class AnssiObjectIdentifiers
+ {
+ private AnssiObjectIdentifiers()
+ {
+ }
+
+ public static readonly DerObjectIdentifier FRP256v1 = new DerObjectIdentifier("1.2.250.1.223.101.256.1");
+ }
+}
diff --git a/crypto/src/asn1/cms/EncryptedData.cs b/crypto/src/asn1/cms/EncryptedData.cs
index 5b8378282..cb109a640 100644
--- a/crypto/src/asn1/cms/EncryptedData.cs
+++ b/crypto/src/asn1/cms/EncryptedData.cs
@@ -52,8 +52,8 @@ namespace Org.BouncyCastle.Asn1.Cms
if (seq.Count > 2)
{
- this.unprotectedAttrs = Asn1Set.GetInstance(seq[2]);
- }
+ this.unprotectedAttrs = Asn1Set.GetInstance((Asn1TaggedObject)seq[2], false);
+ }
}
public virtual DerInteger Version
diff --git a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
index ca57c283d..32d3103af 100644
--- a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
+++ b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -150,7 +150,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
*/
public static IEnumerable Names
{
- get { return new EnumerableProxy(objIds.Keys); }
+ get { return new EnumerableProxy(names.Values); }
}
public static ECDomainParameters GetByName(
diff --git a/crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs b/crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
index b8aba7ee9..bc48c3fa2 100644
--- a/crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
+++ b/crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
@@ -2,17 +2,18 @@ using System;
namespace Org.BouncyCastle.Asn1.Microsoft
{
- public abstract class MicrosoftObjectIdentifiers
- {
- //
- // Microsoft
- // iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) Microsoft(311)
- //
- public static readonly DerObjectIdentifier Microsoft = new DerObjectIdentifier("1.3.6.1.4.1.311");
- public static readonly DerObjectIdentifier MicrosoftCertTemplateV1 = new DerObjectIdentifier(Microsoft + ".20.2");
- public static readonly DerObjectIdentifier MicrosoftCAVersion = new DerObjectIdentifier(Microsoft + ".21.1");
- public static readonly DerObjectIdentifier MicrosoftPrevCACertHash = new DerObjectIdentifier(Microsoft + ".21.2");
- public static readonly DerObjectIdentifier MicrosoftCertTemplateV2 = new DerObjectIdentifier(Microsoft + ".21.7");
- public static readonly DerObjectIdentifier MicrosoftAppPolicies = new DerObjectIdentifier(Microsoft + ".21.10");
- }
+ public abstract class MicrosoftObjectIdentifiers
+ {
+ //
+ // Microsoft
+ // iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) Microsoft(311)
+ //
+ public static readonly DerObjectIdentifier Microsoft = new DerObjectIdentifier("1.3.6.1.4.1.311");
+ public static readonly DerObjectIdentifier MicrosoftCertTemplateV1 = Microsoft.Branch("20.2");
+ public static readonly DerObjectIdentifier MicrosoftCAVersion = Microsoft.Branch("21.1");
+ public static readonly DerObjectIdentifier MicrosoftPrevCACertHash = Microsoft.Branch("21.2");
+ public static readonly DerObjectIdentifier MicrosoftCrlNextPublish = Microsoft.Branch("21.4");
+ public static readonly DerObjectIdentifier MicrosoftCertTemplateV2 = Microsoft.Branch("21.7");
+ public static readonly DerObjectIdentifier MicrosoftAppPolicies = Microsoft.Branch("21.10");
+ }
}
diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
index 01004d889..8128b6952 100644
--- a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
+++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
@@ -1,5 +1,3 @@
-using Org.BouncyCastle.Asn1;
-
namespace Org.BouncyCastle.Asn1.Misc
{
public abstract class MiscObjectIdentifiers
@@ -9,40 +7,73 @@ namespace Org.BouncyCastle.Asn1.Misc
// iso/itu(2) joint-assign(16) us(840) uscompany(1) Netscape(113730) cert-extensions(1) }
//
public static readonly DerObjectIdentifier Netscape = new DerObjectIdentifier("2.16.840.1.113730.1");
- public static readonly DerObjectIdentifier NetscapeCertType = new DerObjectIdentifier(Netscape + ".1");
- public static readonly DerObjectIdentifier NetscapeBaseUrl = new DerObjectIdentifier(Netscape + ".2");
- public static readonly DerObjectIdentifier NetscapeRevocationUrl = new DerObjectIdentifier(Netscape + ".3");
- public static readonly DerObjectIdentifier NetscapeCARevocationUrl = new DerObjectIdentifier(Netscape + ".4");
- public static readonly DerObjectIdentifier NetscapeRenewalUrl = new DerObjectIdentifier(Netscape + ".7");
- public static readonly DerObjectIdentifier NetscapeCAPolicyUrl = new DerObjectIdentifier(Netscape + ".8");
- public static readonly DerObjectIdentifier NetscapeSslServerName = new DerObjectIdentifier(Netscape + ".12");
- public static readonly DerObjectIdentifier NetscapeCertComment = new DerObjectIdentifier(Netscape + ".13");
+ public static readonly DerObjectIdentifier NetscapeCertType = Netscape.Branch("1");
+ public static readonly DerObjectIdentifier NetscapeBaseUrl = Netscape.Branch("2");
+ public static readonly DerObjectIdentifier NetscapeRevocationUrl = Netscape.Branch("3");
+ public static readonly DerObjectIdentifier NetscapeCARevocationUrl = Netscape.Branch("4");
+ public static readonly DerObjectIdentifier NetscapeRenewalUrl = Netscape.Branch("7");
+ public static readonly DerObjectIdentifier NetscapeCAPolicyUrl = Netscape.Branch("8");
+ public static readonly DerObjectIdentifier NetscapeSslServerName = Netscape.Branch("12");
+ public static readonly DerObjectIdentifier NetscapeCertComment = Netscape.Branch("13");
+
//
// Verisign
// iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
//
- internal const string Verisign = "2.16.840.1.113733.1";
+ public static readonly DerObjectIdentifier Verisign = new DerObjectIdentifier("2.16.840.1.113733.1");
- //
+ //
// CZAG - country, zip, age, and gender
//
- public static readonly DerObjectIdentifier VerisignCzagExtension = new DerObjectIdentifier(Verisign + ".6.3");
-
- // D&B D-U-N-S number
- public static readonly DerObjectIdentifier VerisignDnbDunsNumber = new DerObjectIdentifier(Verisign + ".6.15");
-
- //
- // Novell
- // iso/itu(2) country(16) us(840) organization(1) novell(113719)
- //
- public static readonly string Novell = "2.16.840.1.113719";
- public static readonly DerObjectIdentifier NovellSecurityAttribs = new DerObjectIdentifier(Novell + ".1.9.4.1");
-
- //
- // Entrust
- // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
- //
- public static readonly string Entrust = "1.2.840.113533.7";
- public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0");
- }
+ public static readonly DerObjectIdentifier VerisignCzagExtension = Verisign.Branch("6.3");
+
+ public static readonly DerObjectIdentifier VerisignPrivate_6_9 = Verisign.Branch("6.9");
+ public static readonly DerObjectIdentifier VerisignOnSiteJurisdictionHash = Verisign.Branch("6.11");
+ public static readonly DerObjectIdentifier VerisignBitString_6_13 = Verisign.Branch("6.13");
+
+ // D&B D-U-N-S number
+ public static readonly DerObjectIdentifier VerisignDnbDunsNumber = Verisign.Branch("6.15");
+
+ public static readonly DerObjectIdentifier VerisignIssStrongCrypto = Verisign.Branch("8.1");
+
+ //
+ // Novell
+ // iso/itu(2) country(16) us(840) organization(1) novell(113719)
+ //
+ public static readonly string Novell = "2.16.840.1.113719";
+ public static readonly DerObjectIdentifier NovellSecurityAttribs = new DerObjectIdentifier(Novell + ".1.9.4.1");
+
+ //
+ // Entrust
+ // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
+ //
+ public static readonly string Entrust = "1.2.840.113533.7";
+ public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0");
+
+ //
+ // Ascom
+ //
+ public static readonly DerObjectIdentifier as_sys_sec_alg_ideaCBC = new DerObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+
+ //
+ // Peter Gutmann's Cryptlib
+ //
+ public static readonly DerObjectIdentifier cryptlib = new DerObjectIdentifier("1.3.6.1.4.1.3029");
+
+ public static readonly DerObjectIdentifier cryptlib_algorithm = cryptlib.Branch("1");
+ public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_ECB = cryptlib_algorithm.Branch("1.1");
+ public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CBC = cryptlib_algorithm.Branch("1.2");
+ public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CFB = cryptlib_algorithm.Branch("1.3");
+ public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_OFB = cryptlib_algorithm.Branch("1.4");
+
+ //
+ // Blake2b
+ //
+ public static readonly DerObjectIdentifier blake2 = new DerObjectIdentifier("1.3.6.1.4.1.1722.12.2");
+
+ public static readonly DerObjectIdentifier id_blake2b160 = blake2.Branch("1.5");
+ public static readonly DerObjectIdentifier id_blake2b256 = blake2.Branch("1.8");
+ public static readonly DerObjectIdentifier id_blake2b384 = blake2.Branch("1.12");
+ public static readonly DerObjectIdentifier id_blake2b512 = blake2.Branch("1.16");
+ }
}
diff --git a/crypto/src/asn1/nist/NISTNamedCurves.cs b/crypto/src/asn1/nist/NISTNamedCurves.cs
index 0e82dda7a..f6c1598c6 100644
--- a/crypto/src/asn1/nist/NISTNamedCurves.cs
+++ b/crypto/src/asn1/nist/NISTNamedCurves.cs
@@ -21,45 +21,40 @@ namespace Org.BouncyCastle.Asn1.Nist
private static readonly IDictionary objIds = Platform.CreateHashtable();
private static readonly IDictionary names = Platform.CreateHashtable();
- private static void DefineCurve(
+ private static void DefineCurveAlias(
string name,
DerObjectIdentifier oid)
{
- objIds.Add(name, oid);
+ objIds.Add(Platform.ToUpperInvariant(name), oid);
names.Add(oid, name);
}
static NistNamedCurves()
{
- DefineCurve("B-571", SecObjectIdentifiers.SecT571r1);
- DefineCurve("B-409", SecObjectIdentifiers.SecT409r1);
- DefineCurve("B-283", SecObjectIdentifiers.SecT283r1);
- DefineCurve("B-233", SecObjectIdentifiers.SecT233r1);
- DefineCurve("B-163", SecObjectIdentifiers.SecT163r2);
- DefineCurve("K-571", SecObjectIdentifiers.SecT571k1);
- DefineCurve("K-409", SecObjectIdentifiers.SecT409k1);
- DefineCurve("K-283", SecObjectIdentifiers.SecT283k1);
- DefineCurve("K-233", SecObjectIdentifiers.SecT233k1);
- DefineCurve("K-163", SecObjectIdentifiers.SecT163k1);
- DefineCurve("P-521", SecObjectIdentifiers.SecP521r1);
- DefineCurve("P-384", SecObjectIdentifiers.SecP384r1);
- DefineCurve("P-256", SecObjectIdentifiers.SecP256r1);
- DefineCurve("P-224", SecObjectIdentifiers.SecP224r1);
- DefineCurve("P-192", SecObjectIdentifiers.SecP192r1);
+ DefineCurveAlias("B-163", SecObjectIdentifiers.SecT163r2);
+ DefineCurveAlias("B-233", SecObjectIdentifiers.SecT233r1);
+ DefineCurveAlias("B-283", SecObjectIdentifiers.SecT283r1);
+ DefineCurveAlias("B-409", SecObjectIdentifiers.SecT409r1);
+ DefineCurveAlias("B-571", SecObjectIdentifiers.SecT571r1);
+
+ DefineCurveAlias("K-163", SecObjectIdentifiers.SecT163k1);
+ DefineCurveAlias("K-233", SecObjectIdentifiers.SecT233k1);
+ DefineCurveAlias("K-283", SecObjectIdentifiers.SecT283k1);
+ DefineCurveAlias("K-409", SecObjectIdentifiers.SecT409k1);
+ DefineCurveAlias("K-571", SecObjectIdentifiers.SecT571k1);
+
+ DefineCurveAlias("P-192", SecObjectIdentifiers.SecP192r1);
+ DefineCurveAlias("P-224", SecObjectIdentifiers.SecP224r1);
+ DefineCurveAlias("P-256", SecObjectIdentifiers.SecP256r1);
+ DefineCurveAlias("P-384", SecObjectIdentifiers.SecP384r1);
+ DefineCurveAlias("P-521", SecObjectIdentifiers.SecP521r1);
}
public static X9ECParameters GetByName(
string name)
{
- DerObjectIdentifier oid = (DerObjectIdentifier) objIds[
- Platform.ToUpperInvariant(name)];
-
- if (oid != null)
- {
- return GetByOid(oid);
- }
-
- return null;
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
}
/**
@@ -83,8 +78,7 @@ namespace Org.BouncyCastle.Asn1.Nist
public static DerObjectIdentifier GetOid(
string name)
{
- return (DerObjectIdentifier) objIds[
- Platform.ToUpperInvariant(name)];
+ return (DerObjectIdentifier) objIds[Platform.ToUpperInvariant(name)];
}
/**
@@ -102,7 +96,7 @@ namespace Org.BouncyCastle.Asn1.Nist
*/
public static IEnumerable Names
{
- get { return new EnumerableProxy(objIds.Keys); }
+ get { return new EnumerableProxy(names.Values); }
}
}
}
diff --git a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
index 8eb5ed437..55b9d8e68 100644
--- a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
+++ b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
@@ -25,6 +25,12 @@ namespace Org.BouncyCastle.Asn1.Nist
public static readonly DerObjectIdentifier IdSha224 = HashAlgs.Branch("4");
public static readonly DerObjectIdentifier IdSha512_224 = HashAlgs.Branch("5");
public static readonly DerObjectIdentifier IdSha512_256 = HashAlgs.Branch("6");
+ public static readonly DerObjectIdentifier IdSha3_224 = HashAlgs.Branch("7");
+ public static readonly DerObjectIdentifier IdSha3_256 = HashAlgs.Branch("8");
+ public static readonly DerObjectIdentifier IdSha3_384 = HashAlgs.Branch("9");
+ public static readonly DerObjectIdentifier IdSha3_512 = HashAlgs.Branch("10");
+ public static readonly DerObjectIdentifier IdShake128 = HashAlgs.Branch("11");
+ public static readonly DerObjectIdentifier IdShake256 = HashAlgs.Branch("12");
public static readonly DerObjectIdentifier Aes = new DerObjectIdentifier(NistAlgorithm + ".1");
diff --git a/crypto/src/asn1/pkcs/PBKDF2Params.cs b/crypto/src/asn1/pkcs/PBKDF2Params.cs
index 1351b94cf..5d1e9854f 100644
--- a/crypto/src/asn1/pkcs/PBKDF2Params.cs
+++ b/crypto/src/asn1/pkcs/PBKDF2Params.cs
@@ -1,50 +1,73 @@
using System;
-
+using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Asn1.Pkcs
{
- public class Pbkdf2Params
- : Asn1Encodable
- {
- private readonly Asn1OctetString octStr;
- private readonly DerInteger iterationCount;
- private readonly DerInteger keyLength;
-
- public static Pbkdf2Params GetInstance(
- object obj)
- {
- if (obj == null || obj is Pbkdf2Params)
- return (Pbkdf2Params)obj;
-
- if (obj is Asn1Sequence)
- return new Pbkdf2Params((Asn1Sequence)obj);
-
- throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
- }
-
- public Pbkdf2Params(
- Asn1Sequence seq)
- {
- if (seq.Count < 2 || seq.Count > 3)
- throw new ArgumentException("Wrong number of elements in sequence", "seq");
-
- octStr = (Asn1OctetString)seq[0];
- iterationCount = (DerInteger)seq[1];
-
- if (seq.Count > 2)
- {
- keyLength = (DerInteger)seq[2];
- }
- }
-
- public Pbkdf2Params(
- byte[] salt,
- int iterationCount)
- {
- this.octStr = new DerOctetString(salt);
- this.iterationCount = new DerInteger(iterationCount);
- }
+ public class Pbkdf2Params
+ : Asn1Encodable
+ {
+ private static AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdHmacWithSha1, DerNull.Instance);
+
+ private readonly Asn1OctetString octStr;
+ private readonly DerInteger iterationCount, keyLength;
+ private readonly AlgorithmIdentifier prf;
+
+ public static Pbkdf2Params GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Pbkdf2Params)
+ return (Pbkdf2Params)obj;
+
+ if (obj is Asn1Sequence)
+ return new Pbkdf2Params((Asn1Sequence)obj);
+
+ throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+ }
+
+ public Pbkdf2Params(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 2 || seq.Count > 4)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.octStr = (Asn1OctetString)seq[0];
+ this.iterationCount = (DerInteger)seq[1];
+
+ Asn1Encodable kl = null, d = null;
+ if (seq.Count > 3)
+ {
+ kl = seq[2];
+ d = seq[3];
+ }
+ else if (seq.Count > 2)
+ {
+ if (seq[2] is DerInteger)
+ {
+ kl = seq[2];
+ }
+ else
+ {
+ d = seq[2];
+ }
+ }
+ if (kl != null)
+ {
+ keyLength = (DerInteger)kl;
+ }
+ if (d != null)
+ {
+ prf = AlgorithmIdentifier.GetInstance(d);
+ }
+ }
+
+ public Pbkdf2Params(
+ byte[] salt,
+ int iterationCount)
+ {
+ this.octStr = new DerOctetString(salt);
+ this.iterationCount = new DerInteger(iterationCount);
+ }
public Pbkdf2Params(
byte[] salt,
@@ -55,32 +78,65 @@ namespace Org.BouncyCastle.Asn1.Pkcs
this.keyLength = new DerInteger(keyLength);
}
- public byte[] GetSalt()
- {
- return octStr.GetOctets();
- }
-
- public BigInteger IterationCount
- {
- get { return iterationCount.Value; }
- }
-
- public BigInteger KeyLength
- {
- get { return keyLength == null ? null : keyLength.Value; }
- }
-
- public override Asn1Object ToAsn1Object()
- {
- Asn1EncodableVector v = new Asn1EncodableVector(
- octStr, iterationCount);
-
- if (keyLength != null)
- {
- v.Add(keyLength);
- }
-
- return new DerSequence(v);
- }
- }
+ public Pbkdf2Params(
+ byte[] salt,
+ int iterationCount,
+ int keyLength,
+ AlgorithmIdentifier prf)
+ : this(salt, iterationCount, keyLength)
+ {
+ this.prf = prf;
+ }
+
+ public Pbkdf2Params(
+ byte[] salt,
+ int iterationCount,
+ AlgorithmIdentifier prf)
+ : this(salt, iterationCount)
+ {
+ this.prf = prf;
+ }
+
+ public byte[] GetSalt()
+ {
+ return octStr.GetOctets();
+ }
+
+ public BigInteger IterationCount
+ {
+ get { return iterationCount.Value; }
+ }
+
+ public BigInteger KeyLength
+ {
+ get { return keyLength == null ? null : keyLength.Value; }
+ }
+
+ public bool IsDefaultPrf
+ {
+ get { return prf == null || prf.Equals(algid_hmacWithSHA1); }
+ }
+
+ public AlgorithmIdentifier Prf
+ {
+ get { return prf != null ? prf : algid_hmacWithSHA1; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ octStr, iterationCount);
+
+ if (keyLength != null)
+ {
+ v.Add(keyLength);
+ }
+ if (!IsDefaultPrf)
+ {
+ v.Add(prf);
+ }
+
+ return new DerSequence(v);
+ }
+ }
}
diff --git a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
index 91b6fb456..404277ba6 100644
--- a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
+++ b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
@@ -10,46 +10,46 @@ namespace Org.BouncyCastle.Asn1.Pkcs
public class PrivateKeyInfo
: Asn1Encodable
{
- private readonly Asn1Object privKey;
+ private readonly Asn1OctetString privKey;
private readonly AlgorithmIdentifier algID;
- private readonly Asn1Set attributes;
+ private readonly Asn1Set attributes;
- public static PrivateKeyInfo GetInstance(
- object obj)
- {
- if (obj is PrivateKeyInfo)
- return (PrivateKeyInfo) obj;
+ public static PrivateKeyInfo GetInstance(Asn1TaggedObject obj, bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
- if (obj != null)
- return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
+ public static PrivateKeyInfo GetInstance(
+ object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is PrivateKeyInfo)
+ return (PrivateKeyInfo) obj;
+ return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
+ }
- return null;
- }
+ public PrivateKeyInfo(AlgorithmIdentifier algID, Asn1Object privateKey)
+ : this(algID, privateKey, null)
+ {
+ }
- public PrivateKeyInfo(
+ public PrivateKeyInfo(
AlgorithmIdentifier algID,
- Asn1Object privateKey)
- : this(algID, privateKey, null)
- {
- }
-
- public PrivateKeyInfo(
- AlgorithmIdentifier algID,
- Asn1Object privateKey,
- Asn1Set attributes)
- {
- this.privKey = privateKey;
- this.algID = algID;
- this.attributes = attributes;
- }
-
- private PrivateKeyInfo(
- Asn1Sequence seq)
+ Asn1Object privateKey,
+ Asn1Set attributes)
+ {
+ this.algID = algID;
+ this.privKey = new DerOctetString(privateKey.GetEncoded(Asn1Encodable.Der));
+ this.attributes = attributes;
+ }
+
+ private PrivateKeyInfo(Asn1Sequence seq)
{
IEnumerator e = seq.GetEnumerator();
- e.MoveNext();
- BigInteger version = ((DerInteger) e.Current).Value;
+ e.MoveNext();
+ BigInteger version = ((DerInteger)e.Current).Value;
if (version.IntValue != 0)
{
throw new ArgumentException("wrong version for private key info: " + version.IntValue);
@@ -57,41 +57,53 @@ namespace Org.BouncyCastle.Asn1.Pkcs
e.MoveNext();
algID = AlgorithmIdentifier.GetInstance(e.Current);
+ e.MoveNext();
+ privKey = Asn1OctetString.GetInstance(e.Current);
- try
- {
- e.MoveNext();
- Asn1OctetString data = (Asn1OctetString) e.Current;
-
- privKey = Asn1Object.FromByteArray(data.GetOctets());
- }
- catch (IOException)
+ if (e.MoveNext())
{
- throw new ArgumentException("Error recoverying private key from sequence");
+ attributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false);
}
+ }
- if (e.MoveNext())
- {
- attributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false);
- }
- }
+ public virtual AlgorithmIdentifier PrivateKeyAlgorithm
+ {
+ get { return algID; }
+ }
- public AlgorithmIdentifier AlgorithmID
- {
- get { return algID; }
- }
+ [Obsolete("Use 'PrivateKeyAlgorithm' property instead")]
+ public virtual AlgorithmIdentifier AlgorithmID
+ {
+ get { return algID; }
+ }
- public Asn1Object PrivateKey
- {
- get { return privKey; }
- }
+ public virtual Asn1Object ParsePrivateKey()
+ {
+ return Asn1Object.FromByteArray(privKey.GetOctets());
+ }
- public Asn1Set Attributes
- {
- get { return attributes; }
- }
+ [Obsolete("Use 'ParsePrivateKey' instead")]
+ public virtual Asn1Object PrivateKey
+ {
+ get
+ {
+ try
+ {
+ return ParsePrivateKey();
+ }
+ catch (IOException)
+ {
+ throw new InvalidOperationException("unable to parse private key");
+ }
+ }
+ }
- /**
+ public virtual Asn1Set Attributes
+ {
+ get { return attributes; }
+ }
+
+ /**
* write out an RSA private key with its associated information
* as described in Pkcs8.
* <pre>
@@ -110,17 +122,14 @@ namespace Org.BouncyCastle.Asn1.Pkcs
*/
public override Asn1Object ToAsn1Object()
{
- Asn1EncodableVector v = new Asn1EncodableVector(
- new DerInteger(0),
- algID,
- new DerOctetString(privKey));
+ Asn1EncodableVector v = new Asn1EncodableVector(new DerInteger(0), algID, privKey);
- if (attributes != null)
- {
- v.Add(new DerTaggedObject(false, 0, attributes));
- }
+ if (attributes != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, attributes));
+ }
- return new DerSequence(v);
+ return new DerSequence(v);
}
}
}
diff --git a/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs b/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
index dbb07c744..721299105 100644
--- a/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
+++ b/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
@@ -18,7 +18,21 @@ namespace Org.BouncyCastle.Asn1.Pkcs
private readonly BigInteger exponent2;
private readonly BigInteger coefficient;
- public RsaPrivateKeyStructure(
+ public static RsaPrivateKeyStructure GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ public static RsaPrivateKeyStructure GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is RsaPrivateKeyStructure)
+ return (RsaPrivateKeyStructure)obj;
+ return new RsaPrivateKeyStructure(Asn1Sequence.GetInstance(obj));
+ }
+
+ public RsaPrivateKeyStructure(
BigInteger modulus,
BigInteger publicExponent,
BigInteger privateExponent,
@@ -38,64 +52,65 @@ namespace Org.BouncyCastle.Asn1.Pkcs
this.coefficient = coefficient;
}
- public RsaPrivateKeyStructure(
+ [Obsolete("Use 'GetInstance' method(s) instead")]
+ public RsaPrivateKeyStructure(
Asn1Sequence seq)
{
- BigInteger version = ((DerInteger) seq[0]).Value;
- if (version.IntValue != 0)
+ BigInteger version = ((DerInteger) seq[0]).Value;
+ if (version.IntValue != 0)
throw new ArgumentException("wrong version for RSA private key");
- modulus = ((DerInteger) seq[1]).Value;
- publicExponent = ((DerInteger) seq[2]).Value;
- privateExponent = ((DerInteger) seq[3]).Value;
- prime1 = ((DerInteger) seq[4]).Value;
- prime2 = ((DerInteger) seq[5]).Value;
- exponent1 = ((DerInteger) seq[6]).Value;
- exponent2 = ((DerInteger) seq[7]).Value;
- coefficient = ((DerInteger) seq[8]).Value;
- }
-
- public BigInteger Modulus
- {
- get { return modulus; }
- }
-
- public BigInteger PublicExponent
- {
- get { return publicExponent; }
- }
-
- public BigInteger PrivateExponent
- {
- get { return privateExponent; }
- }
-
- public BigInteger Prime1
- {
- get { return prime1; }
- }
-
- public BigInteger Prime2
- {
- get { return prime2; }
- }
-
- public BigInteger Exponent1
- {
- get { return exponent1; }
- }
-
- public BigInteger Exponent2
- {
- get { return exponent2; }
- }
-
- public BigInteger Coefficient
- {
- get { return coefficient; }
- }
-
- /**
+ modulus = ((DerInteger) seq[1]).Value;
+ publicExponent = ((DerInteger) seq[2]).Value;
+ privateExponent = ((DerInteger) seq[3]).Value;
+ prime1 = ((DerInteger) seq[4]).Value;
+ prime2 = ((DerInteger) seq[5]).Value;
+ exponent1 = ((DerInteger) seq[6]).Value;
+ exponent2 = ((DerInteger) seq[7]).Value;
+ coefficient = ((DerInteger) seq[8]).Value;
+ }
+
+ public BigInteger Modulus
+ {
+ get { return modulus; }
+ }
+
+ public BigInteger PublicExponent
+ {
+ get { return publicExponent; }
+ }
+
+ public BigInteger PrivateExponent
+ {
+ get { return privateExponent; }
+ }
+
+ public BigInteger Prime1
+ {
+ get { return prime1; }
+ }
+
+ public BigInteger Prime2
+ {
+ get { return prime2; }
+ }
+
+ public BigInteger Exponent1
+ {
+ get { return exponent1; }
+ }
+
+ public BigInteger Exponent2
+ {
+ get { return exponent2; }
+ }
+
+ public BigInteger Coefficient
+ {
+ get { return coefficient; }
+ }
+
+ /**
* This outputs the key in Pkcs1v2 format.
* <pre>
* RsaPrivateKey ::= Sequence {
@@ -116,16 +131,16 @@ namespace Org.BouncyCastle.Asn1.Pkcs
*/
public override Asn1Object ToAsn1Object()
{
- return new DerSequence(
- new DerInteger(0), // version
- new DerInteger(Modulus),
- new DerInteger(PublicExponent),
- new DerInteger(PrivateExponent),
- new DerInteger(Prime1),
- new DerInteger(Prime2),
- new DerInteger(Exponent1),
- new DerInteger(Exponent2),
- new DerInteger(Coefficient));
+ return new DerSequence(
+ new DerInteger(0), // version
+ new DerInteger(Modulus),
+ new DerInteger(PublicExponent),
+ new DerInteger(PrivateExponent),
+ new DerInteger(Prime1),
+ new DerInteger(Prime2),
+ new DerInteger(Exponent1),
+ new DerInteger(Exponent2),
+ new DerInteger(Coefficient));
}
}
}
diff --git a/crypto/src/asn1/sec/ECPrivateKeyStructure.cs b/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
index 2e9c27fd2..8d805fa30 100644
--- a/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
+++ b/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
@@ -6,113 +6,121 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Asn1.Sec
{
- /**
- * the elliptic curve private key object from SEC 1
- */
- public class ECPrivateKeyStructure
- : Asn1Encodable
- {
- private readonly Asn1Sequence seq;
-
- public ECPrivateKeyStructure(
- Asn1Sequence seq)
- {
- if (seq == null)
- throw new ArgumentNullException("seq");
-
- this.seq = seq;
- }
-
- public ECPrivateKeyStructure(
- BigInteger key)
- {
- if (key == null)
- throw new ArgumentNullException("key");
-
- this.seq = new DerSequence(
- new DerInteger(1),
- new DerOctetString(key.ToByteArrayUnsigned()));
- }
-
- public ECPrivateKeyStructure(
- BigInteger key,
- Asn1Encodable parameters)
- : this(key, null, parameters)
- {
- }
-
- public ECPrivateKeyStructure(
- BigInteger key,
- DerBitString publicKey,
- Asn1Encodable parameters)
- {
- if (key == null)
- throw new ArgumentNullException("key");
-
- Asn1EncodableVector v = new Asn1EncodableVector(
- new DerInteger(1),
- new DerOctetString(key.ToByteArrayUnsigned()));
-
- if (parameters != null)
- {
- v.Add(new DerTaggedObject(true, 0, parameters));
- }
-
- if (publicKey != null)
- {
- v.Add(new DerTaggedObject(true, 1, publicKey));
- }
-
- this.seq = new DerSequence(v);
- }
-
- public BigInteger GetKey()
- {
- Asn1OctetString octs = (Asn1OctetString) seq[1];
-
- return new BigInteger(1, octs.GetOctets());
- }
-
- public DerBitString GetPublicKey()
- {
- return (DerBitString) GetObjectInTag(1);
- }
-
- public Asn1Object GetParameters()
- {
- return GetObjectInTag(0);
- }
-
- private Asn1Object GetObjectInTag(
- int tagNo)
- {
- foreach (Asn1Encodable ae in seq)
- {
- Asn1Object obj = ae.ToAsn1Object();
-
- if (obj is Asn1TaggedObject)
- {
- Asn1TaggedObject tag = (Asn1TaggedObject) obj;
- if (tag.TagNo == tagNo)
- {
- return tag.GetObject();
- }
- }
- }
-
- return null;
- }
-
- /**
- * ECPrivateKey ::= SEQUENCE {
- * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
- * privateKey OCTET STRING,
- * parameters [0] Parameters OPTIONAL,
- * publicKey [1] BIT STRING OPTIONAL }
- */
- public override Asn1Object ToAsn1Object()
- {
- return seq;
- }
- }
+ /**
+ * the elliptic curve private key object from SEC 1
+ */
+ public class ECPrivateKeyStructure
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence seq;
+
+ public static ECPrivateKeyStructure GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is ECPrivateKeyStructure)
+ return (ECPrivateKeyStructure)obj;
+ return new ECPrivateKeyStructure(Asn1Sequence.GetInstance(obj));
+ }
+
+ public ECPrivateKeyStructure(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+
+ this.seq = seq;
+ }
+
+ public ECPrivateKeyStructure(
+ BigInteger key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+
+ this.seq = new DerSequence(
+ new DerInteger(1),
+ new DerOctetString(key.ToByteArrayUnsigned()));
+ }
+
+ public ECPrivateKeyStructure(
+ BigInteger key,
+ Asn1Encodable parameters)
+ : this(key, null, parameters)
+ {
+ }
+
+ public ECPrivateKeyStructure(
+ BigInteger key,
+ DerBitString publicKey,
+ Asn1Encodable parameters)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ new DerInteger(1),
+ new DerOctetString(key.ToByteArrayUnsigned()));
+
+ if (parameters != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, parameters));
+ }
+
+ if (publicKey != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, publicKey));
+ }
+
+ this.seq = new DerSequence(v);
+ }
+
+ public virtual BigInteger GetKey()
+ {
+ Asn1OctetString octs = (Asn1OctetString) seq[1];
+
+ return new BigInteger(1, octs.GetOctets());
+ }
+
+ public virtual DerBitString GetPublicKey()
+ {
+ return (DerBitString) GetObjectInTag(1);
+ }
+
+ public virtual Asn1Object GetParameters()
+ {
+ return GetObjectInTag(0);
+ }
+
+ private Asn1Object GetObjectInTag(int tagNo)
+ {
+ foreach (Asn1Encodable ae in seq)
+ {
+ Asn1Object obj = ae.ToAsn1Object();
+
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tag = (Asn1TaggedObject) obj;
+ if (tag.TagNo == tagNo)
+ {
+ return tag.GetObject();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] Parameters OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL }
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+ }
}
diff --git a/crypto/src/asn1/sec/SECNamedCurves.cs b/crypto/src/asn1/sec/SECNamedCurves.cs
index 7e2afbe6e..ca71a4e66 100644
--- a/crypto/src/asn1/sec/SECNamedCurves.cs
+++ b/crypto/src/asn1/sec/SECNamedCurves.cs
@@ -54,9 +54,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "09487239995A5EE76B55F9C2F098"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "09487239995A5EE76B55F9C2F098"
+ "A89CE5AF8724C0A23E0E0FF77500"));
@@ -85,9 +83,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(4);
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "4BA30AB5E892B4E1649DD0928643"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "4BA30AB5E892B4E1649DD0928643"
+ "ADCD46F5882E3747DEF36E956E97"));
@@ -116,9 +112,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "161FF7528B899B2D0C28607CA52C5B86"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "161FF7528B899B2D0C28607CA52C5B86"
+ "CF5AC8395BAFEB13C02DA292DDED7A83"));
@@ -147,9 +141,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(4);
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "7B6AA5D85E572983E6FB32A7CDEBC140"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "7B6AA5D85E572983E6FB32A7CDEBC140"
+ "27B6916A894D3AEE7106FE805FC34B44"));
@@ -186,14 +178,12 @@ namespace Org.BouncyCastle.Asn1.Sec
new BigInteger[]{
new BigInteger("127971af8721782ecffa3", 16),
new BigInteger("9162fbe73984472a0a9e", 16) },
- new BigInteger("48b17df39cc22395054e8", 16),
- new BigInteger("4b1a0f889c499de17a820", 16),
- 163);
+ new BigInteger("9162fbe73984472a0a9d0590", 16),
+ new BigInteger("96341f1138933bc2f503fd44", 16),
+ 176);
ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+ "938CF935318FDCED6BC28286531733C3F03C4FEE"));
@@ -222,9 +212,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "4A96B5688EF573284664698968C38BB913CBFC82"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "4A96B5688EF573284664698968C38BB913CBFC82"
+ "23A628553168947D59DCC912042351377AC5FB32"));
@@ -253,9 +241,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+ "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
@@ -292,14 +278,12 @@ namespace Org.BouncyCastle.Asn1.Sec
new BigInteger[]{
new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
new BigInteger("71169be7330b3038edb025f1", 16) },
- new BigInteger("1c45a6f9ccc2cc0e3b6c097c7", 16),
- new BigInteger("2cfecd0037b1712b73ae19575", 16),
- 194);
+ new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+ new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+ 208);
ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
@@ -328,9 +312,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
@@ -367,14 +349,12 @@ namespace Org.BouncyCastle.Asn1.Sec
new BigInteger[]{
new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
- new BigInteger("35c6783ea653ae444abeceb382c82", 16),
- new BigInteger("5c56f89bc5375b9a04fd364e31bdd", 16),
- 227);
+ new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+ new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+ 240);
ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+ "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
@@ -403,9 +383,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
@@ -442,14 +420,12 @@ namespace Org.BouncyCastle.Asn1.Sec
new BigInteger[]{
new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
- new BigInteger("c21b48869f51af37a1b243924a13ac55", 16),
- new BigInteger("3910dfb58043a20a1bd51fea42aff9311", 16),
- 258);
+ new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+ new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+ 272);
ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+ "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
@@ -478,9 +454,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
@@ -509,9 +483,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+ "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
@@ -540,9 +512,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.One;
ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+ "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
@@ -572,9 +542,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "009D73616F35F4AB1407D73562C10F"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "009D73616F35F4AB1407D73562C10F"
+ "00A52830277958EE84D1315ED31886"));
@@ -604,9 +572,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "01A57A6A7B26CA5EF52FCDB8164797"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "01A57A6A7B26CA5EF52FCDB8164797"
+ "00B3ADC94ED1FE674C06E695BABA1D"));
@@ -638,9 +604,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "0081BAF91FDF9833C40F9C181343638399"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "0081BAF91FDF9833C40F9C181343638399"
+ "078C6E7EA38C001F73C8134B1B4EF9E150"));
@@ -672,9 +636,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "0356DCD8F2F95031AD652D23951BB366A8"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "0356DCD8F2F95031AD652D23951BB366A8"
+ "0648F06D867940A5366D9E265DE9EB240F"));
@@ -706,9 +668,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+ "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
@@ -740,9 +700,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "0369979697AB43897789566789567F787A7876A654"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "0369979697AB43897789566789567F787A7876A654"
+ "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
@@ -774,9 +732,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+ "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
@@ -806,9 +762,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+ "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
@@ -838,9 +792,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+ "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
@@ -870,9 +822,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(4);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+ "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
@@ -902,9 +852,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+ "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
@@ -934,9 +882,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(4);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+ "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
@@ -968,9 +914,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(4);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+ "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
@@ -1002,9 +946,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+ "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
@@ -1034,9 +976,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(4);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+ "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
@@ -1066,9 +1006,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+ "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
@@ -1100,9 +1038,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(4);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("02"
- //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+ "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
@@ -1134,9 +1070,7 @@ namespace Org.BouncyCastle.Asn1.Sec
BigInteger h = BigInteger.ValueOf(2);
ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
- //ECPoint G = curve.DecodePoint(Hex.Decode("03"
- //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"));
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+ "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
@@ -1154,7 +1088,7 @@ namespace Org.BouncyCastle.Asn1.Sec
DerObjectIdentifier oid,
X9ECParametersHolder holder)
{
- objIds.Add(name, oid);
+ objIds.Add(Platform.ToLowerInvariant(name), oid);
names.Add(oid, name);
curves.Add(oid, holder);
}
@@ -1200,9 +1134,7 @@ namespace Org.BouncyCastle.Asn1.Sec
public static X9ECParameters GetByName(
string name)
{
- DerObjectIdentifier oid = (DerObjectIdentifier)
- objIds[Platform.ToLowerInvariant(name)];
-
+ DerObjectIdentifier oid = GetOid(name);
return oid == null ? null : GetByOid(oid);
}
@@ -1215,8 +1147,7 @@ namespace Org.BouncyCastle.Asn1.Sec
public static X9ECParameters GetByOid(
DerObjectIdentifier oid)
{
- X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
return holder == null ? null : holder.Parameters;
}
@@ -1238,7 +1169,7 @@ namespace Org.BouncyCastle.Asn1.Sec
public static string GetName(
DerObjectIdentifier oid)
{
- return (string) names[oid];
+ return (string)names[oid];
}
/**
@@ -1247,7 +1178,7 @@ namespace Org.BouncyCastle.Asn1.Sec
*/
public static IEnumerable Names
{
- get { return new EnumerableProxy(objIds.Keys); }
+ get { return new EnumerableProxy(names.Values); }
}
}
}
diff --git a/crypto/src/asn1/smime/SMIMECapabilities.cs b/crypto/src/asn1/smime/SMIMECapabilities.cs
index ca3c3af7d..5fb67dde1 100644
--- a/crypto/src/asn1/smime/SMIMECapabilities.cs
+++ b/crypto/src/asn1/smime/SMIMECapabilities.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections;
using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
@@ -25,6 +26,11 @@ namespace Org.BouncyCastle.Asn1.Smime
/**
* encryption algorithms preferences
*/
+ public static readonly DerObjectIdentifier Aes256Cbc = NistObjectIdentifiers.IdAes256Cbc;
+ public static readonly DerObjectIdentifier Aes192Cbc = NistObjectIdentifiers.IdAes192Cbc;
+ public static readonly DerObjectIdentifier Aes128Cbc = NistObjectIdentifiers.IdAes128Cbc;
+ public static readonly DerObjectIdentifier IdeaCbc = new DerObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+ public static readonly DerObjectIdentifier Cast5Cbc = new DerObjectIdentifier("1.2.840.113533.7.66.10");
public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7");
public static readonly DerObjectIdentifier DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc;
public static readonly DerObjectIdentifier RC2Cbc = PkcsObjectIdentifiers.RC2Cbc;
diff --git a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
index 05060c109..ba3eda620 100644
--- a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
+++ b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G
+ new X9ECPoint(curve, Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G
n, h);
}
}
@@ -66,7 +66,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G
+ new X9ECPoint(curve, Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G
n, h);
}
}
@@ -91,7 +91,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G
+ new X9ECPoint(curve, Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G
n, h);
}
}
@@ -117,7 +117,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G'
+ new X9ECPoint(curve, Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G'
n, h);
}
}
@@ -142,7 +142,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G
+ new X9ECPoint(curve, Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G
n, h);
}
}
@@ -168,7 +168,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G'
+ new X9ECPoint(curve, Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G'
n, h);
}
}
@@ -193,7 +193,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G
+ new X9ECPoint(curve, Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G
n, h);
}
}
@@ -219,7 +219,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G'
+ new X9ECPoint(curve, Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G'
n, h);
}
}
@@ -244,7 +244,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G
+ new X9ECPoint(curve, Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G
n, h);
}
}
@@ -270,7 +270,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G'
+ new X9ECPoint(curve, Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G'
n, h);
}
}
@@ -295,7 +295,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G
+ new X9ECPoint(curve, Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G
n, h);
}
}
@@ -321,7 +321,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G'
+ new X9ECPoint(curve, Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G'
n, h);
}
}
@@ -346,7 +346,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G
+ new X9ECPoint(curve, Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G
n, h);
}
}
@@ -372,7 +372,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
return new X9ECParameters(
curve,
- curve.DecodePoint(Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G'
+ new X9ECPoint(curve, Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G'
n, h);
}
}
@@ -387,35 +387,33 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
DerObjectIdentifier oid,
X9ECParametersHolder holder)
{
- objIds.Add(name, oid);
+ objIds.Add(Platform.ToLowerInvariant(name), oid);
names.Add(oid, name);
curves.Add(oid, holder);
}
static TeleTrusTNamedCurves()
{
- DefineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance);
- DefineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance);
- DefineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance);
- DefineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance);
- DefineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance);
- DefineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance);
- DefineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance);
- DefineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance);
- DefineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance);
- DefineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance);
- DefineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance);
- DefineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance);
- DefineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance);
- DefineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance);
+ DefineCurve("brainpoolP160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance);
+ DefineCurve("brainpoolP160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance);
+ DefineCurve("brainpoolP192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance);
+ DefineCurve("brainpoolP192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance);
+ DefineCurve("brainpoolP224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance);
+ DefineCurve("brainpoolP224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance);
+ DefineCurve("brainpoolP256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance);
+ DefineCurve("brainpoolP256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance);
+ DefineCurve("brainpoolP320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance);
+ DefineCurve("brainpoolP320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance);
+ DefineCurve("brainpoolP384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance);
+ DefineCurve("brainpoolP384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance);
+ DefineCurve("brainpoolP512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance);
+ DefineCurve("brainpoolP512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance);
}
public static X9ECParameters GetByName(
string name)
{
- DerObjectIdentifier oid = (DerObjectIdentifier)
- objIds[Platform.ToLowerInvariant(name)];
-
+ DerObjectIdentifier oid = GetOid(name);
return oid == null ? null : GetByOid(oid);
}
@@ -428,8 +426,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
public static X9ECParameters GetByOid(
DerObjectIdentifier oid)
{
- X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
return holder == null ? null : holder.Parameters;
}
@@ -451,17 +448,16 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
public static string GetName(
DerObjectIdentifier oid)
{
- return (string) names[oid];
+ return (string)names[oid];
}
-
/**
* returns an enumeration containing the name strings for curves
* contained in this structure.
*/
public static IEnumerable Names
{
- get { return new EnumerableProxy(objIds.Keys); }
+ get { return new EnumerableProxy(names.Values); }
}
public static DerObjectIdentifier GetOid(
diff --git a/crypto/src/asn1/util/FilterStream.cs b/crypto/src/asn1/util/FilterStream.cs
index 2b0494b78..980e7f176 100644
--- a/crypto/src/asn1/util/FilterStream.cs
+++ b/crypto/src/asn1/util/FilterStream.cs
@@ -3,8 +3,10 @@ using System.IO;
namespace Org.BouncyCastle.Asn1.Utilities
{
+ [Obsolete("Use Org.BouncyCastle.Utilities.IO.FilterStream")]
public class FilterStream : Stream
{
+ [Obsolete("Use Org.BouncyCastle.Utilities.IO.FilterStream")]
public FilterStream(Stream s)
{
this.s = s;
diff --git a/crypto/src/asn1/x509/AlgorithmIdentifier.cs b/crypto/src/asn1/x509/AlgorithmIdentifier.cs
index 4ed3a400d..c6f4af5bf 100644
--- a/crypto/src/asn1/x509/AlgorithmIdentifier.cs
+++ b/crypto/src/asn1/x509/AlgorithmIdentifier.cs
@@ -69,11 +69,22 @@ namespace Org.BouncyCastle.Asn1.X509
}
}
+ /// <summary>
+ /// Return the OID in the Algorithm entry of this identifier.
+ /// </summary>
+ public virtual DerObjectIdentifier Algorithm
+ {
+ get { return objectID; }
+ }
+
public virtual DerObjectIdentifier ObjectID
{
get { return objectID; }
}
+ /// <summary>
+ /// Return the parameters structure in the Parameters entry of this identifier.
+ /// </summary>
public Asn1Encodable Parameters
{
get { return parameters; }
diff --git a/crypto/src/asn1/x509/ExtendedKeyUsage.cs b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
index b5e4b7f8d..a5b11f210 100644
--- a/crypto/src/asn1/x509/ExtendedKeyUsage.cs
+++ b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
@@ -17,14 +17,14 @@ namespace Org.BouncyCastle.Asn1.X509
internal readonly IDictionary usageTable = Platform.CreateHashtable();
internal readonly Asn1Sequence seq;
- public static ExtendedKeyUsage GetInstance(
+ public static ExtendedKeyUsage GetInstance(
Asn1TaggedObject obj,
bool explicitly)
{
return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
}
- public static ExtendedKeyUsage GetInstance(
+ public static ExtendedKeyUsage GetInstance(
object obj)
{
if (obj is ExtendedKeyUsage)
@@ -32,43 +32,43 @@ namespace Org.BouncyCastle.Asn1.X509
return (ExtendedKeyUsage) obj;
}
- if (obj is Asn1Sequence)
+ if (obj is Asn1Sequence)
{
return new ExtendedKeyUsage((Asn1Sequence) obj);
}
- if (obj is X509Extension)
- {
- return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
- }
+ if (obj is X509Extension)
+ {
+ return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+ }
- throw new ArgumentException("Invalid ExtendedKeyUsage: " + obj.GetType().Name);
+ throw new ArgumentException("Invalid ExtendedKeyUsage: " + obj.GetType().Name);
}
- private ExtendedKeyUsage(
+ private ExtendedKeyUsage(
Asn1Sequence seq)
{
this.seq = seq;
- foreach (object o in seq)
- {
- if (!(o is DerObjectIdentifier))
- throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage.");
+ foreach (object o in seq)
+ {
+ if (!(o is DerObjectIdentifier))
+ throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage.");
- this.usageTable.Add(o, o);
+ this.usageTable[o] = o;
}
}
- public ExtendedKeyUsage(
- params KeyPurposeID[] usages)
- {
- this.seq = new DerSequence(usages);
+ public ExtendedKeyUsage(
+ params KeyPurposeID[] usages)
+ {
+ this.seq = new DerSequence(usages);
- foreach (KeyPurposeID usage in usages)
- {
- this.usageTable.Add(usage, usage);
- }
- }
+ foreach (KeyPurposeID usage in usages)
+ {
+ this.usageTable[usage] = usage;
+ }
+ }
#if !SILVERLIGHT
[Obsolete]
@@ -84,20 +84,21 @@ namespace Org.BouncyCastle.Asn1.X509
{
Asn1EncodableVector v = new Asn1EncodableVector();
- foreach (Asn1Object o in usages)
+ foreach (object usage in usages)
{
- v.Add(o);
+ Asn1Encodable o = KeyPurposeID.GetInstance(usage);
- this.usageTable.Add(o, o);
+ v.Add(o);
+ this.usageTable[o] = o;
}
- this.seq = new DerSequence(v);
+ this.seq = new DerSequence(v);
}
- public bool HasKeyPurposeId(
+ public bool HasKeyPurposeId(
KeyPurposeID keyPurposeId)
{
- return usageTable[keyPurposeId] != null;
+ return usageTable.Contains(keyPurposeId);
}
#if !SILVERLIGHT
@@ -109,21 +110,21 @@ namespace Org.BouncyCastle.Asn1.X509
#endif
/**
- * Returns all extended key usages.
- * The returned ArrayList contains DerObjectIdentifier instances.
- * @return An ArrayList with all key purposes.
- */
- public IList GetAllUsages()
- {
- return Platform.CreateArrayList(usageTable.Values);
- }
+ * Returns all extended key usages.
+ * The returned ArrayList contains DerObjectIdentifier instances.
+ * @return An ArrayList with all key purposes.
+ */
+ public IList GetAllUsages()
+ {
+ return Platform.CreateArrayList(usageTable.Values);
+ }
public int Count
- {
- get { return usageTable.Count; }
- }
+ {
+ get { return usageTable.Count; }
+ }
- public override Asn1Object ToAsn1Object()
+ public override Asn1Object ToAsn1Object()
{
return seq;
}
diff --git a/crypto/src/asn1/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs
index 0030d376b..92d4393a8 100644
--- a/crypto/src/asn1/x9/ECNamedCurveTable.cs
+++ b/crypto/src/asn1/x9/ECNamedCurveTable.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
+using Org.BouncyCastle.Asn1.Anssi;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.TeleTrust;
@@ -32,17 +33,44 @@ namespace Org.BouncyCastle.Asn1.X9
if (ecP == null)
{
+ ecP = NistNamedCurves.GetByName(name);
+ }
+
+ if (ecP == null)
+ {
ecP = TeleTrusTNamedCurves.GetByName(name);
}
if (ecP == null)
{
- ecP = NistNamedCurves.GetByName(name);
+ ecP = AnssiNamedCurves.GetByName(name);
}
return ecP;
}
+ public static string GetName(DerObjectIdentifier oid)
+ {
+ string name = X962NamedCurves.GetName(oid);
+ if (name == null)
+ {
+ name = SecNamedCurves.GetName(oid);
+ }
+ if (name == null)
+ {
+ name = NistNamedCurves.GetName(oid);
+ }
+ if (name == null)
+ {
+ name = TeleTrusTNamedCurves.GetName(oid);
+ }
+ if (name == null)
+ {
+ name = AnssiNamedCurves.GetName(oid);
+ }
+ return name;
+ }
+
/**
* return the object identifier signified by the passed in name. Null
* if there is no object identifier associated with name.
@@ -60,12 +88,17 @@ namespace Org.BouncyCastle.Asn1.X9
if (oid == null)
{
+ oid = NistNamedCurves.GetOid(name);
+ }
+
+ if (oid == null)
+ {
oid = TeleTrusTNamedCurves.GetOid(name);
}
if (oid == null)
{
- oid = NistNamedCurves.GetOid(name);
+ oid = AnssiNamedCurves.GetOid(name);
}
return oid;
@@ -87,12 +120,17 @@ namespace Org.BouncyCastle.Asn1.X9
ecP = SecNamedCurves.GetByOid(oid);
}
+ // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+
if (ecP == null)
{
ecP = TeleTrusTNamedCurves.GetByOid(oid);
}
- // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+ if (ecP == null)
+ {
+ ecP = AnssiNamedCurves.GetByOid(oid);
+ }
return ecP;
}
@@ -111,6 +149,7 @@ namespace Org.BouncyCastle.Asn1.X9
CollectionUtilities.AddRange(v, SecNamedCurves.Names);
CollectionUtilities.AddRange(v, NistNamedCurves.Names);
CollectionUtilities.AddRange(v, TeleTrusTNamedCurves.Names);
+ CollectionUtilities.AddRange(v, AnssiNamedCurves.Names);
return v;
}
}
diff --git a/crypto/src/asn1/x9/X962NamedCurves.cs b/crypto/src/asn1/x9/X962NamedCurves.cs
index 6b76c4eb4..6fa4e7c4b 100644
--- a/crypto/src/asn1/x9/X962NamedCurves.cs
+++ b/crypto/src/asn1/x9/X962NamedCurves.cs
@@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
cFp192v1,
- cFp192v1.DecodePoint(
+ new X9ECPoint(cFp192v1,
Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")),
n, h,
Hex.Decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
@@ -65,7 +65,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
cFp192v2,
- cFp192v2.DecodePoint(
+ new X9ECPoint(cFp192v2,
Hex.Decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")),
n, h,
Hex.Decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
@@ -92,7 +92,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
cFp192v3,
- cFp192v3.DecodePoint(
+ new X9ECPoint(cFp192v3,
Hex.Decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")),
n, h,
Hex.Decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
@@ -119,7 +119,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
cFp239v1,
- cFp239v1.DecodePoint(
+ new X9ECPoint(cFp239v1,
Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")),
n, h,
Hex.Decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
@@ -146,7 +146,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
cFp239v2,
- cFp239v2.DecodePoint(
+ new X9ECPoint(cFp239v2,
Hex.Decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")),
n, h,
Hex.Decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
@@ -173,7 +173,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
cFp239v3,
- cFp239v3.DecodePoint(
+ new X9ECPoint(cFp239v3,
Hex.Decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")),
n, h,
Hex.Decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
@@ -200,7 +200,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
cFp256v1,
- cFp256v1.DecodePoint(
+ new X9ECPoint(cFp256v1,
Hex.Decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")),
n, h,
Hex.Decode("c49d360886e704936a6678e1139d26b7819f7e90"));
@@ -231,7 +231,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m163v1,
- c2m163v1.DecodePoint(
+ new X9ECPoint(c2m163v1,
Hex.Decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
n, h,
Hex.Decode("D2C0FB15760860DEF1EEF4D696E6768756151754"));
@@ -259,7 +259,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m163v2,
- c2m163v2.DecodePoint(
+ new X9ECPoint(c2m163v2,
Hex.Decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
n, h,
null);
@@ -287,7 +287,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m163v3,
- c2m163v3.DecodePoint(Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
+ new X9ECPoint(c2m163v3, Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
n, h,
null);
}
@@ -314,7 +314,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m176w1,
- c2m176w1.DecodePoint(
+ new X9ECPoint(c2m176w1,
Hex.Decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
n, h,
null);
@@ -342,7 +342,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m191v1,
- c2m191v1.DecodePoint(
+ new X9ECPoint(c2m191v1,
Hex.Decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
n, h,
Hex.Decode("4E13CA542744D696E67687561517552F279A8C84"));
@@ -370,7 +370,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m191v2,
- c2m191v2.DecodePoint(
+ new X9ECPoint(c2m191v2,
Hex.Decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
n, h,
null);
@@ -398,7 +398,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m191v3,
- c2m191v3.DecodePoint(
+ new X9ECPoint(c2m191v3,
Hex.Decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
n, h,
null);
@@ -426,7 +426,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m208w1,
- c2m208w1.DecodePoint(
+ new X9ECPoint(c2m208w1,
Hex.Decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
n, h,
null);
@@ -454,7 +454,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m239v1,
- c2m239v1.DecodePoint(
+ new X9ECPoint(c2m239v1,
Hex.Decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
n, h,
null);
@@ -482,7 +482,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m239v2,
- c2m239v2.DecodePoint(
+ new X9ECPoint(c2m239v2,
Hex.Decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
n, h,
null);
@@ -510,7 +510,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m239v3,
- c2m239v3.DecodePoint(
+ new X9ECPoint(c2m239v3,
Hex.Decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
n, h,
null);
@@ -538,7 +538,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m272w1,
- c2m272w1.DecodePoint(
+ new X9ECPoint(c2m272w1,
Hex.Decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
n, h,
null);
@@ -566,7 +566,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m304w1,
- c2m304w1.DecodePoint(
+ new X9ECPoint(c2m304w1,
Hex.Decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
n, h,
null);
@@ -594,7 +594,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m359v1,
- c2m359v1.DecodePoint(
+ new X9ECPoint(c2m359v1,
Hex.Decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
n, h,
null);
@@ -622,7 +622,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m368w1,
- c2m368w1.DecodePoint(
+ new X9ECPoint(c2m368w1,
Hex.Decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
n, h,
null);
@@ -650,7 +650,7 @@ namespace Org.BouncyCastle.Asn1.X9
return new X9ECParameters(
c2m431r1,
- c2m431r1.DecodePoint(
+ new X9ECPoint(c2m431r1,
Hex.Decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
n, h,
null);
@@ -666,7 +666,7 @@ namespace Org.BouncyCastle.Asn1.X9
DerObjectIdentifier oid,
X9ECParametersHolder holder)
{
- objIds.Add(name, oid);
+ objIds.Add(Platform.ToLowerInvariant(name), oid);
names.Add(oid, name);
curves.Add(oid, holder);
}
@@ -701,8 +701,7 @@ namespace Org.BouncyCastle.Asn1.X9
public static X9ECParameters GetByName(
string name)
{
- DerObjectIdentifier oid = (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)];
-
+ DerObjectIdentifier oid = GetOid(name);
return oid == null ? null : GetByOid(oid);
}
@@ -715,8 +714,7 @@ namespace Org.BouncyCastle.Asn1.X9
public static X9ECParameters GetByOid(
DerObjectIdentifier oid)
{
- X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
return holder == null ? null : holder.Parameters;
}
@@ -738,7 +736,7 @@ namespace Org.BouncyCastle.Asn1.X9
public static string GetName(
DerObjectIdentifier oid)
{
- return (string) names[oid];
+ return (string)names[oid];
}
/**
@@ -747,7 +745,7 @@ namespace Org.BouncyCastle.Asn1.X9
*/
public static IEnumerable Names
{
- get { return new EnumerableProxy(objIds.Keys); }
+ get { return new EnumerableProxy(names.Values); }
}
}
}
diff --git a/crypto/src/asn1/x9/X9ECParameters.cs b/crypto/src/asn1/x9/X9ECParameters.cs
index a192e4c52..2b6b14bcb 100644
--- a/crypto/src/asn1/x9/X9ECParameters.cs
+++ b/crypto/src/asn1/x9/X9ECParameters.cs
@@ -15,7 +15,7 @@ namespace Org.BouncyCastle.Asn1.X9
{
private X9FieldID fieldID;
private ECCurve curve;
- private ECPoint g;
+ private X9ECPoint g;
private BigInteger n;
private BigInteger h;
private byte[] seed;
@@ -29,36 +29,28 @@ namespace Org.BouncyCastle.Asn1.X9
throw new ArgumentException("bad version in X9ECParameters");
}
- X9Curve x9c = null;
- if (seq[2] is X9Curve)
- {
- x9c = (X9Curve) seq[2];
- }
- else
- {
- x9c = new X9Curve(
- new X9FieldID(
- (Asn1Sequence) seq[1]),
- (Asn1Sequence) seq[2]);
- }
+ X9Curve x9c = new X9Curve(
+ X9FieldID.GetInstance(seq[1]),
+ Asn1Sequence.GetInstance(seq[2]));
this.curve = x9c.Curve;
+ object p = seq[3];
- if (seq[3] is X9ECPoint)
+ if (p is X9ECPoint)
{
- this.g = ((X9ECPoint) seq[3]).Point;
+ this.g = ((X9ECPoint)p);
}
else
{
- this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point;
+ this.g = new X9ECPoint(curve, (Asn1OctetString)p);
}
- this.n = ((DerInteger) seq[4]).Value;
+ this.n = ((DerInteger)seq[4]).Value;
this.seed = x9c.GetSeed();
if (seq.Count == 6)
{
- this.h = ((DerInteger) seq[5]).Value;
+ this.h = ((DerInteger)seq[5]).Value;
}
}
@@ -66,7 +58,16 @@ namespace Org.BouncyCastle.Asn1.X9
ECCurve curve,
ECPoint g,
BigInteger n)
- : this(curve, g, n, BigInteger.One, null)
+ : this(curve, g, n, null, null)
+ {
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ X9ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ : this(curve, g, n, h, null)
{
}
@@ -85,9 +86,19 @@ namespace Org.BouncyCastle.Asn1.X9
BigInteger n,
BigInteger h,
byte[] seed)
+ : this(curve, new X9ECPoint(g), n, h, seed)
+ {
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ X9ECPoint g,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
{
this.curve = curve;
- this.g = g.Normalize();
+ this.g = g;
this.n = n;
this.h = h;
this.seed = seed;
@@ -126,7 +137,7 @@ namespace Org.BouncyCastle.Asn1.X9
public ECPoint G
{
- get { return g; }
+ get { return g.Point; }
}
public BigInteger N
@@ -136,16 +147,7 @@ namespace Org.BouncyCastle.Asn1.X9
public BigInteger H
{
- get
- {
- if (h == null)
- {
- // TODO - this should be calculated, it will cause issues with custom curves.
- return BigInteger.One;
- }
-
- return h;
- }
+ get { return h; }
}
public byte[] GetSeed()
@@ -154,6 +156,36 @@ namespace Org.BouncyCastle.Asn1.X9
}
/**
+ * Return the ASN.1 entry representing the Curve.
+ *
+ * @return the X9Curve for the curve in these parameters.
+ */
+ public X9Curve CurveEntry
+ {
+ get { return new X9Curve(curve, seed); }
+ }
+
+ /**
+ * Return the ASN.1 entry representing the FieldID.
+ *
+ * @return the X9FieldID for the FieldID in these parameters.
+ */
+ public X9FieldID FieldIDEntry
+ {
+ get { return fieldID; }
+ }
+
+ /**
+ * Return the ASN.1 entry representing the base point G.
+ *
+ * @return the X9ECPoint for the base point in these parameters.
+ */
+ public X9ECPoint BaseEntry
+ {
+ get { return g; }
+ }
+
+ /**
* Produce an object suitable for an Asn1OutputStream.
* <pre>
* ECParameters ::= Sequence {
@@ -169,10 +201,10 @@ namespace Org.BouncyCastle.Asn1.X9
public override Asn1Object ToAsn1Object()
{
Asn1EncodableVector v = new Asn1EncodableVector(
- new DerInteger(1),
+ new DerInteger(BigInteger.One),
fieldID,
new X9Curve(curve, seed),
- new X9ECPoint(g),
+ g,
new DerInteger(n));
if (h != null)
diff --git a/crypto/src/asn1/x9/X9ECParametersHolder.cs b/crypto/src/asn1/x9/X9ECParametersHolder.cs
index b3455709c..e802b738c 100644
--- a/crypto/src/asn1/x9/X9ECParametersHolder.cs
+++ b/crypto/src/asn1/x9/X9ECParametersHolder.cs
@@ -8,14 +8,17 @@ namespace Org.BouncyCastle.Asn1.X9
{
get
{
- if (parameters == null)
- {
- parameters = CreateParameters();
- }
+ lock (this)
+ {
+ if (parameters == null)
+ {
+ parameters = CreateParameters();
+ }
- return parameters;
- }
- }
+ return parameters;
+ }
+ }
+ }
protected abstract X9ECParameters CreateParameters();
}
diff --git a/crypto/src/asn1/x9/X9ECPoint.cs b/crypto/src/asn1/x9/X9ECPoint.cs
index 75d58cd38..7ef4f13bc 100644
--- a/crypto/src/asn1/x9/X9ECPoint.cs
+++ b/crypto/src/asn1/x9/X9ECPoint.cs
@@ -1,5 +1,7 @@
using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
namespace Org.BouncyCastle.Asn1.X9
{
/**
@@ -8,24 +10,58 @@ namespace Org.BouncyCastle.Asn1.X9
public class X9ECPoint
: Asn1Encodable
{
- private readonly ECPoint p;
+ private readonly Asn1OctetString encoding;
+
+ private ECCurve c;
+ private ECPoint p;
+
+ public X9ECPoint(ECPoint p)
+ : this(p, false)
+ {
+ }
- public X9ECPoint(
- ECPoint p)
+ public X9ECPoint(ECPoint p, bool compressed)
{
this.p = p.Normalize();
+ this.encoding = new DerOctetString(p.GetEncoded(compressed));
+ }
+
+ public X9ECPoint(ECCurve c, byte[] encoding)
+ {
+ this.c = c;
+ this.encoding = new DerOctetString(Arrays.Clone(encoding));
}
- public X9ECPoint(
- ECCurve c,
- Asn1OctetString s)
+ public X9ECPoint(ECCurve c, Asn1OctetString s)
+ : this(c, s.GetOctets())
{
- this.p = c.DecodePoint(s.GetOctets());
+ }
+
+ public byte[] GetPointEncoding()
+ {
+ return Arrays.Clone(encoding.GetOctets());
}
public ECPoint Point
{
- get { return p; }
+ get
+ {
+ if (p == null)
+ {
+ p = c.DecodePoint(encoding.GetOctets()).Normalize();
+ }
+
+ return p;
+ }
+ }
+
+ public bool IsPointCompressed
+ {
+ get
+ {
+ byte[] octets = encoding.GetOctets();
+ return octets != null && octets.Length > 0 && (octets[0] == 2 || octets[0] == 3);
+ }
}
/**
@@ -38,7 +74,7 @@ namespace Org.BouncyCastle.Asn1.X9
*/
public override Asn1Object ToAsn1Object()
{
- return new DerOctetString(p.GetEncoded());
+ return encoding;
}
}
}
diff --git a/crypto/src/asn1/x9/X9FieldID.cs b/crypto/src/asn1/x9/X9FieldID.cs
index 58823a285..08d7d71b4 100644
--- a/crypto/src/asn1/x9/X9FieldID.cs
+++ b/crypto/src/asn1/x9/X9FieldID.cs
@@ -90,11 +90,19 @@ namespace Org.BouncyCastle.Asn1.X9
this.parameters = new DerSequence(fieldIdParams);
}
- internal X9FieldID(
- Asn1Sequence seq)
+ private X9FieldID(Asn1Sequence seq)
{
- this.id = (DerObjectIdentifier) seq[0];
- this.parameters = (Asn1Object) seq[1];
+ this.id = DerObjectIdentifier.GetInstance(seq[0]);
+ this.parameters = seq[1].ToAsn1Object();
+ }
+
+ public static X9FieldID GetInstance(object obj)
+ {
+ if (obj is X9FieldID)
+ return (X9FieldID)obj;
+ if (obj == null)
+ return null;
+ return new X9FieldID(Asn1Sequence.GetInstance(obj));
}
public DerObjectIdentifier Identifier
diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs
index 3c69fbdf5..2e08cd090 100644
--- a/crypto/src/bcpg/BcpgInputStream.cs
+++ b/crypto/src/bcpg/BcpgInputStream.cs
@@ -105,19 +105,15 @@ namespace Org.BouncyCastle.Bcpg
next = true;
}
- if (nextB >= 0)
+ if (nextB < 0)
+ return (PacketTag)nextB;
+
+ int maskB = nextB & 0x3f;
+ if ((nextB & 0x40) == 0) // old
{
- if ((nextB & 0x40) != 0) // new
- {
- return (PacketTag)(nextB & 0x3f);
- }
- else // old
- {
- return (PacketTag)((nextB & 0x3f) >> 2);
- }
+ maskB >>= 2;
}
-
- return (PacketTag) nextB;
+ return (PacketTag)maskB;
}
public Packet ReadPacket()
diff --git a/crypto/src/bcpg/DsaPublicBcpgKey.cs b/crypto/src/bcpg/DsaPublicBcpgKey.cs
index 61159567c..11294cc22 100644
--- a/crypto/src/bcpg/DsaPublicBcpgKey.cs
+++ b/crypto/src/bcpg/DsaPublicBcpgKey.cs
@@ -4,46 +4,46 @@ using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
- /// <remarks>Base class for a DSA public key.</remarks>
- public class DsaPublicBcpgKey
- : BcpgObject, IBcpgKey
+ /// <remarks>Base class for a DSA public key.</remarks>
+ public class DsaPublicBcpgKey
+ : BcpgObject, IBcpgKey
{
private readonly MPInteger p, q, g, y;
- /// <param name="bcpgIn">The stream to read the packet from.</param>
- public DsaPublicBcpgKey(
- BcpgInputStream bcpgIn)
- {
- this.p = new MPInteger(bcpgIn);
- this.q = new MPInteger(bcpgIn);
- this.g = new MPInteger(bcpgIn);
- this.y = new MPInteger(bcpgIn);
- }
+ /// <param name="bcpgIn">The stream to read the packet from.</param>
+ public DsaPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.p = new MPInteger(bcpgIn);
+ this.q = new MPInteger(bcpgIn);
+ this.g = new MPInteger(bcpgIn);
+ this.y = new MPInteger(bcpgIn);
+ }
- public DsaPublicBcpgKey(
- BigInteger p,
- BigInteger q,
- BigInteger g,
- BigInteger y)
- {
- this.p = new MPInteger(p);
- this.q = new MPInteger(q);
- this.g = new MPInteger(g);
- this.y = new MPInteger(y);
- }
+ public DsaPublicBcpgKey(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g,
+ BigInteger y)
+ {
+ this.p = new MPInteger(p);
+ this.q = new MPInteger(q);
+ this.g = new MPInteger(g);
+ this.y = new MPInteger(y);
+ }
- /// <summary>The format, as a string, always "PGP".</summary>
- public string Format
- {
- get { return "PGP"; }
- }
+ /// <summary>The format, as a string, always "PGP".</summary>
+ public string Format
+ {
+ get { return "PGP"; }
+ }
- /// <summary>Return the standard PGP encoding of the key.</summary>
+ /// <summary>Return the standard PGP encoding of the key.</summary>
public override byte[] GetEncoded()
{
try
{
- return base.GetEncoded();
+ return base.GetEncoded();
}
catch (Exception)
{
@@ -51,30 +51,30 @@ namespace Org.BouncyCastle.Bcpg
}
}
- public override void Encode(
- BcpgOutputStream bcpgOut)
- {
- bcpgOut.WriteObjects(p, q, g, y);
- }
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObjects(p, q, g, y);
+ }
- public BigInteger G
- {
- get { return g.Value; }
- }
+ public BigInteger G
+ {
+ get { return g.Value; }
+ }
- public BigInteger P
- {
- get { return p.Value; }
- }
+ public BigInteger P
+ {
+ get { return p.Value; }
+ }
- public BigInteger Q
- {
- get { return q.Value; }
- }
+ public BigInteger Q
+ {
+ get { return q.Value; }
+ }
- public BigInteger Y
- {
- get { return y.Value; }
- }
+ public BigInteger Y
+ {
+ get { return y.Value; }
+ }
}
}
diff --git a/crypto/src/bcpg/ECDHPublicBCPGKey.cs b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
new file mode 100644
index 000000000..dc225e31e
--- /dev/null
+++ b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// <remarks>Base class for an ECDH Public Key.</remarks>
+ public class ECDHPublicBcpgKey
+ : ECPublicBcpgKey
+ {
+ private byte reserved;
+ private HashAlgorithmTag hashFunctionId;
+ private SymmetricKeyAlgorithmTag symAlgorithmId;
+
+ /// <param name="bcpgIn">The stream to read the packet from.</param>
+ public ECDHPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ int length = bcpgIn.ReadByte();
+ byte[] kdfParameters = new byte[length];
+ if (kdfParameters.Length != 3)
+ throw new InvalidOperationException("kdf parameters size of 3 expected.");
+
+ bcpgIn.ReadFully(kdfParameters);
+
+ reserved = kdfParameters[0];
+ hashFunctionId = (HashAlgorithmTag)kdfParameters[1];
+ symAlgorithmId = (SymmetricKeyAlgorithmTag)kdfParameters[2];
+
+ VerifyHashAlgorithm();
+ VerifySymmetricKeyAlgorithm();
+ }
+
+ public ECDHPublicBcpgKey(
+ DerObjectIdentifier oid,
+ ECPoint point,
+ HashAlgorithmTag hashAlgorithm,
+ SymmetricKeyAlgorithmTag symmetricKeyAlgorithm)
+ : base(oid, point)
+ {
+ reserved = 1;
+ hashFunctionId = hashAlgorithm;
+ symAlgorithmId = symmetricKeyAlgorithm;
+
+ VerifyHashAlgorithm();
+ VerifySymmetricKeyAlgorithm();
+ }
+
+ public virtual byte Reserved
+ {
+ get { return reserved; }
+ }
+
+ public virtual HashAlgorithmTag HashAlgorithm
+ {
+ get { return hashFunctionId; }
+ }
+
+ public virtual SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm
+ {
+ get { return symAlgorithmId; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ base.Encode(bcpgOut);
+ bcpgOut.WriteByte(0x3);
+ bcpgOut.WriteByte(reserved);
+ bcpgOut.WriteByte((byte)hashFunctionId);
+ bcpgOut.WriteByte((byte)symAlgorithmId);
+ }
+
+ private void VerifyHashAlgorithm()
+ {
+ switch ((HashAlgorithmTag)hashFunctionId)
+ {
+ case HashAlgorithmTag.Sha256:
+ case HashAlgorithmTag.Sha384:
+ case HashAlgorithmTag.Sha512:
+ break;
+ default:
+ throw new InvalidOperationException("Hash algorithm must be SHA-256 or stronger.");
+ }
+ }
+
+ private void VerifySymmetricKeyAlgorithm()
+ {
+ switch ((SymmetricKeyAlgorithmTag)symAlgorithmId)
+ {
+ case SymmetricKeyAlgorithmTag.Aes128:
+ case SymmetricKeyAlgorithmTag.Aes192:
+ case SymmetricKeyAlgorithmTag.Aes256:
+ break;
+ default:
+ throw new InvalidOperationException("Symmetric key algorithm must be AES-128 or stronger.");
+ }
+ }
+ }
+}
diff --git a/crypto/src/bcpg/ECDsaPublicBCPGKey.cs b/crypto/src/bcpg/ECDsaPublicBCPGKey.cs
new file mode 100644
index 000000000..5f0c8ac55
--- /dev/null
+++ b/crypto/src/bcpg/ECDsaPublicBCPGKey.cs
@@ -0,0 +1,34 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// <remarks>Base class for an ECDSA Public Key.</remarks>
+ public class ECDsaPublicBcpgKey
+ : ECPublicBcpgKey
+ {
+ /// <param name="bcpgIn">The stream to read the packet from.</param>
+ protected internal ECDsaPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ }
+
+ public ECDsaPublicBcpgKey(
+ DerObjectIdentifier oid,
+ ECPoint point)
+ : base(oid, point)
+ {
+ }
+
+ public ECDsaPublicBcpgKey(
+ DerObjectIdentifier oid,
+ BigInteger encodedPoint)
+ : base(oid, encodedPoint)
+ {
+ }
+ }
+}
diff --git a/crypto/src/bcpg/ECPublicBCPGKey.cs b/crypto/src/bcpg/ECPublicBCPGKey.cs
new file mode 100644
index 000000000..f328f9dc3
--- /dev/null
+++ b/crypto/src/bcpg/ECPublicBCPGKey.cs
@@ -0,0 +1,97 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// <remarks>Base class for an EC Public Key.</remarks>
+ public abstract class ECPublicBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ internal DerObjectIdentifier oid;
+ internal BigInteger point;
+
+ /// <param name="bcpgIn">The stream to read the packet from.</param>
+ protected ECPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.oid = DerObjectIdentifier.GetInstance(Asn1Object.FromByteArray(ReadBytesOfEncodedLength(bcpgIn)));
+ this.point = new MPInteger(bcpgIn).Value;
+ }
+
+ protected ECPublicBcpgKey(
+ DerObjectIdentifier oid,
+ ECPoint point)
+ {
+ this.point = new BigInteger(1, point.GetEncoded());
+ this.oid = oid;
+ }
+
+ protected ECPublicBcpgKey(
+ DerObjectIdentifier oid,
+ BigInteger encodedPoint)
+ {
+ this.point = encodedPoint;
+ this.oid = oid;
+ }
+
+ /// <summary>The format, as a string, always "PGP".</summary>
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// <summary>Return the standard PGP encoding of the key.</summary>
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (IOException)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ byte[] oid = this.oid.GetEncoded();
+ bcpgOut.Write(oid, 1, oid.Length - 1);
+
+ MPInteger point = new MPInteger(this.point);
+ bcpgOut.WriteObject(point);
+ }
+
+ public virtual BigInteger EncodedPoint
+ {
+ get { return point; }
+ }
+
+ public virtual DerObjectIdentifier CurveOid
+ {
+ get { return oid; }
+ }
+
+ protected static byte[] ReadBytesOfEncodedLength(
+ BcpgInputStream bcpgIn)
+ {
+ int length = bcpgIn.ReadByte();
+ if (length == 0 || length == 0xFF)
+ {
+ throw new IOException("future extensions not yet implemented.");
+ }
+
+ byte[] buffer = new byte[length + 2];
+ bcpgIn.ReadFully(buffer, 2, buffer.Length - 2);
+ buffer[0] = (byte)0x06;
+ buffer[1] = (byte)length;
+
+ return buffer;
+ }
+ }
+}
diff --git a/crypto/src/bcpg/ECSecretBCPGKey.cs b/crypto/src/bcpg/ECSecretBCPGKey.cs
new file mode 100644
index 000000000..22e0a3473
--- /dev/null
+++ b/crypto/src/bcpg/ECSecretBCPGKey.cs
@@ -0,0 +1,56 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// <remarks>Base class for an EC Secret Key.</remarks>
+ public class ECSecretBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ internal MPInteger x;
+
+ public ECSecretBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.x = new MPInteger(bcpgIn);
+ }
+
+ public ECSecretBcpgKey(
+ BigInteger x)
+ {
+ this.x = new MPInteger(x);
+ }
+
+ /// <summary>The format, as a string, always "PGP".</summary>
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// <summary>Return the standard PGP encoding of the key.</summary>
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObject(x);
+ }
+
+ public virtual BigInteger X
+ {
+ get { return x.Value; }
+ }
+ }
+}
diff --git a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
index 85ae548eb..9e30b54f7 100644
--- a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
+++ b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
@@ -1,6 +1,8 @@
+using System;
+
namespace Org.BouncyCastle.Bcpg
{
- /// <remarks>Public Key Algorithm tag numbers.</remarks>
+ /// <remarks>Public Key Algorithm tag numbers.</remarks>
public enum PublicKeyAlgorithmTag
{
RsaGeneral = 1, // RSA (Encrypt or Sign)
@@ -8,21 +10,23 @@ namespace Org.BouncyCastle.Bcpg
RsaSign = 3, // RSA Sign-Only
ElGamalEncrypt = 16, // Elgamal (Encrypt-Only), see [ELGAMAL]
Dsa = 17, // DSA (Digital Signature Standard)
+ [Obsolete("Use 'ECDH' instead")]
EC = 18, // Reserved for Elliptic Curve
+ ECDH = 18, // Reserved for Elliptic Curve (actual algorithm name)
ECDsa = 19, // Reserved for ECDSA
ElGamalGeneral = 20, // Elgamal (Encrypt or Sign)
DiffieHellman = 21, // Reserved for Diffie-Hellman (X9.42, as defined for IETF-S/MIME)
- Experimental_1 = 100,
- Experimental_2 = 101,
- Experimental_3 = 102,
- Experimental_4 = 103,
- Experimental_5 = 104,
- Experimental_6 = 105,
- Experimental_7 = 106,
- Experimental_8 = 107,
- Experimental_9 = 108,
- Experimental_10 = 109,
- Experimental_11 = 110,
- }
+ Experimental_1 = 100,
+ Experimental_2 = 101,
+ Experimental_3 = 102,
+ Experimental_4 = 103,
+ Experimental_5 = 104,
+ Experimental_6 = 105,
+ Experimental_7 = 106,
+ Experimental_8 = 107,
+ Experimental_9 = 108,
+ Experimental_10 = 109,
+ Experimental_11 = 110,
+ }
}
diff --git a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
index d10605f1d..74d04f7aa 100644
--- a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
+++ b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
@@ -2,6 +2,8 @@ using System;
using System.IO;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
@@ -12,7 +14,7 @@ namespace Org.BouncyCastle.Bcpg
private int version;
private long keyId;
private PublicKeyAlgorithmTag algorithm;
- private BigInteger[] data;
+ private byte[][] data;
internal PublicKeyEncSessionPacket(
BcpgInputStream bcpgIn)
@@ -34,33 +36,41 @@ namespace Org.BouncyCastle.Bcpg
{
case PublicKeyAlgorithmTag.RsaEncrypt:
case PublicKeyAlgorithmTag.RsaGeneral:
- data = new BigInteger[]{ new MPInteger(bcpgIn).Value };
+ data = new byte[][]{ new MPInteger(bcpgIn).GetEncoded() };
break;
case PublicKeyAlgorithmTag.ElGamalEncrypt:
case PublicKeyAlgorithmTag.ElGamalGeneral:
- data = new BigInteger[]
- {
- new MPInteger(bcpgIn).Value,
- new MPInteger(bcpgIn).Value
- };
+ MPInteger p = new MPInteger(bcpgIn);
+ MPInteger g = new MPInteger(bcpgIn);
+ data = new byte[][]{
+ p.GetEncoded(),
+ g.GetEncoded(),
+ };
break;
+ case PublicKeyAlgorithmTag.ECDH:
+ data = new byte[][]{ Streams.ReadAll(bcpgIn) };
+ break;
default:
throw new IOException("unknown PGP public key algorithm encountered");
}
}
- public PublicKeyEncSessionPacket(
- long keyId,
- PublicKeyAlgorithmTag algorithm,
- BigInteger[] data)
+ public PublicKeyEncSessionPacket(
+ long keyId,
+ PublicKeyAlgorithmTag algorithm,
+ byte[][] data)
{
this.version = 3;
this.keyId = keyId;
this.algorithm = algorithm;
- this.data = (BigInteger[]) data.Clone();
+ this.data = new byte[data.Length][];
+ for (int i = 0; i < data.Length; ++i)
+ {
+ this.data[i] = Arrays.Clone(data[i]);
+ }
}
- public int Version
+ public int Version
{
get { return version; }
}
@@ -75,12 +85,12 @@ namespace Org.BouncyCastle.Bcpg
get { return algorithm; }
}
- public BigInteger[] GetEncSessionKey()
+ public byte[][] GetEncSessionKey()
{
- return (BigInteger[]) data.Clone();
+ return data;
}
- public override void Encode(
+ public override void Encode(
BcpgOutputStream bcpgOut)
{
MemoryStream bOut = new MemoryStream();
@@ -92,12 +102,14 @@ namespace Org.BouncyCastle.Bcpg
pOut.WriteByte((byte)algorithm);
- for (int i = 0; i != data.Length; i++)
- {
- MPInteger.Encode(pOut, data[i]);
- }
+ for (int i = 0; i < data.Length; ++i)
+ {
+ pOut.Write(data[i]);
+ }
+
+ pOut.Close();
- bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
+ bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
}
}
}
diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs
index 32d43149b..bbed941dc 100644
--- a/crypto/src/bcpg/PublicKeyPacket.cs
+++ b/crypto/src/bcpg/PublicKeyPacket.cs
@@ -5,11 +5,11 @@ using Org.BouncyCastle.Utilities.Date;
namespace Org.BouncyCastle.Bcpg
{
- /// <remarks>Basic packet for a PGP public key.</remarks>
+ /// <remarks>Basic packet for a PGP public key.</remarks>
public class PublicKeyPacket
: ContainedPacket //, PublicKeyAlgorithmTag
{
- private int version;
+ private int version;
private long time;
private int validDays;
private PublicKeyAlgorithmTag algorithm;
@@ -44,49 +44,55 @@ namespace Org.BouncyCastle.Bcpg
case PublicKeyAlgorithmTag.ElGamalGeneral:
key = new ElGamalPublicBcpgKey(bcpgIn);
break;
+ case PublicKeyAlgorithmTag.ECDH:
+ key = new ECDHPublicBcpgKey(bcpgIn);
+ break;
+ case PublicKeyAlgorithmTag.ECDsa:
+ key = new ECDsaPublicBcpgKey(bcpgIn);
+ break;
default:
throw new IOException("unknown PGP public key algorithm encountered");
}
}
- /// <summary>Construct a version 4 public key packet.</summary>
+ /// <summary>Construct a version 4 public key packet.</summary>
public PublicKeyPacket(
PublicKeyAlgorithmTag algorithm,
DateTime time,
IBcpgKey key)
{
- this.version = 4;
+ this.version = 4;
this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
this.algorithm = algorithm;
this.key = key;
}
- public int Version
+ public virtual int Version
{
- get { return version; }
+ get { return version; }
}
- public PublicKeyAlgorithmTag Algorithm
+ public virtual PublicKeyAlgorithmTag Algorithm
{
- get { return algorithm; }
+ get { return algorithm; }
}
- public int ValidDays
+ public virtual int ValidDays
{
- get { return validDays; }
+ get { return validDays; }
}
- public DateTime GetTime()
+ public virtual DateTime GetTime()
{
return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
}
- public IBcpgKey Key
+ public virtual IBcpgKey Key
{
- get { return key; }
+ get { return key; }
}
- public byte[] GetEncodedContents()
+ public virtual byte[] GetEncodedContents()
{
MemoryStream bOut = new MemoryStream();
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
@@ -94,22 +100,22 @@ namespace Org.BouncyCastle.Bcpg
pOut.WriteByte((byte) version);
pOut.WriteInt((int) time);
- if (version <= 3)
+ if (version <= 3)
{
pOut.WriteShort((short) validDays);
}
- pOut.WriteByte((byte) algorithm);
+ pOut.WriteByte((byte) algorithm);
- pOut.WriteObject((BcpgObject)key);
+ pOut.WriteObject((BcpgObject)key);
- return bOut.ToArray();
+ return bOut.ToArray();
}
- public override void Encode(
- BcpgOutputStream bcpgOut)
- {
- bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true);
- }
- }
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true);
+ }
+ }
}
diff --git a/crypto/src/bcpg/S2k.cs b/crypto/src/bcpg/S2k.cs
index de08c016c..33fd792fe 100644
--- a/crypto/src/bcpg/S2k.cs
+++ b/crypto/src/bcpg/S2k.cs
@@ -16,6 +16,8 @@ namespace Org.BouncyCastle.Bcpg
public const int Salted = 1;
public const int SaltedAndIterated = 3;
public const int GnuDummyS2K = 101;
+ public const int GnuProtectionModeNoPrivateKey = 1;
+ public const int GnuProtectionModeDivertToCard = 2;
internal int type;
internal HashAlgorithmTag algorithm;
@@ -82,19 +84,19 @@ namespace Org.BouncyCastle.Bcpg
this.itCount = itCount;
}
- public int Type
+ public virtual int Type
{
get { return type; }
}
/// <summary>The hash algorithm.</summary>
- public HashAlgorithmTag HashAlgorithm
+ public virtual HashAlgorithmTag HashAlgorithm
{
get { return algorithm; }
}
/// <summary>The IV for the key generation algorithm.</summary>
- public byte[] GetIV()
+ public virtual byte[] GetIV()
{
return Arrays.Clone(iv);
}
@@ -106,13 +108,13 @@ namespace Org.BouncyCastle.Bcpg
}
/// <summary>The iteration count</summary>
- public long IterationCount
+ public virtual long IterationCount
{
get { return (16 + (itCount & 15)) << ((itCount >> 4) + ExpBias); }
}
/// <summary>The protection mode - only if GnuDummyS2K</summary>
- public int ProtectionMode
+ public virtual int ProtectionMode
{
get { return protectionMode; }
}
diff --git a/crypto/src/bcpg/SignaturePacket.cs b/crypto/src/bcpg/SignaturePacket.cs
index 605ce84c4..5b91c15a3 100644
--- a/crypto/src/bcpg/SignaturePacket.cs
+++ b/crypto/src/bcpg/SignaturePacket.cs
@@ -146,6 +146,11 @@ namespace Org.BouncyCastle.Bcpg
MPInteger y = new MPInteger(bcpgIn);
signature = new MPInteger[]{ p, g, y };
break;
+ case PublicKeyAlgorithmTag.ECDsa:
+ MPInteger ecR = new MPInteger(bcpgIn);
+ MPInteger ecS = new MPInteger(bcpgIn);
+ signature = new MPInteger[]{ ecR, ecS };
+ break;
default:
if (keyAlgorithm >= PublicKeyAlgorithmTag.Experimental_1 && keyAlgorithm <= PublicKeyAlgorithmTag.Experimental_11)
{
diff --git a/crypto/src/bcpg/SignatureSubpacket.cs b/crypto/src/bcpg/SignatureSubpacket.cs
index ac26f8a3c..d99315599 100644
--- a/crypto/src/bcpg/SignatureSubpacket.cs
+++ b/crypto/src/bcpg/SignatureSubpacket.cs
@@ -7,20 +7,22 @@ namespace Org.BouncyCastle.Bcpg
{
private readonly SignatureSubpacketTag type;
private readonly bool critical;
-
- internal readonly byte[] data;
+ private readonly bool isLongLength;
+ internal byte[] data;
protected internal SignatureSubpacket(
SignatureSubpacketTag type,
bool critical,
+ bool isLongLength,
byte[] data)
{
this.type = type;
this.critical = critical;
+ this.isLongLength = isLongLength;
this.data = data;
}
- public SignatureSubpacketTag SubpacketType
+ public SignatureSubpacketTag SubpacketType
{
get { return type; }
}
@@ -30,7 +32,12 @@ namespace Org.BouncyCastle.Bcpg
return critical;
}
- /// <summary>Return the generic data making up the packet.</summary>
+ public bool IsLongLength()
+ {
+ return isLongLength;
+ }
+
+ /// <summary>Return the generic data making up the packet.</summary>
public byte[] GetData()
{
return (byte[]) data.Clone();
@@ -41,18 +48,7 @@ namespace Org.BouncyCastle.Bcpg
{
int bodyLen = data.Length + 1;
- if (bodyLen < 192)
- {
- os.WriteByte((byte)bodyLen);
- }
- else if (bodyLen <= 8383)
- {
- bodyLen -= 192;
-
- os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
- os.WriteByte((byte)bodyLen);
- }
- else
+ if (isLongLength)
{
os.WriteByte(0xff);
os.WriteByte((byte)(bodyLen >> 24));
@@ -60,6 +56,28 @@ namespace Org.BouncyCastle.Bcpg
os.WriteByte((byte)(bodyLen >> 8));
os.WriteByte((byte)bodyLen);
}
+ else
+ {
+ if (bodyLen < 192)
+ {
+ os.WriteByte((byte)bodyLen);
+ }
+ else if (bodyLen <= 8383)
+ {
+ bodyLen -= 192;
+
+ os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
+ os.WriteByte((byte)bodyLen);
+ }
+ else
+ {
+ os.WriteByte(0xff);
+ os.WriteByte((byte)(bodyLen >> 24));
+ os.WriteByte((byte)(bodyLen >> 16));
+ os.WriteByte((byte)(bodyLen >> 8));
+ os.WriteByte((byte)bodyLen);
+ }
+ }
if (critical)
{
diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs
index 8dd1af332..80bedb07c 100644
--- a/crypto/src/bcpg/SignatureSubpacketsReader.cs
+++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs
@@ -1,6 +1,8 @@
using System;
using System.IO;
+
using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
@@ -25,7 +27,9 @@ namespace Org.BouncyCastle.Bcpg
return null;
int bodyLen = 0;
- if (l < 192)
+ bool isLongLength = false;
+
+ if (l < 192)
{
bodyLen = l;
}
@@ -35,54 +39,90 @@ namespace Org.BouncyCastle.Bcpg
}
else if (l == 255)
{
+ isLongLength = true;
bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
| (input.ReadByte() << 8) | input.ReadByte();
}
else
{
- // TODO Error?
+ throw new IOException("unexpected length header");
}
- int tag = input.ReadByte();
+ int tag = input.ReadByte();
if (tag < 0)
throw new EndOfStreamException("unexpected EOF reading signature sub packet");
- byte[] data = new byte[bodyLen - 1];
- if (Streams.ReadFully(input, data) < data.Length)
- throw new EndOfStreamException();
+ byte[] data = new byte[bodyLen - 1];
+
+ //
+ // this may seem a bit strange but it turns out some applications miscode the length
+ // in fixed length fields, so we check the length we do get, only throwing an exception if
+ // we really cannot continue
+ //
+ int bytesRead = Streams.ReadFully(input, data);
+
+ bool isCritical = ((tag & 0x80) != 0);
+ SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
- bool isCritical = ((tag & 0x80) != 0);
- SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
- switch (type)
+ if (bytesRead != data.Length)
+ {
+ switch (type)
+ {
+ case SignatureSubpacketTag.CreationTime:
+ data = CheckData(data, 4, bytesRead, "Signature Creation Time");
+ break;
+ case SignatureSubpacketTag.IssuerKeyId:
+ data = CheckData(data, 8, bytesRead, "Issuer");
+ break;
+ case SignatureSubpacketTag.KeyExpireTime:
+ data = CheckData(data, 4, bytesRead, "Signature Key Expiration Time");
+ break;
+ case SignatureSubpacketTag.ExpireTime:
+ data = CheckData(data, 4, bytesRead, "Signature Expiration Time");
+ break;
+ default:
+ throw new EndOfStreamException("truncated subpacket data.");
+ }
+ }
+
+ switch (type)
{
case SignatureSubpacketTag.CreationTime:
- return new SignatureCreationTime(isCritical, data);
+ return new SignatureCreationTime(isCritical, isLongLength, data);
case SignatureSubpacketTag.KeyExpireTime:
- return new KeyExpirationTime(isCritical, data);
+ return new KeyExpirationTime(isCritical, isLongLength, data);
case SignatureSubpacketTag.ExpireTime:
- return new SignatureExpirationTime(isCritical, data);
+ return new SignatureExpirationTime(isCritical, isLongLength, data);
case SignatureSubpacketTag.Revocable:
- return new Revocable(isCritical, data);
+ return new Revocable(isCritical, isLongLength, data);
case SignatureSubpacketTag.Exportable:
- return new Exportable(isCritical, data);
+ return new Exportable(isCritical, isLongLength, data);
case SignatureSubpacketTag.IssuerKeyId:
- return new IssuerKeyId(isCritical, data);
+ return new IssuerKeyId(isCritical, isLongLength, data);
case SignatureSubpacketTag.TrustSig:
- return new TrustSignature(isCritical, data);
+ return new TrustSignature(isCritical, isLongLength, data);
case SignatureSubpacketTag.PreferredCompressionAlgorithms:
case SignatureSubpacketTag.PreferredHashAlgorithms:
case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
- return new PreferredAlgorithms(type, isCritical, data);
+ return new PreferredAlgorithms(type, isCritical, isLongLength, data);
case SignatureSubpacketTag.KeyFlags:
- return new KeyFlags(isCritical, data);
+ return new KeyFlags(isCritical, isLongLength, data);
case SignatureSubpacketTag.PrimaryUserId:
- return new PrimaryUserId(isCritical, data);
+ return new PrimaryUserId(isCritical, isLongLength, data);
case SignatureSubpacketTag.SignerUserId:
- return new SignerUserId(isCritical, data);
+ return new SignerUserId(isCritical, isLongLength, data);
case SignatureSubpacketTag.NotationData:
- return new NotationData(isCritical, data);
+ return new NotationData(isCritical, isLongLength, data);
}
- return new SignatureSubpacket(type, isCritical, data);
+ return new SignatureSubpacket(type, isCritical, isLongLength, data);
}
+
+ private byte[] CheckData(byte[] data, int expected, int bytesRead, string name)
+ {
+ if (bytesRead != expected)
+ throw new EndOfStreamException("truncated " + name + " subpacket data.");
+
+ return Arrays.CopyOfRange(data, 0, expected);
+ }
}
}
diff --git a/crypto/src/bcpg/UserAttributeSubpacket.cs b/crypto/src/bcpg/UserAttributeSubpacket.cs
index bd49d2150..05f60ac17 100644
--- a/crypto/src/bcpg/UserAttributeSubpacket.cs
+++ b/crypto/src/bcpg/UserAttributeSubpacket.cs
@@ -10,40 +10,44 @@ namespace Org.BouncyCastle.Bcpg
*/
public class UserAttributeSubpacket
{
- private readonly UserAttributeSubpacketTag type;
- private readonly byte[] data;
+ internal readonly UserAttributeSubpacketTag type;
+ private readonly bool longLength; // we preserve this as not everyone encodes length properly.
+ protected readonly byte[] data;
- internal UserAttributeSubpacket(
- UserAttributeSubpacketTag type,
- byte[] data)
+ protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, byte[] data)
+ : this(type, false, data)
+ {
+ }
+
+ protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, bool forceLongLength, byte[] data)
{
this.type = type;
+ this.longLength = forceLongLength;
this.data = data;
}
- public UserAttributeSubpacketTag SubpacketType
+ public virtual UserAttributeSubpacketTag SubpacketType
{
get { return type; }
}
- /**
+ /**
* return the generic data making up the packet.
*/
- public byte[] GetData()
+ public virtual byte[] GetData()
{
return data;
}
- public void Encode(
- Stream os)
+ public virtual void Encode(Stream os)
{
int bodyLen = data.Length + 1;
- if (bodyLen < 192)
+ if (bodyLen < 192 && !longLength)
{
os.WriteByte((byte)bodyLen);
}
- else if (bodyLen <= 8383)
+ else if (bodyLen <= 8383 && !longLength)
{
bodyLen -= 192;
@@ -69,18 +73,18 @@ namespace Org.BouncyCastle.Bcpg
if (obj == this)
return true;
- UserAttributeSubpacket other = obj as UserAttributeSubpacket;
+ UserAttributeSubpacket other = obj as UserAttributeSubpacket;
- if (other == null)
- return false;
+ if (other == null)
+ return false;
- return type == other.type
- && Arrays.AreEqual(data, other.data);
+ return type == other.type
+ && Arrays.AreEqual(data, other.data);
}
- public override int GetHashCode()
+ public override int GetHashCode()
{
- return type.GetHashCode() ^ Arrays.GetHashCode(data);
+ return type.GetHashCode() ^ Arrays.GetHashCode(data);
}
}
}
diff --git a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
index 2e5ea0f3e..f0cc1b8e4 100644
--- a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
+++ b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
@@ -5,59 +5,61 @@ using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
- /**
- * reader for user attribute sub-packets
- */
- public class UserAttributeSubpacketsParser
- {
- private readonly Stream input;
+ /**
+ * reader for user attribute sub-packets
+ */
+ public class UserAttributeSubpacketsParser
+ {
+ private readonly Stream input;
- public UserAttributeSubpacketsParser(
- Stream input)
- {
- this.input = input;
- }
+ public UserAttributeSubpacketsParser(
+ Stream input)
+ {
+ this.input = input;
+ }
- public UserAttributeSubpacket ReadPacket()
- {
- int l = input.ReadByte();
- if (l < 0)
- return null;
+ public virtual UserAttributeSubpacket ReadPacket()
+ {
+ int l = input.ReadByte();
+ if (l < 0)
+ return null;
- int bodyLen = 0;
- if (l < 192)
- {
- bodyLen = l;
- }
- else if (l <= 223)
- {
- bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
- }
- else if (l == 255)
- {
- bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
- | (input.ReadByte() << 8) | input.ReadByte();
- }
- else
- {
- // TODO Error?
- }
+ int bodyLen = 0;
+ bool longLength = false;
+ if (l < 192)
+ {
+ bodyLen = l;
+ }
+ else if (l <= 223)
+ {
+ bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
+ }
+ else if (l == 255)
+ {
+ bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
+ | (input.ReadByte() << 8) | input.ReadByte();
+ longLength = true;
+ }
+ else
+ {
+ throw new IOException("unrecognised length reading user attribute sub packet");
+ }
- int tag = input.ReadByte();
- if (tag < 0)
- throw new EndOfStreamException("unexpected EOF reading user attribute sub packet");
+ int tag = input.ReadByte();
+ if (tag < 0)
+ throw new EndOfStreamException("unexpected EOF reading user attribute sub packet");
- byte[] data = new byte[bodyLen - 1];
- if (Streams.ReadFully(input, data) < data.Length)
- throw new EndOfStreamException();
+ byte[] data = new byte[bodyLen - 1];
+ if (Streams.ReadFully(input, data) < data.Length)
+ throw new EndOfStreamException();
- UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
- switch (type)
- {
- case UserAttributeSubpacketTag.ImageAttribute:
- return new ImageAttrib(data);
- }
- return new UserAttributeSubpacket(type, data);
- }
- }
+ UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
+ switch (type)
+ {
+ case UserAttributeSubpacketTag.ImageAttribute:
+ return new ImageAttrib(longLength, data);
+ }
+ return new UserAttributeSubpacket(type, longLength, data);
+ }
+ }
}
diff --git a/crypto/src/bcpg/attr/ImageAttrib.cs b/crypto/src/bcpg/attr/ImageAttrib.cs
index 73490791c..2d0fef8b8 100644
--- a/crypto/src/bcpg/attr/ImageAttrib.cs
+++ b/crypto/src/bcpg/attr/ImageAttrib.cs
@@ -3,25 +3,29 @@ using System.IO;
namespace Org.BouncyCastle.Bcpg.Attr
{
- /// <remarks>Basic type for a image attribute packet.</remarks>
+ /// <remarks>Basic type for a image attribute packet.</remarks>
public class ImageAttrib
- : UserAttributeSubpacket
+ : UserAttributeSubpacket
{
- public enum Format : byte
- {
- Jpeg = 1
- }
+ public enum Format : byte
+ {
+ Jpeg = 1
+ }
- private static readonly byte[] Zeroes = new byte[12];
+ private static readonly byte[] Zeroes = new byte[12];
- private int hdrLength;
+ private int hdrLength;
private int _version;
private int _encoding;
private byte[] imageData;
- public ImageAttrib(
- byte[] data)
- : base(UserAttributeSubpacketTag.ImageAttribute, data)
+ public ImageAttrib(byte[] data)
+ : this(false, data)
+ {
+ }
+
+ public ImageAttrib(bool forceLongLength, byte[] data)
+ : base(UserAttributeSubpacketTag.ImageAttribute, forceLongLength, data)
{
hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff);
_version = data[2] & 0xff;
@@ -31,36 +35,36 @@ namespace Org.BouncyCastle.Bcpg.Attr
Array.Copy(data, hdrLength, imageData, 0, imageData.Length);
}
- public ImageAttrib(
- Format imageType,
- byte[] imageData)
- : this(ToByteArray(imageType, imageData))
- {
- }
+ public ImageAttrib(
+ Format imageType,
+ byte[] imageData)
+ : this(ToByteArray(imageType, imageData))
+ {
+ }
- private static byte[] ToByteArray(
- Format imageType,
- byte[] imageData)
- {
- MemoryStream bOut = new MemoryStream();
- bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01);
- bOut.WriteByte((byte) imageType);
- bOut.Write(Zeroes, 0, Zeroes.Length);
- bOut.Write(imageData, 0, imageData.Length);
- return bOut.ToArray();
- }
+ private static byte[] ToByteArray(
+ Format imageType,
+ byte[] imageData)
+ {
+ MemoryStream bOut = new MemoryStream();
+ bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01);
+ bOut.WriteByte((byte) imageType);
+ bOut.Write(Zeroes, 0, Zeroes.Length);
+ bOut.Write(imageData, 0, imageData.Length);
+ return bOut.ToArray();
+ }
- public int Version
+ public virtual int Version
{
- get { return _version; }
+ get { return _version; }
}
- public int Encoding
+ public virtual int Encoding
{
- get { return _encoding; }
+ get { return _encoding; }
}
- public byte[] GetImageData()
+ public virtual byte[] GetImageData()
{
return imageData;
}
diff --git a/crypto/src/bcpg/sig/EmbeddedSignature.cs b/crypto/src/bcpg/sig/EmbeddedSignature.cs
index e47604ac8..fffdaef73 100644
--- a/crypto/src/bcpg/sig/EmbeddedSignature.cs
+++ b/crypto/src/bcpg/sig/EmbeddedSignature.cs
@@ -10,8 +10,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
{
public EmbeddedSignature(
bool critical,
+ bool isLongLength,
byte[] data)
- : base(SignatureSubpacketTag.EmbeddedSignature, critical, data)
+ : base(SignatureSubpacketTag.EmbeddedSignature, critical, isLongLength, data)
{
}
}
diff --git a/crypto/src/bcpg/sig/Exportable.cs b/crypto/src/bcpg/sig/Exportable.cs
index 4455c3814..4d030346f 100644
--- a/crypto/src/bcpg/sig/Exportable.cs
+++ b/crypto/src/bcpg/sig/Exportable.cs
@@ -1,7 +1,5 @@
using System;
-
-
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
@@ -27,15 +25,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
public Exportable(
bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.Exportable, critical, data)
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.Exportable, critical, isLongLength, data)
{
}
public Exportable(
bool critical,
bool isExportable)
- : base(SignatureSubpacketTag.Exportable, critical, BooleanToByteArray(isExportable))
+ : base(SignatureSubpacketTag.Exportable, critical, false, BooleanToByteArray(isExportable))
{
}
diff --git a/crypto/src/bcpg/sig/Features.cs b/crypto/src/bcpg/sig/Features.cs
new file mode 100644
index 000000000..29584239a
--- /dev/null
+++ b/crypto/src/bcpg/sig/Features.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving signature expiration time.
+ */
+ public class Features
+ : SignatureSubpacket
+ {
+ /** Identifier for the modification detection feature */
+ public static readonly byte FEATURE_MODIFICATION_DETECTION = 1;
+
+ private static byte[] FeatureToByteArray(byte feature)
+ {
+ return new byte[]{ feature };
+ }
+
+ public Features(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.Features, critical, isLongLength, data)
+ {
+ }
+
+ public Features(bool critical, byte feature)
+ : base(SignatureSubpacketTag.Features, critical, false, FeatureToByteArray(feature))
+ {
+ }
+
+ /**
+ * Returns if modification detection is supported.
+ */
+ public bool SupportsModificationDetection
+ {
+ get { return SupportsFeature(FEATURE_MODIFICATION_DETECTION); }
+ }
+
+ /**
+ * Returns if a particular feature is supported.
+ */
+ public bool SupportsFeature(byte feature)
+ {
+ return Array.IndexOf(data, feature) >= 0;
+ }
+
+ /**
+ * Sets support for a particular feature.
+ */
+ private void SetSupportsFeature(byte feature, bool support)
+ {
+ if (feature == 0)
+ throw new ArgumentException("cannot be 0", "feature");
+
+ int i = Array.IndexOf(data, feature);
+ if ((i >= 0) == support)
+ return;
+
+ if (support)
+ {
+ data = Arrays.Append(data, feature);
+ }
+ else
+ {
+ byte[] temp = new byte[data.Length - 1];
+ Array.Copy(data, 0, temp, 0, i);
+ Array.Copy(data, i + 1, temp, i, temp.Length - i);
+ data = temp;
+ }
+ }
+ }
+}
diff --git a/crypto/src/bcpg/sig/IssuerKeyId.cs b/crypto/src/bcpg/sig/IssuerKeyId.cs
index 91490d33b..627ea3ecf 100644
--- a/crypto/src/bcpg/sig/IssuerKeyId.cs
+++ b/crypto/src/bcpg/sig/IssuerKeyId.cs
@@ -29,15 +29,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
public IssuerKeyId(
bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.IssuerKeyId, critical, data)
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.IssuerKeyId, critical, isLongLength, data)
{
}
public IssuerKeyId(
bool critical,
- long keyId)
- : base(SignatureSubpacketTag.IssuerKeyId, critical, KeyIdToBytes(keyId))
+ long keyId)
+ : base(SignatureSubpacketTag.IssuerKeyId, critical, false, KeyIdToBytes(keyId))
{
}
diff --git a/crypto/src/bcpg/sig/KeyExpirationTime.cs b/crypto/src/bcpg/sig/KeyExpirationTime.cs
index 23b4cac29..dfd3e76fd 100644
--- a/crypto/src/bcpg/sig/KeyExpirationTime.cs
+++ b/crypto/src/bcpg/sig/KeyExpirationTime.cs
@@ -1,7 +1,5 @@
using System;
-
-
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
@@ -25,15 +23,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
public KeyExpirationTime(
bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.KeyExpireTime, critical, data)
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.KeyExpireTime, critical, isLongLength, data)
{
}
public KeyExpirationTime(
bool critical,
- long seconds)
- : base(SignatureSubpacketTag.KeyExpireTime, critical, TimeToBytes(seconds))
+ long seconds)
+ : base(SignatureSubpacketTag.KeyExpireTime, critical, false, TimeToBytes(seconds))
{
}
diff --git a/crypto/src/bcpg/sig/KeyFlags.cs b/crypto/src/bcpg/sig/KeyFlags.cs
index 0592301b3..5b5d85a72 100644
--- a/crypto/src/bcpg/sig/KeyFlags.cs
+++ b/crypto/src/bcpg/sig/KeyFlags.cs
@@ -40,15 +40,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
public KeyFlags(
bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.KeyFlags, critical, data)
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.KeyFlags, critical, isLongLength, data)
{
}
public KeyFlags(
- bool critical,
- int flags)
- : base(SignatureSubpacketTag.KeyFlags, critical, IntToByteArray(flags))
+ bool critical,
+ int flags)
+ : base(SignatureSubpacketTag.KeyFlags, critical, false, IntToByteArray(flags))
{
}
diff --git a/crypto/src/bcpg/sig/NotationData.cs b/crypto/src/bcpg/sig/NotationData.cs
index ccc9aa745..9ac6f89cf 100644
--- a/crypto/src/bcpg/sig/NotationData.cs
+++ b/crypto/src/bcpg/sig/NotationData.cs
@@ -17,8 +17,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
public NotationData(
bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.NotationData, critical, data)
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.NotationData, critical, isLongLength, data)
{
}
@@ -27,12 +28,12 @@ namespace Org.BouncyCastle.Bcpg.Sig
bool humanReadable,
string notationName,
string notationValue)
- : base(SignatureSubpacketTag.NotationData, critical,
- createData(humanReadable, notationName, notationValue))
+ : base(SignatureSubpacketTag.NotationData, critical, false,
+ CreateData(humanReadable, notationName, notationValue))
{
}
- private static byte[] createData(
+ private static byte[] CreateData(
bool humanReadable,
string notationName,
string notationValue)
diff --git a/crypto/src/bcpg/sig/PreferredAlgorithms.cs b/crypto/src/bcpg/sig/PreferredAlgorithms.cs
index 0f282a38c..9514bed2b 100644
--- a/crypto/src/bcpg/sig/PreferredAlgorithms.cs
+++ b/crypto/src/bcpg/sig/PreferredAlgorithms.cs
@@ -1,7 +1,5 @@
using System;
-
-
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
@@ -24,24 +22,25 @@ namespace Org.BouncyCastle.Bcpg.Sig
}
public PreferredAlgorithms(
- SignatureSubpacketTag type,
- bool critical,
- byte[] data)
- : base(type, critical, data)
+ SignatureSubpacketTag type,
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(type, critical, isLongLength, data)
{
}
public PreferredAlgorithms(
- SignatureSubpacketTag type,
- bool critical,
- int[] preferences)
- : base(type, critical, IntToByteArray(preferences))
+ SignatureSubpacketTag type,
+ bool critical,
+ int[] preferences)
+ : base(type, critical, false, IntToByteArray(preferences))
{
}
public int[] GetPreferences()
{
- int[] v = new int[data.Length];
+ int[] v = new int[data.Length];
for (int i = 0; i != v.Length; i++)
{
diff --git a/crypto/src/bcpg/sig/PrimaryUserId.cs b/crypto/src/bcpg/sig/PrimaryUserId.cs
index fc0353afd..1f16f40eb 100644
--- a/crypto/src/bcpg/sig/PrimaryUserId.cs
+++ b/crypto/src/bcpg/sig/PrimaryUserId.cs
@@ -1,7 +1,5 @@
using System;
-
-
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
@@ -28,15 +26,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
public PrimaryUserId(
bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.PrimaryUserId, critical, data)
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.PrimaryUserId, critical, isLongLength, data)
{
}
public PrimaryUserId(
bool critical,
bool isPrimaryUserId)
- : base(SignatureSubpacketTag.PrimaryUserId, critical, BooleanToByteArray(isPrimaryUserId))
+ : base(SignatureSubpacketTag.PrimaryUserId, critical, false, BooleanToByteArray(isPrimaryUserId))
{
}
diff --git a/crypto/src/bcpg/sig/Revocable.cs b/crypto/src/bcpg/sig/Revocable.cs
index b5e94feec..7aa91391f 100644
--- a/crypto/src/bcpg/sig/Revocable.cs
+++ b/crypto/src/bcpg/sig/Revocable.cs
@@ -1,7 +1,5 @@
using System;
-
-
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
@@ -28,16 +26,17 @@ namespace Org.BouncyCastle.Bcpg.Sig
public Revocable(
bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.Revocable, critical, data)
- {
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.Revocable, critical, isLongLength, data)
+ {
}
public Revocable(
bool critical,
bool isRevocable)
- : base(SignatureSubpacketTag.Revocable, critical, BooleanToByteArray(isRevocable))
- {
+ : base(SignatureSubpacketTag.Revocable, critical, false, BooleanToByteArray(isRevocable))
+ {
}
public bool IsRevocable()
diff --git a/crypto/src/bcpg/sig/RevocationKey.cs b/crypto/src/bcpg/sig/RevocationKey.cs
index 66982cb5a..11467d2af 100644
--- a/crypto/src/bcpg/sig/RevocationKey.cs
+++ b/crypto/src/bcpg/sig/RevocationKey.cs
@@ -14,17 +14,18 @@ namespace Org.BouncyCastle.Bcpg
// 20 octets of fingerprint
public RevocationKey(
bool isCritical,
- byte[] data)
- : base(SignatureSubpacketTag.RevocationKey, isCritical, data)
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.RevocationKey, isCritical, isLongLength, data)
{
}
- public RevocationKey(
+ public RevocationKey(
bool isCritical,
RevocationKeyTag signatureClass,
PublicKeyAlgorithmTag keyAlgorithm,
byte[] fingerprint)
- : base(SignatureSubpacketTag.RevocationKey, isCritical,
+ : base(SignatureSubpacketTag.RevocationKey, isCritical, false,
CreateData(signatureClass, keyAlgorithm, fingerprint))
{
}
diff --git a/crypto/src/bcpg/sig/RevocationReason.cs b/crypto/src/bcpg/sig/RevocationReason.cs
index 98e9b0a3d..42afd5f5b 100644
--- a/crypto/src/bcpg/sig/RevocationReason.cs
+++ b/crypto/src/bcpg/sig/RevocationReason.cs
@@ -11,16 +11,16 @@ namespace Org.BouncyCastle.Bcpg
public class RevocationReason
: SignatureSubpacket
{
- public RevocationReason(bool isCritical, byte[] data)
- : base(SignatureSubpacketTag.RevocationReason, isCritical, data)
+ public RevocationReason(bool isCritical, bool isLongLength, byte[] data)
+ : base(SignatureSubpacketTag.RevocationReason, isCritical, isLongLength, data)
{
}
- public RevocationReason(
- bool isCritical,
- RevocationReasonTag reason,
- string description)
- : base(SignatureSubpacketTag.RevocationReason, isCritical, CreateData(reason, description))
+ public RevocationReason(
+ bool isCritical,
+ RevocationReasonTag reason,
+ string description)
+ : base(SignatureSubpacketTag.RevocationReason, isCritical, false, CreateData(reason, description))
{
}
diff --git a/crypto/src/bcpg/sig/SignatureCreationTime.cs b/crypto/src/bcpg/sig/SignatureCreationTime.cs
index e6f241f11..d172e5d52 100644
--- a/crypto/src/bcpg/sig/SignatureCreationTime.cs
+++ b/crypto/src/bcpg/sig/SignatureCreationTime.cs
@@ -21,18 +21,22 @@ namespace Org.BouncyCastle.Bcpg.Sig
data[3] = (byte)t;
return data;
}
+
public SignatureCreationTime(
- bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.CreationTime, critical, data)
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.CreationTime, critical, isLongLength, data)
{
}
+
public SignatureCreationTime(
- bool critical,
- DateTime date)
- : base(SignatureSubpacketTag.CreationTime, critical, TimeToBytes(date))
+ bool critical,
+ DateTime date)
+ : base(SignatureSubpacketTag.CreationTime, critical, false, TimeToBytes(date))
{
}
+
public DateTime GetTime()
{
long time = (long)(
diff --git a/crypto/src/bcpg/sig/SignatureExpirationTime.cs b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
index 7fddf5743..24f0a9f8a 100644
--- a/crypto/src/bcpg/sig/SignatureExpirationTime.cs
+++ b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
@@ -1,7 +1,5 @@
using System;
-
-
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
@@ -11,29 +9,28 @@ namespace Org.BouncyCastle.Bcpg.Sig
: SignatureSubpacket
{
protected static byte[] TimeToBytes(
- long t)
+ long t)
{
- byte[] data = new byte[4];
-
+ byte[] data = new byte[4];
data[0] = (byte)(t >> 24);
data[1] = (byte)(t >> 16);
data[2] = (byte)(t >> 8);
data[3] = (byte)t;
-
return data;
}
public SignatureExpirationTime(
bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.ExpireTime, critical, data)
- {
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.ExpireTime, critical, isLongLength, data)
+ {
}
public SignatureExpirationTime(
bool critical,
- long seconds)
- : base(SignatureSubpacketTag.ExpireTime, critical, TimeToBytes(seconds))
+ long seconds)
+ : base(SignatureSubpacketTag.ExpireTime, critical, false, TimeToBytes(seconds))
{
}
diff --git a/crypto/src/bcpg/sig/SignerUserId.cs b/crypto/src/bcpg/sig/SignerUserId.cs
index 98cc808e7..8ab62ed2e 100644
--- a/crypto/src/bcpg/sig/SignerUserId.cs
+++ b/crypto/src/bcpg/sig/SignerUserId.cs
@@ -24,20 +24,21 @@ namespace Org.BouncyCastle.Bcpg.Sig
}
public SignerUserId(
- bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.SignerUserId, critical, data)
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.SignerUserId, critical, isLongLength, data)
{
}
- public SignerUserId(
- bool critical,
- string userId)
- : base(SignatureSubpacketTag.SignerUserId, critical, UserIdToBytes(userId))
+ public SignerUserId(
+ bool critical,
+ string userId)
+ : base(SignatureSubpacketTag.SignerUserId, critical, false, UserIdToBytes(userId))
{
}
- public string GetId()
+ public string GetId()
{
char[] chars = new char[data.Length];
diff --git a/crypto/src/bcpg/sig/TrustSignature.cs b/crypto/src/bcpg/sig/TrustSignature.cs
index bbadd3067..91458826d 100644
--- a/crypto/src/bcpg/sig/TrustSignature.cs
+++ b/crypto/src/bcpg/sig/TrustSignature.cs
@@ -16,17 +16,18 @@ namespace Org.BouncyCastle.Bcpg.Sig
}
public TrustSignature(
- bool critical,
- byte[] data)
- : base(SignatureSubpacketTag.TrustSig, critical, data)
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.TrustSig, critical, isLongLength, data)
{
}
public TrustSignature(
- bool critical,
- int depth,
- int trustAmount)
- : base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount))
+ bool critical,
+ int depth,
+ int trustAmount)
+ : base(SignatureSubpacketTag.TrustSig, critical, false, IntToByteArray(depth, trustAmount))
{
}
diff --git a/crypto/src/cms/CMSSignedDataGenerator.cs b/crypto/src/cms/CMSSignedDataGenerator.cs
index f31105c41..201cfc5c4 100644
--- a/crypto/src/cms/CMSSignedDataGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataGenerator.cs
@@ -6,11 +6,11 @@ using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Security.Certificates;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Crypto.Operators;
namespace Org.BouncyCastle.Cms
{
@@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Cms
{
private readonly CmsSignedGenerator outer;
- private readonly AsymmetricKeyParameter key;
+ private readonly ISignatureCalculator sigCalc;
private readonly SignerIdentifier signerIdentifier;
private readonly string digestOID;
private readonly string encOID;
@@ -61,8 +61,12 @@ namespace Org.BouncyCastle.Cms
CmsAttributeTableGenerator unsAttr,
Asn1.Cms.AttributeTable baseSignedTable)
{
+ string digestName = Helper.GetDigestAlgName(digestOID);
+
+ string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID);
+
this.outer = outer;
- this.key = key;
+ this.sigCalc = new Asn1SignatureCalculator(signatureName, key);
this.signerIdentifier = signerIdentifier;
this.digestOID = digestOID;
this.encOID = encOID;
@@ -71,7 +75,25 @@ namespace Org.BouncyCastle.Cms
this.baseSignedTable = baseSignedTable;
}
- internal AlgorithmIdentifier DigestAlgorithmID
+ internal SignerInf(
+ CmsSignedGenerator outer,
+ ISignatureCalculator sigCalc,
+ SignerIdentifier signerIdentifier,
+ CmsAttributeTableGenerator sAttr,
+ CmsAttributeTableGenerator unsAttr,
+ Asn1.Cms.AttributeTable baseSignedTable)
+ {
+ this.outer = outer;
+ this.sigCalc = sigCalc;
+ this.signerIdentifier = signerIdentifier;
+ this.digestOID = new DefaultDigestAlgorithmIdentifierFinder().find((AlgorithmIdentifier)sigCalc.AlgorithmDetails).Algorithm.Id;
+ this.encOID = ((AlgorithmIdentifier)sigCalc.AlgorithmDetails).Algorithm.Id;
+ this.sAttr = sAttr;
+ this.unsAttr = unsAttr;
+ this.baseSignedTable = baseSignedTable;
+ }
+
+ internal AlgorithmIdentifier DigestAlgorithmID
{
get { return new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), DerNull.Instance); }
}
@@ -93,25 +115,31 @@ namespace Org.BouncyCastle.Cms
{
AlgorithmIdentifier digAlgId = DigestAlgorithmID;
string digestName = Helper.GetDigestAlgName(digestOID);
- IDigest dig = Helper.GetDigestInstance(digestName);
string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID);
- ISigner sig = Helper.GetSignatureInstance(signatureName);
-
- // TODO Optimise the case where more than one signer with same digest
- if (content != null)
+
+ byte[] hash;
+ if (outer._digests.Contains(digestOID))
{
- content.Write(new DigOutputStream(dig));
- }
+ hash = (byte[])outer._digests[digestOID];
+ }
+ else
+ {
+ IDigest dig = Helper.GetDigestInstance(digestName);
+ if (content != null)
+ {
+ content.Write(new DigOutputStream(dig));
+ }
+ hash = DigestUtilities.DoFinal(dig);
+ outer._digests.Add(digestOID, hash.Clone());
+ }
- byte[] hash = DigestUtilities.DoFinal(dig);
- outer._digests.Add(digestOID, hash.Clone());
+ IStreamCalculator calculator = sigCalc.CreateCalculator();
- sig.Init(true, new ParametersWithRandom(key, random));
#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
- Stream sigStr = new SigOutputStream(sig);
+ Stream sigStr = new SigOutputStream(calculator.Stream);
#else
- Stream sigStr = new BufferedStream(new SigOutputStream(sig));
+ Stream sigStr = new BufferedStream(calculator.Stream);
#endif
Asn1Set signedAttr = null;
@@ -146,7 +174,7 @@ namespace Org.BouncyCastle.Cms
}
sigStr.Close();
- byte[] sigBytes = sig.GenerateSignature();
+ byte[] sigBytes = ((IBlockResult)calculator.GetResult()).DoFinal();
Asn1Set unsignedAttr = null;
if (unsAttr != null)
@@ -164,7 +192,7 @@ namespace Org.BouncyCastle.Cms
// TODO[RSAPSS] Need the ability to specify non-default parameters
Asn1Encodable sigX509Parameters = SignerUtilities.GetDefaultX509Parameters(signatureName);
- AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier(
+ AlgorithmIdentifier encAlgId = Helper.GetEncAlgorithmIdentifier(
new DerObjectIdentifier(encOID), sigX509Parameters);
return new SignerInfo(signerIdentifier, digAlgId,
@@ -197,7 +225,7 @@ namespace Org.BouncyCastle.Cms
X509Certificate cert,
string digestOID)
{
- AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID);
+ AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID);
}
/**
@@ -228,7 +256,7 @@ namespace Org.BouncyCastle.Cms
byte[] subjectKeyID,
string digestOID)
{
- AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID);
+ AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID);
}
/**
@@ -261,7 +289,7 @@ namespace Org.BouncyCastle.Cms
Asn1.Cms.AttributeTable signedAttr,
Asn1.Cms.AttributeTable unsignedAttr)
{
- AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID,
+ AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID,
signedAttr, unsignedAttr);
}
@@ -305,7 +333,7 @@ namespace Org.BouncyCastle.Cms
Asn1.Cms.AttributeTable signedAttr,
Asn1.Cms.AttributeTable unsignedAttr)
{
- AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID,
+ AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID,
signedAttr, unsignedAttr);
}
@@ -343,7 +371,7 @@ namespace Org.BouncyCastle.Cms
CmsAttributeTableGenerator signedAttrGen,
CmsAttributeTableGenerator unsignedAttrGen)
{
- AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID,
+ AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID,
signedAttrGen, unsignedAttrGen);
}
@@ -372,7 +400,7 @@ namespace Org.BouncyCastle.Cms
CmsAttributeTableGenerator signedAttrGen,
CmsAttributeTableGenerator unsignedAttrGen)
{
- AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID,
+ AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID,
signedAttrGen, unsignedAttrGen);
}
@@ -391,7 +419,13 @@ namespace Org.BouncyCastle.Cms
signedAttrGen, unsignedAttrGen, null);
}
- private void doAddSigner(
+ public void AddSignerInfoGenerator(SignerInfoGenerator signerInfoGenerator)
+ {
+ signerInfs.Add(new SignerInf(this, signerInfoGenerator.contentSigner, signerInfoGenerator.sigId,
+ signerInfoGenerator.signedGen, signerInfoGenerator.unsignedGen, null));
+ }
+
+ private void doAddSigner(
AsymmetricKeyParameter privateKey,
SignerIdentifier signerIdentifier,
string encryptionOID,
diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
index 743e9c6c1..223fdb39d 100644
--- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
@@ -52,10 +52,10 @@ namespace Org.BouncyCastle.Cms
private class DigestAndSignerInfoGeneratorHolder
{
- internal readonly SignerInfoGenerator signerInf;
+ internal readonly ISignerInfoGenerator signerInf;
internal readonly string digestOID;
- internal DigestAndSignerInfoGeneratorHolder(SignerInfoGenerator signerInf, String digestOID)
+ internal DigestAndSignerInfoGeneratorHolder(ISignerInfoGenerator signerInf, String digestOID)
{
this.signerInf = signerInf;
this.digestOID = digestOID;
@@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Cms
}
}
- private class SignerInfoGeneratorImpl : SignerInfoGenerator
+ private class SignerInfoGeneratorImpl : ISignerInfoGenerator
{
private readonly CmsSignedDataStreamGenerator outer;
@@ -215,7 +215,7 @@ namespace Org.BouncyCastle.Cms
// TODO[RSAPSS] Need the ability to specify non-default parameters
Asn1Encodable sigX509Parameters = SignerUtilities.GetDefaultX509Parameters(signatureName);
- AlgorithmIdentifier digestEncryptionAlgorithm = CmsSignedGenerator.GetEncAlgorithmIdentifier(
+ AlgorithmIdentifier digestEncryptionAlgorithm = Helper.GetEncAlgorithmIdentifier(
new DerObjectIdentifier(_encOID), sigX509Parameters);
return new SignerInfo(_signerIdentifier, digestAlgorithm,
@@ -347,7 +347,7 @@ namespace Org.BouncyCastle.Cms
CmsAttributeTableGenerator signedAttrGenerator,
CmsAttributeTableGenerator unsignedAttrGenerator)
{
- AddSigner(privateKey, cert, GetEncOid(privateKey, digestOid), digestOid,
+ AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOid), digestOid,
signedAttrGenerator, unsignedAttrGenerator);
}
@@ -420,7 +420,7 @@ namespace Org.BouncyCastle.Cms
CmsAttributeTableGenerator signedAttrGenerator,
CmsAttributeTableGenerator unsignedAttrGenerator)
{
- AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOid),
+ AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOid),
digestOid, signedAttrGenerator, unsignedAttrGenerator);
}
diff --git a/crypto/src/cms/CMSSignedGenerator.cs b/crypto/src/cms/CMSSignedGenerator.cs
index f272c830e..0fb1f314d 100644
--- a/crypto/src/cms/CMSSignedGenerator.cs
+++ b/crypto/src/cms/CMSSignedGenerator.cs
@@ -16,12 +16,106 @@ using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Collections;
-using Org.BouncyCastle.Utilities.IO;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.X509.Store;
namespace Org.BouncyCastle.Cms
{
+ public class DefaultDigestAlgorithmIdentifierFinder
+ {
+ private static readonly IDictionary digestOids = Platform.CreateHashtable();
+ private static readonly IDictionary digestNameToOids = Platform.CreateHashtable();
+
+ static DefaultDigestAlgorithmIdentifierFinder()
+ {
+ //
+ // digests
+ //
+ digestOids.Add(OiwObjectIdentifiers.MD4WithRsaEncryption, PkcsObjectIdentifiers.MD4);
+ digestOids.Add(OiwObjectIdentifiers.MD4WithRsa, PkcsObjectIdentifiers.MD4);
+ digestOids.Add(OiwObjectIdentifiers.Sha1WithRsa, OiwObjectIdentifiers.IdSha1);
+
+ digestOids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, NistObjectIdentifiers.IdSha224);
+ digestOids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, NistObjectIdentifiers.IdSha256);
+ digestOids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, NistObjectIdentifiers.IdSha384);
+ digestOids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, NistObjectIdentifiers.IdSha512);
+ digestOids.Add(PkcsObjectIdentifiers.MD2WithRsaEncryption, PkcsObjectIdentifiers.MD2);
+ digestOids.Add(PkcsObjectIdentifiers.MD4WithRsaEncryption, PkcsObjectIdentifiers.MD4);
+ digestOids.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption, PkcsObjectIdentifiers.MD5);
+ digestOids.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption, OiwObjectIdentifiers.IdSha1);
+
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha1, OiwObjectIdentifiers.IdSha1);
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha224, NistObjectIdentifiers.IdSha224);
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha256, NistObjectIdentifiers.IdSha256);
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha384, NistObjectIdentifiers.IdSha384);
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha512, NistObjectIdentifiers.IdSha512);
+ digestOids.Add(X9ObjectIdentifiers.IdDsaWithSha1, OiwObjectIdentifiers.IdSha1);
+
+ digestOids.Add(NistObjectIdentifiers.DsaWithSha224, NistObjectIdentifiers.IdSha224);
+ digestOids.Add(NistObjectIdentifiers.DsaWithSha256, NistObjectIdentifiers.IdSha256);
+ digestOids.Add(NistObjectIdentifiers.DsaWithSha384, NistObjectIdentifiers.IdSha384);
+ digestOids.Add(NistObjectIdentifiers.DsaWithSha512, NistObjectIdentifiers.IdSha512);
+
+ digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128, TeleTrusTObjectIdentifiers.RipeMD128);
+ digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160, TeleTrusTObjectIdentifiers.RipeMD160);
+ digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256, TeleTrusTObjectIdentifiers.RipeMD256);
+
+ digestOids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, CryptoProObjectIdentifiers.GostR3411);
+ digestOids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, CryptoProObjectIdentifiers.GostR3411);
+
+ digestNameToOids.Add("SHA-1", OiwObjectIdentifiers.IdSha1);
+ digestNameToOids.Add("SHA-224", NistObjectIdentifiers.IdSha224);
+ digestNameToOids.Add("SHA-256", NistObjectIdentifiers.IdSha256);
+ digestNameToOids.Add("SHA-384", NistObjectIdentifiers.IdSha384);
+ digestNameToOids.Add("SHA-512", NistObjectIdentifiers.IdSha512);
+
+ digestNameToOids.Add("SHA1", OiwObjectIdentifiers.IdSha1);
+ digestNameToOids.Add("SHA224", NistObjectIdentifiers.IdSha224);
+ digestNameToOids.Add("SHA256", NistObjectIdentifiers.IdSha256);
+ digestNameToOids.Add("SHA384", NistObjectIdentifiers.IdSha384);
+ digestNameToOids.Add("SHA512", NistObjectIdentifiers.IdSha512);
+
+ digestNameToOids.Add("SHA3-224", NistObjectIdentifiers.IdSha3_224);
+ digestNameToOids.Add("SHA3-256", NistObjectIdentifiers.IdSha3_256);
+ digestNameToOids.Add("SHA3-384", NistObjectIdentifiers.IdSha3_384);
+ digestNameToOids.Add("SHA3-512", NistObjectIdentifiers.IdSha3_512);
+
+ digestNameToOids.Add("SHAKE-128", NistObjectIdentifiers.IdShake128);
+ digestNameToOids.Add("SHAKE-256", NistObjectIdentifiers.IdShake256);
+
+ digestNameToOids.Add("GOST3411", CryptoProObjectIdentifiers.GostR3411);
+
+ digestNameToOids.Add("MD2", PkcsObjectIdentifiers.MD2);
+ digestNameToOids.Add("MD4", PkcsObjectIdentifiers.MD4);
+ digestNameToOids.Add("MD5", PkcsObjectIdentifiers.MD5);
+
+ digestNameToOids.Add("RIPEMD128", TeleTrusTObjectIdentifiers.RipeMD128);
+ digestNameToOids.Add("RIPEMD160", TeleTrusTObjectIdentifiers.RipeMD160);
+ digestNameToOids.Add("RIPEMD256", TeleTrusTObjectIdentifiers.RipeMD256);
+ }
+
+ public AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId)
+ {
+ AlgorithmIdentifier digAlgId;
+
+ if (sigAlgId.Algorithm.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ digAlgId = RsassaPssParameters.GetInstance(sigAlgId.Parameters).HashAlgorithm;
+ }
+ else
+ {
+ digAlgId = new AlgorithmIdentifier((DerObjectIdentifier)digestOids[sigAlgId.Algorithm], DerNull.Instance);
+ }
+
+ return digAlgId;
+ }
+
+ public AlgorithmIdentifier find(String digAlgName)
+ {
+ return new AlgorithmIdentifier((DerObjectIdentifier)digestNameToOids[digAlgName], DerNull.Instance);
+ }
+ }
+
public class CmsSignedGenerator
{
/**
@@ -29,233 +123,145 @@ namespace Org.BouncyCastle.Cms
*/
public static readonly string Data = CmsObjectIdentifiers.Data.Id;
- public static readonly string DigestSha1 = OiwObjectIdentifiers.IdSha1.Id;
+ public static readonly string DigestSha1 = OiwObjectIdentifiers.IdSha1.Id;
public static readonly string DigestSha224 = NistObjectIdentifiers.IdSha224.Id;
public static readonly string DigestSha256 = NistObjectIdentifiers.IdSha256.Id;
public static readonly string DigestSha384 = NistObjectIdentifiers.IdSha384.Id;
public static readonly string DigestSha512 = NistObjectIdentifiers.IdSha512.Id;
public static readonly string DigestMD5 = PkcsObjectIdentifiers.MD5.Id;
public static readonly string DigestGost3411 = CryptoProObjectIdentifiers.GostR3411.Id;
- public static readonly string DigestRipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id;
- public static readonly string DigestRipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id;
- public static readonly string DigestRipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id;
+ public static readonly string DigestRipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id;
+ public static readonly string DigestRipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id;
+ public static readonly string DigestRipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id;
- public static readonly string EncryptionRsa = PkcsObjectIdentifiers.RsaEncryption.Id;
+ public static readonly string EncryptionRsa = PkcsObjectIdentifiers.RsaEncryption.Id;
public static readonly string EncryptionDsa = X9ObjectIdentifiers.IdDsaWithSha1.Id;
public static readonly string EncryptionECDsa = X9ObjectIdentifiers.ECDsaWithSha1.Id;
public static readonly string EncryptionRsaPss = PkcsObjectIdentifiers.IdRsassaPss.Id;
public static readonly string EncryptionGost3410 = CryptoProObjectIdentifiers.GostR3410x94.Id;
public static readonly string EncryptionECGost3410 = CryptoProObjectIdentifiers.GostR3410x2001.Id;
- private static readonly string EncryptionECDsaWithSha1 = X9ObjectIdentifiers.ECDsaWithSha1.Id;
- private static readonly string EncryptionECDsaWithSha224 = X9ObjectIdentifiers.ECDsaWithSha224.Id;
- private static readonly string EncryptionECDsaWithSha256 = X9ObjectIdentifiers.ECDsaWithSha256.Id;
- private static readonly string EncryptionECDsaWithSha384 = X9ObjectIdentifiers.ECDsaWithSha384.Id;
- private static readonly string EncryptionECDsaWithSha512 = X9ObjectIdentifiers.ECDsaWithSha512.Id;
-
- private static readonly ISet noParams = new HashSet();
- private static readonly IDictionary ecAlgorithms = Platform.CreateHashtable();
-
- static CmsSignedGenerator()
- {
- noParams.Add(EncryptionDsa);
-// noParams.Add(EncryptionECDsa);
- noParams.Add(EncryptionECDsaWithSha1);
- noParams.Add(EncryptionECDsaWithSha224);
- noParams.Add(EncryptionECDsaWithSha256);
- noParams.Add(EncryptionECDsaWithSha384);
- noParams.Add(EncryptionECDsaWithSha512);
-
- ecAlgorithms.Add(DigestSha1, EncryptionECDsaWithSha1);
- ecAlgorithms.Add(DigestSha224, EncryptionECDsaWithSha224);
- ecAlgorithms.Add(DigestSha256, EncryptionECDsaWithSha256);
- ecAlgorithms.Add(DigestSha384, EncryptionECDsaWithSha384);
- ecAlgorithms.Add(DigestSha512, EncryptionECDsaWithSha512);
- }
-
- internal IList _certs = Platform.CreateArrayList();
+ internal IList _certs = Platform.CreateArrayList();
internal IList _crls = Platform.CreateArrayList();
- internal IList _signers = Platform.CreateArrayList();
- internal IDictionary _digests = Platform.CreateHashtable();
-
- protected readonly SecureRandom rand;
-
- protected CmsSignedGenerator()
- : this(new SecureRandom())
- {
- }
-
- /// <summary>Constructor allowing specific source of randomness</summary>
- /// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
- protected CmsSignedGenerator(
- SecureRandom rand)
- {
- this.rand = rand;
- }
-
- protected string GetEncOid(
- AsymmetricKeyParameter key,
- string digestOID)
+ internal IList _signers = Platform.CreateArrayList();
+ internal IDictionary _digests = Platform.CreateHashtable();
+
+ protected readonly SecureRandom rand;
+
+ protected CmsSignedGenerator()
+ : this(new SecureRandom())
{
- string encOID = null;
-
- if (key is RsaKeyParameters)
- {
- if (!((RsaKeyParameters) key).IsPrivate)
- throw new ArgumentException("Expected RSA private key");
-
- encOID = EncryptionRsa;
- }
- else if (key is DsaPrivateKeyParameters)
- {
- if (!digestOID.Equals(DigestSha1))
- throw new ArgumentException("can't mix DSA with anything but SHA1");
-
- encOID = EncryptionDsa;
- }
- else if (key is ECPrivateKeyParameters)
- {
- ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters) key;
- string algName = ecPrivKey.AlgorithmName;
-
- if (algName == "ECGOST3410")
- {
- encOID = EncryptionECGost3410;
- }
- else
- {
- // TODO Should we insist on algName being one of "EC" or "ECDSA", as Java does?
- encOID = (string) ecAlgorithms[digestOID];
-
- if (encOID == null)
- throw new ArgumentException("can't mix ECDSA with anything but SHA family digests");
- }
- }
- else if (key is Gost3410PrivateKeyParameters)
- {
- encOID = EncryptionGost3410;
- }
- else
- {
- throw new ArgumentException("Unknown algorithm in CmsSignedGenerator.GetEncOid");
- }
-
- return encOID;
}
- internal static AlgorithmIdentifier GetEncAlgorithmIdentifier(
- DerObjectIdentifier encOid,
- Asn1Encodable sigX509Parameters)
- {
- if (noParams.Contains(encOid.Id))
- {
- return new AlgorithmIdentifier(encOid);
- }
-
- return new AlgorithmIdentifier(encOid, sigX509Parameters);
- }
-
- internal protected virtual IDictionary GetBaseParameters(
- DerObjectIdentifier contentType,
- AlgorithmIdentifier digAlgId,
- byte[] hash)
- {
- IDictionary param = Platform.CreateHashtable();
+ /// <summary>Constructor allowing specific source of randomness</summary>
+ /// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+ protected CmsSignedGenerator(
+ SecureRandom rand)
+ {
+ this.rand = rand;
+ }
+
+ internal protected virtual IDictionary GetBaseParameters(
+ DerObjectIdentifier contentType,
+ AlgorithmIdentifier digAlgId,
+ byte[] hash)
+ {
+ IDictionary param = Platform.CreateHashtable();
if (contentType != null)
{
param[CmsAttributeTableParameter.ContentType] = contentType;
}
- param[CmsAttributeTableParameter.DigestAlgorithmIdentifier] = digAlgId;
+ param[CmsAttributeTableParameter.DigestAlgorithmIdentifier] = digAlgId;
param[CmsAttributeTableParameter.Digest] = hash.Clone();
return param;
- }
+ }
- internal protected virtual Asn1Set GetAttributeSet(
+ internal protected virtual Asn1Set GetAttributeSet(
Asn1.Cms.AttributeTable attr)
{
- return attr == null
- ? null
- : new DerSet(attr.ToAsn1EncodableVector());
+ return attr == null
+ ? null
+ : new DerSet(attr.ToAsn1EncodableVector());
}
- public void AddCertificates(
- IX509Store certStore)
- {
+ public void AddCertificates(
+ IX509Store certStore)
+ {
CollectionUtilities.AddRange(_certs, CmsUtilities.GetCertificatesFromStore(certStore));
}
- public void AddCrls(
- IX509Store crlStore)
- {
+ public void AddCrls(
+ IX509Store crlStore)
+ {
CollectionUtilities.AddRange(_crls, CmsUtilities.GetCrlsFromStore(crlStore));
- }
+ }
- /**
+ /**
* Add the attribute certificates contained in the passed in store to the
* generator.
*
* @param store a store of Version 2 attribute certificates
* @throws CmsException if an error occurse processing the store.
*/
- public void AddAttributeCertificates(
- IX509Store store)
- {
- try
- {
- foreach (IX509AttributeCertificate attrCert in store.GetMatches(null))
- {
- _certs.Add(new DerTaggedObject(false, 2,
- AttributeCertificate.GetInstance(Asn1Object.FromByteArray(attrCert.GetEncoded()))));
- }
- }
- catch (Exception e)
- {
- throw new CmsException("error processing attribute certs", e);
- }
- }
-
- /**
+ public void AddAttributeCertificates(
+ IX509Store store)
+ {
+ try
+ {
+ foreach (IX509AttributeCertificate attrCert in store.GetMatches(null))
+ {
+ _certs.Add(new DerTaggedObject(false, 2,
+ AttributeCertificate.GetInstance(Asn1Object.FromByteArray(attrCert.GetEncoded()))));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CmsException("error processing attribute certs", e);
+ }
+ }
+
+ /**
* Add a store of precalculated signers to the generator.
*
* @param signerStore store of signers
*/
- public void AddSigners(
- SignerInformationStore signerStore)
- {
- foreach (SignerInformation o in signerStore.GetSigners())
- {
- _signers.Add(o);
- AddSignerCallback(o);
- }
- }
-
- /**
+ public void AddSigners(
+ SignerInformationStore signerStore)
+ {
+ foreach (SignerInformation o in signerStore.GetSigners())
+ {
+ _signers.Add(o);
+ AddSignerCallback(o);
+ }
+ }
+
+ /**
* Return a map of oids and byte arrays representing the digests calculated on the content during
* the last generate.
*
* @return a map of oids (as String objects) and byte[] representing digests.
*/
- public IDictionary GetGeneratedDigests()
- {
- return Platform.CreateHashtable(_digests);
- }
-
- internal virtual void AddSignerCallback(
- SignerInformation si)
- {
- }
-
- internal static SignerIdentifier GetSignerIdentifier(X509Certificate cert)
- {
- return new SignerIdentifier(CmsUtilities.GetIssuerAndSerialNumber(cert));
- }
-
- internal static SignerIdentifier GetSignerIdentifier(byte[] subjectKeyIdentifier)
- {
- return new SignerIdentifier(new DerOctetString(subjectKeyIdentifier));
- }
- }
+ public IDictionary GetGeneratedDigests()
+ {
+ return Platform.CreateHashtable(_digests);
+ }
+
+ internal virtual void AddSignerCallback(
+ SignerInformation si)
+ {
+ }
+
+ internal static SignerIdentifier GetSignerIdentifier(X509Certificate cert)
+ {
+ return new SignerIdentifier(CmsUtilities.GetIssuerAndSerialNumber(cert));
+ }
+
+ internal static SignerIdentifier GetSignerIdentifier(byte[] subjectKeyIdentifier)
+ {
+ return new SignerIdentifier(new DerOctetString(subjectKeyIdentifier));
+ }
+ }
}
diff --git a/crypto/src/cms/CMSSignedHelper.cs b/crypto/src/cms/CMSSignedHelper.cs
index b3406fc06..23657ef86 100644
--- a/crypto/src/cms/CMSSignedHelper.cs
+++ b/crypto/src/cms/CMSSignedHelper.cs
@@ -18,6 +18,8 @@ using Org.BouncyCastle.Security.Certificates;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.X509.Store;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Collections;
namespace Org.BouncyCastle.Cms
{
@@ -25,11 +27,20 @@ namespace Org.BouncyCastle.Cms
{
internal static readonly CmsSignedHelper Instance = new CmsSignedHelper();
- private static readonly IDictionary encryptionAlgs = Platform.CreateHashtable();
+ private static readonly string EncryptionECDsaWithSha1 = X9ObjectIdentifiers.ECDsaWithSha1.Id;
+ private static readonly string EncryptionECDsaWithSha224 = X9ObjectIdentifiers.ECDsaWithSha224.Id;
+ private static readonly string EncryptionECDsaWithSha256 = X9ObjectIdentifiers.ECDsaWithSha256.Id;
+ private static readonly string EncryptionECDsaWithSha384 = X9ObjectIdentifiers.ECDsaWithSha384.Id;
+ private static readonly string EncryptionECDsaWithSha512 = X9ObjectIdentifiers.ECDsaWithSha512.Id;
+
+ private static readonly IDictionary encryptionAlgs = Platform.CreateHashtable();
private static readonly IDictionary digestAlgs = Platform.CreateHashtable();
private static readonly IDictionary digestAliases = Platform.CreateHashtable();
- private static void AddEntries(DerObjectIdentifier oid, string digest, string encryption)
+ private static readonly ISet noParams = new HashSet();
+ private static readonly IDictionary ecAlgorithms = Platform.CreateHashtable();
+
+ private static void AddEntries(DerObjectIdentifier oid, string digest, string encryption)
{
string alias = oid.Id;
digestAlgs.Add(alias, digest);
@@ -100,7 +111,21 @@ namespace Org.BouncyCastle.Cms
digestAliases.Add("SHA256", new string[] { "SHA-256" });
digestAliases.Add("SHA384", new string[] { "SHA-384" });
digestAliases.Add("SHA512", new string[] { "SHA-512" });
- }
+
+ noParams.Add(CmsSignedGenerator.EncryptionDsa);
+ // noParams.Add(EncryptionECDsa);
+ noParams.Add(EncryptionECDsaWithSha1);
+ noParams.Add(EncryptionECDsaWithSha224);
+ noParams.Add(EncryptionECDsaWithSha256);
+ noParams.Add(EncryptionECDsaWithSha384);
+ noParams.Add(EncryptionECDsaWithSha512);
+
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha1, EncryptionECDsaWithSha1);
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha224, EncryptionECDsaWithSha224);
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha256, EncryptionECDsaWithSha256);
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha384, EncryptionECDsaWithSha384);
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha512, EncryptionECDsaWithSha512);
+ }
/**
* Return the digest algorithm using one of the standard JCA string
@@ -119,7 +144,19 @@ namespace Org.BouncyCastle.Cms
return digestAlgOid;
}
- internal string[] GetDigestAliases(
+ internal AlgorithmIdentifier GetEncAlgorithmIdentifier(
+ DerObjectIdentifier encOid,
+ Asn1Encodable sigX509Parameters)
+ {
+ if (noParams.Contains(encOid.Id))
+ {
+ return new AlgorithmIdentifier(encOid);
+ }
+
+ return new AlgorithmIdentifier(encOid, sigX509Parameters);
+ }
+
+ internal string[] GetDigestAliases(
string algName)
{
string[] aliases = (string[]) digestAliases[algName];
@@ -315,5 +352,75 @@ namespace Org.BouncyCastle.Cms
return algId;
}
+
+ internal string GetEncOid(
+ AsymmetricKeyParameter key,
+ string digestOID)
+ {
+ string encOID = null;
+
+ if (key is RsaKeyParameters)
+ {
+ if (!((RsaKeyParameters)key).IsPrivate)
+ throw new ArgumentException("Expected RSA private key");
+
+ encOID = CmsSignedGenerator.EncryptionRsa;
+ }
+ else if (key is DsaPrivateKeyParameters)
+ {
+ if (digestOID.Equals(CmsSignedGenerator.DigestSha1))
+ {
+ encOID = CmsSignedGenerator.EncryptionDsa;
+ }
+ else if (digestOID.Equals(CmsSignedGenerator.DigestSha224))
+ {
+ encOID = NistObjectIdentifiers.DsaWithSha224.Id;
+ }
+ else if (digestOID.Equals(CmsSignedGenerator.DigestSha256))
+ {
+ encOID = NistObjectIdentifiers.DsaWithSha256.Id;
+ }
+ else if (digestOID.Equals(CmsSignedGenerator.DigestSha384))
+ {
+ encOID = NistObjectIdentifiers.DsaWithSha384.Id;
+ }
+ else if (digestOID.Equals(CmsSignedGenerator.DigestSha512))
+ {
+ encOID = NistObjectIdentifiers.DsaWithSha512.Id;
+ }
+ else
+ {
+ throw new ArgumentException("can't mix DSA with anything but SHA1/SHA2");
+ }
+ }
+ else if (key is ECPrivateKeyParameters)
+ {
+ ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters)key;
+ string algName = ecPrivKey.AlgorithmName;
+
+ if (algName == "ECGOST3410")
+ {
+ encOID = CmsSignedGenerator.EncryptionECGost3410;
+ }
+ else
+ {
+ // TODO Should we insist on algName being one of "EC" or "ECDSA", as Java does?
+ encOID = (string)ecAlgorithms[digestOID];
+
+ if (encOID == null)
+ throw new ArgumentException("can't mix ECDSA with anything but SHA family digests");
+ }
+ }
+ else if (key is Gost3410PrivateKeyParameters)
+ {
+ encOID = CmsSignedGenerator.EncryptionGost3410;
+ }
+ else
+ {
+ throw new ArgumentException("Unknown algorithm in CmsSignedGenerator.GetEncOid");
+ }
+
+ return encOID;
+ }
}
}
diff --git a/crypto/src/cms/CMSTypedStream.cs b/crypto/src/cms/CMSTypedStream.cs
index 9cb314211..d04846ee1 100644
--- a/crypto/src/cms/CMSTypedStream.cs
+++ b/crypto/src/cms/CMSTypedStream.cs
@@ -2,7 +2,6 @@ using System;
using System.IO;
using Org.BouncyCastle.Asn1.Pkcs;
-using Org.BouncyCastle.Asn1.Utilities;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Cms
diff --git a/crypto/src/cms/KeyAgreeRecipientInformation.cs b/crypto/src/cms/KeyAgreeRecipientInformation.cs
index 38a94b0a4..8e006e545 100644
--- a/crypto/src/cms/KeyAgreeRecipientInformation.cs
+++ b/crypto/src/cms/KeyAgreeRecipientInformation.cs
@@ -18,209 +18,209 @@ using Org.BouncyCastle.X509;
namespace Org.BouncyCastle.Cms
{
- /**
- * the RecipientInfo class for a recipient who has been sent a message
- * encrypted using key agreement.
- */
- public class KeyAgreeRecipientInformation
- : RecipientInformation
- {
- private KeyAgreeRecipientInfo info;
- private Asn1OctetString encryptedKey;
-
- internal static void ReadRecipientInfo(IList infos, KeyAgreeRecipientInfo info,
- CmsSecureReadable secureReadable)
- {
- try
- {
- foreach (Asn1Encodable rek in info.RecipientEncryptedKeys)
- {
- RecipientEncryptedKey id = RecipientEncryptedKey.GetInstance(rek.ToAsn1Object());
-
- RecipientID rid = new RecipientID();
-
- Asn1.Cms.KeyAgreeRecipientIdentifier karid = id.Identifier;
-
- Asn1.Cms.IssuerAndSerialNumber iAndSN = karid.IssuerAndSerialNumber;
- if (iAndSN != null)
- {
- rid.Issuer = iAndSN.Name;
- rid.SerialNumber = iAndSN.SerialNumber.Value;
- }
- else
- {
- Asn1.Cms.RecipientKeyIdentifier rKeyID = karid.RKeyID;
-
- // Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational
-
- rid.SubjectKeyIdentifier = rKeyID.SubjectKeyIdentifier.GetOctets();
- }
-
- infos.Add(new KeyAgreeRecipientInformation(info, rid, id.EncryptedKey,
- secureReadable));
- }
- }
- catch (IOException e)
- {
- throw new ArgumentException("invalid rid in KeyAgreeRecipientInformation", e);
- }
- }
-
- internal KeyAgreeRecipientInformation(
- KeyAgreeRecipientInfo info,
- RecipientID rid,
- Asn1OctetString encryptedKey,
- CmsSecureReadable secureReadable)
- : base(info.KeyEncryptionAlgorithm, secureReadable)
- {
- this.info = info;
- this.rid = rid;
- this.encryptedKey = encryptedKey;
- }
-
- private AsymmetricKeyParameter GetSenderPublicKey(
- AsymmetricKeyParameter receiverPrivateKey,
- OriginatorIdentifierOrKey originator)
- {
- OriginatorPublicKey opk = originator.OriginatorPublicKey;
- if (opk != null)
- {
- return GetPublicKeyFromOriginatorPublicKey(receiverPrivateKey, opk);
- }
-
- OriginatorID origID = new OriginatorID();
-
- Asn1.Cms.IssuerAndSerialNumber iAndSN = originator.IssuerAndSerialNumber;
- if (iAndSN != null)
- {
- origID.Issuer = iAndSN.Name;
- origID.SerialNumber = iAndSN.SerialNumber.Value;
- }
- else
- {
- SubjectKeyIdentifier ski = originator.SubjectKeyIdentifier;
-
- origID.SubjectKeyIdentifier = ski.GetKeyIdentifier();
- }
-
- return GetPublicKeyFromOriginatorID(origID);
- }
-
- private AsymmetricKeyParameter GetPublicKeyFromOriginatorPublicKey(
- AsymmetricKeyParameter receiverPrivateKey,
- OriginatorPublicKey originatorPublicKey)
- {
- PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(receiverPrivateKey);
- SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
- privInfo.AlgorithmID,
- originatorPublicKey.PublicKey.GetBytes());
- return PublicKeyFactory.CreateKey(pubInfo);
- }
-
- private AsymmetricKeyParameter GetPublicKeyFromOriginatorID(
- OriginatorID origID)
- {
- // TODO Support all alternatives for OriginatorIdentifierOrKey
- // see RFC 3852 6.2.2
- throw new CmsException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier");
- }
-
- private KeyParameter CalculateAgreedWrapKey(
- string wrapAlg,
- AsymmetricKeyParameter senderPublicKey,
- AsymmetricKeyParameter receiverPrivateKey)
- {
- DerObjectIdentifier agreeAlgID = keyEncAlg.ObjectID;
-
- ICipherParameters senderPublicParams = senderPublicKey;
- ICipherParameters receiverPrivateParams = receiverPrivateKey;
-
- if (agreeAlgID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
- {
- byte[] ukmEncoding = info.UserKeyingMaterial.GetOctets();
- MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.GetInstance(
- Asn1Object.FromByteArray(ukmEncoding));
-
- AsymmetricKeyParameter ephemeralKey = GetPublicKeyFromOriginatorPublicKey(
- receiverPrivateKey, ukm.EphemeralPublicKey);
-
- senderPublicParams = new MqvPublicParameters(
- (ECPublicKeyParameters)senderPublicParams,
- (ECPublicKeyParameters)ephemeralKey);
- receiverPrivateParams = new MqvPrivateParameters(
- (ECPrivateKeyParameters)receiverPrivateParams,
- (ECPrivateKeyParameters)receiverPrivateParams);
- }
-
- IBasicAgreement agreement = AgreementUtilities.GetBasicAgreementWithKdf(
- agreeAlgID, wrapAlg);
- agreement.Init(receiverPrivateParams);
- BigInteger agreedValue = agreement.CalculateAgreement(senderPublicParams);
-
- int wrapKeySize = GeneratorUtilities.GetDefaultKeySize(wrapAlg) / 8;
- byte[] wrapKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, wrapKeySize);
- return ParameterUtilities.CreateKeyParameter(wrapAlg, wrapKeyBytes);
- }
-
- private KeyParameter UnwrapSessionKey(
- string wrapAlg,
- KeyParameter agreedKey)
- {
- byte[] encKeyOctets = encryptedKey.GetOctets();
-
- IWrapper keyCipher = WrapperUtilities.GetWrapper(wrapAlg);
- keyCipher.Init(false, agreedKey);
- byte[] sKeyBytes = keyCipher.Unwrap(encKeyOctets, 0, encKeyOctets.Length);
- return ParameterUtilities.CreateKeyParameter(GetContentAlgorithmName(), sKeyBytes);
- }
-
- internal KeyParameter GetSessionKey(
- AsymmetricKeyParameter receiverPrivateKey)
- {
- try
- {
- string wrapAlg = DerObjectIdentifier.GetInstance(
- Asn1Sequence.GetInstance(keyEncAlg.Parameters)[0]).Id;
-
- AsymmetricKeyParameter senderPublicKey = GetSenderPublicKey(
- receiverPrivateKey, info.Originator);
-
- KeyParameter agreedWrapKey = CalculateAgreedWrapKey(wrapAlg,
- senderPublicKey, receiverPrivateKey);
-
- return UnwrapSessionKey(wrapAlg, agreedWrapKey);
- }
- catch (SecurityUtilityException e)
- {
- throw new CmsException("couldn't create cipher.", e);
- }
- catch (InvalidKeyException e)
- {
- throw new CmsException("key invalid in message.", e);
- }
- catch (Exception e)
- {
- throw new CmsException("originator key invalid.", e);
- }
- }
-
- /**
- * decrypt the content and return an input stream.
- */
- public override CmsTypedStream GetContentStream(
- ICipherParameters key)
- {
- if (!(key is AsymmetricKeyParameter))
- throw new ArgumentException("KeyAgreement requires asymmetric key", "key");
-
- AsymmetricKeyParameter receiverPrivateKey = (AsymmetricKeyParameter) key;
-
- if (!receiverPrivateKey.IsPrivate)
- throw new ArgumentException("Expected private key", "key");
-
- KeyParameter sKey = GetSessionKey(receiverPrivateKey);
-
- return GetContentFromSessionKey(sKey);
- }
- }
+ /**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using key agreement.
+ */
+ public class KeyAgreeRecipientInformation
+ : RecipientInformation
+ {
+ private KeyAgreeRecipientInfo info;
+ private Asn1OctetString encryptedKey;
+
+ internal static void ReadRecipientInfo(IList infos, KeyAgreeRecipientInfo info,
+ CmsSecureReadable secureReadable)
+ {
+ try
+ {
+ foreach (Asn1Encodable rek in info.RecipientEncryptedKeys)
+ {
+ RecipientEncryptedKey id = RecipientEncryptedKey.GetInstance(rek.ToAsn1Object());
+
+ RecipientID rid = new RecipientID();
+
+ Asn1.Cms.KeyAgreeRecipientIdentifier karid = id.Identifier;
+
+ Asn1.Cms.IssuerAndSerialNumber iAndSN = karid.IssuerAndSerialNumber;
+ if (iAndSN != null)
+ {
+ rid.Issuer = iAndSN.Name;
+ rid.SerialNumber = iAndSN.SerialNumber.Value;
+ }
+ else
+ {
+ Asn1.Cms.RecipientKeyIdentifier rKeyID = karid.RKeyID;
+
+ // Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational
+
+ rid.SubjectKeyIdentifier = rKeyID.SubjectKeyIdentifier.GetOctets();
+ }
+
+ infos.Add(new KeyAgreeRecipientInformation(info, rid, id.EncryptedKey,
+ secureReadable));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new ArgumentException("invalid rid in KeyAgreeRecipientInformation", e);
+ }
+ }
+
+ internal KeyAgreeRecipientInformation(
+ KeyAgreeRecipientInfo info,
+ RecipientID rid,
+ Asn1OctetString encryptedKey,
+ CmsSecureReadable secureReadable)
+ : base(info.KeyEncryptionAlgorithm, secureReadable)
+ {
+ this.info = info;
+ this.rid = rid;
+ this.encryptedKey = encryptedKey;
+ }
+
+ private AsymmetricKeyParameter GetSenderPublicKey(
+ AsymmetricKeyParameter receiverPrivateKey,
+ OriginatorIdentifierOrKey originator)
+ {
+ OriginatorPublicKey opk = originator.OriginatorPublicKey;
+ if (opk != null)
+ {
+ return GetPublicKeyFromOriginatorPublicKey(receiverPrivateKey, opk);
+ }
+
+ OriginatorID origID = new OriginatorID();
+
+ Asn1.Cms.IssuerAndSerialNumber iAndSN = originator.IssuerAndSerialNumber;
+ if (iAndSN != null)
+ {
+ origID.Issuer = iAndSN.Name;
+ origID.SerialNumber = iAndSN.SerialNumber.Value;
+ }
+ else
+ {
+ SubjectKeyIdentifier ski = originator.SubjectKeyIdentifier;
+
+ origID.SubjectKeyIdentifier = ski.GetKeyIdentifier();
+ }
+
+ return GetPublicKeyFromOriginatorID(origID);
+ }
+
+ private AsymmetricKeyParameter GetPublicKeyFromOriginatorPublicKey(
+ AsymmetricKeyParameter receiverPrivateKey,
+ OriginatorPublicKey originatorPublicKey)
+ {
+ PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(receiverPrivateKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
+ privInfo.PrivateKeyAlgorithm,
+ originatorPublicKey.PublicKey.GetBytes());
+ return PublicKeyFactory.CreateKey(pubInfo);
+ }
+
+ private AsymmetricKeyParameter GetPublicKeyFromOriginatorID(
+ OriginatorID origID)
+ {
+ // TODO Support all alternatives for OriginatorIdentifierOrKey
+ // see RFC 3852 6.2.2
+ throw new CmsException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier");
+ }
+
+ private KeyParameter CalculateAgreedWrapKey(
+ string wrapAlg,
+ AsymmetricKeyParameter senderPublicKey,
+ AsymmetricKeyParameter receiverPrivateKey)
+ {
+ DerObjectIdentifier agreeAlgID = keyEncAlg.ObjectID;
+
+ ICipherParameters senderPublicParams = senderPublicKey;
+ ICipherParameters receiverPrivateParams = receiverPrivateKey;
+
+ if (agreeAlgID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
+ {
+ byte[] ukmEncoding = info.UserKeyingMaterial.GetOctets();
+ MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.GetInstance(
+ Asn1Object.FromByteArray(ukmEncoding));
+
+ AsymmetricKeyParameter ephemeralKey = GetPublicKeyFromOriginatorPublicKey(
+ receiverPrivateKey, ukm.EphemeralPublicKey);
+
+ senderPublicParams = new MqvPublicParameters(
+ (ECPublicKeyParameters)senderPublicParams,
+ (ECPublicKeyParameters)ephemeralKey);
+ receiverPrivateParams = new MqvPrivateParameters(
+ (ECPrivateKeyParameters)receiverPrivateParams,
+ (ECPrivateKeyParameters)receiverPrivateParams);
+ }
+
+ IBasicAgreement agreement = AgreementUtilities.GetBasicAgreementWithKdf(
+ agreeAlgID, wrapAlg);
+ agreement.Init(receiverPrivateParams);
+ BigInteger agreedValue = agreement.CalculateAgreement(senderPublicParams);
+
+ int wrapKeySize = GeneratorUtilities.GetDefaultKeySize(wrapAlg) / 8;
+ byte[] wrapKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, wrapKeySize);
+ return ParameterUtilities.CreateKeyParameter(wrapAlg, wrapKeyBytes);
+ }
+
+ private KeyParameter UnwrapSessionKey(
+ string wrapAlg,
+ KeyParameter agreedKey)
+ {
+ byte[] encKeyOctets = encryptedKey.GetOctets();
+
+ IWrapper keyCipher = WrapperUtilities.GetWrapper(wrapAlg);
+ keyCipher.Init(false, agreedKey);
+ byte[] sKeyBytes = keyCipher.Unwrap(encKeyOctets, 0, encKeyOctets.Length);
+ return ParameterUtilities.CreateKeyParameter(GetContentAlgorithmName(), sKeyBytes);
+ }
+
+ internal KeyParameter GetSessionKey(
+ AsymmetricKeyParameter receiverPrivateKey)
+ {
+ try
+ {
+ string wrapAlg = DerObjectIdentifier.GetInstance(
+ Asn1Sequence.GetInstance(keyEncAlg.Parameters)[0]).Id;
+
+ AsymmetricKeyParameter senderPublicKey = GetSenderPublicKey(
+ receiverPrivateKey, info.Originator);
+
+ KeyParameter agreedWrapKey = CalculateAgreedWrapKey(wrapAlg,
+ senderPublicKey, receiverPrivateKey);
+
+ return UnwrapSessionKey(wrapAlg, agreedWrapKey);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ catch (Exception e)
+ {
+ throw new CmsException("originator key invalid.", e);
+ }
+ }
+
+ /**
+ * decrypt the content and return an input stream.
+ */
+ public override CmsTypedStream GetContentStream(
+ ICipherParameters key)
+ {
+ if (!(key is AsymmetricKeyParameter))
+ throw new ArgumentException("KeyAgreement requires asymmetric key", "key");
+
+ AsymmetricKeyParameter receiverPrivateKey = (AsymmetricKeyParameter) key;
+
+ if (!receiverPrivateKey.IsPrivate)
+ throw new ArgumentException("Expected private key", "key");
+
+ KeyParameter sKey = GetSessionKey(receiverPrivateKey);
+
+ return GetContentFromSessionKey(sKey);
+ }
+ }
}
diff --git a/crypto/src/cms/SignerInfoGenerator.cs b/crypto/src/cms/SignerInfoGenerator.cs
index f78cf2c01..62db40ad8 100644
--- a/crypto/src/cms/SignerInfoGenerator.cs
+++ b/crypto/src/cms/SignerInfoGenerator.cs
@@ -3,12 +3,165 @@ using System;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.X509;
namespace Org.BouncyCastle.Cms
{
- internal interface SignerInfoGenerator
- {
- SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
- byte[] calculatedDigest);
- }
+ internal interface ISignerInfoGenerator
+ {
+ SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
+ byte[] calculatedDigest);
+ }
+
+ public class SignerInfoGenerator
+ {
+ internal X509Certificate certificate;
+ internal ISignatureCalculator contentSigner;
+ internal SignerIdentifier sigId;
+ internal CmsAttributeTableGenerator signedGen;
+ internal CmsAttributeTableGenerator unsignedGen;
+ private bool isDirectSignature;
+
+ internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureCalculator contentSigner): this(sigId, contentSigner, false)
+ {
+
+ }
+
+ internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureCalculator contentSigner, bool isDirectSignature)
+ {
+ this.sigId = sigId;
+ this.contentSigner = contentSigner;
+ this.isDirectSignature = isDirectSignature;
+ if (this.isDirectSignature)
+ {
+ this.signedGen = null;
+ this.unsignedGen = null;
+ }
+ else
+ {
+ this.signedGen = new DefaultSignedAttributeTableGenerator();
+ this.unsignedGen = null;
+ }
+ }
+
+ internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureCalculator contentSigner, CmsAttributeTableGenerator signedGen, CmsAttributeTableGenerator unsignedGen)
+ {
+ this.sigId = sigId;
+ this.contentSigner = contentSigner;
+ this.signedGen = signedGen;
+ this.unsignedGen = unsignedGen;
+ this.isDirectSignature = false;
+ }
+
+ internal void setAssociatedCertificate(X509Certificate certificate)
+ {
+ this.certificate = certificate;
+ }
+ }
+
+ public class SignerInfoGeneratorBuilder
+ {
+ private bool directSignature;
+ private CmsAttributeTableGenerator signedGen;
+ private CmsAttributeTableGenerator unsignedGen;
+
+ public SignerInfoGeneratorBuilder()
+ {
+ }
+
+ /**
+ * If the passed in flag is true, the signer signature will be based on the data, not
+ * a collection of signed attributes, and no signed attributes will be included.
+ *
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder SetDirectSignature(bool hasNoSignedAttributes)
+ {
+ this.directSignature = hasNoSignedAttributes;
+
+ return this;
+ }
+
+ /**
+ * Provide a custom signed attribute generator.
+ *
+ * @param signedGen a generator of signed attributes.
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder WithSignedAttributeGenerator(CmsAttributeTableGenerator signedGen)
+ {
+ this.signedGen = signedGen;
+
+ return this;
+ }
+
+ /**
+ * Provide a generator of unsigned attributes.
+ *
+ * @param unsignedGen a generator for signed attributes.
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder WithUnsignedAttributeGenerator(CmsAttributeTableGenerator unsignedGen)
+ {
+ this.unsignedGen = unsignedGen;
+
+ return this;
+ }
+
+ /**
+ * Build a generator with the passed in certHolder issuer and serial number as the signerIdentifier.
+ *
+ * @param contentSigner operator for generating the final signature in the SignerInfo with.
+ * @param certHolder carrier for the X.509 certificate related to the contentSigner.
+ * @return a SignerInfoGenerator
+ * @throws OperatorCreationException if the generator cannot be built.
+ */
+ public SignerInfoGenerator Build(ISignatureCalculator contentSigner, X509Certificate certificate)
+ {
+ SignerIdentifier sigId = new SignerIdentifier(new IssuerAndSerialNumber(certificate.IssuerDN, new DerInteger(certificate.SerialNumber)));
+
+ SignerInfoGenerator sigInfoGen = CreateGenerator(contentSigner, sigId);
+
+ sigInfoGen.setAssociatedCertificate(certificate);
+
+ return sigInfoGen;
+ }
+
+ /**
+ * Build a generator with the passed in subjectKeyIdentifier as the signerIdentifier. If used you should
+ * try to follow the calculation described in RFC 5280 section 4.2.1.2.
+ *
+ * @param contentSigner operator for generating the final signature in the SignerInfo with.
+ * @param subjectKeyIdentifier key identifier to identify the public key for verifying the signature.
+ * @return a SignerInfoGenerator
+ * @throws OperatorCreationException if the generator cannot be built.
+ */
+ public SignerInfoGenerator Build(ISignatureCalculator contentSigner, byte[] subjectKeyIdentifier)
+ {
+ SignerIdentifier sigId = new SignerIdentifier(new DerOctetString(subjectKeyIdentifier));
+
+ return CreateGenerator(contentSigner, sigId);
+ }
+
+ private SignerInfoGenerator CreateGenerator(ISignatureCalculator contentSigner, SignerIdentifier sigId)
+ {
+ if (directSignature)
+ {
+ return new SignerInfoGenerator(sigId, contentSigner, true);
+ }
+
+ if (signedGen != null || unsignedGen != null)
+ {
+ if (signedGen == null)
+ {
+ signedGen = new DefaultSignedAttributeTableGenerator();
+ }
+
+ return new SignerInfoGenerator(sigId, contentSigner, signedGen, unsignedGen);
+ }
+
+ return new SignerInfoGenerator(sigId, contentSigner);
+ }
+ }
}
diff --git a/crypto/src/cms/SignerInformation.cs b/crypto/src/cms/SignerInformation.cs
index 20af29a50..581286a3f 100644
--- a/crypto/src/cms/SignerInformation.cs
+++ b/crypto/src/cms/SignerInformation.cs
@@ -345,9 +345,12 @@ namespace Org.BouncyCastle.Cms
// if (sigParams != null)
// throw new CmsException("unrecognised signature parameters provided");
- string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
+ string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
- sig = Helper.GetSignatureInstance(signatureName);
+ sig = Helper.GetSignatureInstance(signatureName);
+
+ //sig = Helper.GetSignatureInstance(this.EncryptionAlgOid);
+ //sig = SignerUtilities.GetSigner(sigAlgOid);
}
try
diff --git a/crypto/src/cms/SignerInformationStore.cs b/crypto/src/cms/SignerInformationStore.cs
index bd613843d..27940865d 100644
--- a/crypto/src/cms/SignerInformationStore.cs
+++ b/crypto/src/cms/SignerInformationStore.cs
@@ -8,10 +8,31 @@ namespace Org.BouncyCastle.Cms
{
public class SignerInformationStore
{
- private readonly IList all; //ArrayList[SignerInformation]
- private readonly IDictionary table = Platform.CreateHashtable(); // Hashtable[SignerID, ArrayList[SignerInformation]]
+ private readonly IList all; //ArrayList[SignerInformation]
+ private readonly IDictionary table = Platform.CreateHashtable(); // Hashtable[SignerID, ArrayList[SignerInformation]]
- public SignerInformationStore(
+ /**
+ * Create a store containing a single SignerInformation object.
+ *
+ * @param signerInfo the signer information to contain.
+ */
+ public SignerInformationStore(
+ SignerInformation signerInfo)
+ {
+ this.all = Platform.CreateArrayList(1);
+ this.all.Add(signerInfo);
+
+ SignerID sid = signerInfo.SignerID;
+
+ table[sid] = all;
+ }
+
+ /**
+ * Create a store containing a collection of SignerInformation objects.
+ *
+ * @param signerInfos a collection signer information objects to contain.
+ */
+ public SignerInformationStore(
ICollection signerInfos)
{
foreach (SignerInformation signer in signerInfos)
@@ -19,12 +40,12 @@ namespace Org.BouncyCastle.Cms
SignerID sid = signer.SignerID;
IList list = (IList)table[sid];
- if (list == null)
- {
- table[sid] = list = Platform.CreateArrayList(1);
- }
+ if (list == null)
+ {
+ table[sid] = list = Platform.CreateArrayList(1);
+ }
- list.Add(signer);
+ list.Add(signer);
}
this.all = Platform.CreateArrayList(signerInfos);
@@ -40,24 +61,24 @@ namespace Org.BouncyCastle.Cms
public SignerInformation GetFirstSigner(
SignerID selector)
{
- IList list = (IList) table[selector];
+ IList list = (IList) table[selector];
- return list == null ? null : (SignerInformation) list[0];
+ return list == null ? null : (SignerInformation) list[0];
}
- /// <summary>The number of signers in the collection.</summary>
- public int Count
+ /// <summary>The number of signers in the collection.</summary>
+ public int Count
{
- get { return all.Count; }
+ get { return all.Count; }
}
- /// <returns>An ICollection of all signers in the collection</returns>
+ /// <returns>An ICollection of all signers in the collection</returns>
public ICollection GetSigners()
{
return Platform.CreateArrayList(all);
}
- /**
+ /**
* Return possible empty collection with signers matching the passed in SignerID
*
* @param selector a signer id to select against.
@@ -66,7 +87,7 @@ namespace Org.BouncyCastle.Cms
public ICollection GetSigners(
SignerID selector)
{
- IList list = (IList) table[selector];
+ IList list = (IList) table[selector];
return list == null ? Platform.CreateArrayList() : Platform.CreateArrayList(list);
}
diff --git a/crypto/src/crypto/BufferedAeadBlockCipher.cs b/crypto/src/crypto/BufferedAeadBlockCipher.cs
index 04bcb88ed..7ba41090f 100644
--- a/crypto/src/crypto/BufferedAeadBlockCipher.cs
+++ b/crypto/src/crypto/BufferedAeadBlockCipher.cs
@@ -88,7 +88,7 @@ namespace Org.BouncyCastle.Crypto
}
/**
- * process a single byte, producing an output block if neccessary.
+ * process a single byte, producing an output block if necessary.
*
* @param in the input byte.
* @param out the space for any output that might be produced.
diff --git a/crypto/src/crypto/BufferedBlockCipher.cs b/crypto/src/crypto/BufferedBlockCipher.cs
index 3a98798a2..c87d2daf9 100644
--- a/crypto/src/crypto/BufferedBlockCipher.cs
+++ b/crypto/src/crypto/BufferedBlockCipher.cs
@@ -118,7 +118,7 @@ namespace Org.BouncyCastle.Crypto
}
/**
- * process a single byte, producing an output block if neccessary.
+ * process a single byte, producing an output block if necessary.
*
* @param in the input byte.
* @param out the space for any output that might be produced.
@@ -223,13 +223,10 @@ namespace Org.BouncyCastle.Crypto
if (outLength > 0)
{
- if ((outOff + outLength) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.OutputLength(output, outOff, outLength, "output buffer too short");
}
- int resultLen = 0;
+ int resultLen = 0;
int gapLen = buf.Length - bufOff;
if (length > gapLen)
{
@@ -339,17 +336,10 @@ namespace Org.BouncyCastle.Crypto
{
if (bufOff != 0)
{
- if (!cipher.IsPartialBlockOkay)
- {
- throw new DataLengthException("data not block size aligned");
- }
-
- if (outOff + bufOff > output.Length)
- {
- throw new DataLengthException("output buffer too short for DoFinal()");
- }
-
- // NB: Can't copy directly, or we may write too much output
+ Check.DataLength(!cipher.IsPartialBlockOkay, "data not block size aligned");
+ Check.OutputLength(output, outOff, bufOff, "output buffer too short for DoFinal()");
+
+ // NB: Can't copy directly, or we may write too much output
cipher.ProcessBlock(buf, 0, buf, 0);
Array.Copy(buf, 0, output, outOff, bufOff);
}
diff --git a/crypto/src/crypto/Check.cs b/crypto/src/crypto/Check.cs
new file mode 100644
index 000000000..96a05c64b
--- /dev/null
+++ b/crypto/src/crypto/Check.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ internal class Check
+ {
+ internal static void DataLength(bool condition, string msg)
+ {
+ if (condition)
+ throw new DataLengthException(msg);
+ }
+
+ internal static void DataLength(byte[] buf, int off, int len, string msg)
+ {
+ if (off + len > buf.Length)
+ throw new DataLengthException(msg);
+ }
+
+ internal static void OutputLength(byte[] buf, int off, int len, string msg)
+ {
+ if (off + len > buf.Length)
+ throw new OutputLengthException(msg);
+ }
+ }
+}
diff --git a/crypto/src/crypto/IBlockResult.cs b/crypto/src/crypto/IBlockResult.cs
new file mode 100644
index 000000000..c12bdaa1d
--- /dev/null
+++ b/crypto/src/crypto/IBlockResult.cs
@@ -0,0 +1,24 @@
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// <summary>
+ /// Operators that reduce their input to a single block return an object
+ /// of this type.
+ /// </summary>
+ public interface IBlockResult
+ {
+ /// <summary>
+ /// Return the final result of the operation.
+ /// </summary>
+ /// <returns>A block of bytes, representing the result of an operation.</returns>
+ byte[] DoFinal();
+
+ /// <summary>
+ /// Store the final result of the operation by copying it into the destination array.
+ /// </summary>
+ /// <returns>The number of bytes copied into destination.</returns>
+ /// <param name="destination">The byte array to copy the result into.</param>
+ /// <param name="offset">The offset into destination to start copying the result at.</param>
+ int DoFinal(byte[] destination, int offset);
+ }
+}
diff --git a/crypto/src/crypto/ISignatureCalculator.cs b/crypto/src/crypto/ISignatureCalculator.cs
new file mode 100644
index 000000000..bb733818d
--- /dev/null
+++ b/crypto/src/crypto/ISignatureCalculator.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// <summary>
+ /// Base interface for operators that serve as stream-based signature calculators.
+ /// </summary>
+ public interface ISignatureCalculator
+ {
+ /// <summary>The algorithm details object for this calculator.</summary>
+ Object AlgorithmDetails { get ; }
+
+ /// <summary>
+ /// Create a stream calculator for this signature calculator. The stream
+ /// calculator is used for the actual operation of entering the data to be signed
+ /// and producing the signature block.
+ /// </summary>
+ /// <returns>A calculator producing an IBlockResult with a signature in it.</returns>
+ IStreamCalculator CreateCalculator();
+ }
+}
+
+
diff --git a/crypto/src/crypto/ISignatureVerifier.cs b/crypto/src/crypto/ISignatureVerifier.cs
new file mode 100644
index 000000000..1f42a0256
--- /dev/null
+++ b/crypto/src/crypto/ISignatureVerifier.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// <summary>
+ /// Base interface for operators that serve as stream-based signature verifiers.
+ /// </summary>
+ public interface ISignatureVerifier
+ {
+ /// <summary>The algorithm details object for this verifier.</summary>
+ Object AlgorithmDetails { get ; }
+
+ /// <summary>
+ /// Create a stream calculator for this verifier. The stream
+ /// calculator is used for the actual operation of entering the data to be verified
+ /// and producing a result which can be used to verify the original signature.
+ /// </summary>
+ /// <returns>A calculator producing an IVerifier which can verify the signature.</returns>
+ IStreamCalculator CreateCalculator();
+ }
+}
diff --git a/crypto/src/crypto/ISignatureVerifierProvider.cs b/crypto/src/crypto/ISignatureVerifierProvider.cs
new file mode 100644
index 000000000..20180e22a
--- /dev/null
+++ b/crypto/src/crypto/ISignatureVerifierProvider.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// <summary>
+ /// Base interface for a provider to support the dynamic creation of signature verifiers.
+ /// </summary>
+ public interface ISignatureVerifierProvider
+ {
+ /// <summary>
+ /// Return a signature verfier for signature algorithm described in the passed in algorithm details object.
+ /// </summary>
+ /// <param name="algorithmDetails">The details of the signature algorithm verification is required for.</param>
+ /// <returns>A new signature verifier.</returns>
+ ISignatureVerifier CreateSignatureVerifier (Object algorithmDetails);
+ }
+}
+
diff --git a/crypto/src/crypto/IStreamCalculator.cs b/crypto/src/crypto/IStreamCalculator.cs
new file mode 100644
index 000000000..19a542845
--- /dev/null
+++ b/crypto/src/crypto/IStreamCalculator.cs
@@ -0,0 +1,23 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// <summary>
+ /// Base interface for cryptographic operations such as Hashes, MACs, and Signatures which reduce a stream of data
+ /// to a single value.
+ /// </summary>
+ public interface IStreamCalculator
+ {
+ /// <summary>Return a "sink" stream which only exists to update the implementing object.</summary>
+ /// <returns>A stream to write to in order to update the implementing object.</returns>
+ Stream Stream { get; }
+
+ /// <summary>
+ /// Return the result of processing the stream. This value is only available once the stream
+ /// has been closed.
+ /// </summary>
+ /// <returns>The result of processing the stream.</returns>
+ Object GetResult();
+ }
+}
diff --git a/crypto/src/crypto/IVerifier.cs b/crypto/src/crypto/IVerifier.cs
new file mode 100644
index 000000000..560cabf8e
--- /dev/null
+++ b/crypto/src/crypto/IVerifier.cs
@@ -0,0 +1,25 @@
+namespace Org.BouncyCastle.Crypto
+{
+ /// <summary>
+ /// Operators that reduce their input to the validation of a signature produce this type.
+ /// </summary>
+ public interface IVerifier
+ {
+ /// <summary>
+ /// Return true if the passed in data matches what is expected by the verification result.
+ /// </summary>
+ /// <param name="data">The bytes representing the signature.</param>
+ /// <returns>true if the signature verifies, false otherwise.</returns>
+ bool IsVerified(byte[] data);
+
+ /// <summary>
+ /// Return true if the length bytes from off in the source array match the signature
+ /// expected by the verification result.
+ /// </summary>
+ /// <param name="source">Byte array containing the signature.</param>
+ /// <param name="off">The offset into the source array where the signature starts.</param>
+ /// <param name="length">The number of bytes in source making up the signature.</param>
+ /// <returns>true if the signature verifies, false otherwise.</returns>
+ bool IsVerified(byte[] source, int off, int length);
+ }
+}
diff --git a/crypto/src/crypto/IXof.cs b/crypto/src/crypto/IXof.cs
new file mode 100644
index 000000000..e9e2253a0
--- /dev/null
+++ b/crypto/src/crypto/IXof.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// <remarks>
+ /// With FIPS PUB 202 a new kind of message digest was announced which supported extendable output, or variable digest sizes.
+ /// This interface provides the extra method required to support variable output on a digest implementation.
+ /// </remarks>
+ public interface IXof
+ : IDigest
+ {
+ /**
+ * Output the results of the final calculation for this digest to outLen number of bytes.
+ *
+ * @param out output array to write the output bytes to.
+ * @param outOff offset to start writing the bytes at.
+ * @param outLen the number of output bytes requested.
+ * @return the number of bytes written
+ */
+ int DoFinal(byte[] output, int outOff, int outLen);
+ }
+}
diff --git a/crypto/src/crypto/OutputLengthException.cs b/crypto/src/crypto/OutputLengthException.cs
new file mode 100644
index 000000000..e1cf44925
--- /dev/null
+++ b/crypto/src/crypto/OutputLengthException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+ [Serializable]
+#endif
+ public class OutputLengthException
+ : DataLengthException
+ {
+ public OutputLengthException()
+ {
+ }
+
+ public OutputLengthException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public OutputLengthException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/agreement/DHStandardGroups.cs b/crypto/src/crypto/agreement/DHStandardGroups.cs
new file mode 100644
index 000000000..93b65af98
--- /dev/null
+++ b/crypto/src/crypto/agreement/DHStandardGroups.cs
@@ -0,0 +1,206 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /// <summary>Standard Diffie-Hellman groups from various IETF specifications.</summary>
+ public class DHStandardGroups
+ {
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ private static DHParameters FromPG(string hexP, string hexG)
+ {
+ return new DHParameters(FromHex(hexP), FromHex(hexG));
+ }
+
+ private static DHParameters FromPGQ(string hexP, string hexG, string hexQ)
+ {
+ return new DHParameters(FromHex(hexP), FromHex(hexG), FromHex(hexQ));
+ }
+
+ /*
+ * RFC 2409
+ */
+ private static readonly string rfc2409_768_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF";
+ private static readonly string rfc2409_768_g = "02";
+ public static readonly DHParameters rfc2409_768 = FromPG(rfc2409_768_p, rfc2409_768_g);
+
+ private static readonly string rfc2409_1024_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+ + "FFFFFFFFFFFFFFFF";
+ private static readonly string rfc2409_1024_g = "02";
+ public static readonly DHParameters rfc2409_1024 = FromPG(rfc2409_1024_p, rfc2409_1024_g);
+
+ /*
+ * RFC 3526
+ */
+ private static readonly string rfc3526_1536_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_1536_g = "02";
+ public static readonly DHParameters rfc3526_1536 = FromPG(rfc3526_1536_p, rfc3526_1536_g);
+
+ private static readonly string rfc3526_2048_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AACAA68FFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_2048_g = "02";
+ public static readonly DHParameters rfc3526_2048 = FromPG(rfc3526_2048_p, rfc3526_2048_g);
+
+ private static readonly string rfc3526_3072_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_3072_g = "02";
+ public static readonly DHParameters rfc3526_3072 = FromPG(rfc3526_3072_p, rfc3526_3072_g);
+
+ private static readonly string rfc3526_4096_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+ + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+ + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
+ + "FFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_4096_g = "02";
+ public static readonly DHParameters rfc3526_4096 = FromPG(rfc3526_4096_p, rfc3526_4096_g);
+
+ private static readonly string rfc3526_6144_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+ + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+ + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+ + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+ + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+ + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
+ + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
+ + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
+ + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
+ + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
+ + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+ + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
+ + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
+ + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
+ + "6DCC4024FFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_6144_g = "02";
+ public static readonly DHParameters rfc3526_6144 = FromPG(rfc3526_6144_p, rfc3526_6144_g);
+
+ private static readonly string rfc3526_8192_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+ + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+ + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+ + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+ + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+ + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+ + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+ + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
+ + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+ + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
+ + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
+ + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
+ + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_8192_g = "02";
+ public static readonly DHParameters rfc3526_8192 = FromPG(rfc3526_8192_p, rfc3526_8192_g);
+
+ /*
+ * RFC 4306
+ */
+ public static readonly DHParameters rfc4306_768 = rfc2409_768;
+ public static readonly DHParameters rfc4306_1024 = rfc2409_1024;
+
+ /*
+ * RFC 5114
+ */
+ private static readonly string rfc5114_1024_160_p = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6"
+ + "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0" + "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70"
+ + "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0" + "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708"
+ + "DF1FB2BC2E4A4371";
+ private static readonly string rfc5114_1024_160_g = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F"
+ + "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213" + "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1"
+ + "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" + "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24"
+ + "855E6EEB22B3B2E5";
+ private static readonly string rfc5114_1024_160_q = "F518AA8781A8DF278ABA4E7D64B7CB9D49462353";
+ public static readonly DHParameters rfc5114_1024_160 = FromPGQ(rfc5114_1024_160_p, rfc5114_1024_160_g,
+ rfc5114_1024_160_q);
+
+ private static readonly string rfc5114_2048_224_p = "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1"
+ + "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15" + "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212"
+ + "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207" + "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708"
+ + "B3BF8A317091883681286130BC8985DB1602E714415D9330" + "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D"
+ + "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8" + "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763"
+ + "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71" + "CF9DE5384E71B81C0AC4DFFE0C10E64F";
+ private static readonly string rfc5114_2048_224_g = "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF"
+ + "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA" + "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7"
+ + "C17669101999024AF4D027275AC1348BB8A762D0521BC98A" + "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE"
+ + "F180EB34118E98D119529A45D6F834566E3025E316A330EF" + "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB"
+ + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381" + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"
+ + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179" + "81BC087F2A7065B384B890D3191F2BFA";
+ private static readonly string rfc5114_2048_224_q = "801C0D34C58D93FE997177101F80535A4738CEBCBF389A99B36371EB";
+ public static readonly DHParameters rfc5114_2048_224 = FromPGQ(rfc5114_2048_224_p, rfc5114_2048_224_g,
+ rfc5114_2048_224_q);
+
+ private static readonly string rfc5114_2048_256_p = "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F2"
+ + "5D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA30" + "16C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD"
+ + "5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B" + "6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C"
+ + "4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0E" + "F13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D9"
+ + "67E144E5140564251CCACB83E6B486F6B3CA3F7971506026" + "C0B857F689962856DED4010ABD0BE621C3A3960A54E710C3"
+ + "75F26375D7014103A4B54330C198AF126116D2276E11715F" + "693877FAD7EF09CADB094AE91E1A1597";
+ private static readonly string rfc5114_2048_256_g = "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF2054"
+ + "07F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555" + "BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18"
+ + "A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B" + "777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC83"
+ + "1D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55" + "A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14"
+ + "C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915" + "B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6"
+ + "184B523D1DB246C32F63078490F00EF8D647D148D4795451" + "5E2327CFEF98C582664B4C0F6CC41659";
+ private static readonly string rfc5114_2048_256_q = "8CF83642A709A097B447997640129DA299B1A47D1EB3750B"
+ + "A308B0FE64F5FBD3";
+ public static readonly DHParameters rfc5114_2048_256 = FromPGQ(rfc5114_2048_256_p, rfc5114_2048_256_g,
+ rfc5114_2048_256_q);
+
+ /*
+ * RFC 5996
+ */
+ public static readonly DHParameters rfc5996_768 = rfc4306_768;
+ public static readonly DHParameters rfc5996_1024 = rfc4306_1024;
+ }
+}
diff --git a/crypto/src/crypto/agreement/srp/SRP6Client.cs b/crypto/src/crypto/agreement/srp/SRP6Client.cs
index 309736564..f075d7ad1 100644
--- a/crypto/src/crypto/agreement/srp/SRP6Client.cs
+++ b/crypto/src/crypto/agreement/srp/SRP6Client.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
@@ -24,7 +25,11 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp
protected BigInteger u;
protected BigInteger S;
- protected IDigest digest;
+ protected BigInteger M1;
+ protected BigInteger M2;
+ protected BigInteger Key;
+
+ protected IDigest digest;
protected SecureRandom random;
public Srp6Client()
@@ -46,6 +51,11 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp
this.random = random;
}
+ public virtual void Init(Srp6GroupParameters group, IDigest digest, SecureRandom random)
+ {
+ Init(group.N, group.G, digest, random);
+ }
+
/**
* Generates client's credentials given the client's salt, identity and password
* @param salt The salt used in the client's verifier.
@@ -89,5 +99,66 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp
BigInteger tmp = g.ModPow(x, N).Multiply(k).Mod(N);
return B.Subtract(tmp).Mod(N).ModPow(exp, N);
}
+
+ /**
+ * Computes the client evidence message M1 using the previously received values.
+ * To be called after calculating the secret S.
+ * @return M1: the client side generated evidence message
+ * @throws CryptoException
+ */
+ public virtual BigInteger CalculateClientEvidenceMessage()
+ {
+ // Verify pre-requirements
+ if (this.pubA == null || this.B == null || this.S == null)
+ {
+ throw new CryptoException("Impossible to compute M1: " +
+ "some data are missing from the previous operations (A,B,S)");
+ }
+ // compute the client evidence message 'M1'
+ this.M1 = Srp6Utilities.CalculateM1(digest, N, pubA, B, S);
+ return M1;
+ }
+
+ /** Authenticates the server evidence message M2 received and saves it only if correct.
+ * @param M2: the server side generated evidence message
+ * @return A boolean indicating if the server message M2 was the expected one.
+ * @throws CryptoException
+ */
+ public virtual bool VerifyServerEvidenceMessage(BigInteger serverM2)
+ {
+ // Verify pre-requirements
+ if (this.pubA == null || this.M1 == null || this.S == null)
+ {
+ throw new CryptoException("Impossible to compute and verify M2: " +
+ "some data are missing from the previous operations (A,M1,S)");
+ }
+
+ // Compute the own server evidence message 'M2'
+ BigInteger computedM2 = Srp6Utilities.CalculateM2(digest, N, pubA, M1, S);
+ if (computedM2.Equals(serverM2))
+ {
+ this.M2 = serverM2;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Computes the final session key as a result of the SRP successful mutual authentication
+ * To be called after verifying the server evidence message M2.
+ * @return Key: the mutually authenticated symmetric session key
+ * @throws CryptoException
+ */
+ public virtual BigInteger CalculateSessionKey()
+ {
+ // Verify pre-requirements (here we enforce a previous calculation of M1 and M2)
+ if (this.S == null || this.M1 == null || this.M2 == null)
+ {
+ throw new CryptoException("Impossible to compute Key: " +
+ "some data are missing from the previous operations (S,M1,M2)");
+ }
+ this.Key = Srp6Utilities.CalculateKey(digest, N, S);
+ return Key;
+ }
}
}
diff --git a/crypto/src/crypto/agreement/srp/SRP6Server.cs b/crypto/src/crypto/agreement/srp/SRP6Server.cs
index 35b96d488..fd0c9f1cb 100644
--- a/crypto/src/crypto/agreement/srp/SRP6Server.cs
+++ b/crypto/src/crypto/agreement/srp/SRP6Server.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
@@ -26,6 +27,9 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp
protected BigInteger u;
protected BigInteger S;
+ protected BigInteger M1;
+ protected BigInteger M2;
+ protected BigInteger Key;
public Srp6Server()
{
@@ -49,6 +53,11 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp
this.digest = digest;
}
+ public virtual void Init(Srp6GroupParameters group, BigInteger v, IDigest digest, SecureRandom random)
+ {
+ Init(group.N, group.G, v, digest, random);
+ }
+
/**
* Generates the server's credentials that are to be sent to the client.
* @return The server's public value to the client
@@ -82,9 +91,73 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp
return Srp6Utilities.GeneratePrivateValue(digest, N, g, random);
}
- private BigInteger CalculateS()
+ private BigInteger CalculateS()
{
return v.ModPow(u, N).Multiply(A).Mod(N).ModPow(privB, N);
}
+
+ /**
+ * Authenticates the received client evidence message M1 and saves it only if correct.
+ * To be called after calculating the secret S.
+ * @param M1: the client side generated evidence message
+ * @return A boolean indicating if the client message M1 was the expected one.
+ * @throws CryptoException
+ */
+ public virtual bool VerifyClientEvidenceMessage(BigInteger clientM1)
+ {
+ // Verify pre-requirements
+ if (this.A == null || this.pubB == null || this.S == null)
+ {
+ throw new CryptoException("Impossible to compute and verify M1: " +
+ "some data are missing from the previous operations (A,B,S)");
+ }
+
+ // Compute the own client evidence message 'M1'
+ BigInteger computedM1 = Srp6Utilities.CalculateM1(digest, N, A, pubB, S);
+ if (computedM1.Equals(clientM1))
+ {
+ this.M1 = clientM1;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Computes the server evidence message M2 using the previously verified values.
+ * To be called after successfully verifying the client evidence message M1.
+ * @return M2: the server side generated evidence message
+ * @throws CryptoException
+ */
+ public virtual BigInteger CalculateServerEvidenceMessage()
+ {
+ // Verify pre-requirements
+ if (this.A == null || this.M1 == null || this.S == null)
+ {
+ throw new CryptoException("Impossible to compute M2: " +
+ "some data are missing from the previous operations (A,M1,S)");
+ }
+
+ // Compute the server evidence message 'M2'
+ this.M2 = Srp6Utilities.CalculateM2(digest, N, A, M1, S);
+ return M2;
+ }
+
+ /**
+ * Computes the final session key as a result of the SRP successful mutual authentication
+ * To be called after calculating the server evidence message M2.
+ * @return Key: the mutual authenticated symmetric session key
+ * @throws CryptoException
+ */
+ public virtual BigInteger CalculateSessionKey()
+ {
+ // Verify pre-requirements
+ if (this.S == null || this.M1 == null || this.M2 == null)
+ {
+ throw new CryptoException("Impossible to compute Key: " +
+ "some data are missing from the previous operations (S,M1,M2)");
+ }
+ this.Key = Srp6Utilities.CalculateKey(digest, N, S);
+ return Key;
+ }
}
}
diff --git a/crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs b/crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs
new file mode 100644
index 000000000..36f4aba11
--- /dev/null
+++ b/crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs
@@ -0,0 +1,159 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+ public class Srp6StandardGroups
+ {
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ private static Srp6GroupParameters FromNG(string hexN, string hexG)
+ {
+ return new Srp6GroupParameters(FromHex(hexN), FromHex(hexG));
+ }
+
+ /*
+ * RFC 5054
+ */
+ private const string rfc5054_1024_N = "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + "FD5138FE8376435B9FC61D2FC0EB06E3";
+ private const string rfc5054_1024_g = "02";
+ public static readonly Srp6GroupParameters rfc5054_1024 = FromNG(rfc5054_1024_N, rfc5054_1024_g);
+
+ private const string rfc5054_1536_N = "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961"
+ + "4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843"
+ + "80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B"
+ + "E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5"
+ + "6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A"
+ + "F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E"
+ + "8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB";
+ private const string rfc5054_1536_g = "02";
+ public static readonly Srp6GroupParameters rfc5054_1536 = FromNG(rfc5054_1536_N, rfc5054_1536_g);
+
+ private const string rfc5054_2048_N = "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294"
+ + "3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D"
+ + "CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB"
+ + "D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74"
+ + "7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A"
+ + "436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D"
+ + "5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73"
+ + "03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6"
+ + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" + "9E4AFF73";
+ private const string rfc5054_2048_g = "02";
+ public static readonly Srp6GroupParameters rfc5054_2048 = FromNG(rfc5054_2048_N, rfc5054_2048_g);
+
+ private const string rfc5054_3072_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + "E0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
+ private const string rfc5054_3072_g = "05";
+ public static readonly Srp6GroupParameters rfc5054_3072 = FromNG(rfc5054_3072_N, rfc5054_3072_g);
+
+ private const string rfc5054_4096_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+ + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+ + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+ + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+ + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+ + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + "FFFFFFFFFFFFFFFF";
+ private const string rfc5054_4096_g = "05";
+ public static readonly Srp6GroupParameters rfc5054_4096 = FromNG(rfc5054_4096_N, rfc5054_4096_g);
+
+ private const string rfc5054_6144_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+ + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+ + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+ + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+ + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+ + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
+ + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
+ + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
+ + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
+ + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
+ + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+ + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
+ + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
+ + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + "6DCC4024FFFFFFFFFFFFFFFF";
+ private const string rfc5054_6144_g = "05";
+ public static readonly Srp6GroupParameters rfc5054_6144 = FromNG(rfc5054_6144_N, rfc5054_6144_g);
+
+ private const string rfc5054_8192_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+ + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+ + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+ + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+ + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+ + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
+ + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
+ + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
+ + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
+ + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
+ + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+ + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
+ + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
+ + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
+ + "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA"
+ + "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C"
+ + "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+ + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886"
+ + "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6"
+ + "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5"
+ + "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268"
+ + "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6"
+ + "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF";
+ private const string rfc5054_8192_g = "13";
+ public static readonly Srp6GroupParameters rfc5054_8192 = FromNG(rfc5054_8192_N, rfc5054_8192_g);
+ }
+}
diff --git a/crypto/src/crypto/agreement/srp/SRP6Utilities.cs b/crypto/src/crypto/agreement/srp/SRP6Utilities.cs
index 4e790f572..ef6d8f24c 100644
--- a/crypto/src/crypto/agreement/srp/SRP6Utilities.cs
+++ b/crypto/src/crypto/agreement/srp/SRP6Utilities.cs
@@ -54,7 +54,75 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp
return val;
}
- private static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2)
+ /**
+ * Computes the client evidence message (M1) according to the standard routine:
+ * M1 = H( A | B | S )
+ * @param digest The Digest used as the hashing function H
+ * @param N Modulus used to get the pad length
+ * @param A The public client value
+ * @param B The public server value
+ * @param S The secret calculated by both sides
+ * @return M1 The calculated client evidence message
+ */
+ public static BigInteger CalculateM1(IDigest digest, BigInteger N, BigInteger A, BigInteger B, BigInteger S)
+ {
+ BigInteger M1 = HashPaddedTriplet(digest, N, A, B, S);
+ return M1;
+ }
+
+ /**
+ * Computes the server evidence message (M2) according to the standard routine:
+ * M2 = H( A | M1 | S )
+ * @param digest The Digest used as the hashing function H
+ * @param N Modulus used to get the pad length
+ * @param A The public client value
+ * @param M1 The client evidence message
+ * @param S The secret calculated by both sides
+ * @return M2 The calculated server evidence message
+ */
+ public static BigInteger CalculateM2(IDigest digest, BigInteger N, BigInteger A, BigInteger M1, BigInteger S)
+ {
+ BigInteger M2 = HashPaddedTriplet(digest, N, A, M1, S);
+ return M2;
+ }
+
+ /**
+ * Computes the final Key according to the standard routine: Key = H(S)
+ * @param digest The Digest used as the hashing function H
+ * @param N Modulus used to get the pad length
+ * @param S The secret calculated by both sides
+ * @return
+ */
+ public static BigInteger CalculateKey(IDigest digest, BigInteger N, BigInteger S)
+ {
+ int padLength = (N.BitLength + 7) / 8;
+ byte[] _S = GetPadded(S, padLength);
+ digest.BlockUpdate(_S, 0, _S.Length);
+
+ byte[] output = new byte[digest.GetDigestSize()];
+ digest.DoFinal(output, 0);
+ return new BigInteger(1, output);
+ }
+
+ private static BigInteger HashPaddedTriplet(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2, BigInteger n3)
+ {
+ int padLength = (N.BitLength + 7) / 8;
+
+ byte[] n1_bytes = GetPadded(n1, padLength);
+ byte[] n2_bytes = GetPadded(n2, padLength);
+ byte[] n3_bytes = GetPadded(n3, padLength);
+
+ digest.BlockUpdate(n1_bytes, 0, n1_bytes.Length);
+ digest.BlockUpdate(n2_bytes, 0, n2_bytes.Length);
+ digest.BlockUpdate(n3_bytes, 0, n3_bytes.Length);
+
+ byte[] output = new byte[digest.GetDigestSize()];
+ digest.DoFinal(output, 0);
+
+ return new BigInteger(1, output);
+ }
+
+ private static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2)
{
int padLength = (N.BitLength + 7) / 8;
diff --git a/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs b/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs
index 264833b4d..956973598 100644
--- a/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs
+++ b/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Crypto.Agreement.Srp
@@ -31,7 +32,12 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp
this.digest = digest;
}
- /**
+ public virtual void Init(Srp6GroupParameters group, IDigest digest)
+ {
+ Init(group.N, group.G, digest);
+ }
+
+ /**
* Creates a new SRP verifier
* @param salt The salt to use, generally should be large and random
* @param identity The user's identifying information (eg. username)
diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs
new file mode 100644
index 000000000..2d6cf393c
--- /dev/null
+++ b/crypto/src/crypto/digests/KeccakDigest.cs
@@ -0,0 +1,534 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /// <summary>
+ /// Implementation of Keccak based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+ /// </summary>
+ /// <remarks>
+ /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+ /// </remarks>
+ public class KeccakDigest
+ : IDigest, IMemoable
+ {
+ private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
+
+ private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
+
+ private static ulong[] KeccakInitializeRoundConstants()
+ {
+ ulong[] keccakRoundConstants = new ulong[24];
+ byte LFSRState = 0x01;
+
+ for (int i = 0; i < 24; i++)
+ {
+ keccakRoundConstants[i] = 0;
+ for (int j = 0; j < 7; j++)
+ {
+ int bitPosition = (1 << j) - 1;
+
+ // LFSR86540
+
+ bool loBit = (LFSRState & 0x01) != 0;
+ if (loBit)
+ {
+ keccakRoundConstants[i] ^= 1UL << bitPosition;
+ }
+
+ bool hiBit = (LFSRState & 0x80) != 0;
+ LFSRState <<= 1;
+ if (hiBit)
+ {
+ LFSRState ^= 0x71;
+ }
+
+ }
+ }
+
+ return keccakRoundConstants;
+ }
+
+ private static int[] KeccakInitializeRhoOffsets()
+ {
+ int[] keccakRhoOffsets = new int[25];
+ int x, y, t, newX, newY;
+
+ int rhoOffset = 0;
+ keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = rhoOffset;
+ x = 1;
+ y = 0;
+ for (t = 1; t < 25; t++)
+ {
+ //rhoOffset = ((t + 1) * (t + 2) / 2) % 64;
+ rhoOffset = (rhoOffset + t) & 63;
+ keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
+ newX = (0 * x + 1 * y) % 5;
+ newY = (2 * x + 3 * y) % 5;
+ x = newX;
+ y = newY;
+ }
+
+ return keccakRhoOffsets;
+ }
+
+ protected byte[] state = new byte[(1600 / 8)];
+ protected byte[] dataQueue = new byte[(1536 / 8)];
+ protected int rate;
+ protected int bitsInQueue;
+ protected int fixedOutputLength;
+ protected bool squeezing;
+ protected int bitsAvailableForSqueezing;
+ protected byte[] chunk;
+ protected byte[] oneByte;
+
+ private void ClearDataQueueSection(int off, int len)
+ {
+ for (int i = off; i != off + len; i++)
+ {
+ dataQueue[i] = 0;
+ }
+ }
+
+ public KeccakDigest()
+ : this(288)
+ {
+ }
+
+ public KeccakDigest(int bitLength)
+ {
+ Init(bitLength);
+ }
+
+ public KeccakDigest(KeccakDigest source)
+ {
+ CopyIn(source);
+ }
+
+ private void CopyIn(KeccakDigest source)
+ {
+ Array.Copy(source.state, 0, this.state, 0, source.state.Length);
+ Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
+ this.rate = source.rate;
+ this.bitsInQueue = source.bitsInQueue;
+ this.fixedOutputLength = source.fixedOutputLength;
+ this.squeezing = source.squeezing;
+ this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
+ this.chunk = Arrays.Clone(source.chunk);
+ this.oneByte = Arrays.Clone(source.oneByte);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Keccak-" + fixedOutputLength; }
+ }
+
+ public virtual int GetDigestSize()
+ {
+ return fixedOutputLength / 8;
+ }
+
+ public virtual void Update(byte input)
+ {
+ oneByte[0] = input;
+
+ Absorb(oneByte, 0, 8L);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ Absorb(input, inOff, len * 8L);
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ Squeeze(output, outOff, fixedOutputLength);
+
+ Reset();
+
+ return GetDigestSize();
+ }
+
+ /*
+ * TODO Possible API change to support partial-byte suffixes.
+ */
+ protected virtual int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+ {
+ if (partialBits > 0)
+ {
+ oneByte[0] = partialByte;
+ Absorb(oneByte, 0, partialBits);
+ }
+
+ Squeeze(output, outOff, fixedOutputLength);
+
+ Reset();
+
+ return GetDigestSize();
+ }
+
+ public virtual void Reset()
+ {
+ Init(fixedOutputLength);
+ }
+
+ /**
+ * Return the size of block that the compression function is applied to in bytes.
+ *
+ * @return internal byte length of a block.
+ */
+ public virtual int GetByteLength()
+ {
+ return rate / 8;
+ }
+
+ private void Init(int bitLength)
+ {
+ switch (bitLength)
+ {
+ case 128:
+ InitSponge(1344, 256);
+ break;
+ case 224:
+ InitSponge(1152, 448);
+ break;
+ case 256:
+ InitSponge(1088, 512);
+ break;
+ case 288:
+ InitSponge(1024, 576);
+ break;
+ case 384:
+ InitSponge(832, 768);
+ break;
+ case 512:
+ InitSponge(576, 1024);
+ break;
+ default:
+ throw new ArgumentException("must be one of 128, 224, 256, 288, 384, or 512.", "bitLength");
+ }
+ }
+
+ private void InitSponge(int rate, int capacity)
+ {
+ if (rate + capacity != 1600)
+ {
+ throw new InvalidOperationException("rate + capacity != 1600");
+ }
+ if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
+ {
+ throw new InvalidOperationException("invalid rate value");
+ }
+
+ this.rate = rate;
+ // this is never read, need to check to see why we want to save it
+ // this.capacity = capacity;
+ this.fixedOutputLength = 0;
+ Arrays.Fill(this.state, (byte)0);
+ Arrays.Fill(this.dataQueue, (byte)0);
+ this.bitsInQueue = 0;
+ this.squeezing = false;
+ this.bitsAvailableForSqueezing = 0;
+ this.fixedOutputLength = capacity / 2;
+ this.chunk = new byte[rate / 8];
+ this.oneByte = new byte[1];
+ }
+
+ private void AbsorbQueue()
+ {
+ KeccakAbsorb(state, dataQueue, rate / 8);
+
+ bitsInQueue = 0;
+ }
+
+ protected virtual void Absorb(byte[] data, int off, long databitlen)
+ {
+ long i, j, wholeBlocks;
+
+ if ((bitsInQueue % 8) != 0)
+ {
+ throw new InvalidOperationException("attempt to absorb with odd length queue.");
+ }
+ if (squeezing)
+ {
+ throw new InvalidOperationException("attempt to absorb while squeezing.");
+ }
+
+ i = 0;
+ while (i < databitlen)
+ {
+ if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate)))
+ {
+ wholeBlocks = (databitlen - i) / rate;
+
+ for (j = 0; j < wholeBlocks; j++)
+ {
+ Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length);
+
+ KeccakAbsorb(state, chunk, chunk.Length);
+ }
+
+ i += wholeBlocks * rate;
+ }
+ else
+ {
+ int partialBlock = (int)(databitlen - i);
+ if (partialBlock + bitsInQueue > rate)
+ {
+ partialBlock = rate - bitsInQueue;
+ }
+ int partialByte = partialBlock % 8;
+ partialBlock -= partialByte;
+ Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8);
+
+ bitsInQueue += partialBlock;
+ i += partialBlock;
+ if (bitsInQueue == rate)
+ {
+ AbsorbQueue();
+ }
+ if (partialByte > 0)
+ {
+ int mask = (1 << partialByte) - 1;
+ dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask);
+ bitsInQueue += partialByte;
+ i += partialByte;
+ }
+ }
+ }
+ }
+
+ private void PadAndSwitchToSqueezingPhase()
+ {
+ if (bitsInQueue + 1 == rate)
+ {
+ dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
+ AbsorbQueue();
+ ClearDataQueueSection(0, rate / 8);
+ }
+ else
+ {
+ ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
+ dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
+ }
+ dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8));
+ AbsorbQueue();
+
+ if (rate == 1024)
+ {
+ KeccakExtract1024bits(state, dataQueue);
+ bitsAvailableForSqueezing = 1024;
+ }
+ else
+ {
+ KeccakExtract(state, dataQueue, rate / 64);
+ bitsAvailableForSqueezing = rate;
+ }
+
+ squeezing = true;
+ }
+
+ protected virtual void Squeeze(byte[] output, int offset, long outputLength)
+ {
+ long i;
+ int partialBlock;
+
+ if (!squeezing)
+ {
+ PadAndSwitchToSqueezingPhase();
+ }
+ if ((outputLength % 8) != 0)
+ {
+ throw new InvalidOperationException("outputLength not a multiple of 8");
+ }
+
+ i = 0;
+ while (i < outputLength)
+ {
+ if (bitsAvailableForSqueezing == 0)
+ {
+ KeccakPermutation(state);
+
+ if (rate == 1024)
+ {
+ KeccakExtract1024bits(state, dataQueue);
+ bitsAvailableForSqueezing = 1024;
+ }
+ else
+ {
+ KeccakExtract(state, dataQueue, rate / 64);
+ bitsAvailableForSqueezing = rate;
+ }
+ }
+ partialBlock = bitsAvailableForSqueezing;
+ if ((long)partialBlock > outputLength - i)
+ {
+ partialBlock = (int)(outputLength - i);
+ }
+
+ Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8);
+ bitsAvailableForSqueezing -= partialBlock;
+ i += partialBlock;
+ }
+ }
+
+ private static void FromBytesToWords(ulong[] stateAsWords, byte[] state)
+ {
+ for (int i = 0; i < (1600 / 64); i++)
+ {
+ stateAsWords[i] = 0;
+ int index = i * (64 / 8);
+ for (int j = 0; j < (64 / 8); j++)
+ {
+ stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j));
+ }
+ }
+ }
+
+ private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords)
+ {
+ for (int i = 0; i < (1600 / 64); i++)
+ {
+ int index = i * (64 / 8);
+ for (int j = 0; j < (64 / 8); j++)
+ {
+ state[index + j] = (byte)(stateAsWords[i] >> (8 * j));
+ }
+ }
+ }
+
+ private void KeccakPermutation(byte[] state)
+ {
+ ulong[] longState = new ulong[state.Length / 8];
+
+ FromBytesToWords(longState, state);
+
+ KeccakPermutationOnWords(longState);
+
+ FromWordsToBytes(state, longState);
+ }
+
+ private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes)
+ {
+ for (int i = 0; i < dataLengthInBytes; i++)
+ {
+ state[i] ^= data[i];
+ }
+
+ KeccakPermutation(state);
+ }
+
+ private void KeccakPermutationOnWords(ulong[] state)
+ {
+ int i;
+
+ for (i = 0; i < 24; i++)
+ {
+ Theta(state);
+ Rho(state);
+ Pi(state);
+ Chi(state);
+ Iota(state, i);
+ }
+ }
+
+ ulong[] C = new ulong[5];
+
+ private void Theta(ulong[] A)
+ {
+ for (int x = 0; x < 5; x++)
+ {
+ C[x] = 0;
+ for (int y = 0; y < 5; y++)
+ {
+ C[x] ^= A[x + 5 * y];
+ }
+ }
+ for (int x = 0; x < 5; x++)
+ {
+ ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5];
+ for (int y = 0; y < 5; y++)
+ {
+ A[x + 5 * y] ^= dX;
+ }
+ }
+ }
+
+ private void Rho(ulong[] A)
+ {
+ for (int x = 0; x < 5; x++)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ int index = x + 5 * y;
+ A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]);
+ }
+ }
+ }
+
+ ulong[] tempA = new ulong[25];
+
+ private void Pi(ulong[] A)
+ {
+ Array.Copy(A, 0, tempA, 0, tempA.Length);
+
+ for (int x = 0; x < 5; x++)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y];
+ }
+ }
+ }
+
+ ulong[] chiC = new ulong[5];
+
+ private void Chi(ulong[] A)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ for (int x = 0; x < 5; x++)
+ {
+ chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]);
+ }
+ for (int x = 0; x < 5; x++)
+ {
+ A[x + 5 * y] = chiC[x];
+ }
+ }
+ }
+
+ private static void Iota(ulong[] A, int indexRound)
+ {
+ A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound];
+ }
+
+ private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes)
+ {
+ KeccakPermutationAfterXor(byteState, data, dataInBytes);
+ }
+
+ private void KeccakExtract1024bits(byte[] byteState, byte[] data)
+ {
+ Array.Copy(byteState, 0, data, 0, 128);
+ }
+
+ private void KeccakExtract(byte[] byteState, byte[] data, int laneCount)
+ {
+ Array.Copy(byteState, 0, data, 0, laneCount * 8);
+ }
+
+ public virtual IMemoable Copy()
+ {
+ return new KeccakDigest(this);
+ }
+
+ public virtual void Reset(IMemoable other)
+ {
+ KeccakDigest d = (KeccakDigest)other;
+
+ CopyIn(d);
+ }
+ }
+}
diff --git a/crypto/src/crypto/digests/SHA3Digest.cs b/crypto/src/crypto/digests/SHA3Digest.cs
index 2c6837b3c..890b665cf 100644
--- a/crypto/src/crypto/digests/SHA3Digest.cs
+++ b/crypto/src/crypto/digests/SHA3Digest.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using Org.BouncyCastle.Utilities;
@@ -11,550 +12,75 @@ namespace Org.BouncyCastle.Crypto.Digests
/// Following the naming conventions used in the C source code to enable easy review of the implementation.
/// </remarks>
public class Sha3Digest
- : IDigest, IMemoable
+ : KeccakDigest
{
- private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
-
- private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
-
- private static ulong[] KeccakInitializeRoundConstants()
- {
- ulong[] keccakRoundConstants = new ulong[24];
- byte LFSRState = 0x01;
-
- for (int i = 0; i < 24; i++)
- {
- keccakRoundConstants[i] = 0;
- for (int j = 0; j < 7; j++)
- {
- int bitPosition = (1 << j) - 1;
-
- // LFSR86540
-
- bool loBit = (LFSRState & 0x01) != 0;
- if (loBit)
- {
- keccakRoundConstants[i] ^= 1UL << bitPosition;
- }
-
- bool hiBit = (LFSRState & 0x80) != 0;
- LFSRState <<= 1;
- if (hiBit)
- {
- LFSRState ^= 0x71;
- }
-
- }
- }
-
- return keccakRoundConstants;
- }
-
- private static int[] KeccakInitializeRhoOffsets()
- {
- int[] keccakRhoOffsets = new int[25];
- int x, y, t, newX, newY;
-
- int rhoOffset = 0;
- keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = rhoOffset;
- x = 1;
- y = 0;
- for (t = 1; t < 25; t++)
- {
- //rhoOffset = ((t + 1) * (t + 2) / 2) % 64;
- rhoOffset = (rhoOffset + t) & 63;
- keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
- newX = (0 * x + 1 * y) % 5;
- newY = (2 * x + 3 * y) % 5;
- x = newX;
- y = newY;
- }
-
- return keccakRhoOffsets;
- }
-
- private byte[] state = new byte[(1600 / 8)];
- private byte[] dataQueue = new byte[(1536 / 8)];
- private int rate;
- private int bitsInQueue;
- private int fixedOutputLength;
- private bool squeezing;
- private int bitsAvailableForSqueezing;
- private byte[] chunk;
- private byte[] oneByte;
-
- private void ClearDataQueueSection(int off, int len)
- {
- for (int i = off; i != off + len; i++)
- {
- dataQueue[i] = 0;
- }
- }
-
- public Sha3Digest()
- {
- Init(0);
- }
-
- public Sha3Digest(int bitLength)
- {
- Init(bitLength);
- }
-
- public Sha3Digest(Sha3Digest source)
- {
- CopyIn(source);
- }
-
- private void CopyIn(Sha3Digest source)
- {
- Array.Copy(source.state, 0, this.state, 0, source.state.Length);
- Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
- this.rate = source.rate;
- this.bitsInQueue = source.bitsInQueue;
- this.fixedOutputLength = source.fixedOutputLength;
- this.squeezing = source.squeezing;
- this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
- this.chunk = Arrays.Clone(source.chunk);
- this.oneByte = Arrays.Clone(source.oneByte);
- }
-
- public virtual string AlgorithmName
- {
- get { return "SHA3-" + fixedOutputLength; }
- }
-
- public virtual int GetDigestSize()
- {
- return fixedOutputLength / 8;
- }
-
- public virtual void Update(byte input)
- {
- oneByte[0] = input;
-
- DoUpdate(oneByte, 0, 8L);
- }
-
- public virtual void BlockUpdate(byte[] input, int inOff, int len)
- {
- DoUpdate(input, inOff, len * 8L);
- }
-
- public virtual int DoFinal(byte[] output, int outOff)
- {
- Squeeze(output, outOff, fixedOutputLength);
-
- Reset();
-
- return GetDigestSize();
- }
-
- public virtual void Reset()
- {
- Init(fixedOutputLength);
- }
-
- /**
- * Return the size of block that the compression function is applied to in bytes.
- *
- * @return internal byte length of a block.
- */
- public virtual int GetByteLength()
- {
- return rate / 8;
- }
-
- private void Init(int bitLength)
+ private static int CheckBitLength(int bitLength)
{
switch (bitLength)
{
- case 0:
- case 288:
- InitSponge(1024, 576);
- break;
case 224:
- InitSponge(1152, 448);
- break;
case 256:
- InitSponge(1088, 512);
- break;
case 384:
- InitSponge(832, 768);
- break;
case 512:
- InitSponge(576, 1024);
- break;
+ return bitLength;
default:
- throw new ArgumentException("must be one of 224, 256, 384, or 512.", "bitLength");
- }
- }
-
- private void DoUpdate(byte[] data, int off, long databitlen)
- {
- if ((databitlen % 8) == 0)
- {
- Absorb(data, off, databitlen);
- }
- else
- {
- Absorb(data, off, databitlen - (databitlen % 8));
-
- byte[] lastByte = new byte[1];
-
- lastByte[0] = (byte)(data[off + (int)(databitlen / 8)] >> (int)(8 - (databitlen % 8)));
- Absorb(lastByte, off, databitlen % 8);
- }
- }
-
- private void InitSponge(int rate, int capacity)
- {
- if (rate + capacity != 1600)
- {
- throw new InvalidOperationException("rate + capacity != 1600");
- }
- if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
- {
- throw new InvalidOperationException("invalid rate value");
- }
-
- this.rate = rate;
- // this is never read, need to check to see why we want to save it
- // this.capacity = capacity;
- this.fixedOutputLength = 0;
- Arrays.Fill(this.state, (byte)0);
- Arrays.Fill(this.dataQueue, (byte)0);
- this.bitsInQueue = 0;
- this.squeezing = false;
- this.bitsAvailableForSqueezing = 0;
- this.fixedOutputLength = capacity / 2;
- this.chunk = new byte[rate / 8];
- this.oneByte = new byte[1];
- }
-
- private void AbsorbQueue()
- {
- KeccakAbsorb(state, dataQueue, rate / 8);
-
- bitsInQueue = 0;
- }
-
- private void Absorb(byte[] data, int off, long databitlen)
- {
- long i, j, wholeBlocks;
-
- if ((bitsInQueue % 8) != 0)
- {
- throw new InvalidOperationException("attempt to absorb with odd length queue.");
- }
- if (squeezing)
- {
- throw new InvalidOperationException("attempt to absorb while squeezing.");
- }
-
- i = 0;
- while (i < databitlen)
- {
- if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate)))
- {
- wholeBlocks = (databitlen - i) / rate;
-
- for (j = 0; j < wholeBlocks; j++)
- {
- Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length);
-
- //displayIntermediateValues.displayBytes(1, "Block to be absorbed", curData, rate / 8);
-
- KeccakAbsorb(state, chunk, chunk.Length);
- }
-
- i += wholeBlocks * rate;
- }
- else
- {
- int partialBlock = (int)(databitlen - i);
- if (partialBlock + bitsInQueue > rate)
- {
- partialBlock = rate - bitsInQueue;
- }
- int partialByte = partialBlock % 8;
- partialBlock -= partialByte;
- Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8);
-
- bitsInQueue += partialBlock;
- i += partialBlock;
- if (bitsInQueue == rate)
- {
- AbsorbQueue();
- }
- if (partialByte > 0)
- {
- int mask = (1 << partialByte) - 1;
- dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask);
- bitsInQueue += partialByte;
- i += partialByte;
- }
- }
+ throw new ArgumentException(bitLength + " not supported for SHA-3", "bitLength");
}
}
- private void PadAndSwitchToSqueezingPhase()
- {
- if (bitsInQueue + 1 == rate)
- {
- dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
- AbsorbQueue();
- ClearDataQueueSection(0, rate / 8);
- }
- else
- {
- ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
- dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
- }
- dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8));
- AbsorbQueue();
-
- //displayIntermediateValues.displayText(1, "--- Switching to squeezing phase ---");
-
- if (rate == 1024)
- {
- KeccakExtract1024bits(state, dataQueue);
- bitsAvailableForSqueezing = 1024;
- }
- else
- {
- KeccakExtract(state, dataQueue, rate / 64);
- bitsAvailableForSqueezing = rate;
- }
-
- //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8);
-
- squeezing = true;
- }
-
- private void Squeeze(byte[] output, int offset, long outputLength)
- {
- long i;
- int partialBlock;
-
- if (!squeezing)
- {
- PadAndSwitchToSqueezingPhase();
- }
- if ((outputLength % 8) != 0)
- {
- throw new InvalidOperationException("outputLength not a multiple of 8");
- }
-
- i = 0;
- while (i < outputLength)
- {
- if (bitsAvailableForSqueezing == 0)
- {
- KeccakPermutation(state);
-
- if (rate == 1024)
- {
- KeccakExtract1024bits(state, dataQueue);
- bitsAvailableForSqueezing = 1024;
- }
- else
-
- {
- KeccakExtract(state, dataQueue, rate / 64);
- bitsAvailableForSqueezing = rate;
- }
-
- //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8);
-
- }
- partialBlock = bitsAvailableForSqueezing;
- if ((long)partialBlock > outputLength - i)
- {
- partialBlock = (int)(outputLength - i);
- }
-
- Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8);
- bitsAvailableForSqueezing -= partialBlock;
- i += partialBlock;
- }
- }
-
- private static void FromBytesToWords(ulong[] stateAsWords, byte[] state)
- {
- for (int i = 0; i < (1600 / 64); i++)
- {
- stateAsWords[i] = 0;
- int index = i * (64 / 8);
- for (int j = 0; j < (64 / 8); j++)
- {
- stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j));
- }
- }
- }
-
- private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords)
+ public Sha3Digest()
+ : this(256)
{
- for (int i = 0; i < (1600 / 64); i++)
- {
- int index = i * (64 / 8);
- for (int j = 0; j < (64 / 8); j++)
- {
- state[index + j] = (byte)(stateAsWords[i] >> (8 * j));
- }
- }
}
- private void KeccakPermutation(byte[] state)
+ public Sha3Digest(int bitLength)
+ : base(CheckBitLength(bitLength))
{
- ulong[] longState = new ulong[state.Length / 8];
-
- FromBytesToWords(longState, state);
-
- //displayIntermediateValues.displayStateAsBytes(1, "Input of permutation", longState);
-
- KeccakPermutationOnWords(longState);
-
- //displayIntermediateValues.displayStateAsBytes(1, "State after permutation", longState);
-
- FromWordsToBytes(state, longState);
}
- private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes)
+ public Sha3Digest(Sha3Digest source)
+ : base(source)
{
- for (int i = 0; i < dataLengthInBytes; i++)
- {
- state[i] ^= data[i];
- }
-
- KeccakPermutation(state);
}
- private void KeccakPermutationOnWords(ulong[] state)
+ public override string AlgorithmName
{
- int i;
-
- //displayIntermediateValues.displayStateAs64bitWords(3, "Same, with lanes as 64-bit words", state);
-
- for (i = 0; i < 24; i++)
- {
- //displayIntermediateValues.displayRoundNumber(3, i);
-
- Theta(state);
- //displayIntermediateValues.displayStateAs64bitWords(3, "After theta", state);
-
- Rho(state);
- //displayIntermediateValues.displayStateAs64bitWords(3, "After rho", state);
-
- Pi(state);
- //displayIntermediateValues.displayStateAs64bitWords(3, "After pi", state);
-
- Chi(state);
- //displayIntermediateValues.displayStateAs64bitWords(3, "After chi", state);
-
- Iota(state, i);
- //displayIntermediateValues.displayStateAs64bitWords(3, "After iota", state);
- }
+ get { return "SHA3-" + fixedOutputLength; }
}
- ulong[] C = new ulong[5];
-
- private void Theta(ulong[] A)
+ public override int DoFinal(byte[] output, int outOff)
{
- for (int x = 0; x < 5; x++)
- {
- C[x] = 0;
- for (int y = 0; y < 5; y++)
- {
- C[x] ^= A[x + 5 * y];
- }
- }
- for (int x = 0; x < 5; x++)
- {
- ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5];
- for (int y = 0; y < 5; y++)
- {
- A[x + 5 * y] ^= dX;
- }
- }
- }
+ Absorb(new byte[]{ 0x02 }, 0, 2);
- private void Rho(ulong[] A)
- {
- for (int x = 0; x < 5; x++)
- {
- for (int y = 0; y < 5; y++)
- {
- int index = x + 5 * y;
- A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]);
- }
- }
+ return base.DoFinal(output, outOff);
}
- ulong[] tempA = new ulong[25];
-
- private void Pi(ulong[] A)
+ /*
+ * TODO Possible API change to support partial-byte suffixes.
+ */
+ protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
{
- Array.Copy(A, 0, tempA, 0, tempA.Length);
-
- for (int x = 0; x < 5; x++)
- {
- for (int y = 0; y < 5; y++)
- {
- A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y];
- }
- }
- }
+ if (partialBits < 0 || partialBits > 7)
+ throw new ArgumentException("must be in the range [0,7]", "partialBits");
- ulong[] chiC = new ulong[5];
+ int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x02 << partialBits);
+ Debug.Assert(finalInput >= 0);
+ int finalBits = partialBits + 2;
- private void Chi(ulong[] A)
- {
- for (int y = 0; y < 5; y++)
+ if (finalBits >= 8)
{
- for (int x = 0; x < 5; x++)
- {
- chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]);
- }
- for (int x = 0; x < 5; x++)
- {
- A[x + 5 * y] = chiC[x];
- }
+ oneByte[0] = (byte)finalInput;
+ Absorb(oneByte, 0, 8);
+ finalBits -= 8;
+ finalInput >>= 8;
}
- }
-
- private static void Iota(ulong[] A, int indexRound)
- {
- A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound];
- }
-
- private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes)
- {
- KeccakPermutationAfterXor(byteState, data, dataInBytes);
- }
-
- private void KeccakExtract1024bits(byte[] byteState, byte[] data)
- {
- Array.Copy(byteState, 0, data, 0, 128);
- }
- private void KeccakExtract(byte[] byteState, byte[] data, int laneCount)
- {
- Array.Copy(byteState, 0, data, 0, laneCount * 8);
+ return base.DoFinal(output, outOff, (byte)finalInput, finalBits);
}
- public IMemoable Copy()
+ public override IMemoable Copy()
{
return new Sha3Digest(this);
}
-
- public void Reset(IMemoable other)
- {
- Sha3Digest d = (Sha3Digest)other;
-
- CopyIn(d);
- }
-
-
}
}
diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs
new file mode 100644
index 000000000..fd7d85681
--- /dev/null
+++ b/crypto/src/crypto/digests/ShakeDigest.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /// <summary>
+ /// Implementation of SHAKE based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+ /// </summary>
+ /// <remarks>
+ /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+ /// </remarks>
+ public class ShakeDigest
+ : KeccakDigest, IXof
+ {
+ private static int CheckBitLength(int bitLength)
+ {
+ switch (bitLength)
+ {
+ case 128:
+ case 256:
+ return bitLength;
+ default:
+ throw new ArgumentException(bitLength + " not supported for SHAKE", "bitLength");
+ }
+ }
+
+ public ShakeDigest()
+ : this(128)
+ {
+ }
+
+ public ShakeDigest(int bitLength)
+ : base(CheckBitLength(bitLength))
+ {
+ }
+
+ public ShakeDigest(ShakeDigest source)
+ : base(source)
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHAKE" + fixedOutputLength; }
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ return DoFinal(output, outOff, GetDigestSize());
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff, int outLen)
+ {
+ Absorb(new byte[]{ 0x0F }, 0, 4);
+
+ Squeeze(output, outOff, ((long)outLen) * 8);
+
+ Reset();
+
+ return outLen;
+ }
+
+ /*
+ * TODO Possible API change to support partial-byte suffixes.
+ */
+ protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+ {
+ return DoFinal(output, outOff, GetDigestSize(), partialByte, partialBits);
+ }
+
+ /*
+ * TODO Possible API change to support partial-byte suffixes.
+ */
+ protected virtual int DoFinal(byte[] output, int outOff, int outLen, byte partialByte, int partialBits)
+ {
+ if (partialBits < 0 || partialBits > 7)
+ throw new ArgumentException("must be in the range [0,7]", "partialBits");
+
+ int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x0F << partialBits);
+ Debug.Assert(finalInput >= 0);
+ int finalBits = partialBits + 4;
+
+ if (finalBits >= 8)
+ {
+ oneByte[0] = (byte)finalInput;
+ Absorb(oneByte, 0, 8);
+ finalBits -= 8;
+ finalInput >>= 8;
+ }
+
+ if (finalBits > 0)
+ {
+ oneByte[0] = (byte)finalInput;
+ Absorb(oneByte, 0, finalBits);
+ }
+
+ Squeeze(output, outOff, ((long)outLen) * 8);
+
+ Reset();
+
+ return outLen;
+ }
+
+ public override IMemoable Copy()
+ {
+ return new ShakeDigest(this);
+ }
+ }
+}
diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
index 5d2369349..51bb1829a 100644
--- a/crypto/src/crypto/ec/CustomNamedCurves.cs
+++ b/crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections;
using Org.BouncyCastle.Asn1;
@@ -60,7 +60,7 @@ namespace Org.BouncyCastle.Crypto.EC
*
* (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14)
*/
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A"
+ "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"));
@@ -69,14 +69,110 @@ namespace Org.BouncyCastle.Crypto.EC
}
/*
+ * secp128r1
+ */
+ internal class SecP128R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP128R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP128R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("000E0D4D696E6768756151750CC03A4473D03679");
+ ECCurve curve = ConfigureCurve(new SecP128R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "161FF7528B899B2D0C28607CA52C5B86"
+ + "CF5AC8395BAFEB13C02DA292DDED7A83"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * secp160k1
+ */
+ internal class SecP160K1Holder
+ : X9ECParametersHolder
+ {
+ private SecP160K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP160K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+ new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+ new BigInteger[]{
+ new BigInteger("9162fbe73984472a0a9e", 16),
+ new BigInteger("-96341f1138933bc2f505", 16) },
+ new BigInteger[]{
+ new BigInteger("127971af8721782ecffa3", 16),
+ new BigInteger("9162fbe73984472a0a9e", 16) },
+ new BigInteger("9162fbe73984472a0a9d0590", 16),
+ new BigInteger("96341f1138933bc2f503fd44", 16),
+ 176);
+ ECCurve curve = ConfigureCurveGlv(new SecP160K1Curve(), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+ + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * secp160r1
+ */
+ internal class SecP160R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP160R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP160R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("1053CDE42C14D696E67687561517533BF3F83345");
+ ECCurve curve = ConfigureCurve(new SecP160R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "4A96B5688EF573284664698968C38BB913CBFC82"
+ + "23A628553168947D59DCC912042351377AC5FB32"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * secp160r2
+ */
+ internal class SecP160R2Holder
+ : X9ECParametersHolder
+ {
+ private SecP160R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP160R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("B99B99B099B323E02709A4D696E6768756151751");
+ ECCurve curve = ConfigureCurve(new SecP160R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+ + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
* secp192k1
*/
- internal class Secp192k1Holder
+ internal class SecP192K1Holder
: X9ECParametersHolder
{
- private Secp192k1Holder() { }
+ private SecP192K1Holder() { }
- internal static readonly X9ECParametersHolder Instance = new Secp192k1Holder();
+ internal static readonly X9ECParametersHolder Instance = new SecP192K1Holder();
protected override X9ECParameters CreateParameters()
{
@@ -90,11 +186,11 @@ namespace Org.BouncyCastle.Crypto.EC
new BigInteger[]{
new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
new BigInteger("71169be7330b3038edb025f1", 16) },
- new BigInteger("1c45a6f9ccc2cc0e3b6c097c7", 16),
- new BigInteger("2cfecd0037b1712b73ae19575", 16),
- 194);
+ new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+ new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+ 208);
ECCurve curve = ConfigureCurveGlv(new SecP192K1Curve(), glv);
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -104,18 +200,18 @@ namespace Org.BouncyCastle.Crypto.EC
/*
* secp192r1
*/
- internal class Secp192r1Holder
+ internal class SecP192R1Holder
: X9ECParametersHolder
{
- private Secp192r1Holder() { }
+ private SecP192R1Holder() { }
- internal static readonly X9ECParametersHolder Instance = new Secp192r1Holder();
+ internal static readonly X9ECParametersHolder Instance = new SecP192R1Holder();
protected override X9ECParameters CreateParameters()
{
byte[] S = Hex.Decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
ECCurve curve = ConfigureCurve(new SecP192R1Curve());
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -125,12 +221,12 @@ namespace Org.BouncyCastle.Crypto.EC
/*
* secp224k1
*/
- internal class Secp224k1Holder
+ internal class SecP224K1Holder
: X9ECParametersHolder
{
- private Secp224k1Holder() { }
+ private SecP224K1Holder() { }
- internal static readonly X9ECParametersHolder Instance = new Secp224k1Holder();
+ internal static readonly X9ECParametersHolder Instance = new SecP224K1Holder();
protected override X9ECParameters CreateParameters()
{
@@ -144,11 +240,11 @@ namespace Org.BouncyCastle.Crypto.EC
new BigInteger[]{
new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
- new BigInteger("35c6783ea653ae444abeceb382c82", 16),
- new BigInteger("5c56f89bc5375b9a04fd364e31bdd", 16),
- 227);
+ new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+ new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+ 240);
ECCurve curve = ConfigureCurveGlv(new SecP224K1Curve(), glv);
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+ "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -158,18 +254,18 @@ namespace Org.BouncyCastle.Crypto.EC
/*
* secp224r1
*/
- internal class Secp224r1Holder
+ internal class SecP224R1Holder
: X9ECParametersHolder
{
- private Secp224r1Holder() { }
+ private SecP224R1Holder() { }
- internal static readonly X9ECParametersHolder Instance = new Secp224r1Holder();
+ internal static readonly X9ECParametersHolder Instance = new SecP224R1Holder();
protected override X9ECParameters CreateParameters()
{
byte[] S = Hex.Decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
ECCurve curve = ConfigureCurve(new SecP224R1Curve());
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -179,12 +275,12 @@ namespace Org.BouncyCastle.Crypto.EC
/*
* secp256k1
*/
- internal class Secp256k1Holder
+ internal class SecP256K1Holder
: X9ECParametersHolder
{
- private Secp256k1Holder() {}
+ private SecP256K1Holder() {}
- internal static readonly X9ECParametersHolder Instance = new Secp256k1Holder();
+ internal static readonly X9ECParametersHolder Instance = new SecP256K1Holder();
protected override X9ECParameters CreateParameters()
{
@@ -198,11 +294,11 @@ namespace Org.BouncyCastle.Crypto.EC
new BigInteger[]{
new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
- new BigInteger("c21b48869f51af37a1b243924a13ac55", 16),
- new BigInteger("3910dfb58043a20a1bd51fea42aff9311", 16),
- 258);
+ new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+ new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+ 272);
ECCurve curve = ConfigureCurveGlv(new SecP256K1Curve(), glv);
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+ "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -212,18 +308,18 @@ namespace Org.BouncyCastle.Crypto.EC
/*
* secp256r1
*/
- internal class Secp256r1Holder
+ internal class SecP256R1Holder
: X9ECParametersHolder
{
- private Secp256r1Holder() {}
+ private SecP256R1Holder() {}
- internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder();
+ internal static readonly X9ECParametersHolder Instance = new SecP256R1Holder();
protected override X9ECParameters CreateParameters()
{
byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90");
ECCurve curve = ConfigureCurve(new SecP256R1Curve());
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -233,18 +329,18 @@ namespace Org.BouncyCastle.Crypto.EC
/*
* secp384r1
*/
- internal class Secp384r1Holder
+ internal class SecP384R1Holder
: X9ECParametersHolder
{
- private Secp384r1Holder() { }
+ private SecP384R1Holder() { }
- internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder();
+ internal static readonly X9ECParametersHolder Instance = new SecP384R1Holder();
protected override X9ECParameters CreateParameters()
{
byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
ECCurve curve = ConfigureCurve(new SecP384R1Curve());
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+ "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -254,61 +350,487 @@ namespace Org.BouncyCastle.Crypto.EC
/*
* secp521r1
*/
- internal class Secp521r1Holder
+ internal class SecP521R1Holder
: X9ECParametersHolder
{
- private Secp521r1Holder() { }
+ private SecP521R1Holder() { }
- internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder();
+ internal static readonly X9ECParametersHolder Instance = new SecP521R1Holder();
protected override X9ECParameters CreateParameters()
{
byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
ECCurve curve = ConfigureCurve(new SecP521R1Curve());
- ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+ "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
}
}
+ /*
+ * sect113r1
+ */
+ internal class SecT113R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT113R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT113R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+ ECCurve curve = ConfigureCurve(new SecT113R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "009D73616F35F4AB1407D73562C10F"
+ + "00A52830277958EE84D1315ED31886"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect113r2
+ */
+ internal class SecT113R2Holder
+ : X9ECParametersHolder
+ {
+ private SecT113R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT113R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+ ECCurve curve = ConfigureCurve(new SecT113R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "01A57A6A7B26CA5EF52FCDB8164797"
+ + "00B3ADC94ED1FE674C06E695BABA1D"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect131r1
+ */
+ internal class SecT131R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT131R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT131R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+ ECCurve curve = ConfigureCurve(new SecT131R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0081BAF91FDF9833C40F9C181343638399"
+ + "078C6E7EA38C001F73C8134B1B4EF9E150"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect131r2
+ */
+ internal class SecT131R2Holder
+ : X9ECParametersHolder
+ {
+ private SecT131R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT131R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+ ECCurve curve = ConfigureCurve(new SecT131R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0356DCD8F2F95031AD652D23951BB366A8"
+ + "0648F06D867940A5366D9E265DE9EB240F"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect163k1
+ */
+ internal class SecT163K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT163K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT163K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT163K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+ + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect163r1
+ */
+ internal class SecT163R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT163R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT163R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+ ECCurve curve = ConfigureCurve(new SecT163R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0369979697AB43897789566789567F787A7876A654"
+ + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect163r2
+ */
+ internal class SecT163R2Holder
+ : X9ECParametersHolder
+ {
+ private SecT163R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT163R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+ ECCurve curve = ConfigureCurve(new SecT163R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+ + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect193r1
+ */
+ internal class SecT193R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT193R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT193R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("103FAEC74D696E676875615175777FC5B191EF30");
+ ECCurve curve = ConfigureCurve(new SecT193R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+ + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect193r2
+ */
+ internal class SecT193R2Holder
+ : X9ECParametersHolder
+ {
+ private SecT193R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT193R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("10B7B4D696E676875615175137C8A16FD0DA2211");
+ ECCurve curve = ConfigureCurve(new SecT193R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+ + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect233k1
+ */
+ internal class SecT233K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT233K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT233K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT233K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+ + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect233r1
+ */
+ internal class SecT233R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT233R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT233R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+ ECCurve curve = ConfigureCurve(new SecT233R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+ + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect239k1
+ */
+ internal class SecT239K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT239K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT239K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT239K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+ + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect283k1
+ */
+ internal class SecT283K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT283K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT283K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT283K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+ + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect283r1
+ */
+ internal class SecT283R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT283R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT283R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+ ECCurve curve = ConfigureCurve(new SecT283R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+ + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect409k1
+ */
+ internal class SecT409K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT409K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT409K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT409K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+ + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect409r1
+ */
+ internal class SecT409R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT409R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT409R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+ ECCurve curve = ConfigureCurve(new SecT409R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+ + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect571k1
+ */
+ internal class SecT571K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT571K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT571K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT571K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+ + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect571r1
+ */
+ internal class SecT571R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT571R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT571R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+ ECCurve curve = ConfigureCurve(new SecT571R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+ + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+
private static readonly IDictionary nameToCurve = Platform.CreateHashtable();
private static readonly IDictionary nameToOid = Platform.CreateHashtable();
private static readonly IDictionary oidToCurve = Platform.CreateHashtable();
private static readonly IDictionary oidToName = Platform.CreateHashtable();
+ private static readonly IList names = Platform.CreateArrayList();
private static void DefineCurve(string name, X9ECParametersHolder holder)
{
+ names.Add(name);
+ name = Platform.ToLowerInvariant(name);
nameToCurve.Add(name, holder);
}
- private static void DefineCurve(string name, DerObjectIdentifier oid, X9ECParametersHolder holder)
+ private static void DefineCurveWithOid(string name, DerObjectIdentifier oid, X9ECParametersHolder holder)
{
- nameToCurve.Add(name, holder);
- nameToOid.Add(name, oid);
+ names.Add(name);
oidToName.Add(oid, name);
oidToCurve.Add(oid, holder);
+ name = Platform.ToLowerInvariant(name);
+ nameToOid.Add(name, oid);
+ nameToCurve.Add(name, holder);
}
- private static void DefineCurveAlias(string alias, DerObjectIdentifier oid)
+ private static void DefineCurveAlias(string name, DerObjectIdentifier oid)
{
- alias = Platform.ToLowerInvariant(alias);
- nameToOid.Add(alias, oid);
- nameToCurve.Add(alias, oidToCurve[oid]);
+ object curve = oidToCurve[oid];
+ if (curve == null)
+ throw new InvalidOperationException();
+
+ name = Platform.ToLowerInvariant(name);
+ nameToOid.Add(name, oid);
+ nameToCurve.Add(name, curve);
}
static CustomNamedCurves()
{
DefineCurve("curve25519", Curve25519Holder.Instance);
- DefineCurve("secp192k1", SecObjectIdentifiers.SecP192k1, Secp192k1Holder.Instance);
- DefineCurve("secp192r1", SecObjectIdentifiers.SecP192r1, Secp192r1Holder.Instance);
- DefineCurve("secp224k1", SecObjectIdentifiers.SecP224k1, Secp224k1Holder.Instance);
- DefineCurve("secp224r1", SecObjectIdentifiers.SecP224r1, Secp224r1Holder.Instance);
- DefineCurve("secp256k1", SecObjectIdentifiers.SecP256k1, Secp256k1Holder.Instance);
- DefineCurve("secp256r1", SecObjectIdentifiers.SecP256r1, Secp256r1Holder.Instance);
- DefineCurve("secp384r1", SecObjectIdentifiers.SecP384r1, Secp384r1Holder.Instance);
- DefineCurve("secp521r1", SecObjectIdentifiers.SecP521r1, Secp521r1Holder.Instance);
+ //DefineCurveWithOid("secp112r1", SecObjectIdentifiers.SecP112r1, SecP112R1Holder.Instance);
+ //DefineCurveWithOid("secp112r2", SecObjectIdentifiers.SecP112r2, SecP112R2Holder.Instance);
+ DefineCurveWithOid("secp128r1", SecObjectIdentifiers.SecP128r1, SecP128R1Holder.Instance);
+ //DefineCurveWithOid("secp128r2", SecObjectIdentifiers.SecP128r2, SecP128R2Holder.Instance);
+ DefineCurveWithOid("secp160k1", SecObjectIdentifiers.SecP160k1, SecP160K1Holder.Instance);
+ DefineCurveWithOid("secp160r1", SecObjectIdentifiers.SecP160r1, SecP160R1Holder.Instance);
+ DefineCurveWithOid("secp160r2", SecObjectIdentifiers.SecP160r2, SecP160R2Holder.Instance);
+ DefineCurveWithOid("secp192k1", SecObjectIdentifiers.SecP192k1, SecP192K1Holder.Instance);
+ DefineCurveWithOid("secp192r1", SecObjectIdentifiers.SecP192r1, SecP192R1Holder.Instance);
+ DefineCurveWithOid("secp224k1", SecObjectIdentifiers.SecP224k1, SecP224K1Holder.Instance);
+ DefineCurveWithOid("secp224r1", SecObjectIdentifiers.SecP224r1, SecP224R1Holder.Instance);
+ DefineCurveWithOid("secp256k1", SecObjectIdentifiers.SecP256k1, SecP256K1Holder.Instance);
+ DefineCurveWithOid("secp256r1", SecObjectIdentifiers.SecP256r1, SecP256R1Holder.Instance);
+ DefineCurveWithOid("secp384r1", SecObjectIdentifiers.SecP384r1, SecP384R1Holder.Instance);
+ DefineCurveWithOid("secp521r1", SecObjectIdentifiers.SecP521r1, SecP521R1Holder.Instance);
+
+ DefineCurveWithOid("sect113r1", SecObjectIdentifiers.SecT113r1, SecT113R1Holder.Instance);
+ DefineCurveWithOid("sect113r2", SecObjectIdentifiers.SecT113r2, SecT113R2Holder.Instance);
+ DefineCurveWithOid("sect131r1", SecObjectIdentifiers.SecT131r1, SecT131R1Holder.Instance);
+ DefineCurveWithOid("sect131r2", SecObjectIdentifiers.SecT131r2, SecT131R2Holder.Instance);
+ DefineCurveWithOid("sect163k1", SecObjectIdentifiers.SecT163k1, SecT163K1Holder.Instance);
+ DefineCurveWithOid("sect163r1", SecObjectIdentifiers.SecT163r1, SecT163R1Holder.Instance);
+ DefineCurveWithOid("sect163r2", SecObjectIdentifiers.SecT163r2, SecT163R2Holder.Instance);
+ DefineCurveWithOid("sect193r1", SecObjectIdentifiers.SecT193r1, SecT193R1Holder.Instance);
+ DefineCurveWithOid("sect193r2", SecObjectIdentifiers.SecT193r2, SecT193R2Holder.Instance);
+ DefineCurveWithOid("sect233k1", SecObjectIdentifiers.SecT233k1, SecT233K1Holder.Instance);
+ DefineCurveWithOid("sect233r1", SecObjectIdentifiers.SecT233r1, SecT233R1Holder.Instance);
+ DefineCurveWithOid("sect239k1", SecObjectIdentifiers.SecT239k1, SecT239K1Holder.Instance);
+ DefineCurveWithOid("sect283k1", SecObjectIdentifiers.SecT283k1, SecT283K1Holder.Instance);
+ DefineCurveWithOid("sect283r1", SecObjectIdentifiers.SecT283r1, SecT283R1Holder.Instance);
+ DefineCurveWithOid("sect409k1", SecObjectIdentifiers.SecT409k1, SecT409K1Holder.Instance);
+ DefineCurveWithOid("sect409r1", SecObjectIdentifiers.SecT409r1, SecT409R1Holder.Instance);
+ DefineCurveWithOid("sect571k1", SecObjectIdentifiers.SecT571k1, SecT571K1Holder.Instance);
+ DefineCurveWithOid("sect571r1", SecObjectIdentifiers.SecT571r1, SecT571R1Holder.Instance);
+
+ DefineCurveAlias("B-163", SecObjectIdentifiers.SecT163r2);
+ DefineCurveAlias("B-233", SecObjectIdentifiers.SecT233r1);
+ DefineCurveAlias("B-283", SecObjectIdentifiers.SecT283r1);
+ DefineCurveAlias("B-409", SecObjectIdentifiers.SecT409r1);
+ DefineCurveAlias("B-571", SecObjectIdentifiers.SecT571r1);
+
+ DefineCurveAlias("K-163", SecObjectIdentifiers.SecT163k1);
+ DefineCurveAlias("K-233", SecObjectIdentifiers.SecT233k1);
+ DefineCurveAlias("K-283", SecObjectIdentifiers.SecT283k1);
+ DefineCurveAlias("K-409", SecObjectIdentifiers.SecT409k1);
+ DefineCurveAlias("K-571", SecObjectIdentifiers.SecT571k1);
DefineCurveAlias("P-192", SecObjectIdentifiers.SecP192r1);
DefineCurveAlias("P-224", SecObjectIdentifiers.SecP224r1);
@@ -360,7 +882,7 @@ namespace Org.BouncyCastle.Crypto.EC
*/
public static IEnumerable Names
{
- get { return new EnumerableProxy(nameToCurve.Keys); }
+ get { return new EnumerableProxy(names); }
}
}
}
diff --git a/crypto/src/crypto/encodings/Pkcs1Encoding.cs b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
index d2225a7d4..35fd96abe 100644
--- a/crypto/src/crypto/encodings/Pkcs1Encoding.cs
+++ b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
@@ -7,226 +7,376 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Encodings
{
- /**
- * this does your basic Pkcs 1 v1.5 padding - whether or not you should be using this
- * depends on your application - see Pkcs1 Version 2 for details.
- */
- public class Pkcs1Encoding
- : IAsymmetricBlockCipher
- {
- /**
- * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to
- * work with one of these set the system property Org.BouncyCastle.Pkcs1.Strict to false.
- */
- public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict";
-
- private const int HeaderLength = 10;
-
- /**
- * The same effect can be achieved by setting the static property directly
- * <p>
- * The static property is checked during construction of the encoding object, it is set to
- * true by default.
- * </p>
- */
- public static bool StrictLengthEnabled
- {
- get { return strictLengthEnabled[0]; }
- set { strictLengthEnabled[0] = value; }
- }
-
- private static readonly bool[] strictLengthEnabled;
-
- static Pkcs1Encoding()
- {
- string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty);
-
- strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")};
- }
-
-
- private SecureRandom random;
- private IAsymmetricBlockCipher engine;
- private bool forEncryption;
- private bool forPrivateKey;
- private bool useStrictLength;
-
- /**
- * Basic constructor.
- * @param cipher
- */
- public Pkcs1Encoding(
- IAsymmetricBlockCipher cipher)
- {
- this.engine = cipher;
- this.useStrictLength = StrictLengthEnabled;
- }
-
- public IAsymmetricBlockCipher GetUnderlyingCipher()
- {
- return engine;
- }
-
- public string AlgorithmName
- {
- get { return engine.AlgorithmName + "/PKCS1Padding"; }
- }
-
- public void Init(
- bool forEncryption,
- ICipherParameters parameters)
- {
- AsymmetricKeyParameter kParam;
- if (parameters is ParametersWithRandom)
- {
- ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
- this.random = rParam.Random;
- kParam = (AsymmetricKeyParameter)rParam.Parameters;
- }
- else
- {
- this.random = new SecureRandom();
- kParam = (AsymmetricKeyParameter)parameters;
- }
-
- engine.Init(forEncryption, parameters);
-
- this.forPrivateKey = kParam.IsPrivate;
- this.forEncryption = forEncryption;
- }
-
- public int GetInputBlockSize()
- {
- int baseBlockSize = engine.GetInputBlockSize();
-
- return forEncryption
- ? baseBlockSize - HeaderLength
- : baseBlockSize;
- }
-
- public int GetOutputBlockSize()
- {
- int baseBlockSize = engine.GetOutputBlockSize();
-
- return forEncryption
- ? baseBlockSize
- : baseBlockSize - HeaderLength;
- }
-
- public byte[] ProcessBlock(
- byte[] input,
- int inOff,
- int length)
- {
- return forEncryption
- ? EncodeBlock(input, inOff, length)
- : DecodeBlock(input, inOff, length);
- }
-
- private byte[] EncodeBlock(
- byte[] input,
- int inOff,
- int inLen)
- {
- if (inLen > GetInputBlockSize())
- throw new ArgumentException("input data too large", "inLen");
-
- byte[] block = new byte[engine.GetInputBlockSize()];
-
- if (forPrivateKey)
- {
- block[0] = 0x01; // type code 1
-
- for (int i = 1; i != block.Length - inLen - 1; i++)
- {
- block[i] = (byte)0xFF;
- }
- }
- else
- {
- random.NextBytes(block); // random fill
-
- block[0] = 0x02; // type code 2
-
- //
- // a zero byte marks the end of the padding, so all
- // the pad bytes must be non-zero.
- //
- for (int i = 1; i != block.Length - inLen - 1; i++)
- {
- while (block[i] == 0)
- {
- block[i] = (byte)random.NextInt();
- }
- }
- }
-
- block[block.Length - inLen - 1] = 0x00; // mark the end of the padding
- Array.Copy(input, inOff, block, block.Length - inLen, inLen);
-
- return engine.ProcessBlock(block, 0, block.Length);
- }
-
- /**
- * @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format.
- */
- private byte[] DecodeBlock(
- byte[] input,
- int inOff,
- int inLen)
- {
- byte[] block = engine.ProcessBlock(input, inOff, inLen);
-
- if (block.Length < GetOutputBlockSize())
- {
- throw new InvalidCipherTextException("block truncated");
- }
-
- byte type = block[0];
-
- if (type != 1 && type != 2)
- {
- throw new InvalidCipherTextException("unknown block type");
- }
-
- if (useStrictLength && block.Length != engine.GetOutputBlockSize())
- {
- throw new InvalidCipherTextException("block incorrect size");
- }
-
- //
- // find and extract the message block.
- //
- int start;
- for (start = 1; start != block.Length; start++)
- {
- byte pad = block[start];
-
- if (pad == 0)
- {
- break;
- }
-
- if (type == 1 && pad != (byte)0xff)
- {
- throw new InvalidCipherTextException("block padding incorrect");
- }
- }
-
- start++; // data should start at the next byte
-
- if (start > block.Length || start < HeaderLength)
- {
- throw new InvalidCipherTextException("no data in block");
- }
-
- byte[] result = new byte[block.Length - start];
-
- Array.Copy(block, start, result, 0, result.Length);
-
- return result;
- }
- }
+ /**
+ * this does your basic Pkcs 1 v1.5 padding - whether or not you should be using this
+ * depends on your application - see Pkcs1 Version 2 for details.
+ */
+ public class Pkcs1Encoding
+ : IAsymmetricBlockCipher
+ {
+ /**
+ * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to
+ * work with one of these set the system property Org.BouncyCastle.Pkcs1.Strict to false.
+ */
+ public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict";
+
+ private const int HeaderLength = 10;
+
+ /**
+ * The same effect can be achieved by setting the static property directly
+ * <p>
+ * The static property is checked during construction of the encoding object, it is set to
+ * true by default.
+ * </p>
+ */
+ public static bool StrictLengthEnabled
+ {
+ get { return strictLengthEnabled[0]; }
+ set { strictLengthEnabled[0] = value; }
+ }
+
+ private static readonly bool[] strictLengthEnabled;
+
+ static Pkcs1Encoding()
+ {
+ string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty);
+
+ strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")};
+ }
+
+
+ private SecureRandom random;
+ private IAsymmetricBlockCipher engine;
+ private bool forEncryption;
+ private bool forPrivateKey;
+ private bool useStrictLength;
+ private int pLen = -1;
+ private byte[] fallback = null;
+
+ /**
+ * Basic constructor.
+ * @param cipher
+ */
+ public Pkcs1Encoding(
+ IAsymmetricBlockCipher cipher)
+ {
+ this.engine = cipher;
+ this.useStrictLength = StrictLengthEnabled;
+ }
+
+ /**
+ * Constructor for decryption with a fixed plaintext length.
+ *
+ * @param cipher The cipher to use for cryptographic operation.
+ * @param pLen Length of the expected plaintext.
+ */
+ public Pkcs1Encoding(IAsymmetricBlockCipher cipher, int pLen)
+ {
+ this.engine = cipher;
+ this.useStrictLength = StrictLengthEnabled;
+ this.pLen = pLen;
+ }
+
+ /**
+ * Constructor for decryption with a fixed plaintext length and a fallback
+ * value that is returned, if the padding is incorrect.
+ *
+ * @param cipher
+ * The cipher to use for cryptographic operation.
+ * @param fallback
+ * The fallback value, we don't to a arraycopy here.
+ */
+ public Pkcs1Encoding(IAsymmetricBlockCipher cipher, byte[] fallback)
+ {
+ this.engine = cipher;
+ this.useStrictLength = StrictLengthEnabled;
+ this.fallback = fallback;
+ this.pLen = fallback.Length;
+ }
+
+ public IAsymmetricBlockCipher GetUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.AlgorithmName + "/PKCS1Padding"; }
+ }
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ AsymmetricKeyParameter kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ kParam = (AsymmetricKeyParameter)rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ kParam = (AsymmetricKeyParameter)parameters;
+ }
+
+ engine.Init(forEncryption, parameters);
+
+ this.forPrivateKey = kParam.IsPrivate;
+ this.forEncryption = forEncryption;
+ }
+
+ public int GetInputBlockSize()
+ {
+ int baseBlockSize = engine.GetInputBlockSize();
+
+ return forEncryption
+ ? baseBlockSize - HeaderLength
+ : baseBlockSize;
+ }
+
+ public int GetOutputBlockSize()
+ {
+ int baseBlockSize = engine.GetOutputBlockSize();
+
+ return forEncryption
+ ? baseBlockSize
+ : baseBlockSize - HeaderLength;
+ }
+
+ public byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ return forEncryption
+ ? EncodeBlock(input, inOff, length)
+ : DecodeBlock(input, inOff, length);
+ }
+
+ private byte[] EncodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (inLen > GetInputBlockSize())
+ throw new ArgumentException("input data too large", "inLen");
+
+ byte[] block = new byte[engine.GetInputBlockSize()];
+
+ if (forPrivateKey)
+ {
+ block[0] = 0x01; // type code 1
+
+ for (int i = 1; i != block.Length - inLen - 1; i++)
+ {
+ block[i] = (byte)0xFF;
+ }
+ }
+ else
+ {
+ random.NextBytes(block); // random fill
+
+ block[0] = 0x02; // type code 2
+
+ //
+ // a zero byte marks the end of the padding, so all
+ // the pad bytes must be non-zero.
+ //
+ for (int i = 1; i != block.Length - inLen - 1; i++)
+ {
+ while (block[i] == 0)
+ {
+ block[i] = (byte)random.NextInt();
+ }
+ }
+ }
+
+ block[block.Length - inLen - 1] = 0x00; // mark the end of the padding
+ Array.Copy(input, inOff, block, block.Length - inLen, inLen);
+
+ return engine.ProcessBlock(block, 0, block.Length);
+ }
+
+ /**
+ * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext
+ * for encryption.
+ *
+ * @param encoded The Plaintext.
+ * @param pLen Expected length of the plaintext.
+ * @return Either 0, if the encoding is correct, or -1, if it is incorrect.
+ */
+ private static int CheckPkcs1Encoding(byte[] encoded, int pLen)
+ {
+ int correct = 0;
+ /*
+ * Check if the first two bytes are 0 2
+ */
+ correct |= (encoded[0] ^ 2);
+
+ /*
+ * Now the padding check, check for no 0 byte in the padding
+ */
+ int plen = encoded.Length - (
+ pLen /* Lenght of the PMS */
+ + 1 /* Final 0-byte before PMS */
+ );
+
+ for (int i = 1; i < plen; i++)
+ {
+ int tmp = encoded[i];
+ tmp |= tmp >> 1;
+ tmp |= tmp >> 2;
+ tmp |= tmp >> 4;
+ correct |= (tmp & 1) - 1;
+ }
+
+ /*
+ * Make sure the padding ends with a 0 byte.
+ */
+ correct |= encoded[encoded.Length - (pLen + 1)];
+
+ /*
+ * Return 0 or 1, depending on the result.
+ */
+ correct |= correct >> 1;
+ correct |= correct >> 2;
+ correct |= correct >> 4;
+ return ~((correct & 1) - 1);
+ }
+
+ /**
+ * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct.
+ *
+ * @param in The encrypted block.
+ * @param inOff Offset in the encrypted block.
+ * @param inLen Length of the encrypted block.
+ * @param pLen Length of the desired output.
+ * @return The plaintext without padding, or a random value if the padding was incorrect.
+ *
+ * @throws InvalidCipherTextException
+ */
+ private byte[] DecodeBlockOrRandom(byte[] input, int inOff, int inLen)
+ {
+ if (!forPrivateKey)
+ throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
+
+ byte[] block = engine.ProcessBlock(input, inOff, inLen);
+ byte[] random = null;
+ if (this.fallback == null)
+ {
+ random = new byte[this.pLen];
+ this.random.NextBytes(random);
+ }
+ else
+ {
+ random = fallback;
+ }
+
+ /*
+ * TODO: This is a potential dangerous side channel. However, you can
+ * fix this by changing the RSA engine in a way, that it will always
+ * return blocks of the same length and prepend them with 0 bytes if
+ * needed.
+ */
+ if (block.Length < GetOutputBlockSize())
+ throw new InvalidCipherTextException("block truncated");
+
+ /*
+ * TODO: Potential side channel. Fix it by making the engine always
+ * return blocks of the correct length.
+ */
+ if (useStrictLength && block.Length != engine.GetOutputBlockSize())
+ throw new InvalidCipherTextException("block incorrect size");
+
+ /*
+ * Check the padding.
+ */
+ int correct = Pkcs1Encoding.CheckPkcs1Encoding(block, this.pLen);
+
+ /*
+ * Now, to a constant time constant memory copy of the decrypted value
+ * or the random value, depending on the validity of the padding.
+ */
+ byte[] result = new byte[this.pLen];
+ for (int i = 0; i < this.pLen; i++)
+ {
+ result[i] = (byte)((block[i+(block.Length-pLen)]&(~correct)) | (random[i]&correct));
+ }
+
+ return result;
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format.
+ */
+ private byte[] DecodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ /*
+ * If the length of the expected plaintext is known, we use a constant-time decryption.
+ * If the decryption fails, we return a random value.
+ */
+ if (this.pLen != -1)
+ {
+ return this.DecodeBlockOrRandom(input, inOff, inLen);
+ }
+
+ byte[] block = engine.ProcessBlock(input, inOff, inLen);
+
+ if (block.Length < GetOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block truncated");
+ }
+
+ byte type = block[0];
+
+ if (type != 1 && type != 2)
+ {
+ throw new InvalidCipherTextException("unknown block type");
+ }
+
+ if (useStrictLength && block.Length != engine.GetOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block incorrect size");
+ }
+
+ //
+ // find and extract the message block.
+ //
+ int start;
+ for (start = 1; start != block.Length; start++)
+ {
+ byte pad = block[start];
+
+ if (pad == 0)
+ {
+ break;
+ }
+
+ if (type == 1 && pad != (byte)0xff)
+ {
+ throw new InvalidCipherTextException("block padding incorrect");
+ }
+ }
+
+ start++; // data should start at the next byte
+
+ if (start > block.Length || start < HeaderLength)
+ {
+ throw new InvalidCipherTextException("no data in block");
+ }
+
+ byte[] result = new byte[block.Length - start];
+
+ Array.Copy(block, start, result, 0, result.Length);
+
+ return result;
+ }
+ }
}
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 47eaada3e..164c43ee9 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -6,288 +6,299 @@ using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
- /**
- * an implementation of the AES (Rijndael), from FIPS-197.
- * <p>
- * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
- *
- * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
- * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
- *
- * There are three levels of tradeoff of speed vs memory
- * Because java has no preprocessor, they are written as three separate classes from which to choose
- *
- * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
- * and 4 for decryption.
- *
- * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
- * adding 12 rotate operations per round to compute the values contained in the other tables from
- * the contents of the first.
- *
- * The slowest version uses no static tables at all and computes the values in each round.
- * </p>
- * <p>
- * This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
- * </p>
- */
- public class AesEngine
- : IBlockCipher
- {
- // The S box
- private static readonly byte[] S =
- {
- 99, 124, 119, 123, 242, 107, 111, 197,
- 48, 1, 103, 43, 254, 215, 171, 118,
- 202, 130, 201, 125, 250, 89, 71, 240,
- 173, 212, 162, 175, 156, 164, 114, 192,
- 183, 253, 147, 38, 54, 63, 247, 204,
- 52, 165, 229, 241, 113, 216, 49, 21,
- 4, 199, 35, 195, 24, 150, 5, 154,
- 7, 18, 128, 226, 235, 39, 178, 117,
- 9, 131, 44, 26, 27, 110, 90, 160,
- 82, 59, 214, 179, 41, 227, 47, 132,
- 83, 209, 0, 237, 32, 252, 177, 91,
- 106, 203, 190, 57, 74, 76, 88, 207,
- 208, 239, 170, 251, 67, 77, 51, 133,
- 69, 249, 2, 127, 80, 60, 159, 168,
- 81, 163, 64, 143, 146, 157, 56, 245,
- 188, 182, 218, 33, 16, 255, 243, 210,
- 205, 12, 19, 236, 95, 151, 68, 23,
- 196, 167, 126, 61, 100, 93, 25, 115,
- 96, 129, 79, 220, 34, 42, 144, 136,
- 70, 238, 184, 20, 222, 94, 11, 219,
- 224, 50, 58, 10, 73, 6, 36, 92,
- 194, 211, 172, 98, 145, 149, 228, 121,
- 231, 200, 55, 109, 141, 213, 78, 169,
- 108, 86, 244, 234, 101, 122, 174, 8,
- 186, 120, 37, 46, 28, 166, 180, 198,
- 232, 221, 116, 31, 75, 189, 139, 138,
- 112, 62, 181, 102, 72, 3, 246, 14,
- 97, 53, 87, 185, 134, 193, 29, 158,
- 225, 248, 152, 17, 105, 217, 142, 148,
- 155, 30, 135, 233, 206, 85, 40, 223,
- 140, 161, 137, 13, 191, 230, 66, 104,
- 65, 153, 45, 15, 176, 84, 187, 22,
- };
-
- // The inverse S-box
- private static readonly byte[] Si =
- {
- 82, 9, 106, 213, 48, 54, 165, 56,
- 191, 64, 163, 158, 129, 243, 215, 251,
- 124, 227, 57, 130, 155, 47, 255, 135,
- 52, 142, 67, 68, 196, 222, 233, 203,
- 84, 123, 148, 50, 166, 194, 35, 61,
- 238, 76, 149, 11, 66, 250, 195, 78,
- 8, 46, 161, 102, 40, 217, 36, 178,
- 118, 91, 162, 73, 109, 139, 209, 37,
- 114, 248, 246, 100, 134, 104, 152, 22,
- 212, 164, 92, 204, 93, 101, 182, 146,
- 108, 112, 72, 80, 253, 237, 185, 218,
- 94, 21, 70, 87, 167, 141, 157, 132,
- 144, 216, 171, 0, 140, 188, 211, 10,
- 247, 228, 88, 5, 184, 179, 69, 6,
- 208, 44, 30, 143, 202, 63, 15, 2,
- 193, 175, 189, 3, 1, 19, 138, 107,
- 58, 145, 17, 65, 79, 103, 220, 234,
- 151, 242, 207, 206, 240, 180, 230, 115,
- 150, 172, 116, 34, 231, 173, 53, 133,
- 226, 249, 55, 232, 28, 117, 223, 110,
- 71, 241, 26, 113, 29, 41, 197, 137,
- 111, 183, 98, 14, 170, 24, 190, 27,
- 252, 86, 62, 75, 198, 210, 121, 32,
- 154, 219, 192, 254, 120, 205, 90, 244,
- 31, 221, 168, 51, 136, 7, 199, 49,
- 177, 18, 16, 89, 39, 128, 236, 95,
- 96, 81, 127, 169, 25, 181, 74, 13,
- 45, 229, 122, 159, 147, 201, 156, 239,
- 160, 224, 59, 77, 174, 42, 245, 176,
- 200, 235, 187, 60, 131, 83, 153, 97,
- 23, 43, 4, 126, 186, 119, 214, 38,
- 225, 105, 20, 99, 85, 33, 12, 125,
- };
-
- // vector used in calculating key schedule (powers of x in GF(256))
- private static readonly byte[] rcon =
- {
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
- 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
- };
-
- // precomputation tables of calculations for rounds
- private static readonly uint[] T0 =
- {
- 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
- 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
- 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
- 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
- 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
- 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
- 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
- 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
- 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
- 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
- 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
- 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
- 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
- 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
- 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
- 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
- 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
- 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
- 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
- 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
- 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
- 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
- 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
- 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
- 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
- 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
- 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
- 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
- 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
- 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
- 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
- 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
- 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
- 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
- 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
- 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
- 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
- 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
- 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
- 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
- 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
- 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
- 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
- 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
- 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
- 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
- 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
- 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
- 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
- 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
- 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
- 0x3a16162c
- };
-
- private static readonly uint[] Tinv0 =
- {
- 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
- 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
- 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
- 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
- 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
- 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
- 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
- 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
- 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
- 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
- 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
- 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
- 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
- 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
- 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
- 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
- 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
- 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
- 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
- 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
- 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
- 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
- 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
- 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
- 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
- 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
- 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
- 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
- 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
- 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
- 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
- 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
- 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
- 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
- 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
- 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
- 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
- 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
- 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
- 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
- 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
- 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
- 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
- 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
- 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
- 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
- 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
- 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
- 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
- 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
- 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
- 0x4257b8d0
- };
-
- private static uint Shift(uint r, int shift)
- {
- return (r >> shift) | (r << (32 - shift));
- }
-
- /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
-
- private const uint m1 = 0x80808080;
- private const uint m2 = 0x7f7f7f7f;
- private const uint m3 = 0x0000001b;
-
- private static uint FFmulX(uint x)
- {
- return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
- }
-
- /*
- The following defines provide alternative definitions of FFmulX that might
- give improved performance if a fast 32-bit multiply is not available.
-
- private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
- private static final int m4 = 0x1b1b1b1b;
- private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
-
- */
-
- private static uint Inv_Mcol(uint x)
- {
- uint f2 = FFmulX(x);
- uint f4 = FFmulX(f2);
- uint f8 = FFmulX(f4);
- uint f9 = x ^ f8;
-
- return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
- }
-
- private static uint SubWord(uint x)
- {
- return (uint)S[x&255]
- | (((uint)S[(x>>8)&255]) << 8)
- | (((uint)S[(x>>16)&255]) << 16)
- | (((uint)S[(x>>24)&255]) << 24);
- }
-
- /**
- * Calculate the necessary round keys
- * The number of calculations depends on key size and block size
- * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
- * This code is written assuming those are the only possible values
- */
- private uint[][] GenerateWorkingKey(
- byte[] key,
- bool forEncryption)
- {
- int KC = key.Length / 4; // key length in words
- int t;
-
- if ((KC != 4) && (KC != 6) && (KC != 8))
- throw new ArgumentException("Key length not 128/192/256 bits.");
-
- ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+ /**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first.
+ *
+ * The slowest version uses no static tables at all and computes the values in each round.
+ * </p>
+ * <p>
+ * This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
+ * </p>
+ */
+ public class AesEngine
+ : IBlockCipher
+ {
+ // The S box
+ private static readonly byte[] S =
+ {
+ 99, 124, 119, 123, 242, 107, 111, 197,
+ 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240,
+ 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204,
+ 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154,
+ 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160,
+ 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91,
+ 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133,
+ 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23,
+ 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136,
+ 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92,
+ 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169,
+ 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198,
+ 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14,
+ 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148,
+ 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104,
+ 65, 153, 45, 15, 176, 84, 187, 22,
+ };
+
+ // The inverse S-box
+ private static readonly byte[] Si =
+ {
+ 82, 9, 106, 213, 48, 54, 165, 56,
+ 191, 64, 163, 158, 129, 243, 215, 251,
+ 124, 227, 57, 130, 155, 47, 255, 135,
+ 52, 142, 67, 68, 196, 222, 233, 203,
+ 84, 123, 148, 50, 166, 194, 35, 61,
+ 238, 76, 149, 11, 66, 250, 195, 78,
+ 8, 46, 161, 102, 40, 217, 36, 178,
+ 118, 91, 162, 73, 109, 139, 209, 37,
+ 114, 248, 246, 100, 134, 104, 152, 22,
+ 212, 164, 92, 204, 93, 101, 182, 146,
+ 108, 112, 72, 80, 253, 237, 185, 218,
+ 94, 21, 70, 87, 167, 141, 157, 132,
+ 144, 216, 171, 0, 140, 188, 211, 10,
+ 247, 228, 88, 5, 184, 179, 69, 6,
+ 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107,
+ 58, 145, 17, 65, 79, 103, 220, 234,
+ 151, 242, 207, 206, 240, 180, 230, 115,
+ 150, 172, 116, 34, 231, 173, 53, 133,
+ 226, 249, 55, 232, 28, 117, 223, 110,
+ 71, 241, 26, 113, 29, 41, 197, 137,
+ 111, 183, 98, 14, 170, 24, 190, 27,
+ 252, 86, 62, 75, 198, 210, 121, 32,
+ 154, 219, 192, 254, 120, 205, 90, 244,
+ 31, 221, 168, 51, 136, 7, 199, 49,
+ 177, 18, 16, 89, 39, 128, 236, 95,
+ 96, 81, 127, 169, 25, 181, 74, 13,
+ 45, 229, 122, 159, 147, 201, 156, 239,
+ 160, 224, 59, 77, 174, 42, 245, 176,
+ 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38,
+ 225, 105, 20, 99, 85, 33, 12, 125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static readonly byte[] rcon =
+ {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
+ };
+
+ // precomputation tables of calculations for rounds
+ private static readonly uint[] T0 =
+ {
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
+ 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
+ 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
+ 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+ 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
+ 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
+ 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
+ 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+ 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
+ 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
+ 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
+ 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+ 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
+ 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
+ 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
+ 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+ 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
+ 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
+ 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
+ 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+ 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
+ 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
+ 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
+ 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
+ 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
+ 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
+ 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+ 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
+ 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
+ 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
+ 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+ 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
+ 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
+ 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
+ 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+ 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
+ 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
+ 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
+ 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+ 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
+ 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
+ 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
+ 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+ 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
+ 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
+ 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
+ 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
+ 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
+ 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
+ 0x3a16162c
+ };
+
+ private static readonly uint[] Tinv0 =
+ {
+ 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
+ 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
+ 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
+ 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
+ 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
+ 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
+ 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
+ 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
+ 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
+ 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
+ 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
+ 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+ 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
+ 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
+ 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
+ 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
+ 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
+ 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
+ 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
+ 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
+ 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
+ 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
+ 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
+ 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+ 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
+ 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
+ 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
+ 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
+ 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
+ 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
+ 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
+ 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
+ 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
+ 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
+ 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
+ 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+ 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
+ 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
+ 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
+ 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
+ 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
+ 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
+ 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
+ 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
+ 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
+ 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
+ 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
+ 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+ 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
+ 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
+ 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
+ 0x4257b8d0
+ };
+
+ private static uint Shift(uint r, int shift)
+ {
+ return (r >> shift) | (r << (32 - shift));
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private const uint m1 = 0x80808080;
+ private const uint m2 = 0x7f7f7f7f;
+ private const uint m3 = 0x0000001b;
+ private const uint m4 = 0xC0C0C0C0;
+ private const uint m5 = 0x3f3f3f3f;
+
+ private static uint FFmulX(uint x)
+ {
+ return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
+ }
+
+ private static uint FFmulX2(uint x)
+ {
+ uint t0 = (x & m5) << 2;
+ uint t1 = (x & m4);
+ t1 ^= (t1 >> 1);
+ return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+ }
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private static uint Inv_Mcol(uint x)
+ {
+ uint t0, t1;
+ t0 = x;
+ t1 = t0 ^ Shift(t0, 8);
+ t0 ^= FFmulX(t1);
+ t1 ^= FFmulX2(t0);
+ t0 ^= t1 ^ Shift(t1, 16);
+ return t0;
+ }
+
+ private static uint SubWord(uint x)
+ {
+ return (uint)S[x&255]
+ | (((uint)S[(x>>8)&255]) << 8)
+ | (((uint)S[(x>>16)&255]) << 16)
+ | (((uint)S[(x>>24)&255]) << 24);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+ * This code is written assuming those are the only possible values
+ */
+ private uint[][] GenerateWorkingKey(
+ byte[] key,
+ bool forEncryption)
+ {
+ int KC = key.Length / 4; // key length in words
+ int t;
+
+ if ((KC != 4) && (KC != 6) && (KC != 8))
+ throw new ArgumentException("Key length not 128/192/256 bits.");
+
+ ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
for (int i = 0; i <= ROUNDS; ++i)
@@ -295,252 +306,229 @@ namespace Org.BouncyCastle.Crypto.Engines
W[i] = new uint[4];
}
- //
- // copy the key into the round key array
- //
-
- t = 0;
- for (int i = 0; i < key.Length; t++)
- {
- W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
- i+=4;
- }
-
- //
- // while not enough round key material calculated
- // calculate new values
- //
- int k = (ROUNDS + 1) << 2;
- for (int i = KC; (i < k); i++)
- {
- uint temp = W[(i-1)>>2][(i-1)&3];
- if ((i % KC) == 0)
- {
- temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
- }
- else if ((KC > 6) && ((i % KC) == 4))
- {
- temp = SubWord(temp);
- }
-
- W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
- }
-
- if (!forEncryption)
- {
- for (int j = 1; j < ROUNDS; j++)
- {
+ //
+ // copy the key into the round key array
+ //
+
+ t = 0;
+ for (int i = 0; i < key.Length; t++)
+ {
+ W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
+ i+=4;
+ }
+
+ //
+ // while not enough round key material calculated
+ // calculate new values
+ //
+ int k = (ROUNDS + 1) << 2;
+ for (int i = KC; (i < k); i++)
+ {
+ uint temp = W[(i-1)>>2][(i-1)&3];
+ if ((i % KC) == 0)
+ {
+ temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
+ }
+ else if ((KC > 6) && ((i % KC) == 4))
+ {
+ temp = SubWord(temp);
+ }
+
+ W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
+ }
+
+ if (!forEncryption)
+ {
+ for (int j = 1; j < ROUNDS; j++)
+ {
uint[] w = W[j];
for (int i = 0; i < 4; i++)
{
w[i] = Inv_Mcol(w[i]);
}
}
- }
-
- return W;
- }
-
- private int ROUNDS;
- private uint[][] WorkingKey;
- private uint C0, C1, C2, C3;
- private bool forEncryption;
-
- private const int BLOCK_SIZE = 16;
-
- /**
- * default constructor - 128 bit block size.
- */
- public AesEngine()
- {
- }
-
- /**
- * initialise an AES cipher.
- *
- * @param forEncryption whether or not we are for encryption.
- * @param parameters the parameters required to set up the cipher.
- * @exception ArgumentException if the parameters argument is
- * inappropriate.
- */
- public void Init(
- bool forEncryption,
- ICipherParameters parameters)
- {
- KeyParameter keyParameter = parameters as KeyParameter;
-
- if (keyParameter == null)
- throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
-
- WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
-
- this.forEncryption = forEncryption;
- }
-
- public string AlgorithmName
- {
- get { return "AES"; }
- }
-
- public bool IsPartialBlockOkay
- {
- get { return false; }
- }
-
- public int GetBlockSize()
- {
- return BLOCK_SIZE;
- }
-
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
- {
- if (WorkingKey == null)
- {
- throw new InvalidOperationException("AES engine not initialised");
- }
-
- if ((inOff + (32 / 2)) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + (32 / 2)) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
-
- UnPackBlock(input, inOff);
-
- if (forEncryption)
- {
- EncryptBlock();
- }
- else
- {
- DecryptBlock();
- }
-
- PackBlock(output, outOff);
-
- return BLOCK_SIZE;
- }
-
- public void Reset()
- {
- }
-
- private void UnPackBlock(
- byte[] bytes,
- int off)
- {
- C0 = Pack.LE_To_UInt32(bytes, off);
- C1 = Pack.LE_To_UInt32(bytes, off + 4);
- C2 = Pack.LE_To_UInt32(bytes, off + 8);
- C3 = Pack.LE_To_UInt32(bytes, off + 12);
- }
-
- private void PackBlock(
- byte[] bytes,
- int off)
- {
- Pack.UInt32_To_LE(C0, bytes, off);
- Pack.UInt32_To_LE(C1, bytes, off + 4);
- Pack.UInt32_To_LE(C2, bytes, off + 8);
- Pack.UInt32_To_LE(C3, bytes, off + 12);
- }
-
- private void EncryptBlock()
- {
- uint[][] KW = WorkingKey;
-
- int r = 0;
- uint[] kw = KW[r];
-
- C0 ^= kw[0];
- C1 ^= kw[1];
- C2 ^= kw[2];
- C3 ^= kw[3];
-
- uint r0, r1, r2, r3;
-
- while (r < (ROUNDS - 2))
- {
- kw = KW[++r];
- r0 = T0[C0 & 255] ^ Shift(T0[(C1 >> 8) & 255], 24) ^ Shift(T0[(C2 >> 16) & 255], 16) ^ Shift(T0[(C3 >> 24) & 255], 8) ^ kw[0];
- r1 = T0[C1 & 255] ^ Shift(T0[(C2 >> 8) & 255], 24) ^ Shift(T0[(C3 >> 16) & 255], 16) ^ Shift(T0[(C0 >> 24) & 255], 8) ^ kw[1];
- r2 = T0[C2 & 255] ^ Shift(T0[(C3 >> 8) & 255], 24) ^ Shift(T0[(C0 >> 16) & 255], 16) ^ Shift(T0[(C1 >> 24) & 255], 8) ^ kw[2];
- r3 = T0[C3 & 255] ^ Shift(T0[(C0 >> 8) & 255], 24) ^ Shift(T0[(C1 >> 16) & 255], 16) ^ Shift(T0[(C2 >> 24) & 255], 8) ^ kw[3];
- kw = KW[++r];
- C0 = T0[r0 & 255] ^ Shift(T0[(r1 >> 8) & 255], 24) ^ Shift(T0[(r2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
- C1 = T0[r1 & 255] ^ Shift(T0[(r2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(r0 >> 24) & 255], 8) ^ kw[1];
- C2 = T0[r2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(r0 >> 16) & 255], 16) ^ Shift(T0[(r1 >> 24) & 255], 8) ^ kw[2];
- C3 = T0[r3 & 255] ^ Shift(T0[(r0 >> 8) & 255], 24) ^ Shift(T0[(r1 >> 16) & 255], 16) ^ Shift(T0[(r2 >> 24) & 255], 8) ^ kw[3];
- }
-
- kw = KW[++r];
- r0 = T0[C0 & 255] ^ Shift(T0[(C1 >> 8) & 255], 24) ^ Shift(T0[(C2 >> 16) & 255], 16) ^ Shift(T0[(C3 >> 24) & 255], 8) ^ kw[0];
- r1 = T0[C1 & 255] ^ Shift(T0[(C2 >> 8) & 255], 24) ^ Shift(T0[(C3 >> 16) & 255], 16) ^ Shift(T0[(C0 >> 24) & 255], 8) ^ kw[1];
- r2 = T0[C2 & 255] ^ Shift(T0[(C3 >> 8) & 255], 24) ^ Shift(T0[(C0 >> 16) & 255], 16) ^ Shift(T0[(C1 >> 24) & 255], 8) ^ kw[2];
- r3 = T0[C3 & 255] ^ Shift(T0[(C0 >> 8) & 255], 24) ^ Shift(T0[(C1 >> 16) & 255], 16) ^ Shift(T0[(C2 >> 24) & 255], 8) ^ kw[3];
-
- // the final round's table is a simple function of S so we don't use a whole other four tables for it
-
- kw = KW[++r];
- C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24) ^ kw[0];
- C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24) ^ kw[1];
- C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
- C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
-
- Debug.Assert(r == ROUNDS);
+ }
+
+ return W;
}
- private void DecryptBlock()
- {
- uint[][] KW = WorkingKey;
-
- int r = ROUNDS;
- uint[] kw = KW[r];
-
- C0 ^= kw[0];
- C1 ^= kw[1];
- C2 ^= kw[2];
- C3 ^= kw[3];
-
- uint r0, r1, r2, r3;
-
- while (r > 2)
- {
- kw = KW[--r];
- r0 = Tinv0[C0 & 255] ^ Shift(Tinv0[(C3 >> 8) & 255], 24) ^ Shift(Tinv0[(C2 >> 16) & 255], 16) ^ Shift(Tinv0[(C1 >> 24) & 255], 8) ^ kw[0];
- r1 = Tinv0[C1 & 255] ^ Shift(Tinv0[(C0 >> 8) & 255], 24) ^ Shift(Tinv0[(C3 >> 16) & 255], 16) ^ Shift(Tinv0[(C2 >> 24) & 255], 8) ^ kw[1];
- r2 = Tinv0[C2 & 255] ^ Shift(Tinv0[(C1 >> 8) & 255], 24) ^ Shift(Tinv0[(C0 >> 16) & 255], 16) ^ Shift(Tinv0[(C3 >> 24) & 255], 8) ^ kw[2];
- r3 = Tinv0[C3 & 255] ^ Shift(Tinv0[(C2 >> 8) & 255], 24) ^ Shift(Tinv0[(C1 >> 16) & 255], 16) ^ Shift(Tinv0[(C0 >> 24) & 255], 8) ^ kw[3];
- kw = KW[--r];
- C0 = Tinv0[r0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(r2 >> 16) & 255], 16) ^ Shift(Tinv0[(r1 >> 24) & 255], 8) ^ kw[0];
- C1 = Tinv0[r1 & 255] ^ Shift(Tinv0[(r0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(r2 >> 24) & 255], 8) ^ kw[1];
- C2 = Tinv0[r2 & 255] ^ Shift(Tinv0[(r1 >> 8) & 255], 24) ^ Shift(Tinv0[(r0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
- C3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(r2 >> 8) & 255], 24) ^ Shift(Tinv0[(r1 >> 16) & 255], 16) ^ Shift(Tinv0[(r0 >> 24) & 255], 8) ^ kw[3];
- }
-
- kw = KW[--r];
- r0 = Tinv0[C0 & 255] ^ Shift(Tinv0[(C3 >> 8) & 255], 24) ^ Shift(Tinv0[(C2 >> 16) & 255], 16) ^ Shift(Tinv0[(C1 >> 24) & 255], 8) ^ kw[0];
- r1 = Tinv0[C1 & 255] ^ Shift(Tinv0[(C0 >> 8) & 255], 24) ^ Shift(Tinv0[(C3 >> 16) & 255], 16) ^ Shift(Tinv0[(C2 >> 24) & 255], 8) ^ kw[1];
- r2 = Tinv0[C2 & 255] ^ Shift(Tinv0[(C1 >> 8) & 255], 24) ^ Shift(Tinv0[(C0 >> 16) & 255], 16) ^ Shift(Tinv0[(C3 >> 24) & 255], 8) ^ kw[2];
- r3 = Tinv0[C3 & 255] ^ Shift(Tinv0[(C2 >> 8) & 255], 24) ^ Shift(Tinv0[(C1 >> 16) & 255], 16) ^ Shift(Tinv0[(C0 >> 24) & 255], 8) ^ kw[3];
-
- // the final round's table is a simple function of Si so we don't use a whole other four tables for it
-
- kw = KW[--r];
- C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
- C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[(r2 >> 24) & 255]) << 24) ^ kw[1];
- C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[(r3 >> 24) & 255]) << 24) ^ kw[2];
- C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[(r0 >> 24) & 255]) << 24) ^ kw[3];
-
- Debug.Assert(r == 0);
+ private int ROUNDS;
+ private uint[][] WorkingKey;
+ private uint C0, C1, C2, C3;
+ private bool forEncryption;
+
+ private const int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AesEngine()
+ {
+ }
+
+ /**
+ * initialise an AES cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ KeyParameter keyParameter = parameters as KeyParameter;
+
+ if (keyParameter == null)
+ throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
+
+ WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
+
+ this.forEncryption = forEncryption;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "AES"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ throw new InvalidOperationException("AES engine not initialised");
+
+ Check.DataLength(input, inOff, 16, "input buffer too short");
+ Check.OutputLength(output, outOff, 16, "output buffer too short");
+
+ UnPackBlock(input, inOff);
+
+ if (forEncryption)
+ {
+ EncryptBlock(WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(WorkingKey);
+ }
+
+ PackBlock(output, outOff);
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ C0 = Pack.LE_To_UInt32(bytes, off);
+ C1 = Pack.LE_To_UInt32(bytes, off + 4);
+ C2 = Pack.LE_To_UInt32(bytes, off + 8);
+ C3 = Pack.LE_To_UInt32(bytes, off + 12);
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ Pack.UInt32_To_LE(C0, bytes, off);
+ Pack.UInt32_To_LE(C1, bytes, off + 4);
+ Pack.UInt32_To_LE(C2, bytes, off + 8);
+ Pack.UInt32_To_LE(C3, bytes, off + 12);
+ }
+
+ private void EncryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[0];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+ int r = 1;
+ while (r < ROUNDS - 1)
+ {
+ kw = KW[r++];
+ r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+ r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
+ r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
+ r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
+ kw = KW[r++];
+ t0 = T0[r0 & 255] ^ Shift(T0[(r1 >> 8) & 255], 24) ^ Shift(T0[(r2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+ t1 = T0[r1 & 255] ^ Shift(T0[(r2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(r0 >> 24) & 255], 8) ^ kw[1];
+ t2 = T0[r2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(r0 >> 16) & 255], 16) ^ Shift(T0[(r1 >> 24) & 255], 8) ^ kw[2];
+ r3 = T0[r3 & 255] ^ Shift(T0[(r0 >> 8) & 255], 24) ^ Shift(T0[(r1 >> 16) & 255], 16) ^ Shift(T0[(r2 >> 24) & 255], 8) ^ kw[3];
+ }
+
+ kw = KW[r++];
+ r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+ r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
+ r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
+ r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
+
+ // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+ kw = KW[r];
+ this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24) ^ kw[0];
+ this.C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24) ^ kw[1];
+ this.C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
+ this.C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
+ }
+
+ private void DecryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[ROUNDS];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+ int r = ROUNDS - 1;
+ while (r > 1)
+ {
+ kw = KW[r--];
+ r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
+ r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
+ r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
+ kw = KW[r--];
+ t0 = Tinv0[r0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(r2 >> 16) & 255], 16) ^ Shift(Tinv0[(r1 >> 24) & 255], 8) ^ kw[0];
+ t1 = Tinv0[r1 & 255] ^ Shift(Tinv0[(r0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(r2 >> 24) & 255], 8) ^ kw[1];
+ t2 = Tinv0[r2 & 255] ^ Shift(Tinv0[(r1 >> 8) & 255], 24) ^ Shift(Tinv0[(r0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(r2 >> 8) & 255], 24) ^ Shift(Tinv0[(r1 >> 16) & 255], 16) ^ Shift(Tinv0[(r0 >> 24) & 255], 8) ^ kw[3];
+ }
+
+ kw = KW[1];
+ r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
+ r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
+ r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
+
+ // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+ kw = KW[0];
+ this.C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
+ this.C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[(r2 >> 24) & 255]) << 24) ^ kw[1];
+ this.C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[(r3 >> 24) & 255]) << 24) ^ kw[2];
+ this.C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[(r0 >> 24) & 255]) << 24) ^ kw[3];
}
- }
+ }
}
diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs
index d76955dd8..38ce1a946 100644
--- a/crypto/src/crypto/engines/AesFastEngine.cs
+++ b/crypto/src/crypto/engines/AesFastEngine.cs
@@ -31,11 +31,11 @@ namespace Org.BouncyCastle.Crypto.Engines
* </p>
*/
public class AesFastEngine
- : IBlockCipher
+ : IBlockCipher
{
// The S box
private static readonly byte[] S =
- {
+ {
99, 124, 119, 123, 242, 107, 111, 197,
48, 1, 103, 43, 254, 215, 171, 118,
202, 130, 201, 125, 250, 89, 71, 240,
@@ -72,511 +72,521 @@ namespace Org.BouncyCastle.Crypto.Engines
// The inverse S-box
private static readonly byte[] Si =
- {
- 82, 9, 106, 213, 48, 54, 165, 56,
- 191, 64, 163, 158, 129, 243, 215, 251,
- 124, 227, 57, 130, 155, 47, 255, 135,
- 52, 142, 67, 68, 196, 222, 233, 203,
- 84, 123, 148, 50, 166, 194, 35, 61,
- 238, 76, 149, 11, 66, 250, 195, 78,
- 8, 46, 161, 102, 40, 217, 36, 178,
- 118, 91, 162, 73, 109, 139, 209, 37,
- 114, 248, 246, 100, 134, 104, 152, 22,
- 212, 164, 92, 204, 93, 101, 182, 146,
- 108, 112, 72, 80, 253, 237, 185, 218,
- 94, 21, 70, 87, 167, 141, 157, 132,
- 144, 216, 171, 0, 140, 188, 211, 10,
- 247, 228, 88, 5, 184, 179, 69, 6,
- 208, 44, 30, 143, 202, 63, 15, 2,
- 193, 175, 189, 3, 1, 19, 138, 107,
- 58, 145, 17, 65, 79, 103, 220, 234,
- 151, 242, 207, 206, 240, 180, 230, 115,
- 150, 172, 116, 34, 231, 173, 53, 133,
- 226, 249, 55, 232, 28, 117, 223, 110,
- 71, 241, 26, 113, 29, 41, 197, 137,
- 111, 183, 98, 14, 170, 24, 190, 27,
- 252, 86, 62, 75, 198, 210, 121, 32,
- 154, 219, 192, 254, 120, 205, 90, 244,
- 31, 221, 168, 51, 136, 7, 199, 49,
- 177, 18, 16, 89, 39, 128, 236, 95,
- 96, 81, 127, 169, 25, 181, 74, 13,
- 45, 229, 122, 159, 147, 201, 156, 239,
- 160, 224, 59, 77, 174, 42, 245, 176,
- 200, 235, 187, 60, 131, 83, 153, 97,
- 23, 43, 4, 126, 186, 119, 214, 38,
- 225, 105, 20, 99, 85, 33, 12, 125,
- };
-
- // vector used in calculating key schedule (powers of x in GF(256))
+ {
+ 82, 9, 106, 213, 48, 54, 165, 56,
+ 191, 64, 163, 158, 129, 243, 215, 251,
+ 124, 227, 57, 130, 155, 47, 255, 135,
+ 52, 142, 67, 68, 196, 222, 233, 203,
+ 84, 123, 148, 50, 166, 194, 35, 61,
+ 238, 76, 149, 11, 66, 250, 195, 78,
+ 8, 46, 161, 102, 40, 217, 36, 178,
+ 118, 91, 162, 73, 109, 139, 209, 37,
+ 114, 248, 246, 100, 134, 104, 152, 22,
+ 212, 164, 92, 204, 93, 101, 182, 146,
+ 108, 112, 72, 80, 253, 237, 185, 218,
+ 94, 21, 70, 87, 167, 141, 157, 132,
+ 144, 216, 171, 0, 140, 188, 211, 10,
+ 247, 228, 88, 5, 184, 179, 69, 6,
+ 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107,
+ 58, 145, 17, 65, 79, 103, 220, 234,
+ 151, 242, 207, 206, 240, 180, 230, 115,
+ 150, 172, 116, 34, 231, 173, 53, 133,
+ 226, 249, 55, 232, 28, 117, 223, 110,
+ 71, 241, 26, 113, 29, 41, 197, 137,
+ 111, 183, 98, 14, 170, 24, 190, 27,
+ 252, 86, 62, 75, 198, 210, 121, 32,
+ 154, 219, 192, 254, 120, 205, 90, 244,
+ 31, 221, 168, 51, 136, 7, 199, 49,
+ 177, 18, 16, 89, 39, 128, 236, 95,
+ 96, 81, 127, 169, 25, 181, 74, 13,
+ 45, 229, 122, 159, 147, 201, 156, 239,
+ 160, 224, 59, 77, 174, 42, 245, 176,
+ 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38,
+ 225, 105, 20, 99, 85, 33, 12, 125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
private static readonly byte[] rcon =
- {
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
- 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
- };
-
- // precomputation tables of calculations for rounds
- private static readonly uint[] T0 =
- {
- 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
- 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
- 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
- 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
- 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
- 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
- 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
- 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
- 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
- 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
- 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
- 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
- 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
- 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
- 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
- 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
- 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
- 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
- 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
- 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
- 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
- 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
- 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
- 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
- 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
- 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
- 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
- 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
- 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
- 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
- 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
- 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
- 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
- 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
- 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
- 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
- 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
- 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
- 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
- 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
- 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
- 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
- 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
- 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
- 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
- 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
- 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
- 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
- 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
- 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
- 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
- 0x3a16162c
- };
-
- private static readonly uint[] T1 =
- {
- 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d,
- 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203,
- 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6,
- 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
- 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec,
- 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7,
- 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae,
- 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
- 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293,
- 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552,
- 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f,
- 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
- 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b,
- 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2,
- 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761,
- 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
- 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060,
- 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46,
- 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8,
- 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
- 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf,
- 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844,
- 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0,
- 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
- 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030,
- 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814,
- 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc,
- 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
- 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0,
- 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e,
- 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3,
- 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
- 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db,
- 0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e,
- 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337,
- 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
- 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4,
- 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e,
- 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f,
- 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
- 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd,
- 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42,
- 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701,
- 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
- 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938,
- 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970,
- 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592,
- 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
- 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da,
- 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0,
- 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6,
- 0x16162c3a
- };
-
- private static readonly uint[] T2 =
- {
- 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2,
- 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301,
- 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab,
- 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
- 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad,
- 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4,
- 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93,
- 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
- 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371,
- 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7,
- 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05,
- 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
- 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09,
- 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e,
- 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6,
- 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
- 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020,
- 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb,
- 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858,
- 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
- 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45,
- 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c,
- 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040,
- 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
- 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010,
- 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c,
- 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44,
- 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
- 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060,
- 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a,
- 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8,
- 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
- 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49,
- 0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3,
- 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4,
- 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
- 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c,
- 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a,
- 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25,
- 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
- 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b,
- 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e,
- 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6,
- 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
- 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1,
- 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9,
- 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287,
- 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
- 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf,
- 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099,
- 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb,
- 0x162c3a16
- };
-
- private static readonly uint[] T3 =
- {
- 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2,
- 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101,
- 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab,
- 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
- 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad,
- 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4,
- 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393,
- 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
- 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171,
- 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7,
- 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505,
- 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
- 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909,
- 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e,
- 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6,
- 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
- 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020,
- 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb,
- 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858,
- 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
- 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545,
- 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c,
- 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040,
- 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
- 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010,
- 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c,
- 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444,
- 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
- 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060,
- 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a,
- 0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8,
- 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
- 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949,
- 0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3,
- 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4,
- 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
- 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c,
- 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a,
- 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525,
- 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
- 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b,
- 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e,
- 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6,
- 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
- 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1,
- 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9,
- 0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787,
- 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
- 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf,
- 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999,
- 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb,
- 0x2c3a1616
- };
-
- private static readonly uint[] Tinv0 =
- {
- 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
- 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
- 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
- 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
- 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
- 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
- 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
- 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
- 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
- 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
- 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
- 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
- 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
- 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
- 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
- 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
- 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
- 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
- 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
- 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
- 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
- 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
- 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
- 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
- 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
- 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
- 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
- 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
- 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
- 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
- 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
- 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
- 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
- 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
- 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
- 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
- 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
- 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
- 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
- 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
- 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
- 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
- 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
- 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
- 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
- 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
- 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
- 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
- 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
- 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
- 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
- 0x4257b8d0
- };
-
- private static readonly uint[] Tinv1 =
- {
- 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb,
- 0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6,
- 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680,
- 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1,
- 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7,
- 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3,
- 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b,
- 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4,
- 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0,
- 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19,
- 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357,
- 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5,
- 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b,
- 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5,
- 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532,
- 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51,
- 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5,
- 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697,
- 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738,
- 0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000,
- 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb,
- 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821,
- 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2,
- 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16,
- 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b,
- 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c,
- 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5,
- 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863,
- 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d,
- 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3,
- 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa,
- 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef,
- 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf,
- 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d,
- 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e,
- 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3,
- 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09,
- 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e,
- 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4,
- 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0,
- 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a,
- 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d,
- 0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8,
- 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e,
- 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c,
- 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735,
- 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879,
- 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886,
- 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672,
- 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de,
- 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874,
- 0x57b8d042
- };
-
- private static readonly uint[] Tinv2 =
- {
- 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b,
- 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d,
- 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044,
- 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0,
- 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f,
- 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321,
- 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e,
- 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a,
- 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077,
- 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd,
- 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f,
- 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508,
- 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c,
- 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be,
- 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1,
- 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110,
- 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d,
- 0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9,
- 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b,
- 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000,
- 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff,
- 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6,
- 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296,
- 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a,
- 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d,
- 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07,
- 0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b,
- 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1,
- 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24,
- 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330,
- 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48,
- 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90,
- 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81,
- 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92,
- 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7,
- 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312,
- 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978,
- 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6,
- 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409,
- 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066,
- 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98,
- 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0,
- 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f,
- 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41,
- 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61,
- 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9,
- 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce,
- 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db,
- 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3,
- 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3,
- 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c,
- 0xb8d04257
- };
-
- private static readonly uint[] Tinv3 =
- {
- 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab,
- 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76,
- 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435,
- 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe,
- 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f,
- 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174,
- 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58,
- 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace,
- 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764,
- 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45,
- 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f,
- 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837,
- 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf,
- 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05,
- 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a,
- 0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e,
- 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54,
- 0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd,
- 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19,
- 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000,
- 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e,
- 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c,
- 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee,
- 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12,
- 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09,
- 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775,
- 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66,
- 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4,
- 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a,
- 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2,
- 0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894,
- 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033,
- 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5,
- 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278,
- 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739,
- 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225,
- 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826,
- 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff,
- 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f,
- 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2,
- 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804,
- 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef,
- 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c,
- 0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b,
- 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7,
- 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961,
- 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14,
- 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44,
- 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d,
- 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c,
- 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c,
- 0xd04257b8
- };
+ {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
+ };
+
+ // precomputation tables of calculations for rounds
+ private static readonly uint[] T0 =
+ {
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
+ 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
+ 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
+ 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+ 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
+ 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
+ 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
+ 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+ 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
+ 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
+ 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
+ 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+ 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
+ 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
+ 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
+ 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+ 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
+ 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
+ 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
+ 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+ 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
+ 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
+ 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
+ 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
+ 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
+ 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
+ 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+ 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
+ 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
+ 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
+ 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+ 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
+ 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
+ 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
+ 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+ 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
+ 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
+ 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
+ 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+ 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
+ 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
+ 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
+ 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+ 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
+ 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
+ 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
+ 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
+ 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
+ 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
+ 0x3a16162c
+ };
+
+ private static readonly uint[] T1 =
+ {
+ 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d,
+ 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203,
+ 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6,
+ 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
+ 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec,
+ 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7,
+ 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae,
+ 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
+ 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293,
+ 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552,
+ 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f,
+ 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
+ 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b,
+ 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2,
+ 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761,
+ 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
+ 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060,
+ 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46,
+ 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8,
+ 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
+ 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf,
+ 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844,
+ 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0,
+ 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
+ 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030,
+ 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814,
+ 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc,
+ 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
+ 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0,
+ 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e,
+ 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3,
+ 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
+ 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db,
+ 0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e,
+ 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337,
+ 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
+ 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4,
+ 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e,
+ 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f,
+ 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
+ 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd,
+ 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42,
+ 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701,
+ 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
+ 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938,
+ 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970,
+ 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592,
+ 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
+ 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da,
+ 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0,
+ 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6,
+ 0x16162c3a
+ };
+
+ private static readonly uint[] T2 =
+ {
+ 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2,
+ 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301,
+ 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab,
+ 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
+ 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad,
+ 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4,
+ 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93,
+ 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
+ 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371,
+ 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7,
+ 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05,
+ 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
+ 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09,
+ 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e,
+ 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6,
+ 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
+ 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020,
+ 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb,
+ 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858,
+ 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
+ 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45,
+ 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c,
+ 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040,
+ 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
+ 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010,
+ 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c,
+ 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44,
+ 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
+ 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060,
+ 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a,
+ 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8,
+ 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
+ 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49,
+ 0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3,
+ 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4,
+ 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
+ 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c,
+ 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a,
+ 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25,
+ 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
+ 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b,
+ 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e,
+ 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6,
+ 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
+ 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1,
+ 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9,
+ 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287,
+ 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
+ 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf,
+ 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099,
+ 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb,
+ 0x162c3a16
+ };
+
+ private static readonly uint[] T3 =
+ {
+ 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2,
+ 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101,
+ 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab,
+ 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
+ 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad,
+ 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4,
+ 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393,
+ 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
+ 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171,
+ 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7,
+ 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505,
+ 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
+ 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909,
+ 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e,
+ 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6,
+ 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
+ 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020,
+ 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb,
+ 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858,
+ 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
+ 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545,
+ 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c,
+ 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040,
+ 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
+ 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010,
+ 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c,
+ 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444,
+ 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
+ 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060,
+ 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a,
+ 0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8,
+ 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
+ 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949,
+ 0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3,
+ 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4,
+ 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
+ 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c,
+ 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a,
+ 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525,
+ 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
+ 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b,
+ 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e,
+ 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6,
+ 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
+ 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1,
+ 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9,
+ 0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787,
+ 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
+ 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf,
+ 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999,
+ 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb,
+ 0x2c3a1616
+ };
+
+ private static readonly uint[] Tinv0 =
+ {
+ 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
+ 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
+ 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
+ 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
+ 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
+ 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
+ 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
+ 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
+ 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
+ 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
+ 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
+ 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+ 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
+ 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
+ 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
+ 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
+ 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
+ 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
+ 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
+ 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
+ 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
+ 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
+ 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
+ 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+ 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
+ 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
+ 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
+ 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
+ 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
+ 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
+ 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
+ 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
+ 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
+ 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
+ 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
+ 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+ 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
+ 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
+ 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
+ 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
+ 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
+ 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
+ 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
+ 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
+ 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
+ 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
+ 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
+ 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+ 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
+ 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
+ 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
+ 0x4257b8d0
+ };
+
+ private static readonly uint[] Tinv1 =
+ {
+ 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb,
+ 0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6,
+ 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680,
+ 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1,
+ 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7,
+ 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3,
+ 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b,
+ 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4,
+ 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0,
+ 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19,
+ 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357,
+ 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5,
+ 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b,
+ 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5,
+ 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532,
+ 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51,
+ 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5,
+ 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697,
+ 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738,
+ 0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000,
+ 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb,
+ 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821,
+ 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2,
+ 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16,
+ 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b,
+ 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c,
+ 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5,
+ 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863,
+ 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d,
+ 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3,
+ 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa,
+ 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef,
+ 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf,
+ 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d,
+ 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e,
+ 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3,
+ 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09,
+ 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e,
+ 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4,
+ 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0,
+ 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a,
+ 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d,
+ 0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8,
+ 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e,
+ 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c,
+ 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735,
+ 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879,
+ 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886,
+ 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672,
+ 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de,
+ 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874,
+ 0x57b8d042
+ };
+
+ private static readonly uint[] Tinv2 =
+ {
+ 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b,
+ 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d,
+ 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044,
+ 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0,
+ 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f,
+ 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321,
+ 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e,
+ 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a,
+ 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077,
+ 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd,
+ 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f,
+ 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508,
+ 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c,
+ 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be,
+ 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1,
+ 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110,
+ 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d,
+ 0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9,
+ 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b,
+ 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000,
+ 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff,
+ 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6,
+ 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296,
+ 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a,
+ 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d,
+ 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07,
+ 0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b,
+ 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1,
+ 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24,
+ 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330,
+ 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48,
+ 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90,
+ 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81,
+ 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92,
+ 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7,
+ 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312,
+ 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978,
+ 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6,
+ 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409,
+ 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066,
+ 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98,
+ 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0,
+ 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f,
+ 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41,
+ 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61,
+ 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9,
+ 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce,
+ 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db,
+ 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3,
+ 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3,
+ 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c,
+ 0xb8d04257
+ };
+
+ private static readonly uint[] Tinv3 =
+ {
+ 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab,
+ 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76,
+ 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435,
+ 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe,
+ 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f,
+ 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174,
+ 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58,
+ 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace,
+ 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764,
+ 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45,
+ 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f,
+ 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837,
+ 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf,
+ 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05,
+ 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a,
+ 0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e,
+ 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54,
+ 0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd,
+ 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19,
+ 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000,
+ 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e,
+ 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c,
+ 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee,
+ 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12,
+ 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09,
+ 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775,
+ 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66,
+ 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4,
+ 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a,
+ 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2,
+ 0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894,
+ 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033,
+ 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5,
+ 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278,
+ 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739,
+ 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225,
+ 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826,
+ 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff,
+ 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f,
+ 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2,
+ 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804,
+ 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef,
+ 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c,
+ 0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b,
+ 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7,
+ 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961,
+ 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14,
+ 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44,
+ 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d,
+ 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c,
+ 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c,
+ 0xd04257b8
+ };
private static uint Shift(uint r, int shift)
- {
- return (r >> shift) | (r << (32 - shift));
- }
+ {
+ return (r >> shift) | (r << (32 - shift));
+ }
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
private const uint m1 = 0x80808080;
private const uint m2 = 0x7f7f7f7f;
private const uint m3 = 0x0000001b;
+ private const uint m4 = 0xC0C0C0C0;
+ private const uint m5 = 0x3f3f3f3f;
+
+ private static uint FFmulX(uint x)
+ {
+ return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
+ }
- private static uint FFmulX(uint x)
- {
- return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
+ private static uint FFmulX2(uint x)
+ {
+ uint t0 = (x & m5) << 2;
+ uint t1 = (x & m4);
+ t1 ^= (t1 >> 1);
+ return t0 ^ (t1 >> 2) ^ (t1 >> 5);
}
/*
@@ -591,20 +601,21 @@ namespace Org.BouncyCastle.Crypto.Engines
private static uint Inv_Mcol(uint x)
{
- uint f2 = FFmulX(x);
- uint f4 = FFmulX(f2);
- uint f8 = FFmulX(f4);
- uint f9 = x ^ f8;
-
- return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+ uint t0, t1;
+ t0 = x;
+ t1 = t0 ^ Shift(t0, 8);
+ t0 ^= FFmulX(t1);
+ t1 ^= FFmulX2(t0);
+ t0 ^= t1 ^ Shift(t1, 16);
+ return t0;
}
private static uint SubWord(uint x)
- {
- return (uint)S[x&255]
- | (((uint)S[(x>>8)&255]) << 8)
- | (((uint)S[(x>>16)&255]) << 16)
- | (((uint)S[(x>>24)&255]) << 24);
+ {
+ return (uint)S[x&255]
+ | (((uint)S[(x>>8)&255]) << 8)
+ | (((uint)S[(x>>16)&255]) << 16)
+ | (((uint)S[(x>>24)&255]) << 24);
}
/**
@@ -622,7 +633,7 @@ namespace Org.BouncyCastle.Crypto.Engines
if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length))
throw new ArgumentException("Key length not 128/192/256 bits.");
- ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+ ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
for (int i = 0; i <= ROUNDS; ++i)
@@ -636,10 +647,10 @@ namespace Org.BouncyCastle.Crypto.Engines
int t = 0;
for (int i = 0; i < key.Length; t++)
- {
- W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
- i+=4;
- }
+ {
+ W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
+ i+=4;
+ }
//
// while not enough round key material calculated
@@ -659,12 +670,12 @@ namespace Org.BouncyCastle.Crypto.Engines
}
if (!forEncryption)
- {
+ {
for (int j = 1; j < ROUNDS; j++)
- {
+ {
uint[] w = W[j];
for (int i = 0; i < 4; i++)
- {
+ {
w[i] = Inv_Mcol(w[i]);
}
}
@@ -695,7 +706,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -709,59 +720,50 @@ namespace Org.BouncyCastle.Crypto.Engines
this.forEncryption = forEncryption;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "AES"; }
}
- public bool IsPartialBlockOkay
- {
- get { return false; }
- }
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (WorkingKey == null)
- {
throw new InvalidOperationException("AES engine not initialised");
- }
- if ((inOff + (32 / 2)) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + (32 / 2)) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, 16, "input buffer too short");
+ Check.OutputLength(output, outOff, 16, "output buffer too short");
UnPackBlock(input, inOff);
if (forEncryption)
{
- EncryptBlock();
+ EncryptBlock(WorkingKey);
}
else
{
- DecryptBlock();
+ DecryptBlock(WorkingKey);
}
PackBlock(output, outOff);
- return BLOCK_SIZE;
+ return BLOCK_SIZE;
}
- public void Reset()
+ public virtual void Reset()
{
}
@@ -769,110 +771,96 @@ namespace Org.BouncyCastle.Crypto.Engines
byte[] bytes,
int off)
{
- C0 = Pack.LE_To_UInt32(bytes, off);
- C1 = Pack.LE_To_UInt32(bytes, off + 4);
- C2 = Pack.LE_To_UInt32(bytes, off + 8);
- C3 = Pack.LE_To_UInt32(bytes, off + 12);
+ C0 = Pack.LE_To_UInt32(bytes, off);
+ C1 = Pack.LE_To_UInt32(bytes, off + 4);
+ C2 = Pack.LE_To_UInt32(bytes, off + 8);
+ C3 = Pack.LE_To_UInt32(bytes, off + 12);
}
- private void PackBlock(
+ private void PackBlock(
byte[] bytes,
int off)
{
- Pack.UInt32_To_LE(C0, bytes, off);
- Pack.UInt32_To_LE(C1, bytes, off + 4);
- Pack.UInt32_To_LE(C2, bytes, off + 8);
- Pack.UInt32_To_LE(C3, bytes, off + 12);
+ Pack.UInt32_To_LE(C0, bytes, off);
+ Pack.UInt32_To_LE(C1, bytes, off + 4);
+ Pack.UInt32_To_LE(C2, bytes, off + 8);
+ Pack.UInt32_To_LE(C3, bytes, off + 12);
}
- private void EncryptBlock()
+ private void EncryptBlock(uint[][] KW)
{
- uint[][] KW = WorkingKey;
-
- int r = 0;
- uint[] kw = KW[r];
-
- C0 ^= kw[0];
- C1 ^= kw[1];
- C2 ^= kw[2];
- C3 ^= kw[3];
-
- uint r0, r1, r2, r3;
-
- while (r < (ROUNDS - 2))
- {
- kw = KW[++r];
- r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ kw[0];
- r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ kw[1];
- r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[C1 >> 24] ^ kw[2];
- r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[C2 >> 24] ^ kw[3];
- kw = KW[++r];
- C0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
- C1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ kw[1];
- C2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ kw[2];
- C3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ kw[3];
+ uint[] kw = KW[0];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+ int r = 1;
+ while (r < ROUNDS - 1)
+ {
+ kw = KW[r++];
+ r0 = T0[t0 & 255] ^ T1[(t1 >> 8) & 255] ^ T2[(t2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+ r1 = T0[t1 & 255] ^ T1[(t2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[t0 >> 24] ^ kw[1];
+ r2 = T0[t2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(t0 >> 16) & 255] ^ T3[t1 >> 24] ^ kw[2];
+ r3 = T0[r3 & 255] ^ T1[(t0 >> 8) & 255] ^ T2[(t1 >> 16) & 255] ^ T3[t2 >> 24] ^ kw[3];
+ kw = KW[r++];
+ t0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+ t1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ kw[1];
+ t2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ kw[2];
+ r3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ kw[3];
}
- kw = KW[++r];
- r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ kw[0];
- r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ kw[1];
- r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[C1 >> 24] ^ kw[2];
- r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[C2 >> 24] ^ kw[3];
+ kw = KW[r++];
+ r0 = T0[t0 & 255] ^ T1[(t1 >> 8) & 255] ^ T2[(t2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+ r1 = T0[t1 & 255] ^ T1[(t2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[t0 >> 24] ^ kw[1];
+ r2 = T0[t2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(t0 >> 16) & 255] ^ T3[t1 >> 24] ^ kw[2];
+ r3 = T0[r3 & 255] ^ T1[(t0 >> 8) & 255] ^ T2[(t1 >> 16) & 255] ^ T3[t2 >> 24] ^ kw[3];
// the final round's table is a simple function of S so we don't use a whole other four tables for it
- kw = KW[++r];
- C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ kw[0];
- C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ kw[1];
- C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ kw[2];
- C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ kw[3];
-
- Debug.Assert(r == ROUNDS);
+ kw = KW[r];
+ this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ kw[0];
+ this.C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ kw[1];
+ this.C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ kw[2];
+ this.C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ kw[3];
}
- private void DecryptBlock()
+ private void DecryptBlock(uint[][] KW)
{
- uint[][] KW = WorkingKey;
-
- int r = ROUNDS;
- uint[] kw = KW[r];
-
- C0 ^= kw[0];
- C1 ^= kw[1];
- C2 ^= kw[2];
- C3 ^= kw[3];
-
- uint r0, r1, r2, r3;
-
- while (r > 2)
+ uint[] kw = KW[ROUNDS];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+ int r = ROUNDS - 1;
+ while (r > 1)
{
- kw = KW[--r];
- r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ kw[0];
- r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ kw[1];
- r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[C3 >> 24] ^ kw[2];
- r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[C0 >> 24] ^ kw[3];
- kw = KW[--r];
- C0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ kw[0];
- C1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ kw[1];
- C2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
- C3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ kw[3];
+ kw = KW[r--];
+ r0 = Tinv0[t0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(t2 >> 16) & 255] ^ Tinv3[t1 >> 24] ^ kw[0];
+ r1 = Tinv0[t1 & 255] ^ Tinv1[(t0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[t2 >> 24] ^ kw[1];
+ r2 = Tinv0[t2 & 255] ^ Tinv1[(t1 >> 8) & 255] ^ Tinv2[(t0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Tinv1[(t2 >> 8) & 255] ^ Tinv2[(t1 >> 16) & 255] ^ Tinv3[t0 >> 24] ^ kw[3];
+ kw = KW[r--];
+ t0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ kw[0];
+ t1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ kw[1];
+ t2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ kw[3];
}
- kw = KW[--r];
- r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ kw[0];
- r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ kw[1];
- r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[C3 >> 24] ^ kw[2];
- r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[C0 >> 24] ^ kw[3];
+ kw = KW[1];
+ r0 = Tinv0[t0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(t2 >> 16) & 255] ^ Tinv3[t1 >> 24] ^ kw[0];
+ r1 = Tinv0[t1 & 255] ^ Tinv1[(t0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[t2 >> 24] ^ kw[1];
+ r2 = Tinv0[t2 & 255] ^ Tinv1[(t1 >> 8) & 255] ^ Tinv2[(t0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Tinv1[(t2 >> 8) & 255] ^ Tinv2[(t1 >> 16) & 255] ^ Tinv3[t0 >> 24] ^ kw[3];
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
- kw = KW[--r];
- C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ kw[0];
- C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ kw[1];
- C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ kw[2];
- C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ kw[3];
-
- Debug.Assert(r == 0);
- }
+ kw = KW[0];
+ this.C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ kw[0];
+ this.C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ kw[1];
+ this.C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ kw[2];
+ this.C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ kw[3];
+ }
}
}
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index 828ceaa33..a42b34971 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -6,183 +6,196 @@ using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
- /**
- * an implementation of the AES (Rijndael), from FIPS-197.
- * <p>
- * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
- *
- * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
- * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
- *
- * There are three levels of tradeoff of speed vs memory
- * Because java has no preprocessor, they are written as three separate classes from which to choose
- *
- * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
- * and 4 for decryption.
- *
- * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
- * adding 12 rotate operations per round to compute the values contained in the other tables from
- * the contents of the first
- *
- * The slowest version uses no static tables at all and computes the values
- * in each round.
- * </p>
- * <p>
- * This file contains the slowest performance version with no static tables
- * for round precomputation, but it has the smallest foot print.
- * </p>
- */
- public class AesLightEngine
- : IBlockCipher
- {
- // The S box
- private static readonly byte[] S =
- {
- 99, 124, 119, 123, 242, 107, 111, 197,
- 48, 1, 103, 43, 254, 215, 171, 118,
- 202, 130, 201, 125, 250, 89, 71, 240,
- 173, 212, 162, 175, 156, 164, 114, 192,
- 183, 253, 147, 38, 54, 63, 247, 204,
- 52, 165, 229, 241, 113, 216, 49, 21,
- 4, 199, 35, 195, 24, 150, 5, 154,
- 7, 18, 128, 226, 235, 39, 178, 117,
- 9, 131, 44, 26, 27, 110, 90, 160,
- 82, 59, 214, 179, 41, 227, 47, 132,
- 83, 209, 0, 237, 32, 252, 177, 91,
- 106, 203, 190, 57, 74, 76, 88, 207,
- 208, 239, 170, 251, 67, 77, 51, 133,
- 69, 249, 2, 127, 80, 60, 159, 168,
- 81, 163, 64, 143, 146, 157, 56, 245,
- 188, 182, 218, 33, 16, 255, 243, 210,
- 205, 12, 19, 236, 95, 151, 68, 23,
- 196, 167, 126, 61, 100, 93, 25, 115,
- 96, 129, 79, 220, 34, 42, 144, 136,
- 70, 238, 184, 20, 222, 94, 11, 219,
- 224, 50, 58, 10, 73, 6, 36, 92,
- 194, 211, 172, 98, 145, 149, 228, 121,
- 231, 200, 55, 109, 141, 213, 78, 169,
- 108, 86, 244, 234, 101, 122, 174, 8,
- 186, 120, 37, 46, 28, 166, 180, 198,
- 232, 221, 116, 31, 75, 189, 139, 138,
- 112, 62, 181, 102, 72, 3, 246, 14,
- 97, 53, 87, 185, 134, 193, 29, 158,
- 225, 248, 152, 17, 105, 217, 142, 148,
- 155, 30, 135, 233, 206, 85, 40, 223,
- 140, 161, 137, 13, 191, 230, 66, 104,
- 65, 153, 45, 15, 176, 84, 187, 22,
- };
-
- // The inverse S-box
- private static readonly byte[] Si =
- {
- 82, 9, 106, 213, 48, 54, 165, 56,
- 191, 64, 163, 158, 129, 243, 215, 251,
- 124, 227, 57, 130, 155, 47, 255, 135,
- 52, 142, 67, 68, 196, 222, 233, 203,
- 84, 123, 148, 50, 166, 194, 35, 61,
- 238, 76, 149, 11, 66, 250, 195, 78,
- 8, 46, 161, 102, 40, 217, 36, 178,
- 118, 91, 162, 73, 109, 139, 209, 37,
- 114, 248, 246, 100, 134, 104, 152, 22,
- 212, 164, 92, 204, 93, 101, 182, 146,
- 108, 112, 72, 80, 253, 237, 185, 218,
- 94, 21, 70, 87, 167, 141, 157, 132,
- 144, 216, 171, 0, 140, 188, 211, 10,
- 247, 228, 88, 5, 184, 179, 69, 6,
- 208, 44, 30, 143, 202, 63, 15, 2,
- 193, 175, 189, 3, 1, 19, 138, 107,
- 58, 145, 17, 65, 79, 103, 220, 234,
- 151, 242, 207, 206, 240, 180, 230, 115,
- 150, 172, 116, 34, 231, 173, 53, 133,
- 226, 249, 55, 232, 28, 117, 223, 110,
- 71, 241, 26, 113, 29, 41, 197, 137,
- 111, 183, 98, 14, 170, 24, 190, 27,
- 252, 86, 62, 75, 198, 210, 121, 32,
- 154, 219, 192, 254, 120, 205, 90, 244,
- 31, 221, 168, 51, 136, 7, 199, 49,
- 177, 18, 16, 89, 39, 128, 236, 95,
- 96, 81, 127, 169, 25, 181, 74, 13,
- 45, 229, 122, 159, 147, 201, 156, 239,
- 160, 224, 59, 77, 174, 42, 245, 176,
- 200, 235, 187, 60, 131, 83, 153, 97,
- 23, 43, 4, 126, 186, 119, 214, 38,
- 225, 105, 20, 99, 85, 33, 12, 125,
- };
-
- // vector used in calculating key schedule (powers of x in GF(256))
- private static readonly byte[] rcon =
- {
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
- 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
- };
-
- private static uint Shift(uint r, int shift)
- {
- return (r >> shift) | (r << (32 - shift));
- }
-
- /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
-
- private const uint m1 = 0x80808080;
- private const uint m2 = 0x7f7f7f7f;
- private const uint m3 = 0x0000001b;
-
- private static uint FFmulX(uint x)
- {
- return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
- }
+ /**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values
+ * in each round.
+ * </p>
+ * <p>
+ * This file contains the slowest performance version with no static tables
+ * for round precomputation, but it has the smallest foot print.
+ * </p>
+ */
+ public class AesLightEngine
+ : IBlockCipher
+ {
+ // The S box
+ private static readonly byte[] S =
+ {
+ 99, 124, 119, 123, 242, 107, 111, 197,
+ 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240,
+ 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204,
+ 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154,
+ 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160,
+ 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91,
+ 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133,
+ 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23,
+ 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136,
+ 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92,
+ 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169,
+ 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198,
+ 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14,
+ 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148,
+ 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104,
+ 65, 153, 45, 15, 176, 84, 187, 22,
+ };
+
+ // The inverse S-box
+ private static readonly byte[] Si =
+ {
+ 82, 9, 106, 213, 48, 54, 165, 56,
+ 191, 64, 163, 158, 129, 243, 215, 251,
+ 124, 227, 57, 130, 155, 47, 255, 135,
+ 52, 142, 67, 68, 196, 222, 233, 203,
+ 84, 123, 148, 50, 166, 194, 35, 61,
+ 238, 76, 149, 11, 66, 250, 195, 78,
+ 8, 46, 161, 102, 40, 217, 36, 178,
+ 118, 91, 162, 73, 109, 139, 209, 37,
+ 114, 248, 246, 100, 134, 104, 152, 22,
+ 212, 164, 92, 204, 93, 101, 182, 146,
+ 108, 112, 72, 80, 253, 237, 185, 218,
+ 94, 21, 70, 87, 167, 141, 157, 132,
+ 144, 216, 171, 0, 140, 188, 211, 10,
+ 247, 228, 88, 5, 184, 179, 69, 6,
+ 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107,
+ 58, 145, 17, 65, 79, 103, 220, 234,
+ 151, 242, 207, 206, 240, 180, 230, 115,
+ 150, 172, 116, 34, 231, 173, 53, 133,
+ 226, 249, 55, 232, 28, 117, 223, 110,
+ 71, 241, 26, 113, 29, 41, 197, 137,
+ 111, 183, 98, 14, 170, 24, 190, 27,
+ 252, 86, 62, 75, 198, 210, 121, 32,
+ 154, 219, 192, 254, 120, 205, 90, 244,
+ 31, 221, 168, 51, 136, 7, 199, 49,
+ 177, 18, 16, 89, 39, 128, 236, 95,
+ 96, 81, 127, 169, 25, 181, 74, 13,
+ 45, 229, 122, 159, 147, 201, 156, 239,
+ 160, 224, 59, 77, 174, 42, 245, 176,
+ 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38,
+ 225, 105, 20, 99, 85, 33, 12, 125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static readonly byte[] rcon =
+ {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
+ };
+
+ private static uint Shift(uint r, int shift)
+ {
+ return (r >> shift) | (r << (32 - shift));
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private const uint m1 = 0x80808080;
+ private const uint m2 = 0x7f7f7f7f;
+ private const uint m3 = 0x0000001b;
+ private const uint m4 = 0xC0C0C0C0;
+ private const uint m5 = 0x3f3f3f3f;
+
+ private static uint FFmulX(uint x)
+ {
+ return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
+ }
+
+ private static uint FFmulX2(uint x)
+ {
+ uint t0 = (x & m5) << 2;
+ uint t1 = (x & m4);
+ t1 ^= (t1 >> 1);
+ return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+ }
/*
- The following defines provide alternative definitions of FFmulX that might
- give improved performance if a fast 32-bit multiply is not available.
-
- private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
- private static final int m4 = 0x1b1b1b1b;
- private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
-
- */
-
- private static uint Mcol(uint x)
- {
- uint f2 = FFmulX(x);
- return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24);
- }
-
- private static uint Inv_Mcol(uint x)
- {
- uint f2 = FFmulX(x);
- uint f4 = FFmulX(f2);
- uint f8 = FFmulX(f4);
- uint f9 = x ^ f8;
-
- return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
- }
-
- private static uint SubWord(uint x)
- {
- return (uint)S[x&255]
- | (((uint)S[(x>>8)&255]) << 8)
- | (((uint)S[(x>>16)&255]) << 16)
- | (((uint)S[(x>>24)&255]) << 24);
- }
-
- /**
- * Calculate the necessary round keys
- * The number of calculations depends on key size and block size
- * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
- * This code is written assuming those are the only possible values
- */
- private uint[][] GenerateWorkingKey(
- byte[] key,
- bool forEncryption)
- {
- int KC = key.Length / 4; // key length in words
- int t;
-
- if ((KC != 4) && (KC != 6) && (KC != 8))
- throw new ArgumentException("Key length not 128/192/256 bits.");
-
- ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private static uint Mcol(uint x)
+ {
+ uint t0, t1;
+ t0 = Shift(x, 8);
+ t1 = x ^ t0;
+ return Shift(t1, 16) ^ t0 ^ FFmulX(t1);
+ }
+
+ private static uint Inv_Mcol(uint x)
+ {
+ uint t0, t1;
+ t0 = x;
+ t1 = t0 ^ Shift(t0, 8);
+ t0 ^= FFmulX(t1);
+ t1 ^= FFmulX2(t0);
+ t0 ^= t1 ^ Shift(t1, 16);
+ return t0;
+ }
+
+ private static uint SubWord(uint x)
+ {
+ return (uint)S[x&255]
+ | (((uint)S[(x>>8)&255]) << 8)
+ | (((uint)S[(x>>16)&255]) << 16)
+ | (((uint)S[(x>>24)&255]) << 24);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+ * This code is written assuming those are the only possible values
+ */
+ private uint[][] GenerateWorkingKey(
+ byte[] key,
+ bool forEncryption)
+ {
+ int KC = key.Length / 4; // key length in words
+ int t;
+
+ if ((KC != 4) && (KC != 6) && (KC != 8))
+ throw new ArgumentException("Key length not 128/192/256 bits.");
+
+ ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
for (int i = 0; i <= ROUNDS; ++i)
@@ -190,78 +203,78 @@ namespace Org.BouncyCastle.Crypto.Engines
W[i] = new uint[4];
}
- //
- // copy the key into the round key array
- //
-
- t = 0;
- for (int i = 0; i < key.Length; t++)
- {
- W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
- i+=4;
- }
-
- //
- // while not enough round key material calculated
- // calculate new values
- //
- int k = (ROUNDS + 1) << 2;
- for (int i = KC; (i < k); i++)
- {
- uint temp = W[(i-1)>>2][(i-1)&3];
- if ((i % KC) == 0)
- {
- temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
- }
- else if ((KC > 6) && ((i % KC) == 4))
- {
- temp = SubWord(temp);
- }
-
- W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
- }
-
- if (!forEncryption)
- {
- for (int j = 1; j < ROUNDS; j++)
- {
+ //
+ // copy the key into the round key array
+ //
+
+ t = 0;
+ for (int i = 0; i < key.Length; t++)
+ {
+ W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
+ i+=4;
+ }
+
+ //
+ // while not enough round key material calculated
+ // calculate new values
+ //
+ int k = (ROUNDS + 1) << 2;
+ for (int i = KC; (i < k); i++)
+ {
+ uint temp = W[(i-1)>>2][(i-1)&3];
+ if ((i % KC) == 0)
+ {
+ temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
+ }
+ else if ((KC > 6) && ((i % KC) == 4))
+ {
+ temp = SubWord(temp);
+ }
+
+ W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
+ }
+
+ if (!forEncryption)
+ {
+ for (int j = 1; j < ROUNDS; j++)
+ {
uint[] w = W[j];
for (int i = 0; i < 4; i++)
{
w[i] = Inv_Mcol(w[i]);
}
- }
- }
-
- return W;
- }
-
- private int ROUNDS;
- private uint[][] WorkingKey;
- private uint C0, C1, C2, C3;
- private bool forEncryption;
-
- private const int BLOCK_SIZE = 16;
-
- /**
- * default constructor - 128 bit block size.
- */
- public AesLightEngine()
- {
- }
-
- /**
- * initialise an AES cipher.
- *
- * @param forEncryption whether or not we are for encryption.
- * @param parameters the parameters required to set up the cipher.
- * @exception ArgumentException if the parameters argument is
- * inappropriate.
- */
- public void Init(
- bool forEncryption,
- ICipherParameters parameters)
- {
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private uint[][] WorkingKey;
+ private uint C0, C1, C2, C3;
+ private bool forEncryption;
+
+ private const int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AesLightEngine()
+ {
+ }
+
+ /**
+ * initialise an AES cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
KeyParameter keyParameter = parameters as KeyParameter;
if (keyParameter == null)
@@ -272,170 +285,147 @@ namespace Org.BouncyCastle.Crypto.Engines
this.forEncryption = forEncryption;
}
- public string AlgorithmName
- {
- get { return "AES"; }
- }
-
- public bool IsPartialBlockOkay
- {
- get { return false; }
- }
-
- public int GetBlockSize()
- {
- return BLOCK_SIZE;
- }
-
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
- {
- if (WorkingKey == null)
- {
- throw new InvalidOperationException("AES engine not initialised");
- }
-
- if ((inOff + (32 / 2)) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + (32 / 2)) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
-
- if (forEncryption)
- {
- UnPackBlock(input, inOff);
- EncryptBlock();
- PackBlock(output, outOff);
- }
- else
- {
- UnPackBlock(input, inOff);
- DecryptBlock();
- PackBlock(output, outOff);
- }
-
- return BLOCK_SIZE;
- }
-
- public void Reset()
- {
- }
-
- private void UnPackBlock(
- byte[] bytes,
- int off)
- {
- C0 = Pack.LE_To_UInt32(bytes, off);
- C1 = Pack.LE_To_UInt32(bytes, off + 4);
- C2 = Pack.LE_To_UInt32(bytes, off + 8);
- C3 = Pack.LE_To_UInt32(bytes, off + 12);
- }
-
- private void PackBlock(
- byte[] bytes,
- int off)
- {
- Pack.UInt32_To_LE(C0, bytes, off);
- Pack.UInt32_To_LE(C1, bytes, off + 4);
- Pack.UInt32_To_LE(C2, bytes, off + 8);
- Pack.UInt32_To_LE(C3, bytes, off + 12);
- }
-
- private void EncryptBlock()
- {
- uint[][] KW = WorkingKey;
-
- int r = 0;
- uint[] kw = KW[r];
-
- C0 ^= kw[0];
- C1 ^= kw[1];
- C2 ^= kw[2];
- C3 ^= kw[3];
-
- uint r0, r1, r2, r3;
-
- while (r < (ROUNDS - 2))
- {
- kw = KW[++r];
- r0 = Mcol((uint)S[C0 & 255] ^ (((uint)S[(C1 >> 8) & 255]) << 8) ^ (((uint)S[(C2 >> 16) & 255]) << 16) ^ (((uint)S[(C3 >> 24) & 255]) << 24)) ^ kw[0];
- r1 = Mcol((uint)S[C1 & 255] ^ (((uint)S[(C2 >> 8) & 255]) << 8) ^ (((uint)S[(C3 >> 16) & 255]) << 16) ^ (((uint)S[(C0 >> 24) & 255]) << 24)) ^ kw[1];
- r2 = Mcol((uint)S[C2 & 255] ^ (((uint)S[(C3 >> 8) & 255]) << 8) ^ (((uint)S[(C0 >> 16) & 255]) << 16) ^ (((uint)S[(C1 >> 24) & 255]) << 24)) ^ kw[2];
- r3 = Mcol((uint)S[C3 & 255] ^ (((uint)S[(C0 >> 8) & 255]) << 8) ^ (((uint)S[(C1 >> 16) & 255]) << 16) ^ (((uint)S[(C2 >> 24) & 255]) << 24)) ^ kw[3];
- kw = KW[++r];
- C0 = Mcol((uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
- C1 = Mcol((uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24)) ^ kw[1];
- C2 = Mcol((uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24)) ^ kw[2];
- C3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24)) ^ kw[3];
- }
-
- kw = KW[++r];
- r0 = Mcol((uint)S[C0 & 255] ^ (((uint)S[(C1 >> 8) & 255]) << 8) ^ (((uint)S[(C2 >> 16) & 255]) << 16) ^ (((uint)S[(C3 >> 24) & 255]) << 24)) ^ kw[0];
- r1 = Mcol((uint)S[C1 & 255] ^ (((uint)S[(C2 >> 8) & 255]) << 8) ^ (((uint)S[(C3 >> 16) & 255]) << 16) ^ (((uint)S[(C0 >> 24) & 255]) << 24)) ^ kw[1];
- r2 = Mcol((uint)S[C2 & 255] ^ (((uint)S[(C3 >> 8) & 255]) << 8) ^ (((uint)S[(C0 >> 16) & 255]) << 16) ^ (((uint)S[(C1 >> 24) & 255]) << 24)) ^ kw[2];
- r3 = Mcol((uint)S[C3 & 255] ^ (((uint)S[(C0 >> 8) & 255]) << 8) ^ (((uint)S[(C1 >> 16) & 255]) << 16) ^ (((uint)S[(C2 >> 24) & 255]) << 24)) ^ kw[3];
-
- // the final round is a simple function of S
-
- kw = KW[++r];
- C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24) ^ kw[0];
- C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24) ^ kw[1];
- C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
- C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
-
- Debug.Assert(r == ROUNDS);
+ public virtual string AlgorithmName
+ {
+ get { return "AES"; }
}
- private void DecryptBlock()
- {
- uint[][] KW = WorkingKey;
-
- int r = ROUNDS;
- uint[] kw = KW[r];
-
- C0 ^= kw[0];
- C1 ^= kw[1];
- C2 ^= kw[2];
- C3 ^= kw[3];
-
- uint r0, r1, r2, r3;
-
- while (r > 2)
- {
- kw = KW[--r];
- r0 = Inv_Mcol((uint)Si[C0 & 255] ^ (((uint)Si[(C3 >> 8) & 255]) << 8) ^ (((uint)Si[(C2 >> 16) & 255]) << 16) ^ ((uint)Si[(C1 >> 24) & 255] << 24)) ^ kw[0];
- r1 = Inv_Mcol((uint)Si[C1 & 255] ^ (((uint)Si[(C0 >> 8) & 255]) << 8) ^ (((uint)Si[(C3 >> 16) & 255]) << 16) ^ ((uint)Si[(C2 >> 24) & 255] << 24)) ^ kw[1];
- r2 = Inv_Mcol((uint)Si[C2 & 255] ^ (((uint)Si[(C1 >> 8) & 255]) << 8) ^ (((uint)Si[(C0 >> 16) & 255]) << 16) ^ ((uint)Si[(C3 >> 24) & 255] << 24)) ^ kw[2];
- r3 = Inv_Mcol((uint)Si[C3 & 255] ^ (((uint)Si[(C2 >> 8) & 255]) << 8) ^ (((uint)Si[(C1 >> 16) & 255]) << 16) ^ ((uint)Si[(C0 >> 24) & 255] << 24)) ^ kw[3];
- kw = KW[--r];
- C0 = Inv_Mcol((uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ ((uint)Si[(r1 >> 24) & 255] << 24)) ^ kw[0];
- C1 = Inv_Mcol((uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(r2 >> 24) & 255] << 24)) ^ kw[1];
- C2 = Inv_Mcol((uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
- C3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ ((uint)Si[(r0 >> 24) & 255] << 24)) ^ kw[3];
- }
-
- kw = KW[--r];
- r0 = Inv_Mcol((uint)Si[C0 & 255] ^ (((uint)Si[(C3 >> 8) & 255]) << 8) ^ (((uint)Si[(C2 >> 16) & 255]) << 16) ^ ((uint)Si[(C1 >> 24) & 255] << 24)) ^ kw[0];
- r1 = Inv_Mcol((uint)Si[C1 & 255] ^ (((uint)Si[(C0 >> 8) & 255]) << 8) ^ (((uint)Si[(C3 >> 16) & 255]) << 16) ^ ((uint)Si[(C2 >> 24) & 255] << 24)) ^ kw[1];
- r2 = Inv_Mcol((uint)Si[C2 & 255] ^ (((uint)Si[(C1 >> 8) & 255]) << 8) ^ (((uint)Si[(C0 >> 16) & 255]) << 16) ^ ((uint)Si[(C3 >> 24) & 255] << 24)) ^ kw[2];
- r3 = Inv_Mcol((uint)Si[C3 & 255] ^ (((uint)Si[(C2 >> 8) & 255]) << 8) ^ (((uint)Si[(C1 >> 16) & 255]) << 16) ^ ((uint)Si[(C0 >> 24) & 255] << 24)) ^ kw[3];
-
- // the final round's table is a simple function of Si
-
- kw = KW[--r];
- C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
- C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[(r2 >> 24) & 255]) << 24) ^ kw[1];
- C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[(r3 >> 24) & 255]) << 24) ^ kw[2];
- C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[(r0 >> 24) & 255]) << 24) ^ kw[3];
-
- Debug.Assert(r == 0);
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ throw new InvalidOperationException("AES engine not initialised");
+
+ Check.DataLength(input, inOff, 16, "input buffer too short");
+ Check.OutputLength(output, outOff, 16, "output buffer too short");
+
+ UnPackBlock(input, inOff);
+
+ if (forEncryption)
+ {
+ EncryptBlock(WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(WorkingKey);
+ }
+
+ PackBlock(output, outOff);
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ C0 = Pack.LE_To_UInt32(bytes, off);
+ C1 = Pack.LE_To_UInt32(bytes, off + 4);
+ C2 = Pack.LE_To_UInt32(bytes, off + 8);
+ C3 = Pack.LE_To_UInt32(bytes, off + 12);
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ Pack.UInt32_To_LE(C0, bytes, off);
+ Pack.UInt32_To_LE(C1, bytes, off + 4);
+ Pack.UInt32_To_LE(C2, bytes, off + 8);
+ Pack.UInt32_To_LE(C3, bytes, off + 12);
+ }
+
+ private void EncryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[0];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+ int r = 1;
+ while (r < ROUNDS - 1)
+ {
+ kw = KW[r++];
+ r0 = Mcol((uint)S[t0 & 255] ^ (((uint)S[(t1 >> 8) & 255]) << 8) ^ (((uint)S[(t2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+ r1 = Mcol((uint)S[t1 & 255] ^ (((uint)S[(t2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(t0 >> 24) & 255]) << 24)) ^ kw[1];
+ r2 = Mcol((uint)S[t2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(t0 >> 16) & 255]) << 16) ^ (((uint)S[(t1 >> 24) & 255]) << 24)) ^ kw[2];
+ r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(t0 >> 8) & 255]) << 8) ^ (((uint)S[(t1 >> 16) & 255]) << 16) ^ (((uint)S[(t2 >> 24) & 255]) << 24)) ^ kw[3];
+ kw = KW[r++];
+ t0 = Mcol((uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+ t1 = Mcol((uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24)) ^ kw[1];
+ t2 = Mcol((uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24)) ^ kw[2];
+ r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24)) ^ kw[3];
+ }
+
+ kw = KW[r++];
+ r0 = Mcol((uint)S[t0 & 255] ^ (((uint)S[(t1 >> 8) & 255]) << 8) ^ (((uint)S[(t2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+ r1 = Mcol((uint)S[t1 & 255] ^ (((uint)S[(t2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(t0 >> 24) & 255]) << 24)) ^ kw[1];
+ r2 = Mcol((uint)S[t2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(t0 >> 16) & 255]) << 16) ^ (((uint)S[(t1 >> 24) & 255]) << 24)) ^ kw[2];
+ r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(t0 >> 8) & 255]) << 8) ^ (((uint)S[(t1 >> 16) & 255]) << 16) ^ (((uint)S[(t2 >> 24) & 255]) << 24)) ^ kw[3];
+
+ // the final round is a simple function of S
+
+ kw = KW[r];
+ this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24) ^ kw[0];
+ this.C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24) ^ kw[1];
+ this.C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
+ this.C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
+ }
+
+ private void DecryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[ROUNDS];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+ int r = ROUNDS - 1;
+ while (r > 1)
+ {
+ kw = KW[r--];
+ r0 = Inv_Mcol((uint)Si[t0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(t2 >> 16) & 255]) << 16) ^ ((uint)Si[(t1 >> 24) & 255] << 24)) ^ kw[0];
+ r1 = Inv_Mcol((uint)Si[t1 & 255] ^ (((uint)Si[(t0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(t2 >> 24) & 255] << 24)) ^ kw[1];
+ r2 = Inv_Mcol((uint)Si[t2 & 255] ^ (((uint)Si[(t1 >> 8) & 255]) << 8) ^ (((uint)Si[(t0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+ r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(t2 >> 8) & 255]) << 8) ^ (((uint)Si[(t1 >> 16) & 255]) << 16) ^ ((uint)Si[(t0 >> 24) & 255] << 24)) ^ kw[3];
+ kw = KW[r--];
+ t0 = Inv_Mcol((uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ ((uint)Si[(r1 >> 24) & 255] << 24)) ^ kw[0];
+ t1 = Inv_Mcol((uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(r2 >> 24) & 255] << 24)) ^ kw[1];
+ t2 = Inv_Mcol((uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+ r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ ((uint)Si[(r0 >> 24) & 255] << 24)) ^ kw[3];
+ }
+
+ kw = KW[1];
+ r0 = Inv_Mcol((uint)Si[t0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(t2 >> 16) & 255]) << 16) ^ ((uint)Si[(t1 >> 24) & 255] << 24)) ^ kw[0];
+ r1 = Inv_Mcol((uint)Si[t1 & 255] ^ (((uint)Si[(t0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(t2 >> 24) & 255] << 24)) ^ kw[1];
+ r2 = Inv_Mcol((uint)Si[t2 & 255] ^ (((uint)Si[(t1 >> 8) & 255]) << 8) ^ (((uint)Si[(t0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+ r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(t2 >> 8) & 255]) << 8) ^ (((uint)Si[(t1 >> 16) & 255]) << 16) ^ ((uint)Si[(t0 >> 24) & 255] << 24)) ^ kw[3];
+
+ // the final round's table is a simple function of Si
+
+ kw = KW[0];
+ this.C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
+ this.C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[(r2 >> 24) & 255]) << 24) ^ kw[1];
+ this.C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[(r3 >> 24) & 255]) << 24) ^ kw[2];
+ this.C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[(r0 >> 24) & 255]) << 24) ^ kw[3];
}
- }
+ }
}
diff --git a/crypto/src/crypto/engines/BlowfishEngine.cs b/crypto/src/crypto/engines/BlowfishEngine.cs
index 8f80f712e..7b50e832f 100644
--- a/crypto/src/crypto/engines/BlowfishEngine.cs
+++ b/crypto/src/crypto/engines/BlowfishEngine.cs
@@ -296,7 +296,7 @@ namespace Org.BouncyCastle.Crypto.Engines
//====================================
private static readonly int ROUNDS = 16;
- private const int BLOCK_SIZE = 8; // bytes = 64 bits
+ private const int BLOCK_SIZE = 8; // bytes = 64 bits
private static readonly int SBOX_SK = 256;
private static readonly int P_SZ = ROUNDS+2;
@@ -353,19 +353,10 @@ namespace Org.BouncyCastle.Crypto.Engines
int outOff)
{
if (workingKey == null)
- {
throw new InvalidOperationException("Blowfish not initialised");
- }
- if ((inOff + BLOCK_SIZE) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + BLOCK_SIZE) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
if (encrypting)
{
diff --git a/crypto/src/crypto/engines/CamelliaEngine.cs b/crypto/src/crypto/engines/CamelliaEngine.cs
index 8f4a442e9..71bd1b0dc 100644
--- a/crypto/src/crypto/engines/CamelliaEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaEngine.cs
@@ -611,7 +611,7 @@ namespace Org.BouncyCastle.Crypto.Engines
{
}
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -623,22 +623,22 @@ namespace Org.BouncyCastle.Crypto.Engines
initialised = true;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Camellia"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -646,12 +646,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!initialised)
throw new InvalidOperationException("Camellia engine not initialised");
- if ((inOff + BLOCK_SIZE) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BLOCK_SIZE) > output.Length)
- throw new DataLengthException("output buffer too short");
- if (_keyIs128)
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (_keyIs128)
{
return processBlock128(input, inOff, output, outOff);
}
@@ -661,7 +660,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public void Reset()
+ public virtual void Reset()
{
// nothing
}
diff --git a/crypto/src/crypto/engines/CamelliaLightEngine.cs b/crypto/src/crypto/engines/CamelliaLightEngine.cs
index a301eb55e..a132227c5 100644
--- a/crypto/src/crypto/engines/CamelliaLightEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaLightEngine.cs
@@ -524,22 +524,22 @@ namespace Org.BouncyCastle.Crypto.Engines
initialised = false;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Camellia"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -551,7 +551,7 @@ namespace Org.BouncyCastle.Crypto.Engines
initialised = true;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -559,12 +559,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!initialised)
throw new InvalidOperationException("Camellia engine not initialised");
- if ((inOff + BLOCK_SIZE) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BLOCK_SIZE) > output.Length)
- throw new DataLengthException("output buffer too short");
- if (_keyis128)
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (_keyis128)
{
return processBlock128(input, inOff, output, outOff);
}
@@ -574,7 +573,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public void Reset()
+ public virtual void Reset()
{
}
}
diff --git a/crypto/src/crypto/engines/Cast5Engine.cs b/crypto/src/crypto/engines/Cast5Engine.cs
index 4c3f84a55..1af30a335 100644
--- a/crypto/src/crypto/engines/Cast5Engine.cs
+++ b/crypto/src/crypto/engines/Cast5Engine.cs
@@ -329,7 +329,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -360,12 +360,11 @@ namespace Org.BouncyCastle.Crypto.Engines
int blockSize = GetBlockSize();
if (_workingKey == null)
throw new InvalidOperationException(AlgorithmName + " not initialised");
- if ((inOff + blockSize) > input.Length)
- throw new DataLengthException("Input buffer too short");
- if ((outOff + blockSize) > output.Length)
- throw new DataLengthException("Output buffer too short");
- if (_encrypting)
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, blockSize, "output buffer too short");
+
+ if (_encrypting)
{
return EncryptBlock(input, inOff, output, outOff);
}
diff --git a/crypto/src/crypto/engines/ChaChaEngine.cs b/crypto/src/crypto/engines/ChaChaEngine.cs
index f4a7b8fe1..46b59ed2e 100644
--- a/crypto/src/crypto/engines/ChaChaEngine.cs
+++ b/crypto/src/crypto/engines/ChaChaEngine.cs
@@ -162,7 +162,6 @@ namespace Org.BouncyCastle.Crypto.Engines
x09 += x14; x04 = R(x04 ^ x09, 12);
x03 += x04; x14 = R(x14 ^ x03, 8);
x09 += x14; x04 = R(x04 ^ x09, 7);
-
}
x[ 0] = x00 + input[ 0];
@@ -182,8 +181,6 @@ namespace Org.BouncyCastle.Crypto.Engines
x[14] = x14 + input[14];
x[15] = x15 + input[15];
}
-
}
-
}
diff --git a/crypto/src/crypto/engines/DesEdeEngine.cs b/crypto/src/crypto/engines/DesEdeEngine.cs
index eec4ec59d..bc40b56a8 100644
--- a/crypto/src/crypto/engines/DesEdeEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeEngine.cs
@@ -70,10 +70,9 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (workingKey1 == null)
throw new InvalidOperationException("DESede engine not initialised");
- if ((inOff + BLOCK_SIZE) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BLOCK_SIZE) > output.Length)
- throw new DataLengthException("output buffer too short");
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
byte[] temp = new byte[BLOCK_SIZE];
diff --git a/crypto/src/crypto/engines/DesEdeWrapEngine.cs b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
index fdc71687f..43100a9bd 100644
--- a/crypto/src/crypto/engines/DesEdeWrapEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
@@ -52,7 +52,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param forWrapping
* @param param
*/
- public void Init(
+ public virtual void Init(
bool forWrapping,
ICipherParameters parameters)
{
@@ -103,7 +103,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return
*/
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "DESede"; }
}
@@ -116,7 +116,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param inLen
* @return
*/
- public byte[] Wrap(
+ public virtual byte[] Wrap(
byte[] input,
int inOff,
int length)
@@ -185,7 +185,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return
* @throws InvalidCipherTextException
*/
- public byte[] Unwrap(
+ public virtual byte[] Unwrap(
byte[] input,
int inOff,
int length)
diff --git a/crypto/src/crypto/engines/DesEngine.cs b/crypto/src/crypto/engines/DesEngine.cs
index 067cf45e3..a6d580bb6 100644
--- a/crypto/src/crypto/engines/DesEngine.cs
+++ b/crypto/src/crypto/engines/DesEngine.cs
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Crypto.Engines
get { return "DES"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
@@ -59,12 +59,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (workingKey == null)
throw new InvalidOperationException("DES engine not initialised");
- if ((inOff + BLOCK_SIZE) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BLOCK_SIZE) > output.Length)
- throw new DataLengthException("output buffer too short");
- DesFunc(workingKey, input, inOff, output, outOff);
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ DesFunc(workingKey, input, inOff, output, outOff);
return BLOCK_SIZE;
}
diff --git a/crypto/src/crypto/engines/ElGamalEngine.cs b/crypto/src/crypto/engines/ElGamalEngine.cs
index 3d256a087..197d7bc15 100644
--- a/crypto/src/crypto/engines/ElGamalEngine.cs
+++ b/crypto/src/crypto/engines/ElGamalEngine.cs
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Crypto.Engines
private bool forEncryption;
private int bitSize;
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "ElGamal"; }
}
@@ -28,7 +28,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary ElGamal key parameters.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an input block.
*/
- public int GetInputBlockSize()
+ public virtual int GetInputBlockSize()
{
if (forEncryption)
{
@@ -88,7 +88,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an output block.
*/
- public int GetOutputBlockSize()
+ public virtual int GetOutputBlockSize()
{
if (forEncryption)
{
@@ -107,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return the result of the ElGamal process.
* @exception DataLengthException the input block is too large.
*/
- public byte[] ProcessBlock(
+ public virtual byte[] ProcessBlock(
byte[] input,
int inOff,
int length)
diff --git a/crypto/src/crypto/engines/GOST28147Engine.cs b/crypto/src/crypto/engines/GOST28147Engine.cs
index 8eb6f36b5..e37ddaefd 100644
--- a/crypto/src/crypto/engines/GOST28147Engine.cs
+++ b/crypto/src/crypto/engines/GOST28147Engine.cs
@@ -150,7 +150,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -187,48 +187,39 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Gost28147"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BlockSize;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
- {
throw new InvalidOperationException("Gost28147 engine not initialised");
- }
- if ((inOff + BlockSize) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + BlockSize) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
- Gost28147Func(workingKey, input, inOff, output, outOff);
+ Gost28147Func(workingKey, input, inOff, output, outOff);
return BlockSize;
}
- public void Reset()
+ public virtual void Reset()
{
}
diff --git a/crypto/src/crypto/engines/HC128Engine.cs b/crypto/src/crypto/engines/HC128Engine.cs
index a2d099f87..40c7a4e17 100644
--- a/crypto/src/crypto/engines/HC128Engine.cs
+++ b/crypto/src/crypto/engines/HC128Engine.cs
@@ -142,7 +142,7 @@ namespace Org.BouncyCastle.Crypto.Engines
cnt = 0;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "HC-128"; }
}
@@ -156,7 +156,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @throws ArgumentException if the params argument is
* inappropriate (ie. the key is not 128 bit long).
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -201,7 +201,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return ret;
}
- public void ProcessBytes(
+ public virtual void ProcessBytes(
byte[] input,
int inOff,
int len,
@@ -210,24 +210,23 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
- if ((inOff + len) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + len) > output.Length)
- throw new DataLengthException("output buffer too short");
- for (int i = 0; i < len; i++)
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
+
+ for (int i = 0; i < len; i++)
{
output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
}
}
- public void Reset()
+ public virtual void Reset()
{
idx = 0;
Init();
}
- public byte ReturnByte(byte input)
+ public virtual byte ReturnByte(byte input)
{
return (byte)(input ^ GetByte());
}
diff --git a/crypto/src/crypto/engines/HC256Engine.cs b/crypto/src/crypto/engines/HC256Engine.cs
index da717dab7..6eb360711 100644
--- a/crypto/src/crypto/engines/HC256Engine.cs
+++ b/crypto/src/crypto/engines/HC256Engine.cs
@@ -126,7 +126,7 @@ namespace Org.BouncyCastle.Crypto.Engines
cnt = 0;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "HC-256"; }
}
@@ -140,7 +140,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @throws ArgumentException if the params argument is
* inappropriate (ie. the key is not 256 bit long).
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -185,7 +185,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return ret;
}
- public void ProcessBytes(
+ public virtual void ProcessBytes(
byte[] input,
int inOff,
int len,
@@ -194,24 +194,23 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
- if ((inOff + len) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + len) > output.Length)
- throw new DataLengthException("output buffer too short");
- for (int i = 0; i < len; i++)
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
+
+ for (int i = 0; i < len; i++)
{
output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
}
}
- public void Reset()
+ public virtual void Reset()
{
idx = 0;
Init();
}
- public byte ReturnByte(byte input)
+ public virtual byte ReturnByte(byte input)
{
return (byte)(input ^ GetByte());
}
diff --git a/crypto/src/crypto/engines/ISAACEngine.cs b/crypto/src/crypto/engines/ISAACEngine.cs
index 9c58678a0..f25577130 100644
--- a/crypto/src/crypto/engines/ISAACEngine.cs
+++ b/crypto/src/crypto/engines/ISAACEngine.cs
@@ -35,7 +35,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the params argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -53,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Engines
setKey(p.GetKey());
}
- public byte ReturnByte(
+ public virtual byte ReturnByte(
byte input)
{
if (index == 0)
@@ -68,7 +68,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return output;
}
- public void ProcessBytes(
+ public virtual void ProcessBytes(
byte[] input,
int inOff,
int len,
@@ -77,10 +77,9 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
- if ((inOff + len) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + len) > output.Length)
- throw new DataLengthException("output buffer too short");
+
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
for (int i = 0; i < len; i++)
{
@@ -94,12 +93,12 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "ISAAC"; }
}
- public void Reset()
+ public virtual void Reset()
{
setKey(workingKey);
}
diff --git a/crypto/src/crypto/engines/IdeaEngine.cs b/crypto/src/crypto/engines/IdeaEngine.cs
index 46b5a787c..4909510ac 100644
--- a/crypto/src/crypto/engines/IdeaEngine.cs
+++ b/crypto/src/crypto/engines/IdeaEngine.cs
@@ -47,7 +47,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -58,43 +58,37 @@ namespace Org.BouncyCastle.Crypto.Engines
((KeyParameter)parameters).GetKey());
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "IDEA"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
- {
throw new InvalidOperationException("IDEA engine not initialised");
- }
- if ((inOff + BLOCK_SIZE) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
- if ((outOff + BLOCK_SIZE) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
IdeaFunc(workingKey, input, inOff, output, outOff);
return BLOCK_SIZE;
}
- public void Reset()
+ public virtual void Reset()
{
}
private static readonly int MASK = 0xffff;
diff --git a/crypto/src/crypto/engines/IesEngine.cs b/crypto/src/crypto/engines/IesEngine.cs
index 6520c86f8..a2004a9d6 100644
--- a/crypto/src/crypto/engines/IesEngine.cs
+++ b/crypto/src/crypto/engines/IesEngine.cs
@@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param pubParam the recipient's/sender's public key parameters
* @param param encoding and derivation parameters.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters privParameters,
ICipherParameters pubParameters,
@@ -133,7 +133,7 @@ namespace Org.BouncyCastle.Crypto.Engines
inOff += inLen;
- byte[] T1 = Arrays.Copy(in_enc, inOff, macBuf.Length);
+ byte[] T1 = Arrays.CopyOfRange(in_enc, inOff, inOff + macBuf.Length);
if (!Arrays.ConstantTimeAreEqual(T1, macBuf))
throw (new InvalidCipherTextException("Invalid MAC."));
@@ -213,7 +213,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return buf;
}
- public byte[] ProcessBlock(
+ public virtual byte[] ProcessBlock(
byte[] input,
int inOff,
int inLen)
@@ -224,10 +224,16 @@ namespace Org.BouncyCastle.Crypto.Engines
byte[] zBytes = BigIntegers.AsUnsignedByteArray(agree.GetFieldSize(), z);
- return forEncryption
- ? EncryptBlock(input, inOff, inLen, zBytes)
- : DecryptBlock(input, inOff, inLen, zBytes);
+ try
+ {
+ return forEncryption
+ ? EncryptBlock(input, inOff, inLen, zBytes)
+ : DecryptBlock(input, inOff, inLen, zBytes);
+ }
+ finally
+ {
+ Array.Clear(zBytes, 0, zBytes.Length);
+ }
}
}
-
}
diff --git a/crypto/src/crypto/engines/NaccacheSternEngine.cs b/crypto/src/crypto/engines/NaccacheSternEngine.cs
index 9ca092351..e547e0caf 100644
--- a/crypto/src/crypto/engines/NaccacheSternEngine.cs
+++ b/crypto/src/crypto/engines/NaccacheSternEngine.cs
@@ -33,7 +33,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
* org.bouncycastle.crypto.CipherParameters)
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -83,7 +83,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public bool Debug
+ public virtual bool Debug
{
set { this.debug = value; }
}
@@ -93,7 +93,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
*/
- public int GetInputBlockSize()
+ public virtual int GetInputBlockSize()
{
if (forEncryption)
{
@@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
*/
- public int GetOutputBlockSize()
+ public virtual int GetOutputBlockSize()
{
if (forEncryption)
{
@@ -134,7 +134,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
* int, int)
*/
- public byte[] ProcessBlock(
+ public virtual byte[] ProcessBlock(
byte[] inBytes,
int inOff,
int length)
@@ -245,7 +245,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return The byte[] representation of the encrypted BigInteger (i.e.
* crypted.toByteArray())
*/
- public byte[] Encrypt(
+ public virtual byte[] Encrypt(
BigInteger plain)
{
// Always return modulus size values 0-padded at the beginning
@@ -273,7 +273,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return encrypt((block1 + block2) mod sigma)
* @throws InvalidCipherTextException
*/
- public byte[] AddCryptedBlocks(
+ public virtual byte[] AddCryptedBlocks(
byte[] block1,
byte[] block2)
{
@@ -329,7 +329,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return the data after it went through the NaccacheSternEngine.
* @throws InvalidCipherTextException
*/
- public byte[] ProcessData(
+ public virtual byte[] ProcessData(
byte[] data)
{
if (debug)
diff --git a/crypto/src/crypto/engines/NoekeonEngine.cs b/crypto/src/crypto/engines/NoekeonEngine.cs
index b73e696a9..dd78a4ea5 100644
--- a/crypto/src/crypto/engines/NoekeonEngine.cs
+++ b/crypto/src/crypto/engines/NoekeonEngine.cs
@@ -42,17 +42,17 @@ namespace Org.BouncyCastle.Crypto.Engines
_initialised = false;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Noekeon"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return GenericSize;
}
@@ -65,7 +65,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the params argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -80,7 +80,7 @@ namespace Org.BouncyCastle.Crypto.Engines
setKey(p.GetKey());
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -88,17 +88,16 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
- if ((inOff + GenericSize) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + GenericSize) > output.Length)
- throw new DataLengthException("output buffer too short");
- return _forEncryption
+ Check.DataLength(input, inOff, GenericSize, "input buffer too short");
+ Check.OutputLength(output, outOff, GenericSize, "output buffer too short");
+
+ return _forEncryption
? encryptBlock(input, inOff, output, outOff)
: decryptBlock(input, inOff, output, outOff);
}
- public void Reset()
+ public virtual void Reset()
{
// TODO This should do something in case the encryption is aborted
}
diff --git a/crypto/src/crypto/engines/NullEngine.cs b/crypto/src/crypto/engines/NullEngine.cs
index 407b8ccc6..f883b7c29 100644
--- a/crypto/src/crypto/engines/NullEngine.cs
+++ b/crypto/src/crypto/engines/NullEngine.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Crypto.Engines
{
}
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -26,22 +26,22 @@ namespace Org.BouncyCastle.Crypto.Engines
initialised = true;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Null"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return true; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BlockSize;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -49,12 +49,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (!initialised)
throw new InvalidOperationException("Null engine not initialised");
- if ((inOff + BlockSize) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BlockSize) > output.Length)
- throw new DataLengthException("output buffer too short");
- for (int i = 0; i < BlockSize; ++i)
+ Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
+
+ for (int i = 0; i < BlockSize; ++i)
{
output[outOff + i] = input[inOff + i];
}
@@ -62,7 +61,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BlockSize;
}
- public void Reset()
+ public virtual void Reset()
{
// nothing needs to be done
}
diff --git a/crypto/src/crypto/engines/RC2Engine.cs b/crypto/src/crypto/engines/RC2Engine.cs
index aaf8c714c..b56953de5 100644
--- a/crypto/src/crypto/engines/RC2Engine.cs
+++ b/crypto/src/crypto/engines/RC2Engine.cs
@@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -139,26 +139,26 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public void Reset()
+ public virtual void Reset()
{
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RC2"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -166,12 +166,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (workingKey == null)
throw new InvalidOperationException("RC2 engine not initialised");
- if ((inOff + BLOCK_SIZE) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BLOCK_SIZE) > output.Length)
- throw new DataLengthException("output buffer too short");
- if (encrypting)
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
@@ -308,5 +307,4 @@ namespace Org.BouncyCastle.Crypto.Engines
outBytes[outOff + 7] = (byte)(x76 >> 8);
}
}
-
}
diff --git a/crypto/src/crypto/engines/RC2WrapEngine.cs b/crypto/src/crypto/engines/RC2WrapEngine.cs
index 238c9f76a..5742aa8b7 100644
--- a/crypto/src/crypto/engines/RC2WrapEngine.cs
+++ b/crypto/src/crypto/engines/RC2WrapEngine.cs
@@ -51,7 +51,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param forWrapping
* @param param
*/
- public void Init(
+ public virtual void Init(
bool forWrapping,
ICipherParameters parameters)
{
@@ -101,7 +101,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return
*/
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RC2"; }
}
@@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param inLen
* @return
*/
- public byte[] Wrap(
+ public virtual byte[] Wrap(
byte[] input,
int inOff,
int length)
@@ -215,7 +215,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return
* @throws InvalidCipherTextException
*/
- public byte[] Unwrap(
+ public virtual byte[] Unwrap(
byte[] input,
int inOff,
int length)
diff --git a/crypto/src/crypto/engines/RC4Engine.cs b/crypto/src/crypto/engines/RC4Engine.cs
index c65468d93..fd84b7d23 100644
--- a/crypto/src/crypto/engines/RC4Engine.cs
+++ b/crypto/src/crypto/engines/RC4Engine.cs
@@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -47,12 +47,12 @@ namespace Org.BouncyCastle.Crypto.Engines
throw new ArgumentException("invalid parameter passed to RC4 init - " + parameters.GetType().ToString());
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RC4"; }
}
- public byte ReturnByte(
+ public virtual byte ReturnByte(
byte input)
{
x = (x + 1) & 0xff;
@@ -67,23 +67,15 @@ namespace Org.BouncyCastle.Crypto.Engines
return (byte)(input ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
}
- public void ProcessBytes(
+ public virtual void ProcessBytes(
byte[] input,
int inOff,
int length,
byte[] output,
- int outOff
- )
+ int outOff)
{
- if ((inOff + length) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + length) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, length, "input buffer too short");
+ Check.OutputLength(output, outOff, length, "output buffer too short");
for (int i = 0; i < length ; i++)
{
@@ -101,7 +93,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public void Reset()
+ public virtual void Reset()
{
SetKey(workingKey);
}
@@ -143,5 +135,4 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
}
-
}
diff --git a/crypto/src/crypto/engines/RC532Engine.cs b/crypto/src/crypto/engines/RC532Engine.cs
index 1661707ef..169a60b98 100644
--- a/crypto/src/crypto/engines/RC532Engine.cs
+++ b/crypto/src/crypto/engines/RC532Engine.cs
@@ -48,17 +48,17 @@ namespace Org.BouncyCastle.Crypto.Engines
// _S = null;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RC5-32"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return 2 * 4;
}
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -97,7 +97,7 @@ namespace Org.BouncyCastle.Crypto.Engines
this.forEncryption = forEncryption;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -108,7 +108,7 @@ namespace Org.BouncyCastle.Crypto.Engines
: DecryptBlock(input, inOff, output, outOff);
}
- public void Reset()
+ public virtual void Reset()
{
}
@@ -290,5 +290,4 @@ namespace Org.BouncyCastle.Crypto.Engines
dst[dstOff + 3] = (byte)(word >> 24);
}
}
-
}
diff --git a/crypto/src/crypto/engines/RC564Engine.cs b/crypto/src/crypto/engines/RC564Engine.cs
index 5c69d40ff..ddcce0fa8 100644
--- a/crypto/src/crypto/engines/RC564Engine.cs
+++ b/crypto/src/crypto/engines/RC564Engine.cs
@@ -51,17 +51,17 @@ namespace Org.BouncyCastle.Crypto.Engines
// _S = null;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RC5-64"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return 2 * bytesPerWord;
}
@@ -74,7 +74,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -92,7 +92,7 @@ namespace Org.BouncyCastle.Crypto.Engines
SetKey(p.GetKey());
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -102,7 +102,7 @@ namespace Org.BouncyCastle.Crypto.Engines
: DecryptBlock(input, inOff, output, outOff);
}
- public void Reset()
+ public virtual void Reset()
{
}
@@ -291,5 +291,4 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
}
-
}
diff --git a/crypto/src/crypto/engines/RC6Engine.cs b/crypto/src/crypto/engines/RC6Engine.cs
index d72cc2f7b..196bd8394 100644
--- a/crypto/src/crypto/engines/RC6Engine.cs
+++ b/crypto/src/crypto/engines/RC6Engine.cs
@@ -48,17 +48,17 @@ namespace Org.BouncyCastle.Crypto.Engines
// _S = null;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RC6"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return 4 * bytesPerWord;
}
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -84,7 +84,7 @@ namespace Org.BouncyCastle.Crypto.Engines
SetKey(p.GetKey());
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -93,17 +93,16 @@ namespace Org.BouncyCastle.Crypto.Engines
int blockSize = GetBlockSize();
if (_S == null)
throw new InvalidOperationException("RC6 engine not initialised");
- if ((inOff + blockSize) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + blockSize) > output.Length)
- throw new DataLengthException("output buffer too short");
- return (forEncryption)
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, blockSize, "output buffer too short");
+
+ return (forEncryption)
? EncryptBlock(input, inOff, output, outOff)
: DecryptBlock(input, inOff, output, outOff);
}
- public void Reset()
+ public virtual void Reset()
{
}
@@ -358,5 +357,4 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
}
-
}
diff --git a/crypto/src/crypto/engines/RFC3211WrapEngine.cs b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
index e520075f9..4e3af5227 100644
--- a/crypto/src/crypto/engines/RFC3211WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -24,7 +24,7 @@ namespace Org.BouncyCastle.Crypto.Engines
this.engine = new CbcBlockCipher(engine);
}
- public void Init(
+ public virtual void Init(
bool forWrapping,
ICipherParameters param)
{
@@ -48,12 +48,12 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
}
- public byte[] Wrap(
+ public virtual byte[] Wrap(
byte[] inBytes,
int inOff,
int inLen)
@@ -99,7 +99,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return cekBlock;
}
- public byte[] Unwrap(
+ public virtual byte[] Unwrap(
byte[] inBytes,
int inOff,
int inLen)
diff --git a/crypto/src/crypto/engines/RFC3394WrapEngine.cs b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
index 5615a63e5..4bb0e2114 100644
--- a/crypto/src/crypto/engines/RFC3394WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
@@ -32,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Engines
this.engine = engine;
}
- public void Init(
+ public virtual void Init(
bool forWrapping,
ICipherParameters parameters)
{
@@ -64,12 +64,12 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return engine.AlgorithmName; }
}
- public byte[] Wrap(
+ public virtual byte[] Wrap(
byte[] input,
int inOff,
int inLen)
@@ -119,7 +119,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return block;
}
- public byte[] Unwrap(
+ public virtual byte[] Unwrap(
byte[] input,
int inOff,
int inLen)
diff --git a/crypto/src/crypto/engines/RSABlindedEngine.cs b/crypto/src/crypto/engines/RSABlindedEngine.cs
index cdf69ddda..f95f145f6 100644
--- a/crypto/src/crypto/engines/RSABlindedEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindedEngine.cs
@@ -7,118 +7,122 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
- /**
- * this does your basic RSA algorithm with blinding
- */
- public class RsaBlindedEngine
- : IAsymmetricBlockCipher
- {
- private readonly RsaCoreEngine core = new RsaCoreEngine();
- private RsaKeyParameters key;
- private SecureRandom random;
+ /**
+ * this does your basic RSA algorithm with blinding
+ */
+ public class RsaBlindedEngine
+ : IAsymmetricBlockCipher
+ {
+ private readonly RsaCoreEngine core = new RsaCoreEngine();
+ private RsaKeyParameters key;
+ private SecureRandom random;
- public string AlgorithmName
- {
- get { return "RSA"; }
- }
+ public virtual string AlgorithmName
+ {
+ get { return "RSA"; }
+ }
- /**
- * initialise the RSA engine.
- *
- * @param forEncryption true if we are encrypting, false otherwise.
- * @param param the necessary RSA key parameters.
- */
- public void Init(
- bool forEncryption,
- ICipherParameters param)
- {
- core.Init(forEncryption, param);
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters param)
+ {
+ core.Init(forEncryption, param);
- if (param is ParametersWithRandom)
- {
- ParametersWithRandom rParam = (ParametersWithRandom)param;
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
- key = (RsaKeyParameters)rParam.Parameters;
- random = rParam.Random;
- }
- else
- {
- key = (RsaKeyParameters)param;
- random = new SecureRandom();
- }
- }
+ key = (RsaKeyParameters)rParam.Parameters;
+ random = rParam.Random;
+ }
+ else
+ {
+ key = (RsaKeyParameters)param;
+ random = new SecureRandom();
+ }
+ }
- /**
- * Return the maximum size for an input block to this engine.
- * For RSA this is always one byte less than the key size on
- * encryption, and the same length as the key size on decryption.
- *
- * @return maximum size for an input block.
- */
- public int GetInputBlockSize()
- {
- return core.GetInputBlockSize();
- }
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public virtual int GetInputBlockSize()
+ {
+ return core.GetInputBlockSize();
+ }
- /**
- * Return the maximum size for an output block to this engine.
- * For RSA this is always one byte less than the key size on
- * decryption, and the same length as the key size on encryption.
- *
- * @return maximum size for an output block.
- */
- public int GetOutputBlockSize()
- {
- return core.GetOutputBlockSize();
- }
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public virtual int GetOutputBlockSize()
+ {
+ return core.GetOutputBlockSize();
+ }
- /**
- * Process a single block using the basic RSA algorithm.
- *
- * @param inBuf the input array.
- * @param inOff the offset into the input buffer where the data starts.
- * @param inLen the length of the data to be processed.
- * @return the result of the RSA process.
- * @exception DataLengthException the input block is too large.
- */
- public byte[] ProcessBlock(
- byte[] inBuf,
- int inOff,
- int inLen)
- {
- if (key == null)
- throw new InvalidOperationException("RSA engine not initialised");
+ /**
+ * Process a single block using the basic RSA algorithm.
+ *
+ * @param inBuf the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public virtual byte[] ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ if (key == null)
+ throw new InvalidOperationException("RSA engine not initialised");
- BigInteger input = core.ConvertInput(inBuf, inOff, inLen);
+ BigInteger input = core.ConvertInput(inBuf, inOff, inLen);
- BigInteger result;
- if (key is RsaPrivateCrtKeyParameters)
- {
- RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
- BigInteger e = k.PublicExponent;
- if (e != null) // can't do blinding without a public exponent
- {
- BigInteger m = k.Modulus;
- BigInteger r = BigIntegers.CreateRandomInRange(
- BigInteger.One, m.Subtract(BigInteger.One), random);
+ BigInteger result;
+ if (key is RsaPrivateCrtKeyParameters)
+ {
+ RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
+ BigInteger e = k.PublicExponent;
+ if (e != null) // can't do blinding without a public exponent
+ {
+ BigInteger m = k.Modulus;
+ BigInteger r = BigIntegers.CreateRandomInRange(
+ BigInteger.One, m.Subtract(BigInteger.One), random);
- BigInteger blindedInput = r.ModPow(e, m).Multiply(input).Mod(m);
- BigInteger blindedResult = core.ProcessBlock(blindedInput);
+ BigInteger blindedInput = r.ModPow(e, m).Multiply(input).Mod(m);
+ BigInteger blindedResult = core.ProcessBlock(blindedInput);
- BigInteger rInv = r.ModInverse(m);
- result = blindedResult.Multiply(rInv).Mod(m);
- }
- else
- {
- result = core.ProcessBlock(input);
- }
- }
- else
- {
- result = core.ProcessBlock(input);
- }
+ BigInteger rInv = r.ModInverse(m);
+ result = blindedResult.Multiply(rInv).Mod(m);
- return core.ConvertOutput(result);
- }
- }
+ // defence against Arjen Lenstra’s CRT attack
+ if (!input.Equals(result.ModPow(e, m)))
+ throw new InvalidOperationException("RSA engine faulty decryption/signing detected");
+ }
+ else
+ {
+ result = core.ProcessBlock(input);
+ }
+ }
+ else
+ {
+ result = core.ProcessBlock(input);
+ }
+
+ return core.ConvertOutput(result);
+ }
+ }
}
diff --git a/crypto/src/crypto/engines/RSABlindingEngine.cs b/crypto/src/crypto/engines/RSABlindingEngine.cs
index 76b57a3f7..c636627bf 100644
--- a/crypto/src/crypto/engines/RSABlindingEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindingEngine.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Engines
private bool forEncryption;
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RSA"; }
}
@@ -32,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param forEncryption true if we are encrypting (blinding), false otherwise.
* @param param the necessary RSA key parameters.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters param)
{
@@ -63,7 +63,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an input block.
*/
- public int GetInputBlockSize()
+ public virtual int GetInputBlockSize()
{
return core.GetInputBlockSize();
}
@@ -75,7 +75,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an output block.
*/
- public int GetOutputBlockSize()
+ public virtual int GetOutputBlockSize()
{
return core.GetOutputBlockSize();
}
@@ -89,7 +89,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return the result of the RSA process.
* @throws DataLengthException the input block is too large.
*/
- public byte[] ProcessBlock(
+ public virtual byte[] ProcessBlock(
byte[] inBuf,
int inOff,
int inLen)
diff --git a/crypto/src/crypto/engines/RSACoreEngine.cs b/crypto/src/crypto/engines/RSACoreEngine.cs
index 4e64d25d6..38326371f 100644
--- a/crypto/src/crypto/engines/RSACoreEngine.cs
+++ b/crypto/src/crypto/engines/RSACoreEngine.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary RSA key parameters.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -45,7 +45,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an input block.
*/
- public int GetInputBlockSize()
+ public virtual int GetInputBlockSize()
{
if (forEncryption)
{
@@ -62,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an output block.
*/
- public int GetOutputBlockSize()
+ public virtual int GetOutputBlockSize()
{
if (forEncryption)
{
@@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return (bitSize - 1) / 8;
}
- public BigInteger ConvertInput(
+ public virtual BigInteger ConvertInput(
byte[] inBuf,
int inOff,
int inLen)
@@ -90,7 +90,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return input;
}
- public byte[] ConvertOutput(
+ public virtual byte[] ConvertOutput(
BigInteger result)
{
byte[] output = result.ToByteArrayUnsigned();
@@ -112,7 +112,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return output;
}
- public BigInteger ProcessBlock(
+ public virtual BigInteger ProcessBlock(
BigInteger input)
{
if (key is RsaPrivateCrtKeyParameters)
diff --git a/crypto/src/crypto/engines/RijndaelEngine.cs b/crypto/src/crypto/engines/RijndaelEngine.cs
index df2e5baea..80f522353 100644
--- a/crypto/src/crypto/engines/RijndaelEngine.cs
+++ b/crypto/src/crypto/engines/RijndaelEngine.cs
@@ -571,7 +571,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -585,43 +585,34 @@ namespace Org.BouncyCastle.Crypto.Engines
throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString());
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Rijndael"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BC / 2;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
- {
throw new InvalidOperationException("Rijndael engine not initialised");
- }
-
- if ((inOff + (BC / 2)) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
- if ((outOff + (BC / 2)) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, (BC / 2), "input buffer too short");
+ Check.OutputLength(output, outOff, (BC / 2), "output buffer too short");
- UnPackBlock(input, inOff);
+ UnPackBlock(input, inOff);
if (forEncryption)
{
@@ -637,11 +628,11 @@ namespace Org.BouncyCastle.Crypto.Engines
return BC / 2;
}
- public void Reset()
+ public virtual void Reset()
{
}
- private void UnPackBlock(
+ private void UnPackBlock(
byte[] bytes,
int off)
{
@@ -743,5 +734,4 @@ namespace Org.BouncyCastle.Crypto.Engines
KeyAddition(rk[0]);
}
}
-
}
diff --git a/crypto/src/crypto/engines/RsaEngine.cs b/crypto/src/crypto/engines/RsaEngine.cs
index 7e6dfb163..4399b4409 100644
--- a/crypto/src/crypto/engines/RsaEngine.cs
+++ b/crypto/src/crypto/engines/RsaEngine.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Engines
{
private RsaCoreEngine core;
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RSA"; }
}
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary RSA key parameters.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an input block.
*/
- public int GetInputBlockSize()
+ public virtual int GetInputBlockSize()
{
return core.GetInputBlockSize();
}
@@ -50,7 +50,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an output block.
*/
- public int GetOutputBlockSize()
+ public virtual int GetOutputBlockSize()
{
return core.GetOutputBlockSize();
}
@@ -64,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return the result of the RSA process.
* @exception DataLengthException the input block is too large.
*/
- public byte[] ProcessBlock(
+ public virtual byte[] ProcessBlock(
byte[] inBuf,
int inOff,
int inLen)
diff --git a/crypto/src/crypto/engines/SEEDEngine.cs b/crypto/src/crypto/engines/SEEDEngine.cs
index efea0f1fe..f615b8476 100644
--- a/crypto/src/crypto/engines/SEEDEngine.cs
+++ b/crypto/src/crypto/engines/SEEDEngine.cs
@@ -168,7 +168,7 @@ namespace Org.BouncyCastle.Crypto.Engines
private int[] wKey;
private bool forEncryption;
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -176,22 +176,22 @@ namespace Org.BouncyCastle.Crypto.Engines
wKey = createWorkingKey(((KeyParameter)parameters).GetKey());
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "SEED"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BlockSize;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] inBuf,
int inOff,
byte[] outBuf,
@@ -199,12 +199,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (wKey == null)
throw new InvalidOperationException("SEED engine not initialised");
- if (inOff + BlockSize > inBuf.Length)
- throw new DataLengthException("input buffer too short");
- if (outOff + BlockSize > outBuf.Length)
- throw new DataLengthException("output buffer too short");
- long l = bytesToLong(inBuf, inOff + 0);
+ Check.DataLength(inBuf, inOff, BlockSize, "input buffer too short");
+ Check.OutputLength(outBuf, outOff, BlockSize, "output buffer too short");
+
+ long l = bytesToLong(inBuf, inOff + 0);
long r = bytesToLong(inBuf, inOff + 8);
if (forEncryption)
@@ -234,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BlockSize;
}
- public void Reset()
+ public virtual void Reset()
{
}
diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index 81884d603..9b27dc7b4 100644
--- a/crypto/src/crypto/engines/Salsa20Engine.cs
+++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -61,7 +61,7 @@ namespace Org.BouncyCastle.Crypto.Engines
this.rounds = rounds;
}
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -108,7 +108,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public byte ReturnByte(
+ public virtual byte ReturnByte(
byte input)
{
if (LimitExceeded())
@@ -136,7 +136,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public void ProcessBytes(
+ public virtual void ProcessBytes(
byte[] inBytes,
int inOff,
int len,
@@ -144,26 +144,15 @@ namespace Org.BouncyCastle.Crypto.Engines
int outOff)
{
if (!initialised)
- {
throw new InvalidOperationException(AlgorithmName + " not initialised");
- }
- if ((inOff + len) > inBytes.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
+ Check.DataLength(inBytes, inOff, len, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, len, "output buffer too short");
- if ((outOff + len) > outBytes.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
-
- if (LimitExceeded((uint)len))
- {
+ if (LimitExceeded((uint)len))
throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
- }
- for (int i = 0; i < len; i++)
+ for (int i = 0; i < len; i++)
{
if (index == 0)
{
@@ -175,7 +164,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public void Reset()
+ public virtual void Reset()
{
index = 0;
ResetLimitCounter();
diff --git a/crypto/src/crypto/engines/SerpentEngine.cs b/crypto/src/crypto/engines/SerpentEngine.cs
index 92b25acc6..255c204ab 100644
--- a/crypto/src/crypto/engines/SerpentEngine.cs
+++ b/crypto/src/crypto/engines/SerpentEngine.cs
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -48,17 +48,17 @@ namespace Org.BouncyCastle.Crypto.Engines
this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey());
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Serpent"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
@@ -76,7 +76,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception InvalidOperationException if the cipher isn't initialised.
* @return the number of bytes processed and produced.
*/
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -84,12 +84,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (wKey == null)
throw new InvalidOperationException("Serpent not initialised");
- if ((inOff + BLOCK_SIZE) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BLOCK_SIZE) > output.Length)
- throw new DataLengthException("output buffer too short");
- if (encrypting)
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
@@ -101,7 +100,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public void Reset()
+ public virtual void Reset()
{
}
@@ -775,5 +774,4 @@ namespace Org.BouncyCastle.Crypto.Engines
X0 = RotateRight(x0, 13);
}
}
-
}
diff --git a/crypto/src/crypto/engines/SkipjackEngine.cs b/crypto/src/crypto/engines/SkipjackEngine.cs
index 3d2a781e6..a45dc9b24 100644
--- a/crypto/src/crypto/engines/SkipjackEngine.cs
+++ b/crypto/src/crypto/engines/SkipjackEngine.cs
@@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -71,22 +71,22 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "SKIPJACK"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
@@ -94,12 +94,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (key1 == null)
throw new InvalidOperationException("SKIPJACK engine not initialised");
- if ((inOff + BLOCK_SIZE) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BLOCK_SIZE) > output.Length)
- throw new DataLengthException("output buffer too short");
- if (encrypting)
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
@@ -111,7 +110,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public void Reset()
+ public virtual void Reset()
{
}
@@ -135,7 +134,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return ((g5 << 8) + g6);
}
- public int EncryptBlock(
+ public virtual int EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
@@ -203,7 +202,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return ((h6 << 8) + h5);
}
- public int DecryptBlock(
+ public virtual int DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
@@ -251,5 +250,4 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
}
-
}
diff --git a/crypto/src/crypto/engines/TEAEngine.cs b/crypto/src/crypto/engines/TEAEngine.cs
index 582dd0f73..2e1a7002b 100644
--- a/crypto/src/crypto/engines/TEAEngine.cs
+++ b/crypto/src/crypto/engines/TEAEngine.cs
@@ -36,17 +36,17 @@ namespace Org.BouncyCastle.Crypto.Engines
_initialised = false;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "TEA"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return block_size;
}
@@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the params argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -77,7 +77,7 @@ namespace Org.BouncyCastle.Crypto.Engines
setKey(p.GetKey());
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] inBytes,
int inOff,
byte[] outBytes,
@@ -86,18 +86,15 @@ namespace Org.BouncyCastle.Crypto.Engines
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
- if ((inOff + block_size) > inBytes.Length)
- throw new DataLengthException("input buffer too short");
+ Check.DataLength(inBytes, inOff, block_size, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, block_size, "output buffer too short");
- if ((outOff + block_size) > outBytes.Length)
- throw new DataLengthException("output buffer too short");
-
- return _forEncryption
+ return _forEncryption
? encryptBlock(inBytes, inOff, outBytes, outOff)
: decryptBlock(inBytes, inOff, outBytes, outOff);
}
- public void Reset()
+ public virtual void Reset()
{
}
diff --git a/crypto/src/crypto/engines/ThreefishEngine.cs b/crypto/src/crypto/engines/ThreefishEngine.cs
index 954470345..33ff3a421 100644
--- a/crypto/src/crypto/engines/ThreefishEngine.cs
+++ b/crypto/src/crypto/engines/ThreefishEngine.cs
@@ -155,7 +155,7 @@ namespace Org.BouncyCastle.Crypto.Engines
/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
/// <param name="parameters">an instance of <see cref="TweakableBlockCipherParameters"/> or <see cref="KeyParameter"/> (to
/// use a 0 tweak)</param>
- public void Init(bool forEncryption, ICipherParameters parameters)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
byte[] keyBytes;
byte[] tweakBytes;
@@ -266,26 +266,26 @@ namespace Org.BouncyCastle.Crypto.Engines
t[4] = t[1];
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Threefish-" + (blocksizeBytes * 8); }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return blocksizeBytes;
}
- public void Reset()
+ public virtual void Reset()
{
}
- public int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+ public virtual int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
if ((outOff + blocksizeBytes) > outBytes.Length)
{
diff --git a/crypto/src/crypto/engines/TwofishEngine.cs b/crypto/src/crypto/engines/TwofishEngine.cs
index b983d9d31..04a579ced 100644
--- a/crypto/src/crypto/engines/TwofishEngine.cs
+++ b/crypto/src/crypto/engines/TwofishEngine.cs
@@ -293,12 +293,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (workingKey == null)
throw new InvalidOperationException("Twofish not initialised");
- if ((inOff + BLOCK_SIZE) > input.Length)
- throw new DataLengthException("input buffer too short");
- if ((outOff + BLOCK_SIZE) > output.Length)
- throw new DataLengthException("output buffer too short");
- if (encrypting)
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
diff --git a/crypto/src/crypto/engines/VMPCEngine.cs b/crypto/src/crypto/engines/VMPCEngine.cs
index 1c2802a80..852901e36 100644
--- a/crypto/src/crypto/engines/VMPCEngine.cs
+++ b/crypto/src/crypto/engines/VMPCEngine.cs
@@ -92,15 +92,8 @@ namespace Org.BouncyCastle.Crypto.Engines
byte[] output,
int outOff)
{
- if ((inOff + len) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + len) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
for (int i = 0; i < len; i++)
{
diff --git a/crypto/src/crypto/engines/XSalsa20Engine.cs b/crypto/src/crypto/engines/XSalsa20Engine.cs
index fc6630905..2898b46c8 100644
--- a/crypto/src/crypto/engines/XSalsa20Engine.cs
+++ b/crypto/src/crypto/engines/XSalsa20Engine.cs
@@ -13,7 +13,6 @@ namespace Org.BouncyCastle.Crypto.Engines
public class XSalsa20Engine
: Salsa20Engine
{
-
public override string AlgorithmName
{
get { return "XSalsa20"; }
@@ -65,7 +64,6 @@ namespace Org.BouncyCastle.Crypto.Engines
// Counter reset
ResetCounter();
}
-
}
}
diff --git a/crypto/src/crypto/engines/XTEAEngine.cs b/crypto/src/crypto/engines/XTEAEngine.cs
index eb9291775..40d81fbe6 100644
--- a/crypto/src/crypto/engines/XTEAEngine.cs
+++ b/crypto/src/crypto/engines/XTEAEngine.cs
@@ -34,17 +34,17 @@ namespace Org.BouncyCastle.Crypto.Engines
_initialised = false;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "XTEA"; }
}
- public bool IsPartialBlockOkay
+ public virtual bool IsPartialBlockOkay
{
get { return false; }
}
- public int GetBlockSize()
+ public virtual int GetBlockSize()
{
return block_size;
}
@@ -57,7 +57,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the params argument is
* inappropriate.
*/
- public void Init(
+ public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
@@ -75,7 +75,7 @@ namespace Org.BouncyCastle.Crypto.Engines
setKey(p.GetKey());
}
- public int ProcessBlock(
+ public virtual int ProcessBlock(
byte[] inBytes,
int inOff,
byte[] outBytes,
@@ -84,18 +84,15 @@ namespace Org.BouncyCastle.Crypto.Engines
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
- if ((inOff + block_size) > inBytes.Length)
- throw new DataLengthException("input buffer too short");
+ Check.DataLength(inBytes, inOff, block_size, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, block_size, "output buffer too short");
- if ((outOff + block_size) > outBytes.Length)
- throw new DataLengthException("output buffer too short");
-
- return _forEncryption
+ return _forEncryption
? encryptBlock(inBytes, inOff, outBytes, outOff)
: decryptBlock(inBytes, inOff, outBytes, outOff);
}
- public void Reset()
+ public virtual void Reset()
{
}
diff --git a/crypto/src/crypto/generators/DHKeyGeneratorHelper.cs b/crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
index d05c51e80..68aba64f7 100644
--- a/crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
+++ b/crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
@@ -23,7 +24,15 @@ namespace Org.BouncyCastle.Crypto.Generators
if (limit != 0)
{
- return new BigInteger(limit, random).SetBit(limit - 1);
+ int minWeight = limit >> 2;
+ for (;;)
+ {
+ BigInteger x = new BigInteger(limit, random).SetBit(limit - 1);
+ if (WNafUtilities.GetNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
}
BigInteger min = BigInteger.Two;
@@ -40,7 +49,17 @@ namespace Org.BouncyCastle.Crypto.Generators
}
BigInteger max = q.Subtract(BigInteger.Two);
- return BigIntegers.CreateRandomInRange(min, max, random);
+ {
+ int minWeight = max.BitLength >> 2;
+ for (;;)
+ {
+ BigInteger x = BigIntegers.CreateRandomInRange(min, max, random);
+ if (WNafUtilities.GetNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
+ }
}
internal BigInteger CalculatePublic(
diff --git a/crypto/src/crypto/generators/DsaKeyPairGenerator.cs b/crypto/src/crypto/generators/DsaKeyPairGenerator.cs
index bb8ec591b..1c9ce5a16 100644
--- a/crypto/src/crypto/generators/DsaKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/DsaKeyPairGenerator.cs
@@ -1,8 +1,10 @@
using System;
-using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Security;
+
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Generators
@@ -11,51 +13,60 @@ namespace Org.BouncyCastle.Crypto.Generators
* a DSA key pair generator.
*
* This Generates DSA keys in line with the method described
- * in <i>FIPS 186-3 B.1 FFC Key Pair Generation</i>.
+ * in <i>FIPS 186-3 B.1 FFC Key Pair Generation</i>.
*/
public class DsaKeyPairGenerator
- : IAsymmetricCipherKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
{
+ private static readonly BigInteger One = BigInteger.One;
+
private DsaKeyGenerationParameters param;
- public void Init(
- KeyGenerationParameters parameters)
+ public void Init(
+ KeyGenerationParameters parameters)
{
- if (parameters == null)
- throw new ArgumentNullException("parameters");
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
- // Note: If we start accepting instances of KeyGenerationParameters,
- // must apply constraint checking on strength (see DsaParametersGenerator.Init)
+ // Note: If we start accepting instances of KeyGenerationParameters,
+ // must apply constraint checking on strength (see DsaParametersGenerator.Init)
- this.param = (DsaKeyGenerationParameters) parameters;
+ this.param = (DsaKeyGenerationParameters) parameters;
}
- public AsymmetricCipherKeyPair GenerateKeyPair()
+ public AsymmetricCipherKeyPair GenerateKeyPair()
{
- DsaParameters dsaParams = param.Parameters;
+ DsaParameters dsaParams = param.Parameters;
- BigInteger x = GeneratePrivateKey(dsaParams.Q, param.Random);
- BigInteger y = CalculatePublicKey(dsaParams.P, dsaParams.G, x);
+ BigInteger x = GeneratePrivateKey(dsaParams.Q, param.Random);
+ BigInteger y = CalculatePublicKey(dsaParams.P, dsaParams.G, x);
- return new AsymmetricCipherKeyPair(
- new DsaPublicKeyParameters(y, dsaParams),
- new DsaPrivateKeyParameters(x, dsaParams));
+ return new AsymmetricCipherKeyPair(
+ new DsaPublicKeyParameters(y, dsaParams),
+ new DsaPrivateKeyParameters(x, dsaParams));
}
- private static BigInteger GeneratePrivateKey(BigInteger q, SecureRandom random)
- {
- // TODO Prefer this method? (change test cases that used fixed random)
- // B.1.1 Key Pair Generation Using Extra Random Bits
-// BigInteger c = new BigInteger(q.BitLength + 64, random);
-// return c.Mod(q.Subtract(BigInteger.One)).Add(BigInteger.One);
-
- // B.1.2 Key Pair Generation by Testing Candidates
- return BigIntegers.CreateRandomInRange(BigInteger.One, q.Subtract(BigInteger.One), random);
- }
-
- private static BigInteger CalculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
- {
- return g.ModPow(x, p);
- }
- }
+ private static BigInteger GeneratePrivateKey(BigInteger q, SecureRandom random)
+ {
+ // B.1.2 Key Pair Generation by Testing Candidates
+ int minWeight = q.BitLength >> 2;
+ for (;;)
+ {
+ // TODO Prefer this method? (change test cases that used fixed random)
+ // B.1.1 Key Pair Generation Using Extra Random Bits
+ //BigInteger x = new BigInteger(q.BitLength + 64, random).Mod(q.Subtract(One)).Add(One);
+
+ BigInteger x = BigIntegers.CreateRandomInRange(One, q.Subtract(One), random);
+ if (WNafUtilities.GetNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
+ }
+
+ private static BigInteger CalculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
+ {
+ return g.ModPow(x, p);
+ }
+ }
}
diff --git a/crypto/src/crypto/generators/DsaParametersGenerator.cs b/crypto/src/crypto/generators/DsaParametersGenerator.cs
index cf6343a16..d7ae3ec54 100644
--- a/crypto/src/crypto/generators/DsaParametersGenerator.cs
+++ b/crypto/src/crypto/generators/DsaParametersGenerator.cs
@@ -31,13 +31,11 @@ namespace Org.BouncyCastle.Crypto.Generators
this.digest = digest;
}
- /**
- * initialise the key generator.
- *
- * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
- * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
- * @param random random byte source.
- */
+ /// <summary>Initialise the generator</summary>
+ /// <remarks>This form can only be used for older DSA (pre-DSA2) parameters</remarks>
+ /// <param name="size">the size of keys in bits (from 512 up to 1024, and a multiple of 64)</param>
+ /// <param name="certainty">measure of robustness of primes (at least 80 for FIPS 186-2 compliance)</param>
+ /// <param name="random">the source of randomness to use</param>
public virtual void Init(
int size,
int certainty,
@@ -53,14 +51,9 @@ namespace Org.BouncyCastle.Crypto.Generators
this.random = random;
}
- /**
- * Initialise the key generator for DSA 2.
- * <p>
- * Use this init method if you need to generate parameters for DSA 2 keys.
- * </p>
- *
- * @param params DSA 2 key generation parameters.
- */
+ /// <summary>Initialise the generator for DSA 2</summary>
+ /// <remarks>You must use this Init method if you need to generate parameters for DSA 2 keys</remarks>
+ /// <param name="parameters">An instance of <c>DsaParameterGenerationParameters</c> used to configure this generator</param>
public virtual void Init(DsaParameterGenerationParameters parameters)
{
// TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1?
@@ -84,35 +77,8 @@ namespace Org.BouncyCastle.Crypto.Generators
throw new InvalidOperationException("Digest output size too small for value of N");
}
-// /**
-// * add value to b, returning the result in a. The a value is treated
-// * as a BigInteger of length (a.Length * 8) bits. The result is
-// * modulo 2^a.Length in case of overflow.
-// */
-// private static void Add(
-// byte[] a,
-// byte[] b,
-// int value)
-// {
-// int x = (b[b.Length - 1] & 0xff) + value;
-//
-// a[b.Length - 1] = (byte)x;
-// x = (int) ((uint) x >>8);
-//
-// for (int i = b.Length - 2; i >= 0; i--)
-// {
-// x += (b[i] & 0xff);
-// a[i] = (byte)x;
-// x = (int) ((uint) x >>8);
-// }
-// }
-
- /**
- * which Generates the p and g values from the given parameters,
- * returning the DsaParameters object.
- * <p>
- * Note: can take a while...</p>
- */
+ /// <summary>Generates a set of <c>DsaParameters</c></summary>
+ /// <remarks>Can take a while...</remarks>
public virtual DsaParameters GenerateParameters()
{
return use186_3
@@ -242,8 +208,7 @@ namespace Org.BouncyCastle.Crypto.Generators
BigInteger U = new BigInteger(1, output).Mod(BigInteger.One.ShiftLeft(N - 1));
// 7. q = 2^(N–1) + U + 1 – ( U mod 2).
- BigInteger q = BigInteger.One.ShiftLeft(N - 1).Add(U).Add(BigInteger.One).Subtract(
- U.Mod(BigInteger.Two));
+ BigInteger q = U.SetBit(0).SetBit(N - 1);
// 8. Test whether or not q is prime as specified in Appendix C.3.
// TODO Review C.3 for primality checking
diff --git a/crypto/src/crypto/generators/ECKeyPairGenerator.cs b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
index 6e777c74c..d4afff750 100644
--- a/crypto/src/crypto/generators/ECKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -78,6 +78,7 @@ namespace Org.BouncyCastle.Crypto.Generators
X9ECParameters ecps = FindECCurveByOid(oid);
+ this.publicKeyParamSet = oid;
this.parameters = new ECDomainParameters(
ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
}
diff --git a/crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs b/crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
index 5878da64b..013b81810 100644
--- a/crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
@@ -3,71 +3,86 @@ using System;
using Org.BouncyCastle.Asn1.CryptoPro;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Generators
{
- /**
- * a GOST3410 key pair generator.
- * This generates GOST3410 keys in line with the method described
- * in GOST R 34.10-94.
- */
- public class Gost3410KeyPairGenerator
- : IAsymmetricCipherKeyPairGenerator
- {
- private Gost3410KeyGenerationParameters param;
+ /**
+ * a GOST3410 key pair generator.
+ * This generates GOST3410 keys in line with the method described
+ * in GOST R 34.10-94.
+ */
+ public class Gost3410KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private Gost3410KeyGenerationParameters param;
- public void Init(
- KeyGenerationParameters parameters)
- {
- if (parameters is Gost3410KeyGenerationParameters)
- {
- this.param = (Gost3410KeyGenerationParameters) parameters;
- }
- else
- {
- Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters(
- parameters.Random,
- CryptoProObjectIdentifiers.GostR3410x94CryptoProA);
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is Gost3410KeyGenerationParameters)
+ {
+ this.param = (Gost3410KeyGenerationParameters) parameters;
+ }
+ else
+ {
+ Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters(
+ parameters.Random,
+ CryptoProObjectIdentifiers.GostR3410x94CryptoProA);
- if (parameters.Strength != kgp.Parameters.P.BitLength - 1)
- {
- // TODO Should we complain?
- }
+ if (parameters.Strength != kgp.Parameters.P.BitLength - 1)
+ {
+ // TODO Should we complain?
+ }
- this.param = kgp;
- }
- }
+ this.param = kgp;
+ }
+ }
- public AsymmetricCipherKeyPair GenerateKeyPair()
- {
- SecureRandom random = param.Random;
- Gost3410Parameters gost3410Params = param.Parameters;
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ SecureRandom random = param.Random;
+ Gost3410Parameters gost3410Params = param.Parameters;
- BigInteger q = gost3410Params.Q;
- BigInteger x;
- do
- {
- x = new BigInteger(256, random);
- }
- while (x.SignValue < 1 || x.CompareTo(q) >= 0);
+ BigInteger q = gost3410Params.Q, x;
- BigInteger p = gost3410Params.P;
- BigInteger a = gost3410Params.A;
+ int minWeight = 64;
+ for (;;)
+ {
+ x = new BigInteger(256, random);
- // calculate the public key.
- BigInteger y = a.ModPow(x, p);
+ if (x.SignValue < 1 || x.CompareTo(q) >= 0)
+ continue;
- if (param.PublicKeyParamSet != null)
- {
- return new AsymmetricCipherKeyPair(
- new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet),
- new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet));
- }
+ /*
+ * Require a minimum weight of the NAF representation, since low-weight primes may be
+ * weak against a version of the number-field-sieve for the discrete-logarithm-problem.
+ *
+ * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+ */
+ if (WNafUtilities.GetNafWeight(x) < minWeight)
+ continue;
- return new AsymmetricCipherKeyPair(
- new Gost3410PublicKeyParameters(y, gost3410Params),
- new Gost3410PrivateKeyParameters(x, gost3410Params));
- }
- }
+ break;
+ }
+
+ BigInteger p = gost3410Params.P;
+ BigInteger a = gost3410Params.A;
+
+ // calculate the public key.
+ BigInteger y = a.ModPow(x, p);
+
+ if (param.PublicKeyParamSet != null)
+ {
+ return new AsymmetricCipherKeyPair(
+ new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet),
+ new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet));
+ }
+
+ return new AsymmetricCipherKeyPair(
+ new Gost3410PublicKeyParameters(y, gost3410Params),
+ new Gost3410PrivateKeyParameters(x, gost3410Params));
+ }
+ }
}
diff --git a/crypto/src/crypto/generators/RsaKeyPairGenerator.cs b/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
index e870f1c08..2613b902b 100644
--- a/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
@@ -4,6 +4,7 @@ using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Generators
{
@@ -11,117 +12,127 @@ namespace Org.BouncyCastle.Crypto.Generators
* an RSA key pair generator.
*/
public class RsaKeyPairGenerator
- : IAsymmetricCipherKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
{
- private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
- private const int DefaultTests = 12;
+ private static readonly int[] SPECIAL_E_VALUES = new int[]{ 3, 5, 17, 257, 65537 };
+ private static readonly int SPECIAL_E_HIGHEST = SPECIAL_E_VALUES[SPECIAL_E_VALUES.Length - 1];
+ private static readonly int SPECIAL_E_BITS = BigInteger.ValueOf(SPECIAL_E_HIGHEST).BitLength;
- private RsaKeyGenerationParameters param;
+ protected static readonly BigInteger One = BigInteger.One;
+ protected static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
+ protected const int DefaultTests = 100;
- public void Init(
+ protected RsaKeyGenerationParameters parameters;
+
+ public virtual void Init(
KeyGenerationParameters parameters)
{
if (parameters is RsaKeyGenerationParameters)
{
- this.param = (RsaKeyGenerationParameters)parameters;
+ this.parameters = (RsaKeyGenerationParameters)parameters;
}
else
{
- this.param = new RsaKeyGenerationParameters(
+ this.parameters = new RsaKeyGenerationParameters(
DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
}
}
- public AsymmetricCipherKeyPair GenerateKeyPair()
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
{
- BigInteger p, q, n, d, e, pSub1, qSub1, phi;
-
- //
- // p and q values should have a length of half the strength in bits
- //
- int strength = param.Strength;
- int qBitlength = strength >> 1;
- int pBitlength = strength - qBitlength;
- int mindiffbits = strength / 3;
- int minWeight = strength >> 2;
-
- e = param.PublicExponent;
-
- // TODO Consider generating safe primes for p, q (see DHParametersHelper.GenerateSafePrimes)
- // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
-
- p = ChooseRandomPrime(pBitlength, e);
-
- //
- // Generate a modulus of the required length
- //
for (;;)
{
- q = ChooseRandomPrime(qBitlength, e);
+ //
+ // p and q values should have a length of half the strength in bits
+ //
+ int strength = parameters.Strength;
+ int pBitlength = (strength + 1) / 2;
+ int qBitlength = strength - pBitlength;
+ int mindiffbits = strength / 3;
+ int minWeight = strength >> 2;
- // p and q should not be too close together (or equal!)
- BigInteger diff = q.Subtract(p).Abs();
- if (diff.BitLength < mindiffbits)
- continue;
+ BigInteger e = parameters.PublicExponent;
+
+ // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
+ // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
+
+ BigInteger p = ChooseRandomPrime(pBitlength, e);
+ BigInteger q, n;
//
- // calculate the modulus
+ // generate a modulus of the required length
//
- n = p.Multiply(q);
-
- if (n.BitLength != strength)
+ for (;;)
{
+ q = ChooseRandomPrime(qBitlength, e);
+
+ // p and q should not be too close together (or equal!)
+ BigInteger diff = q.Subtract(p).Abs();
+ if (diff.BitLength < mindiffbits)
+ continue;
+
//
- // if we get here our primes aren't big enough, make the largest
- // of the two p and try again
+ // calculate the modulus
//
- p = p.Max(q);
- continue;
+ n = p.Multiply(q);
+
+ if (n.BitLength != strength)
+ {
+ //
+ // if we get here our primes aren't big enough, make the largest
+ // of the two p and try again
+ //
+ p = p.Max(q);
+ continue;
+ }
+
+ /*
+ * Require a minimum weight of the NAF representation, since low-weight composites may
+ * be weak against a version of the number-field-sieve for factoring.
+ *
+ * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+ */
+ if (WNafUtilities.GetNafWeight(n) < minWeight)
+ {
+ p = ChooseRandomPrime(pBitlength, e);
+ continue;
+ }
+
+ break;
}
- /*
- * Require a minimum weight of the NAF representation, since low-weight composites may
- * be weak against a version of the number-field-sieve for factoring.
- *
- * See "The number field sieve for integers of low weight", Oliver Schirokauer.
- */
- if (WNafUtilities.GetNafWeight(n) < minWeight)
+ if (p.CompareTo(q) < 0)
{
- p = ChooseRandomPrime(pBitlength, e);
- continue;
+ BigInteger tmp = p;
+ p = q;
+ q = tmp;
}
- break;
- }
-
- if (p.CompareTo(q) < 0)
- {
- phi = p;
- p = q;
- q = phi;
- }
-
- pSub1 = p.Subtract(BigInteger.One);
- qSub1 = q.Subtract(BigInteger.One);
- phi = pSub1.Multiply(qSub1);
+ BigInteger pSub1 = p.Subtract(One);
+ BigInteger qSub1 = q.Subtract(One);
+ //BigInteger phi = pSub1.Multiply(qSub1);
+ BigInteger gcd = pSub1.Gcd(qSub1);
+ BigInteger lcm = pSub1.Divide(gcd).Multiply(qSub1);
- //
- // calculate the private exponent
- //
- d = e.ModInverse(phi);
+ //
+ // calculate the private exponent
+ //
+ BigInteger d = e.ModInverse(lcm);
- //
- // calculate the CRT factors
- //
- BigInteger dP, dQ, qInv;
+ if (d.BitLength <= qBitlength)
+ continue;
- dP = d.Remainder(pSub1);
- dQ = d.Remainder(qSub1);
- qInv = q.ModInverse(p);
+ //
+ // calculate the CRT factors
+ //
+ BigInteger dP = d.Remainder(pSub1);
+ BigInteger dQ = d.Remainder(qSub1);
+ BigInteger qInv = q.ModInverse(p);
- return new AsymmetricCipherKeyPair(
- new RsaKeyParameters(false, n, e),
- new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ return new AsymmetricCipherKeyPair(
+ new RsaKeyParameters(false, n, e),
+ new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ }
}
/// <summary>Choose a random prime value for use with RSA</summary>
@@ -130,17 +141,19 @@ namespace Org.BouncyCastle.Crypto.Generators
/// <returns>a prime p, with (p-1) relatively prime to e</returns>
protected virtual BigInteger ChooseRandomPrime(int bitlength, BigInteger e)
{
+ bool eIsKnownOddPrime = (e.BitLength <= SPECIAL_E_BITS) && Arrays.Contains(SPECIAL_E_VALUES, e.IntValue);
+
for (;;)
{
- BigInteger p = new BigInteger(bitlength, 1, param.Random);
+ BigInteger p = new BigInteger(bitlength, 1, parameters.Random);
- if (p.Mod(e).Equals(BigInteger.One))
+ if (p.Mod(e).Equals(One))
continue;
- if (!p.IsProbablePrime(param.Certainty))
+ if (!p.IsProbablePrime(parameters.Certainty))
continue;
- if (!e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One))
+ if (!eIsKnownOddPrime && !e.Gcd(p.Subtract(One)).Equals(One))
continue;
return p;
diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs
index eb340ddbc..f2c3990c6 100644
--- a/crypto/src/crypto/macs/GMac.cs
+++ b/crypto/src/crypto/macs/GMac.cs
@@ -8,104 +8,105 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Macs
{
- /// <summary>
- /// The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication
- /// 800-38D.
- /// </summary>
- /// <remarks>
- /// GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac
- /// is processed as additional authenticated data with the underlying GCM block cipher).
- /// </remarks>
- public class GMac
- : IMac
- {
- private readonly GcmBlockCipher cipher;
- private readonly int macSizeBits;
+ /// <summary>
+ /// The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication
+ /// 800-38D.
+ /// </summary>
+ /// <remarks>
+ /// GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac
+ /// is processed as additional authenticated data with the underlying GCM block cipher).
+ /// </remarks>
+ public class GMac
+ : IMac
+ {
+ private readonly GcmBlockCipher cipher;
+ private readonly int macSizeBits;
- /// <summary>
- /// Creates a GMAC based on the operation of a block cipher in GCM mode.
- /// </summary>
- /// <remarks>
- /// This will produce an authentication code the length of the block size of the cipher.
- /// </remarks>
- /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
- public GMac(GcmBlockCipher cipher)
- : this(cipher, 128)
- {
- }
+ /// <summary>
+ /// Creates a GMAC based on the operation of a block cipher in GCM mode.
+ /// </summary>
+ /// <remarks>
+ /// This will produce an authentication code the length of the block size of the cipher.
+ /// </remarks>
+ /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
+ public GMac(GcmBlockCipher cipher)
+ : this(cipher, 128)
+ {
+ }
- /// <summary>
- /// Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode.
- /// </summary>
- /// <remarks>
- /// This will produce an authentication code the length of the block size of the cipher.
- /// </remarks>
- /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
- /// <param name="macSizeBits">the mac size to generate, in bits. Must be a multiple of 8, between 96 and 128 (inclusive).</param>
- public GMac(GcmBlockCipher cipher, int macSizeBits)
- {
- this.cipher = cipher;
- this.macSizeBits = macSizeBits;
- }
+ /// <summary>
+ /// Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode.
+ /// </summary>
+ /// <remarks>
+ /// This will produce an authentication code the length of the block size of the cipher.
+ /// </remarks>
+ /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
+ /// <param name="macSizeBits">the mac size to generate, in bits. Must be a multiple of 8, between 32 and 128 (inclusive).
+ /// Sizes less than 96 are not recommended, but are supported for specialized applications.</param>
+ public GMac(GcmBlockCipher cipher, int macSizeBits)
+ {
+ this.cipher = cipher;
+ this.macSizeBits = macSizeBits;
+ }
- /// <summary>
- /// Initialises the GMAC - requires a <see cref="Org.BouncyCastle.Crypto.Parameters.ParametersWithIV"/>
- /// providing a <see cref="Org.BouncyCastle.Crypto.Parameters.KeyParameter"/> and a nonce.
- /// </summary>
- public void Init(ICipherParameters parameters)
- {
- if (parameters is ParametersWithIV)
- {
- ParametersWithIV param = (ParametersWithIV)parameters;
+ /// <summary>
+ /// Initialises the GMAC - requires a <see cref="Org.BouncyCastle.Crypto.Parameters.ParametersWithIV"/>
+ /// providing a <see cref="Org.BouncyCastle.Crypto.Parameters.KeyParameter"/> and a nonce.
+ /// </summary>
+ public void Init(ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)parameters;
- byte[] iv = param.GetIV();
- KeyParameter keyParam = (KeyParameter)param.Parameters;
+ byte[] iv = param.GetIV();
+ KeyParameter keyParam = (KeyParameter)param.Parameters;
- // GCM is always operated in encrypt mode to calculate MAC
- cipher.Init(true, new AeadParameters(keyParam, macSizeBits, iv));
- }
- else
- {
- throw new ArgumentException("GMAC requires ParametersWithIV");
- }
- }
+ // GCM is always operated in encrypt mode to calculate MAC
+ cipher.Init(true, new AeadParameters(keyParam, macSizeBits, iv));
+ }
+ else
+ {
+ throw new ArgumentException("GMAC requires ParametersWithIV");
+ }
+ }
- public string AlgorithmName
- {
- get { return cipher.GetUnderlyingCipher().AlgorithmName + "-GMAC"; }
- }
+ public string AlgorithmName
+ {
+ get { return cipher.GetUnderlyingCipher().AlgorithmName + "-GMAC"; }
+ }
- public int GetMacSize()
- {
- return macSizeBits / 8;
- }
+ public int GetMacSize()
+ {
+ return macSizeBits / 8;
+ }
- public void Update(byte input)
- {
- cipher.ProcessAadByte(input);
- }
+ public void Update(byte input)
+ {
+ cipher.ProcessAadByte(input);
+ }
- public void BlockUpdate(byte[] input, int inOff, int len)
- {
- cipher.ProcessAadBytes(input, inOff, len);
- }
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ cipher.ProcessAadBytes(input, inOff, len);
+ }
- public int DoFinal(byte[] output, int outOff)
- {
- try
- {
- return cipher.DoFinal(output, outOff);
- }
- catch (InvalidCipherTextException e)
- {
- // Impossible in encrypt mode
- throw new InvalidOperationException(e.ToString());
- }
- }
+ public int DoFinal(byte[] output, int outOff)
+ {
+ try
+ {
+ return cipher.DoFinal(output, outOff);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ // Impossible in encrypt mode
+ throw new InvalidOperationException(e.ToString());
+ }
+ }
- public void Reset()
- {
- cipher.Reset();
- }
- }
+ public void Reset()
+ {
+ cipher.Reset();
+ }
+ }
}
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index 2d453b6ad..1a951ca04 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -7,266 +7,285 @@ using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Macs
{
- /// <summary>
- /// Poly1305 message authentication code, designed by D. J. Bernstein.
- /// </summary>
- /// <remarks>
- /// Poly1305 computes a 128-bit (16 bytes) authenticator, using a 128 bit nonce and a 256 bit key
- /// consisting of a 128 bit key applied to an underlying cipher, and a 128 bit key (with 106
- /// effective key bits) used in the authenticator.
- ///
- /// The polynomial calculation in this implementation is adapted from the public domain <a
- /// href="https://github.com/floodyberry/poly1305-donna">poly1305-donna-unrolled</a> C implementation
- /// by Andrew M (@floodyberry).
- /// </remarks>
- /// <seealso cref="Org.BouncyCastle.Crypto.Generators.Poly1305KeyGenerator"/>
- public class Poly1305
- : IMac
- {
- private const int BLOCK_SIZE = 16;
-
- private readonly IBlockCipher cipher;
-
- private readonly byte[] singleByte = new byte[1];
-
- // Initialised state
-
- /** Polynomial key */
- private uint r0, r1, r2, r3, r4;
-
- /** Precomputed 5 * r[1..4] */
- private uint s1, s2, s3, s4;
-
- /** Encrypted nonce */
- private uint k0, k1, k2, k3;
-
- // Accumulating state
-
- /** Current block of buffered input */
- private byte[] currentBlock = new byte[BLOCK_SIZE];
-
- /** Current offset in input buffer */
- private int currentBlockOffset = 0;
-
- /** Polynomial accumulator */
- private uint h0, h1, h2, h3, h4;
-
- /**
- * Constructs a Poly1305 MAC, using a 128 bit block cipher.
- */
- public Poly1305(IBlockCipher cipher)
- {
- if (cipher.GetBlockSize() != BLOCK_SIZE)
- {
- throw new ArgumentException("Poly1305 requires a 128 bit block cipher.");
- }
- this.cipher = cipher;
- }
-
- /// <summary>
- /// Initialises the Poly1305 MAC.
- /// </summary>
- /// <param name="parameters">a {@link ParametersWithIV} containing a 128 bit nonce and a {@link KeyParameter} with
- /// a 256 bit key complying to the {@link Poly1305KeyGenerator Poly1305 key format}.</param>
- public void Init(ICipherParameters parameters)
- {
- byte[] nonce;
- byte[] key;
- if ((parameters is ParametersWithIV) && ((ParametersWithIV)parameters).Parameters is KeyParameter)
- {
- nonce = ((ParametersWithIV)parameters).GetIV();
- key = ((KeyParameter)((ParametersWithIV)parameters).Parameters).GetKey();
- }
- else
- {
- throw new ArgumentException("Poly1305 requires a key and and IV.");
- }
-
- setKey(key, nonce);
- Reset();
- }
-
- private void setKey(byte[] key, byte[] nonce)
- {
- if (nonce.Length != BLOCK_SIZE)
- {
- throw new ArgumentException("Poly1305 requires a 128 bit IV.");
- }
- Poly1305KeyGenerator.CheckKey(key);
-
- // Extract r portion of key
- uint t0 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 0);
- uint t1 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 4);
- uint t2 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 8);
- uint t3 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 12);
-
- r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6;
- r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12;
- r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18;
- r3 = t2 & 0x3f03fff; t3 >>= 8;
- r4 = t3 & 0x00fffff;
-
- // Precompute multipliers
- s1 = r1 * 5;
- s2 = r2 * 5;
- s3 = r3 * 5;
- s4 = r4 * 5;
-
- // Compute encrypted nonce
- byte[] cipherKey = new byte[BLOCK_SIZE];
- Array.Copy(key, 0, cipherKey, 0, cipherKey.Length);
-
- cipher.Init(true, new KeyParameter(cipherKey));
- cipher.ProcessBlock(nonce, 0, cipherKey, 0);
-
- k0 = Pack.LE_To_UInt32(cipherKey, 0);
- k1 = Pack.LE_To_UInt32(cipherKey, 4);
- k2 = Pack.LE_To_UInt32(cipherKey, 8);
- k3 = Pack.LE_To_UInt32(cipherKey, 12);
- }
-
- public string AlgorithmName
- {
- get { return "Poly1305-" + cipher.AlgorithmName; }
- }
-
- public int GetMacSize()
- {
- return BLOCK_SIZE;
- }
-
- public void Update(byte input)
- {
- singleByte[0] = input;
- BlockUpdate(singleByte, 0, 1);
- }
-
- public void BlockUpdate(byte[] input, int inOff, int len)
- {
- int copied = 0;
- while (len > copied)
- {
- if (currentBlockOffset == BLOCK_SIZE)
- {
- processBlock();
- currentBlockOffset = 0;
- }
-
- int toCopy = System.Math.Min((len - copied), BLOCK_SIZE - currentBlockOffset);
- Array.Copy(input, copied + inOff, currentBlock, currentBlockOffset, toCopy);
- copied += toCopy;
- currentBlockOffset += toCopy;
- }
-
- }
-
- private void processBlock()
- {
- if (currentBlockOffset < BLOCK_SIZE)
- {
- currentBlock[currentBlockOffset] = 1;
- for (int i = currentBlockOffset + 1; i < BLOCK_SIZE; i++)
- {
- currentBlock[i] = 0;
- }
- }
-
- ulong t0 = Pack.LE_To_UInt32(currentBlock, 0);
- ulong t1 = Pack.LE_To_UInt32(currentBlock, 4);
- ulong t2 = Pack.LE_To_UInt32(currentBlock, 8);
- ulong t3 = Pack.LE_To_UInt32(currentBlock, 12);
-
- h0 += (uint)(t0 & 0x3ffffffU);
- h1 += (uint)((((t1 << 32) | t0) >> 26) & 0x3ffffff);
- h2 += (uint)((((t2 << 32) | t1) >> 20) & 0x3ffffff);
- h3 += (uint)((((t3 << 32) | t2) >> 14) & 0x3ffffff);
- h4 += (uint)(t3 >> 8);
-
- if (currentBlockOffset == BLOCK_SIZE)
- {
- h4 += (1 << 24);
- }
-
- ulong tp0 = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1);
- ulong tp1 = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2);
- ulong tp2 = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3);
- ulong tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
- ulong tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
-
- ulong b;
- h0 = (uint)tp0 & 0x3ffffff; b = (tp0 >> 26);
- tp1 += b; h1 = (uint)tp1 & 0x3ffffff; b = (tp1 >> 26);
- tp2 += b; h2 = (uint)tp2 & 0x3ffffff; b = (tp2 >> 26);
- tp3 += b; h3 = (uint)tp3 & 0x3ffffff; b = (tp3 >> 26);
- tp4 += b; h4 = (uint)tp4 & 0x3ffffff; b = (tp4 >> 26);
- h0 += (uint)(b * 5);
- }
-
- public int DoFinal(byte[] output, int outOff)
- {
- if (outOff + BLOCK_SIZE > output.Length)
- {
- throw new DataLengthException("Output buffer is too short.");
- }
-
- if (currentBlockOffset > 0)
- {
- // Process padded block
- processBlock();
- }
-
- ulong f0, f1, f2, f3;
-
- uint b = h0 >> 26;
- h0 = h0 & 0x3ffffff;
- h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff;
- h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff;
- h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff;
- h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff;
- h0 += b * 5;
-
- uint g0, g1, g2, g3, g4;
- g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff;
- g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff;
- g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff;
- g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff;
- g4 = h4 + b - (1 << 26);
-
- b = (g4 >> 31) - 1;
- uint nb = ~b;
- h0 = (h0 & nb) | (g0 & b);
- h1 = (h1 & nb) | (g1 & b);
- h2 = (h2 & nb) | (g2 & b);
- h3 = (h3 & nb) | (g3 & b);
- h4 = (h4 & nb) | (g4 & b);
-
- f0 = ((h0 ) | (h1 << 26)) + (ulong)k0;
- f1 = ((h1 >> 6 ) | (h2 << 20)) + (ulong)k1;
- f2 = ((h2 >> 12) | (h3 << 14)) + (ulong)k2;
- f3 = ((h3 >> 18) | (h4 << 8 )) + (ulong)k3;
-
- Pack.UInt32_To_LE((uint)f0, output, outOff);
- f1 += (f0 >> 32);
- Pack.UInt32_To_LE((uint)f1, output, outOff + 4);
- f2 += (f1 >> 32);
- Pack.UInt32_To_LE((uint)f2, output, outOff + 8);
- f3 += (f2 >> 32);
- Pack.UInt32_To_LE((uint)f3, output, outOff + 12);
-
- Reset();
- return BLOCK_SIZE;
- }
-
- public void Reset()
- {
- currentBlockOffset = 0;
-
- h0 = h1 = h2 = h3 = h4 = 0;
- }
-
- private static ulong mul32x32_64(uint i1, uint i2)
- {
- return ((ulong)i1) * i2;
- }
- }
+ /// <summary>
+ /// Poly1305 message authentication code, designed by D. J. Bernstein.
+ /// </summary>
+ /// <remarks>
+ /// Poly1305 computes a 128-bit (16 bytes) authenticator, using a 128 bit nonce and a 256 bit key
+ /// consisting of a 128 bit key applied to an underlying cipher, and a 128 bit key (with 106
+ /// effective key bits) used in the authenticator.
+ ///
+ /// The polynomial calculation in this implementation is adapted from the public domain <a
+ /// href="https://github.com/floodyberry/poly1305-donna">poly1305-donna-unrolled</a> C implementation
+ /// by Andrew M (@floodyberry).
+ /// </remarks>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Generators.Poly1305KeyGenerator"/>
+ public class Poly1305
+ : IMac
+ {
+ private const int BLOCK_SIZE = 16;
+
+ private readonly IBlockCipher cipher;
+
+ private readonly byte[] singleByte = new byte[1];
+
+ // Initialised state
+
+ /** Polynomial key */
+ private uint r0, r1, r2, r3, r4;
+
+ /** Precomputed 5 * r[1..4] */
+ private uint s1, s2, s3, s4;
+
+ /** Encrypted nonce */
+ private uint k0, k1, k2, k3;
+
+ // Accumulating state
+
+ /** Current block of buffered input */
+ private byte[] currentBlock = new byte[BLOCK_SIZE];
+
+ /** Current offset in input buffer */
+ private int currentBlockOffset = 0;
+
+ /** Polynomial accumulator */
+ private uint h0, h1, h2, h3, h4;
+
+ /**
+ * Constructs a Poly1305 MAC, where the key passed to init() will be used directly.
+ */
+ public Poly1305()
+ {
+ this.cipher = null;
+ }
+
+ /**
+ * Constructs a Poly1305 MAC, using a 128 bit block cipher.
+ */
+ public Poly1305(IBlockCipher cipher)
+ {
+ if (cipher.GetBlockSize() != BLOCK_SIZE)
+ {
+ throw new ArgumentException("Poly1305 requires a 128 bit block cipher.");
+ }
+ this.cipher = cipher;
+ }
+
+ /// <summary>
+ /// Initialises the Poly1305 MAC.
+ /// </summary>
+ /// <param name="parameters">a {@link ParametersWithIV} containing a 128 bit nonce and a {@link KeyParameter} with
+ /// a 256 bit key complying to the {@link Poly1305KeyGenerator Poly1305 key format}.</param>
+ public void Init(ICipherParameters parameters)
+ {
+ byte[] nonce = null;
+
+ if (cipher != null)
+ {
+ if (!(parameters is ParametersWithIV))
+ throw new ArgumentException("Poly1305 requires an IV when used with a block cipher.", "parameters");
+
+ ParametersWithIV ivParams = (ParametersWithIV)parameters;
+ nonce = ivParams.GetIV();
+ parameters = ivParams.Parameters;
+ }
+
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("Poly1305 requires a key.");
+
+ KeyParameter keyParams = (KeyParameter)parameters;
+
+ SetKey(keyParams.GetKey(), nonce);
+
+ Reset();
+ }
+
+ private void SetKey(byte[] key, byte[] nonce)
+ {
+ if (cipher != null && (nonce == null || nonce.Length != BLOCK_SIZE))
+ throw new ArgumentException("Poly1305 requires a 128 bit IV.");
+
+ Poly1305KeyGenerator.CheckKey(key);
+
+ // Extract r portion of key
+ uint t0 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 0);
+ uint t1 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 4);
+ uint t2 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 8);
+ uint t3 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 12);
+
+ r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6;
+ r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12;
+ r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18;
+ r3 = t2 & 0x3f03fff; t3 >>= 8;
+ r4 = t3 & 0x00fffff;
+
+ // Precompute multipliers
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ byte[] kBytes;
+ if (cipher == null)
+ {
+ kBytes = key;
+ }
+ else
+ {
+ // Compute encrypted nonce
+ kBytes = new byte[BLOCK_SIZE];
+ cipher.Init(true, new KeyParameter(key, 0, BLOCK_SIZE));
+ cipher.ProcessBlock(nonce, 0, kBytes, 0);
+ }
+
+ k0 = Pack.LE_To_UInt32(kBytes, 0);
+ k1 = Pack.LE_To_UInt32(kBytes, 4);
+ k2 = Pack.LE_To_UInt32(kBytes, 8);
+ k3 = Pack.LE_To_UInt32(kBytes, 12);
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher == null ? "Poly1305" : "Poly1305-" + cipher.AlgorithmName; }
+ }
+
+ public int GetMacSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public void Update(byte input)
+ {
+ singleByte[0] = input;
+ BlockUpdate(singleByte, 0, 1);
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ int copied = 0;
+ while (len > copied)
+ {
+ if (currentBlockOffset == BLOCK_SIZE)
+ {
+ processBlock();
+ currentBlockOffset = 0;
+ }
+
+ int toCopy = System.Math.Min((len - copied), BLOCK_SIZE - currentBlockOffset);
+ Array.Copy(input, copied + inOff, currentBlock, currentBlockOffset, toCopy);
+ copied += toCopy;
+ currentBlockOffset += toCopy;
+ }
+
+ }
+
+ private void processBlock()
+ {
+ if (currentBlockOffset < BLOCK_SIZE)
+ {
+ currentBlock[currentBlockOffset] = 1;
+ for (int i = currentBlockOffset + 1; i < BLOCK_SIZE; i++)
+ {
+ currentBlock[i] = 0;
+ }
+ }
+
+ ulong t0 = Pack.LE_To_UInt32(currentBlock, 0);
+ ulong t1 = Pack.LE_To_UInt32(currentBlock, 4);
+ ulong t2 = Pack.LE_To_UInt32(currentBlock, 8);
+ ulong t3 = Pack.LE_To_UInt32(currentBlock, 12);
+
+ h0 += (uint)(t0 & 0x3ffffffU);
+ h1 += (uint)((((t1 << 32) | t0) >> 26) & 0x3ffffff);
+ h2 += (uint)((((t2 << 32) | t1) >> 20) & 0x3ffffff);
+ h3 += (uint)((((t3 << 32) | t2) >> 14) & 0x3ffffff);
+ h4 += (uint)(t3 >> 8);
+
+ if (currentBlockOffset == BLOCK_SIZE)
+ {
+ h4 += (1 << 24);
+ }
+
+ ulong tp0 = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1);
+ ulong tp1 = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2);
+ ulong tp2 = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3);
+ ulong tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
+ ulong tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
+
+ ulong b;
+ h0 = (uint)tp0 & 0x3ffffff; b = (tp0 >> 26);
+ tp1 += b; h1 = (uint)tp1 & 0x3ffffff; b = (tp1 >> 26);
+ tp2 += b; h2 = (uint)tp2 & 0x3ffffff; b = (tp2 >> 26);
+ tp3 += b; h3 = (uint)tp3 & 0x3ffffff; b = (tp3 >> 26);
+ tp4 += b; h4 = (uint)tp4 & 0x3ffffff; b = (tp4 >> 26);
+ h0 += (uint)(b * 5);
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (outOff + BLOCK_SIZE > output.Length)
+ {
+ throw new DataLengthException("Output buffer is too short.");
+ }
+
+ if (currentBlockOffset > 0)
+ {
+ // Process padded block
+ processBlock();
+ }
+
+ ulong f0, f1, f2, f3;
+
+ uint b = h0 >> 26;
+ h0 = h0 & 0x3ffffff;
+ h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff;
+ h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff;
+ h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff;
+ h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff;
+ h0 += b * 5;
+
+ uint g0, g1, g2, g3, g4;
+ g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff;
+ g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff;
+ g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff;
+ g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff;
+ g4 = h4 + b - (1 << 26);
+
+ b = (g4 >> 31) - 1;
+ uint nb = ~b;
+ h0 = (h0 & nb) | (g0 & b);
+ h1 = (h1 & nb) | (g1 & b);
+ h2 = (h2 & nb) | (g2 & b);
+ h3 = (h3 & nb) | (g3 & b);
+ h4 = (h4 & nb) | (g4 & b);
+
+ f0 = ((h0 ) | (h1 << 26)) + (ulong)k0;
+ f1 = ((h1 >> 6 ) | (h2 << 20)) + (ulong)k1;
+ f2 = ((h2 >> 12) | (h3 << 14)) + (ulong)k2;
+ f3 = ((h3 >> 18) | (h4 << 8 )) + (ulong)k3;
+
+ Pack.UInt32_To_LE((uint)f0, output, outOff);
+ f1 += (f0 >> 32);
+ Pack.UInt32_To_LE((uint)f1, output, outOff + 4);
+ f2 += (f1 >> 32);
+ Pack.UInt32_To_LE((uint)f2, output, outOff + 8);
+ f3 += (f2 >> 32);
+ Pack.UInt32_To_LE((uint)f3, output, outOff + 12);
+
+ Reset();
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ currentBlockOffset = 0;
+
+ h0 = h1 = h2 = h3 = h4 = 0;
+ }
+
+ private static ulong mul32x32_64(uint i1, uint i2)
+ {
+ return ((ulong)i1) * i2;
+ }
+ }
}
diff --git a/crypto/src/crypto/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index 653d75cb9..19e273d7c 100644
--- a/crypto/src/crypto/modes/CcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -61,6 +61,7 @@ namespace Org.BouncyCastle.Crypto.Modes
{
this.forEncryption = forEncryption;
+ ICipherParameters cipherParameters;
if (parameters is AeadParameters)
{
AeadParameters param = (AeadParameters) parameters;
@@ -68,7 +69,7 @@ namespace Org.BouncyCastle.Crypto.Modes
nonce = param.GetNonce();
initialAssociatedText = param.GetAssociatedText();
macSize = param.MacSize / 8;
- keyParam = param.Key;
+ cipherParameters = param.Key;
}
else if (parameters is ParametersWithIV)
{
@@ -77,17 +78,25 @@ namespace Org.BouncyCastle.Crypto.Modes
nonce = param.GetIV();
initialAssociatedText = null;
macSize = macBlock.Length / 2;
- keyParam = param.Parameters;
+ cipherParameters = param.Parameters;
}
else
{
throw new ArgumentException("invalid parameters passed to CCM");
}
+ // NOTE: Very basic support for key re-use, but no performance gain from it
+ if (cipherParameters != null)
+ {
+ keyParam = cipherParameters;
+ }
+
if (nonce == null || nonce.Length < 7 || nonce.Length > 13)
{
throw new ArgumentException("nonce must have length from 7 to 13 octets");
}
+
+ Reset();
}
public virtual string AlgorithmName
@@ -128,6 +137,8 @@ namespace Org.BouncyCastle.Crypto.Modes
byte[] outBytes,
int outOff)
{
+ Check.DataLength(inBytes, inOff, inLen, "Input buffer too short");
+
data.Write(inBytes, inOff, inLen);
return 0;
@@ -137,13 +148,11 @@ namespace Org.BouncyCastle.Crypto.Modes
byte[] outBytes,
int outOff)
{
- byte[] enc = ProcessPacket(data.GetBuffer(), 0, (int)data.Position);
-
- Array.Copy(enc, 0, outBytes, outOff, enc.Length);
+ int len = ProcessPacket(data.GetBuffer(), 0, (int)data.Position, outBytes, outOff);
Reset();
- return enc.Length;
+ return len;
}
public virtual void Reset()
@@ -161,11 +170,7 @@ namespace Org.BouncyCastle.Crypto.Modes
*/
public virtual byte[] GetMac()
{
- byte[] mac = new byte[macSize];
-
- Array.Copy(macBlock, 0, mac, 0, mac.Length);
-
- return mac;
+ return Arrays.CopyOfRange(macBlock, 0, macSize);
}
public virtual int GetUpdateOutputSize(
@@ -174,7 +179,7 @@ namespace Org.BouncyCastle.Crypto.Modes
return 0;
}
- public int GetOutputSize(
+ public virtual int GetOutputSize(
int len)
{
int totalData = (int)data.Length + len;
@@ -187,10 +192,51 @@ namespace Org.BouncyCastle.Crypto.Modes
return totalData < macSize ? 0 : totalData - macSize;
}
- public byte[] ProcessPacket(
- byte[] input,
- int inOff,
- int inLen)
+ /**
+ * Process a packet of data for either CCM decryption or encryption.
+ *
+ * @param in data for processing.
+ * @param inOff offset at which data starts in the input array.
+ * @param inLen length of the data in the input array.
+ * @return a byte array containing the processed input..
+ * @throws IllegalStateException if the cipher is not appropriately set up.
+ * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+ */
+ public virtual byte[] ProcessPacket(byte[] input, int inOff, int inLen)
+ {
+ byte[] output;
+
+ if (forEncryption)
+ {
+ output = new byte[inLen + macSize];
+ }
+ else
+ {
+ if (inLen < macSize)
+ throw new InvalidCipherTextException("data too short");
+
+ output = new byte[inLen - macSize];
+ }
+
+ ProcessPacket(input, inOff, inLen, output, 0);
+
+ return output;
+ }
+
+ /**
+ * Process a packet of data for either CCM decryption or encryption.
+ *
+ * @param in data for processing.
+ * @param inOff offset at which data starts in the input array.
+ * @param inLen length of the data in the input array.
+ * @param output output array.
+ * @param outOff offset into output array to start putting processed bytes.
+ * @return the number of bytes added to output.
+ * @throws IllegalStateException if the cipher is not appropriately set up.
+ * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+ * @throws DataLengthException if output buffer too short.
+ */
+ public virtual int ProcessPacket(byte[] input, int inOff, int inLen, byte[] output, int outOff)
{
// TODO: handle null keyParam (e.g. via RepeatedKeySpec)
// Need to keep the CTR and CBC Mac parts around and reset
@@ -213,42 +259,46 @@ namespace Org.BouncyCastle.Crypto.Modes
IBlockCipher ctrCipher = new SicBlockCipher(cipher);
ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
- int index = inOff;
- int outOff = 0;
- byte[] output;
+ int outputLen;
+ int inIndex = inOff;
+ int outIndex = outOff;
if (forEncryption)
{
- output = new byte[inLen + macSize];
+ outputLen = inLen + macSize;
+ Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
- calculateMac(input, inOff, inLen, macBlock);
+ CalculateMac(input, inOff, inLen, macBlock);
- ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0); // S0
+ byte[] encMac = new byte[BlockSize];
+ ctrCipher.ProcessBlock(macBlock, 0, encMac, 0); // S0
- while (index < inLen - BlockSize) // S1...
+ while (inIndex < (inOff + inLen - BlockSize)) // S1...
{
- ctrCipher.ProcessBlock(input, index, output, outOff);
- outOff += BlockSize;
- index += BlockSize;
+ ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
+ outIndex += BlockSize;
+ inIndex += BlockSize;
}
byte[] block = new byte[BlockSize];
- Array.Copy(input, index, block, 0, inLen - index);
+ Array.Copy(input, inIndex, block, 0, inLen + inOff - inIndex);
ctrCipher.ProcessBlock(block, 0, block, 0);
- Array.Copy(block, 0, output, outOff, inLen - index);
+ Array.Copy(block, 0, output, outIndex, inLen + inOff - inIndex);
- outOff += inLen - index;
-
- Array.Copy(macBlock, 0, output, outOff, output.Length - outOff);
+ Array.Copy(encMac, 0, output, outOff + inLen, macSize);
}
else
{
- output = new byte[inLen - macSize];
+ if (inLen < macSize)
+ throw new InvalidCipherTextException("data too short");
- Array.Copy(input, inOff + inLen - macSize, macBlock, 0, macSize);
+ outputLen = inLen - macSize;
+ Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
+
+ Array.Copy(input, inOff + outputLen, macBlock, 0, macSize);
ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);
@@ -257,33 +307,33 @@ namespace Org.BouncyCastle.Crypto.Modes
macBlock[i] = 0;
}
- while (outOff < output.Length - BlockSize)
+ while (inIndex < (inOff + outputLen - BlockSize))
{
- ctrCipher.ProcessBlock(input, index, output, outOff);
- outOff += BlockSize;
- index += BlockSize;
+ ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
+ outIndex += BlockSize;
+ inIndex += BlockSize;
}
byte[] block = new byte[BlockSize];
- Array.Copy(input, index, block, 0, output.Length - outOff);
+ Array.Copy(input, inIndex, block, 0, outputLen - (inIndex - inOff));
ctrCipher.ProcessBlock(block, 0, block, 0);
- Array.Copy(block, 0, output, outOff, output.Length - outOff);
+ Array.Copy(block, 0, output, outIndex, outputLen - (inIndex - inOff));
byte[] calculatedMacBlock = new byte[BlockSize];
- calculateMac(output, 0, output.Length, calculatedMacBlock);
+ CalculateMac(output, outOff, outputLen, calculatedMacBlock);
if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
throw new InvalidCipherTextException("mac check in CCM failed");
}
- return output;
+ return outputLen;
}
- private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+ private int CalculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
{
IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
diff --git a/crypto/src/crypto/modes/CtsBlockCipher.cs b/crypto/src/crypto/modes/CtsBlockCipher.cs
index a32b49675..ff37844ab 100644
--- a/crypto/src/crypto/modes/CtsBlockCipher.cs
+++ b/crypto/src/crypto/modes/CtsBlockCipher.cs
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Modes
}
/**
- * process a single byte, producing an output block if neccessary.
+ * process a single byte, producing an output block if necessary.
*
* @param in the input byte.
* @param out the space for any output that might be produced.
diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index 5ccc69b66..624f385b5 100644
--- a/crypto/src/crypto/modes/EAXBlockCipher.cs
+++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -54,7 +54,6 @@ namespace Org.BouncyCastle.Crypto.Modes
blockSize = cipher.GetBlockSize();
mac = new CMac(cipher);
macBlock = new byte[blockSize];
- bufBlock = new byte[blockSize * 2];
associatedTextMac = new byte[mac.GetMacSize()];
nonceMac = new byte[mac.GetMacSize()];
this.cipher = new SicBlockCipher(cipher);
@@ -65,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Modes
get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
}
- public IBlockCipher GetUnderlyingCipher()
+ public virtual IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
@@ -107,6 +106,8 @@ namespace Org.BouncyCastle.Crypto.Modes
throw new ArgumentException("invalid parameters passed to EAX");
}
+ bufBlock = new byte[forEncryption ? blockSize : (blockSize + macSize)];
+
byte[] tag = new byte[blockSize];
// Key reuse implemented in CBC mode of underlying CMac
@@ -117,16 +118,10 @@ namespace Org.BouncyCastle.Crypto.Modes
mac.BlockUpdate(nonce, 0, nonce.Length);
mac.DoFinal(nonceMac, 0);
- tag[blockSize - 1] = (byte)Tag.H;
- mac.BlockUpdate(tag, 0, blockSize);
-
- if (initialAssociatedText != null)
- {
- ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
- }
-
- // Same BlockCipher underlies this and the mac, so reuse last key on cipher
+ // Same BlockCipher underlies this and the mac, so reuse last key on cipher
cipher.Init(true, new ParametersWithIV(null, nonceMac));
+
+ Reset();
}
private void InitCipher()
@@ -191,16 +186,16 @@ namespace Org.BouncyCastle.Crypto.Modes
{
if (cipherInitialized)
{
- throw new InvalidOperationException("AAD data cannot be added after encryption/decription processing has begun.");
+ throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
}
mac.Update(input);
}
- public void ProcessAadBytes(byte[] inBytes, int inOff, int len)
+ public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
{
if (cipherInitialized)
{
- throw new InvalidOperationException("AAD data cannot be added after encryption/decription processing has begun.");
+ throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
}
mac.BlockUpdate(inBytes, inOff, len);
}
@@ -247,10 +242,11 @@ namespace Org.BouncyCastle.Crypto.Modes
if (forEncryption)
{
- cipher.ProcessBlock(bufBlock, 0, tmp, 0);
- cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
+ Check.OutputLength(outBytes, outOff, extra + macSize, "Output buffer too short");
+
+ cipher.ProcessBlock(bufBlock, 0, tmp, 0);
- Array.Copy(tmp, 0, outBytes, outOff, extra);
+ Array.Copy(tmp, 0, outBytes, outOff, extra);
mac.BlockUpdate(tmp, 0, extra);
@@ -264,14 +260,18 @@ namespace Org.BouncyCastle.Crypto.Modes
}
else
{
- if (extra > macSize)
+ if (extra < macSize)
+ throw new InvalidCipherTextException("data too short");
+
+ Check.OutputLength(outBytes, outOff, extra - macSize, "Output buffer too short");
+
+ if (extra > macSize)
{
mac.BlockUpdate(bufBlock, 0, extra - macSize);
cipher.ProcessBlock(bufBlock, 0, tmp, 0);
- cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
- Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
+ Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
}
CalculateMac();
@@ -331,6 +331,11 @@ namespace Org.BouncyCastle.Crypto.Modes
if (bufOff == bufBlock.Length)
{
+ Check.OutputLength(outBytes, outOff, blockSize, "Output buffer is too short");
+
+ // TODO Could move the ProcessByte(s) calls to here
+// InitCipher();
+
int size;
if (forEncryption)
@@ -346,10 +351,14 @@ namespace Org.BouncyCastle.Crypto.Modes
size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
}
- bufOff = blockSize;
- Array.Copy(bufBlock, blockSize, bufBlock, 0, blockSize);
+ bufOff = 0;
+ if (!forEncryption)
+ {
+ Array.Copy(bufBlock, blockSize, bufBlock, 0, macSize);
+ bufOff = macSize;
+ }
- return size;
+ return size;
}
return 0;
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 74b895e7b..8e6120eef 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -8,127 +8,129 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes
{
- /// <summary>
- /// Implements the Galois/Counter mode (GCM) detailed in
- /// NIST Special Publication 800-38D.
- /// </summary>
- public class GcmBlockCipher
- : IAeadBlockCipher
- {
- private const int BlockSize = 16;
+ /// <summary>
+ /// Implements the Galois/Counter mode (GCM) detailed in
+ /// NIST Special Publication 800-38D.
+ /// </summary>
+ public class GcmBlockCipher
+ : IAeadBlockCipher
+ {
+ private const int BlockSize = 16;
private readonly IBlockCipher cipher;
- private readonly IGcmMultiplier multiplier;
+ private readonly IGcmMultiplier multiplier;
private IGcmExponentiator exp;
// These fields are set by Init and not modified by processing
- private bool forEncryption;
- private int macSize;
- private byte[] nonce;
- private byte[] initialAssociatedText;
+ private bool forEncryption;
+ private int macSize;
+ private byte[] nonce;
+ private byte[] initialAssociatedText;
private byte[] H;
- private byte[] J0;
+ private byte[] J0;
// These fields are modified during processing
- private byte[] bufBlock;
- private byte[] macBlock;
+ private byte[] bufBlock;
+ private byte[] macBlock;
private byte[] S, S_at, S_atPre;
- private byte[] counter;
- private int bufOff;
- private ulong totalLength;
+ private byte[] counter;
+ private int bufOff;
+ private ulong totalLength;
private byte[] atBlock;
private int atBlockPos;
private ulong atLength;
private ulong atLengthPre;
public GcmBlockCipher(
- IBlockCipher c)
- : this(c, null)
- {
- }
-
- public GcmBlockCipher(
- IBlockCipher c,
- IGcmMultiplier m)
- {
- if (c.GetBlockSize() != BlockSize)
- throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
-
- if (m == null)
- {
- // TODO Consider a static property specifying default multiplier
- m = new Tables8kGcmMultiplier();
- }
-
- this.cipher = c;
- this.multiplier = m;
- }
-
- public virtual string AlgorithmName
- {
- get { return cipher.AlgorithmName + "/GCM"; }
- }
-
- public IBlockCipher GetUnderlyingCipher()
- {
- return cipher;
- }
-
- public virtual int GetBlockSize()
- {
- return BlockSize;
- }
-
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
- {
- this.forEncryption = forEncryption;
- this.macBlock = null;
+ IBlockCipher c)
+ : this(c, null)
+ {
+ }
+
+ public GcmBlockCipher(
+ IBlockCipher c,
+ IGcmMultiplier m)
+ {
+ if (c.GetBlockSize() != BlockSize)
+ throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
+
+ if (m == null)
+ {
+ // TODO Consider a static property specifying default multiplier
+ m = new Tables8kGcmMultiplier();
+ }
+
+ this.cipher = c;
+ this.multiplier = m;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/GCM"; }
+ }
+
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ /// <remarks>
+ /// MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default is 128 bits.
+ /// Sizes less than 96 are not recommended, but are supported for specialized applications.
+ /// </remarks>
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+ this.macBlock = null;
KeyParameter keyParam;
if (parameters is AeadParameters)
- {
- AeadParameters param = (AeadParameters)parameters;
-
- nonce = param.GetNonce();
- initialAssociatedText = param.GetAssociatedText();
-
- int macSizeBits = param.MacSize;
- if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0)
- {
- throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
- }
-
- macSize = macSizeBits / 8;
- keyParam = param.Key;
- }
- else if (parameters is ParametersWithIV)
- {
- ParametersWithIV param = (ParametersWithIV)parameters;
-
- nonce = param.GetIV();
+ {
+ AeadParameters param = (AeadParameters)parameters;
+
+ nonce = param.GetNonce();
+ initialAssociatedText = param.GetAssociatedText();
+
+ int macSizeBits = param.MacSize;
+ if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
+ {
+ throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
+ }
+
+ macSize = macSizeBits / 8;
+ keyParam = param.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)parameters;
+
+ nonce = param.GetIV();
initialAssociatedText = null;
- macSize = 16;
- keyParam = (KeyParameter)param.Parameters;
- }
- else
- {
- throw new ArgumentException("invalid parameters passed to GCM");
- }
-
- int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
- this.bufBlock = new byte[bufLength];
-
- if (nonce == null || nonce.Length < 1)
- {
- throw new ArgumentException("IV must be at least 1 byte");
- }
-
- // TODO This should be configurable by Init parameters
- // (but must be 16 if nonce length not 12) (BlockSize?)
-// this.tagLength = 16;
+ macSize = 16;
+ keyParam = (KeyParameter)param.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameters passed to GCM");
+ }
+
+ int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
+ this.bufBlock = new byte[bufLength];
+
+ if (nonce == null || nonce.Length < 1)
+ {
+ throw new ArgumentException("IV must be at least 1 byte");
+ }
+
+ // TODO Restrict macSize to 16 if nonce length not 12?
// Cipher always used in forward mode
// if keyParam is null we're reusing the last key.
@@ -136,28 +138,32 @@ namespace Org.BouncyCastle.Crypto.Modes
{
cipher.Init(true, keyParam);
- this.H = new byte[BlockSize];
- cipher.ProcessBlock(H, 0, H, 0);
+ this.H = new byte[BlockSize];
+ cipher.ProcessBlock(H, 0, H, 0);
// if keyParam is null we're reusing the last key and the multiplier doesn't need re-init
multiplier.Init(H);
exp = null;
}
+ else if (this.H == null)
+ {
+ throw new ArgumentException("Key must be specified in initial init");
+ }
this.J0 = new byte[BlockSize];
if (nonce.Length == 12)
- {
- Array.Copy(nonce, 0, J0, 0, nonce.Length);
- this.J0[BlockSize - 1] = 0x01;
- }
- else
- {
+ {
+ Array.Copy(nonce, 0, J0, 0, nonce.Length);
+ this.J0[BlockSize - 1] = 0x01;
+ }
+ else
+ {
gHASH(J0, nonce, nonce.Length);
- byte[] X = new byte[BlockSize];
+ byte[] X = new byte[BlockSize];
Pack.UInt64_To_BE((ulong)nonce.Length * 8UL, X, 8);
gHASHBlock(J0, X);
- }
+ }
this.S = new byte[BlockSize];
this.S_at = new byte[BlockSize];
@@ -174,16 +180,16 @@ namespace Org.BouncyCastle.Crypto.Modes
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
- }
+ }
- public virtual byte[] GetMac()
- {
- return Arrays.Clone(macBlock);
- }
+ public virtual byte[] GetMac()
+ {
+ return Arrays.Clone(macBlock);
+ }
- public virtual int GetOutputSize(
- int len)
- {
+ public virtual int GetOutputSize(
+ int len)
+ {
int totalData = len + bufOff;
if (forEncryption)
@@ -192,11 +198,11 @@ namespace Org.BouncyCastle.Crypto.Modes
}
return totalData < macSize ? 0 : totalData - macSize;
- }
+ }
public virtual int GetUpdateOutputSize(
- int len)
- {
+ int len)
+ {
int totalData = len + bufOff;
if (!forEncryption)
{
@@ -207,7 +213,7 @@ namespace Org.BouncyCastle.Crypto.Modes
totalData -= macSize;
}
return totalData - totalData % BlockSize;
- }
+ }
public virtual void ProcessAadByte(byte input)
{
@@ -258,10 +264,10 @@ namespace Org.BouncyCastle.Crypto.Modes
}
public virtual int ProcessByte(
- byte input,
- byte[] output,
- int outOff)
- {
+ byte input,
+ byte[] output,
+ int outOff)
+ {
bufBlock[bufOff] = input;
if (++bufOff == bufBlock.Length)
{
@@ -269,15 +275,18 @@ namespace Org.BouncyCastle.Crypto.Modes
return BlockSize;
}
return 0;
- }
+ }
public virtual int ProcessBytes(
- byte[] input,
- int inOff,
- int len,
- byte[] output,
- int outOff)
- {
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ if (input.Length < (inOff + len))
+ throw new DataLengthException("Input buffer too short");
+
int resultLen = 0;
for (int i = 0; i < len; ++i)
@@ -291,10 +300,11 @@ namespace Org.BouncyCastle.Crypto.Modes
}
return resultLen;
- }
+ }
private void OutputBlock(byte[] output, int offset)
{
+ Check.OutputLength(output, offset, BlockSize, "Output buffer too short");
if (totalLength == 0)
{
InitCipher();
@@ -311,20 +321,27 @@ namespace Org.BouncyCastle.Crypto.Modes
}
}
- public int DoFinal(byte[] output, int outOff)
- {
+ public int DoFinal(byte[] output, int outOff)
+ {
if (totalLength == 0)
{
InitCipher();
}
int extra = bufOff;
- if (!forEncryption)
+
+ if (forEncryption)
+ {
+ Check.OutputLength(output, outOff, extra + macSize, "Output buffer too short");
+ }
+ else
{
if (extra < macSize)
throw new InvalidCipherTextException("data too short");
extra -= macSize;
+
+ Check.OutputLength(output, outOff, extra, "Output buffer too short");
}
if (extra > 0)
@@ -375,52 +392,51 @@ namespace Org.BouncyCastle.Crypto.Modes
}
// Final gHASH
- byte[] X = new byte[BlockSize];
+ byte[] X = new byte[BlockSize];
Pack.UInt64_To_BE(atLength * 8UL, X, 0);
Pack.UInt64_To_BE(totalLength * 8UL, X, 8);
gHASHBlock(S, X);
- // TODO Fix this if tagLength becomes configurable
- // T = MSBt(GCTRk(J0,S))
- byte[] tag = new byte[BlockSize];
- cipher.ProcessBlock(J0, 0, tag, 0);
- GcmUtilities.Xor(tag, S);
-
- int resultLen = extra;
-
- // We place into macBlock our calculated value for T
- this.macBlock = new byte[macSize];
- Array.Copy(tag, 0, macBlock, 0, macSize);
-
- if (forEncryption)
- {
- // Append T to the message
- Array.Copy(macBlock, 0, output, outOff + bufOff, macSize);
- resultLen += macSize;
- }
- else
- {
- // Retrieve the T value from the message and compare to calculated one
- byte[] msgMac = new byte[macSize];
- Array.Copy(bufBlock, extra, msgMac, 0, macSize);
- if (!Arrays.ConstantTimeAreEqual(this.macBlock, msgMac))
- throw new InvalidCipherTextException("mac check in GCM failed");
- }
-
- Reset(false);
-
- return resultLen;
- }
-
- public virtual void Reset()
- {
- Reset(true);
- }
-
- private void Reset(
- bool clearMac)
- {
+ // T = MSBt(GCTRk(J0,S))
+ byte[] tag = new byte[BlockSize];
+ cipher.ProcessBlock(J0, 0, tag, 0);
+ GcmUtilities.Xor(tag, S);
+
+ int resultLen = extra;
+
+ // We place into macBlock our calculated value for T
+ this.macBlock = new byte[macSize];
+ Array.Copy(tag, 0, macBlock, 0, macSize);
+
+ if (forEncryption)
+ {
+ // Append T to the message
+ Array.Copy(macBlock, 0, output, outOff + bufOff, macSize);
+ resultLen += macSize;
+ }
+ else
+ {
+ // Retrieve the T value from the message and compare to calculated one
+ byte[] msgMac = new byte[macSize];
+ Array.Copy(bufBlock, extra, msgMac, 0, macSize);
+ if (!Arrays.ConstantTimeAreEqual(this.macBlock, msgMac))
+ throw new InvalidCipherTextException("mac check in GCM failed");
+ }
+
+ Reset(false);
+
+ return resultLen;
+ }
+
+ public virtual void Reset()
+ {
+ Reset(true);
+ }
+
+ private void Reset(
+ bool clearMac)
+ {
cipher.Reset();
S = new byte[BlockSize];
@@ -448,7 +464,7 @@ namespace Org.BouncyCastle.Crypto.Modes
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
- }
+ }
private void gCTRBlock(byte[] block, byte[] output, int outOff)
{
@@ -507,5 +523,5 @@ namespace Org.BouncyCastle.Crypto.Modes
cipher.ProcessBlock(counter, 0, tmp, 0);
return tmp;
}
- }
+ }
}
diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
index 8fb6f213f..e7dc466e6 100644
--- a/crypto/src/crypto/modes/OCBBlockCipher.cs
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -7,9 +7,8 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes
{
/**
- * An implementation of the "work in progress" Internet-Draft <a
- * href="http://tools.ietf.org/html/draft-irtf-cfrg-ocb-07">The OCB Authenticated-Encryption
- * Algorithm</a>, licensed per:
+ * An implementation of <a href="http://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB
+ * Authenticated-Encryption Algorithm</a>, licensed per:
*
* <blockquote><p><a href="http://www.cs.ucdavis.edu/~rogaway/ocb/license1.pdf">License for
* Open-Source Software Implementations of OCB</a> (Jan 9, 2013) - 'License 1'<br/>
@@ -71,9 +70,8 @@ namespace Org.BouncyCastle.Crypto.Modes
throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "hashCipher");
if (mainCipher == null)
throw new ArgumentNullException("mainCipher");
- if (mainCipher.GetBlockSize() != BLOCK_SIZE) {
+ if (mainCipher.GetBlockSize() != BLOCK_SIZE)
throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "mainCipher");
- }
if (!hashCipher.AlgorithmName.Equals(mainCipher.AlgorithmName))
throw new ArgumentException("'hashCipher' and 'mainCipher' must be the same algorithm");
@@ -94,6 +92,7 @@ namespace Org.BouncyCastle.Crypto.Modes
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
+ bool oldForEncryption = this.forEncryption;
this.forEncryption = forEncryption;
this.macBlock = null;
@@ -145,20 +144,18 @@ namespace Org.BouncyCastle.Crypto.Modes
* KEY-DEPENDENT INITIALISATION
*/
- // if keyParam is null we're reusing the last key.
if (keyParameter != null)
{
- // TODO
+ // hashCipher always used in forward mode
+ hashCipher.Init(true, keyParameter);
+ mainCipher.Init(forEncryption, keyParameter);
+ KtopInput = null;
}
- else
+ else if (oldForEncryption != forEncryption)
{
- KtopInput = null;
+ throw new ArgumentException("cannot change encrypting state without providing key.");
}
- // hashCipher always used in forward mode
- hashCipher.Init(true, keyParameter);
- mainCipher.Init(forEncryption, keyParameter);
-
this.L_Asterisk = new byte[16];
hashCipher.ProcessBlock(L_Asterisk, 0, L_Asterisk, 0);
@@ -358,6 +355,7 @@ namespace Org.BouncyCastle.Crypto.Modes
Xor(mainBlock, Pad);
+ Check.OutputLength(output, outOff, mainBlockPos, "Output buffer too short");
Array.Copy(mainBlock, 0, output, outOff, mainBlockPos);
if (!forEncryption)
@@ -385,6 +383,8 @@ namespace Org.BouncyCastle.Crypto.Modes
if (forEncryption)
{
+ Check.OutputLength(output, outOff, resultLen + macSize, "Output buffer too short");
+
// Append tag to the message
Array.Copy(macBlock, 0, output, outOff + resultLen, macSize);
resultLen += macSize;
@@ -434,6 +434,8 @@ namespace Org.BouncyCastle.Crypto.Modes
protected virtual void ProcessMainBlock(byte[] output, int outOff)
{
+ Check.DataLength(output, outOff, BLOCK_SIZE, "Output buffer too short");
+
/*
* OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
*/
@@ -528,10 +530,11 @@ namespace Org.BouncyCastle.Crypto.Modes
}
int n = 0;
- while ((x & 1L) == 0L)
+ ulong ux = (ulong)x;
+ while ((ux & 1UL) == 0UL)
{
++n;
- x >>= 1;
+ ux >>= 1;
}
return n;
}
diff --git a/crypto/src/crypto/modes/SicBlockCipher.cs b/crypto/src/crypto/modes/SicBlockCipher.cs
index 07c5d1978..da7ed7859 100644
--- a/crypto/src/crypto/modes/SicBlockCipher.cs
+++ b/crypto/src/crypto/modes/SicBlockCipher.cs
@@ -5,52 +5,52 @@ using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Crypto.Modes
{
- /**
- * Implements the Segmented Integer Counter (SIC) mode on top of a simple
- * block cipher.
- */
- public class SicBlockCipher
- : IBlockCipher
- {
- private readonly IBlockCipher cipher;
- private readonly int blockSize;
- private readonly byte[] IV;
- private readonly byte[] counter;
- private readonly byte[] counterOut;
+ /**
+ * Implements the Segmented Integer Counter (SIC) mode on top of a simple
+ * block cipher.
+ */
+ public class SicBlockCipher
+ : IBlockCipher
+ {
+ private readonly IBlockCipher cipher;
+ private readonly int blockSize;
+ private readonly byte[] IV;
+ private readonly byte[] counter;
+ private readonly byte[] counterOut;
- /**
- * Basic constructor.
- *
- * @param c the block cipher to be used.
- */
- public SicBlockCipher(IBlockCipher cipher)
- {
- this.cipher = cipher;
- this.blockSize = cipher.GetBlockSize();
- this.IV = new byte[blockSize];
- this.counter = new byte[blockSize];
- this.counterOut = new byte[blockSize];
- }
+ /**
+ * Basic constructor.
+ *
+ * @param c the block cipher to be used.
+ */
+ public SicBlockCipher(IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.GetBlockSize();
+ this.IV = new byte[blockSize];
+ this.counter = new byte[blockSize];
+ this.counterOut = new byte[blockSize];
+ }
- /**
- * return the underlying block cipher that we are wrapping.
- *
- * @return the underlying block cipher that we are wrapping.
- */
- public IBlockCipher GetUnderlyingCipher()
- {
- return cipher;
- }
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
- public void Init(
- bool forEncryption, //ignored by this CTR mode
- ICipherParameters parameters)
- {
- if (parameters is ParametersWithIV)
- {
- ParametersWithIV ivParam = (ParametersWithIV) parameters;
- byte[] iv = ivParam.GetIV();
- Array.Copy(iv, 0, IV, 0, IV.Length);
+ public void Init(
+ bool forEncryption, //ignored by this CTR mode
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV) parameters;
+ byte[] iv = ivParam.GetIV();
+ Array.Copy(iv, 0, IV, 0, IV.Length);
Reset();
@@ -59,57 +59,57 @@ namespace Org.BouncyCastle.Crypto.Modes
{
cipher.Init(true, ivParam.Parameters);
}
- }
- else
- {
- throw new ArgumentException("SIC mode requires ParametersWithIV", "parameters");
- }
- }
+ }
+ else
+ {
+ throw new ArgumentException("SIC mode requires ParametersWithIV", "parameters");
+ }
+ }
- public string AlgorithmName
- {
- get { return cipher.AlgorithmName + "/SIC"; }
- }
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/SIC"; }
+ }
- public bool IsPartialBlockOkay
- {
- get { return true; }
- }
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
- public int GetBlockSize()
- {
- return cipher.GetBlockSize();
- }
+ public int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
- {
- cipher.ProcessBlock(counter, 0, counterOut, 0);
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ cipher.ProcessBlock(counter, 0, counterOut, 0);
- //
- // XOR the counterOut with the plaintext producing the cipher text
- //
- for (int i = 0; i < counterOut.Length; i++)
- {
- output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
- }
+ //
+ // XOR the counterOut with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < counterOut.Length; i++)
+ {
+ output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
+ }
- // Increment the counter
- int j = counter.Length;
- while (--j >= 0 && ++counter[j] == 0)
- {
- }
+ // Increment the counter
+ int j = counter.Length;
+ while (--j >= 0 && ++counter[j] == 0)
+ {
+ }
- return counter.Length;
- }
+ return counter.Length;
+ }
- public void Reset()
- {
- Array.Copy(IV, 0, counter, 0, counter.Length);
- cipher.Reset();
- }
- }
+ public void Reset()
+ {
+ Array.Copy(IV, 0, counter, 0, counter.Length);
+ cipher.Reset();
+ }
+ }
}
diff --git a/crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs b/crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
index 98049e1db..5660a1f84 100644
--- a/crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
+++ b/crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
@@ -4,37 +4,37 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
- public class BasicGcmExponentiator
- : IGcmExponentiator
- {
- private byte[] x;
+ public class BasicGcmExponentiator
+ : IGcmExponentiator
+ {
+ private uint[] x;
- public void Init(byte[] x)
- {
- this.x = Arrays.Clone(x);
- }
+ public void Init(byte[] x)
+ {
+ this.x = GcmUtilities.AsUints(x);
+ }
- public void ExponentiateX(long pow, byte[] output)
- {
- // Initial value is little-endian 1
- byte[] y = GcmUtilities.OneAsBytes();
+ public void ExponentiateX(long pow, byte[] output)
+ {
+ // Initial value is little-endian 1
+ uint[] y = GcmUtilities.OneAsUints();
- if (pow > 0)
- {
- byte[] powX = Arrays.Clone(x);
- do
- {
- if ((pow & 1L) != 0)
- {
- GcmUtilities.Multiply(y, powX);
- }
- GcmUtilities.Multiply(powX, powX);
- pow >>= 1;
- }
- while (pow > 0);
- }
+ if (pow > 0)
+ {
+ uint[] powX = Arrays.Clone(x);
+ do
+ {
+ if ((pow & 1L) != 0)
+ {
+ GcmUtilities.Multiply(y, powX);
+ }
+ GcmUtilities.Multiply(powX, powX);
+ pow >>= 1;
+ }
+ while (pow > 0);
+ }
- Array.Copy(y, 0, output, 0, 16);
- }
- }
+ GcmUtilities.AsBytes(y, output);
+ }
+ }
}
diff --git a/crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs b/crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
index 85e3ac9b1..eb89383fb 100644
--- a/crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
+++ b/crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
@@ -1,22 +1,22 @@
using System;
-using Org.BouncyCastle.Utilities;
-
namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
- public class BasicGcmMultiplier
- : IGcmMultiplier
- {
- private byte[] H;
+ public class BasicGcmMultiplier
+ : IGcmMultiplier
+ {
+ private uint[] H;
- public void Init(byte[] H)
- {
- this.H = Arrays.Clone(H);
- }
+ public void Init(byte[] H)
+ {
+ this.H = GcmUtilities.AsUints(H);
+ }
public void MultiplyH(byte[] x)
- {
- GcmUtilities.Multiply(x, H);
- }
- }
+ {
+ uint[] t = GcmUtilities.AsUints(x);
+ GcmUtilities.Multiply(t, H);
+ GcmUtilities.AsBytes(t, x);
+ }
+ }
}
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index 71e63c8fd..d8ab2ca73 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -7,6 +7,31 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
internal abstract class GcmUtilities
{
+ private const uint E1 = 0xe1000000;
+ private const ulong E1L = (ulong)E1 << 32;
+
+ private static uint[] GenerateLookup()
+ {
+ uint[] lookup = new uint[256];
+
+ for (int c = 0; c < 256; ++c)
+ {
+ uint v = 0;
+ for (int i = 7; i >= 0; --i)
+ {
+ if ((c & (1 << i)) != 0)
+ {
+ v ^= (E1 >> (7 - i));
+ }
+ }
+ lookup[c] = v;
+ }
+
+ return lookup;
+ }
+
+ private static readonly uint[] LOOKUP = GenerateLookup();
+
internal static byte[] OneAsBytes()
{
byte[] tmp = new byte[16];
@@ -21,6 +46,35 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
return tmp;
}
+ internal static ulong[] OneAsUlongs()
+ {
+ ulong[] tmp = new ulong[2];
+ tmp[0] = 1UL << 63;
+ return tmp;
+ }
+
+ internal static byte[] AsBytes(uint[] x)
+ {
+ return Pack.UInt32_To_BE(x);
+ }
+
+ internal static void AsBytes(uint[] x, byte[] z)
+ {
+ Pack.UInt32_To_BE(x, z, 0);
+ }
+
+ internal static byte[] AsBytes(ulong[] x)
+ {
+ byte[] z = new byte[16];
+ Pack.UInt64_To_BE(x, z, 0);
+ return z;
+ }
+
+ internal static void AsBytes(ulong[] x, byte[] z)
+ {
+ Pack.UInt64_To_BE(x, z, 0);
+ }
+
internal static uint[] AsUints(byte[] bs)
{
uint[] output = new uint[4];
@@ -33,56 +87,90 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
Pack.BE_To_UInt32(bs, 0, output);
}
- internal static void Multiply(byte[] block, byte[] val)
+ internal static ulong[] AsUlongs(byte[] x)
{
- byte[] tmp = Arrays.Clone(block);
- byte[] c = new byte[16];
+ ulong[] z = new ulong[2];
+ Pack.BE_To_UInt64(x, 0, z);
+ return z;
+ }
+
+ public static void AsUlongs(byte[] x, ulong[] z)
+ {
+ Pack.BE_To_UInt64(x, 0, z);
+ }
- for (int i = 0; i < 16; ++i)
+ internal static void Multiply(byte[] x, byte[] y)
+ {
+ uint[] t1 = GcmUtilities.AsUints(x);
+ uint[] t2 = GcmUtilities.AsUints(y);
+ GcmUtilities.Multiply(t1, t2);
+ GcmUtilities.AsBytes(t1, x);
+ }
+
+ internal static void Multiply(uint[] x, uint[] y)
+ {
+ uint r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3];
+ uint r10 = 0, r11 = 0, r12 = 0, r13 = 0;
+
+ for (int i = 0; i < 4; ++i)
{
- byte bits = val[i];
- for (int j = 7; j >= 0; --j)
+ int bits = (int)y[i];
+ for (int j = 0; j < 32; ++j)
{
- if ((bits & (1 << j)) != 0)
- {
- Xor(c, tmp);
- }
+ uint m1 = (uint)(bits >> 31); bits <<= 1;
+ r10 ^= (r00 & m1);
+ r11 ^= (r01 & m1);
+ r12 ^= (r02 & m1);
+ r13 ^= (r03 & m1);
- bool lsb = (tmp[15] & 1) != 0;
- ShiftRight(tmp);
- if (lsb)
- {
- // R = new byte[]{ 0xe1, ... };
- //GCMUtilities.Xor(tmp, R);
- tmp[0] ^= (byte)0xe1;
- }
+ uint m2 = (uint)((int)(r03 << 31) >> 8);
+ r03 = (r03 >> 1) | (r02 << 31);
+ r02 = (r02 >> 1) | (r01 << 31);
+ r01 = (r01 >> 1) | (r00 << 31);
+ r00 = (r00 >> 1) ^ (m2 & E1);
}
}
- Array.Copy(c, 0, block, 0, 16);
+ x[0] = r10;
+ x[1] = r11;
+ x[2] = r12;
+ x[3] = r13;
}
- // P is the value with only bit i=1 set
- internal static void MultiplyP(uint[] x)
+ internal static void Multiply(ulong[] x, ulong[] y)
{
- bool lsb = (x[3] & 1) != 0;
- ShiftRight(x);
- if (lsb)
+ ulong r00 = x[0], r01 = x[1], r10 = 0, r11 = 0;
+
+ for (int i = 0; i < 2; ++i)
{
- // R = new uint[]{ 0xe1000000, 0, 0, 0 };
- //Xor(v, R);
- x[0] ^= 0xe1000000;
+ long bits = (long)y[i];
+ for (int j = 0; j < 64; ++j)
+ {
+ ulong m1 = (ulong)(bits >> 63); bits <<= 1;
+ r10 ^= (r00 & m1);
+ r11 ^= (r01 & m1);
+
+ ulong m2 = (ulong)((long)(r01 << 63) >> 8);
+ r01 = (r01 >> 1) | (r00 << 63);
+ r00 = (r00 >> 1) ^ (m2 & E1L);
+ }
}
+
+ x[0] = r10;
+ x[1] = r11;
}
- internal static void MultiplyP(uint[] x, uint[] output)
+ // P is the value with only bit i=1 set
+ internal static void MultiplyP(uint[] x)
{
- bool lsb = (x[3] & 1) != 0;
- ShiftRight(x, output);
- if (lsb)
- {
- output[0] ^= 0xe1000000;
- }
+ uint m = (uint)((int)ShiftRight(x) >> 8);
+ x[0] ^= (m & E1);
+ }
+
+ internal static void MultiplyP(uint[] x, uint[] z)
+ {
+ uint m = (uint)((int)ShiftRight(x, z) >> 8);
+ z[0] ^= (m & E1);
}
internal static void MultiplyP8(uint[] x)
@@ -92,146 +180,140 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
// MultiplyP(x);
// }
- uint lsw = x[3];
- ShiftRightN(x, 8);
- for (int i = 7; i >= 0; --i)
- {
- if ((lsw & (1 << i)) != 0)
- {
- x[0] ^= (0xe1000000 >> (7 - i));
- }
- }
+ uint c = ShiftRightN(x, 8);
+ x[0] ^= LOOKUP[c >> 24];
}
- internal static void MultiplyP8(uint[] x, uint[] output)
+ internal static void MultiplyP8(uint[] x, uint[] y)
{
- uint lsw = x[3];
- ShiftRightN(x, 8, output);
- for (int i = 7; i >= 0; --i)
- {
- if ((lsw & (1 << i)) != 0)
- {
- output[0] ^= (0xe1000000 >> (7 - i));
- }
- }
+ uint c = ShiftRightN(x, 8, y);
+ y[0] ^= LOOKUP[c >> 24];
}
- internal static void ShiftRight(byte[] block)
+ internal static uint ShiftRight(uint[] x)
{
- int i = 0;
- byte bit = 0;
- for (; ; )
- {
- byte b = block[i];
- block[i] = (byte)((b >> 1) | bit);
- if (++i == 16) break;
- bit = (byte)(b << 7);
- }
+ uint b = x[0];
+ x[0] = b >> 1;
+ uint c = b << 31;
+ b = x[1];
+ x[1] = (b >> 1) | c;
+ c = b << 31;
+ b = x[2];
+ x[2] = (b >> 1) | c;
+ c = b << 31;
+ b = x[3];
+ x[3] = (b >> 1) | c;
+ return b << 31;
}
- static void ShiftRight(byte[] block, byte[] output)
+ internal static uint ShiftRight(uint[] x, uint[] z)
{
- int i = 0;
- byte bit = 0;
- for (;;)
- {
- byte b = block[i];
- output[i] = (byte)((b >> 1) | bit);
- if (++i == 16) break;
- bit = (byte)(b << 7);
- }
+ uint b = x[0];
+ z[0] = b >> 1;
+ uint c = b << 31;
+ b = x[1];
+ z[1] = (b >> 1) | c;
+ c = b << 31;
+ b = x[2];
+ z[2] = (b >> 1) | c;
+ c = b << 31;
+ b = x[3];
+ z[3] = (b >> 1) | c;
+ return b << 31;
}
- internal static void ShiftRight(uint[] block)
+ internal static uint ShiftRightN(uint[] x, int n)
{
- int i = 0;
- uint bit = 0;
- for (; ; )
- {
- uint b = block[i];
- block[i] = (b >> 1) | bit;
- if (++i == 4) break;
- bit = b << 31;
- }
+ uint b = x[0]; int nInv = 32 - n;
+ x[0] = b >> n;
+ uint c = b << nInv;
+ b = x[1];
+ x[1] = (b >> n) | c;
+ c = b << nInv;
+ b = x[2];
+ x[2] = (b >> n) | c;
+ c = b << nInv;
+ b = x[3];
+ x[3] = (b >> n) | c;
+ return b << nInv;
}
- internal static void ShiftRight(uint[] block, uint[] output)
+ internal static uint ShiftRightN(uint[] x, int n, uint[] z)
{
- int i = 0;
- uint bit = 0;
- for (; ; )
- {
- uint b = block[i];
- output[i] = (b >> 1) | bit;
- if (++i == 4) break;
- bit = b << 31;
- }
+ uint b = x[0]; int nInv = 32 - n;
+ z[0] = b >> n;
+ uint c = b << nInv;
+ b = x[1];
+ z[1] = (b >> n) | c;
+ c = b << nInv;
+ b = x[2];
+ z[2] = (b >> n) | c;
+ c = b << nInv;
+ b = x[3];
+ z[3] = (b >> n) | c;
+ return b << nInv;
}
- internal static void ShiftRightN(uint[] block, int n)
+ internal static void Xor(byte[] x, byte[] y)
{
int i = 0;
- uint bit = 0;
- for (; ; )
+ do
{
- uint b = block[i];
- block[i] = (b >> n) | bit;
- if (++i == 4) break;
- bit = b << (32 - n);
+ x[i] ^= y[i]; ++i;
+ x[i] ^= y[i]; ++i;
+ x[i] ^= y[i]; ++i;
+ x[i] ^= y[i]; ++i;
}
+ while (i < 16);
}
- internal static void ShiftRightN(uint[] block, int n, uint[] output)
+ internal static void Xor(byte[] x, byte[] y, int yOff, int yLen)
{
- int i = 0;
- uint bit = 0;
- for (; ; )
+ while (--yLen >= 0)
{
- uint b = block[i];
- output[i] = (b >> n) | bit;
- if (++i == 4) break;
- bit = b << (32 - n);
+ x[yLen] ^= y[yOff + yLen];
}
}
- internal static void Xor(byte[] block, byte[] val)
+ internal static void Xor(byte[] x, byte[] y, byte[] z)
{
- for (int i = 15; i >= 0; --i)
+ int i = 0;
+ do
{
- block[i] ^= val[i];
+ z[i] = (byte)(x[i] ^ y[i]); ++i;
+ z[i] = (byte)(x[i] ^ y[i]); ++i;
+ z[i] = (byte)(x[i] ^ y[i]); ++i;
+ z[i] = (byte)(x[i] ^ y[i]); ++i;
}
+ while (i < 16);
}
- internal static void Xor(byte[] block, byte[] val, int off, int len)
+ internal static void Xor(uint[] x, uint[] y)
{
- while (--len >= 0)
- {
- block[len] ^= val[off + len];
- }
+ x[0] ^= y[0];
+ x[1] ^= y[1];
+ x[2] ^= y[2];
+ x[3] ^= y[3];
}
- internal static void Xor(byte[] block, byte[] val, byte[] output)
+ internal static void Xor(uint[] x, uint[] y, uint[] z)
{
- for (int i = 15; i >= 0; --i)
- {
- output[i] = (byte)(block[i] ^ val[i]);
- }
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
}
- internal static void Xor(uint[] block, uint[] val)
+ internal static void Xor(ulong[] x, ulong[] y)
{
- for (int i = 3; i >= 0; --i)
- {
- block[i] ^= val[i];
- }
+ x[0] ^= y[0];
+ x[1] ^= y[1];
}
- internal static void Xor(uint[] block, uint[] val, uint[] output)
+ internal static void Xor(ulong[] x, ulong[] y, ulong[] z)
{
- for (int i = 3; i >= 0; --i)
- {
- output[i] = block[i] ^ val[i];
- }
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
}
}
}
diff --git a/crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs b/crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
index 44933bba7..e649d6770 100644
--- a/crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
+++ b/crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
@@ -5,48 +5,47 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
- public class Tables1kGcmExponentiator
- : IGcmExponentiator
- {
+ public class Tables1kGcmExponentiator
+ : IGcmExponentiator
+ {
// A lookup table of the power-of-two powers of 'x'
// - lookupPowX2[i] = x^(2^i)
private IList lookupPowX2;
public void Init(byte[] x)
- {
- if (lookupPowX2 != null && Arrays.AreEqual(x, (byte[])lookupPowX2[0]))
- {
+ {
+ uint[] y = GcmUtilities.AsUints(x);
+ if (lookupPowX2 != null && Arrays.AreEqual(y, (uint[])lookupPowX2[0]))
return;
- }
lookupPowX2 = Platform.CreateArrayList(8);
- lookupPowX2.Add(Arrays.Clone(x));
- }
+ lookupPowX2.Add(y);
+ }
- public void ExponentiateX(long pow, byte[] output)
- {
- byte[] y = GcmUtilities.OneAsBytes();
+ public void ExponentiateX(long pow, byte[] output)
+ {
+ uint[] y = GcmUtilities.OneAsUints();
int bit = 0;
while (pow > 0)
{
if ((pow & 1L) != 0)
{
EnsureAvailable(bit);
- GcmUtilities.Multiply(y, (byte[])lookupPowX2[bit]);
+ GcmUtilities.Multiply(y, (uint[])lookupPowX2[bit]);
}
++bit;
pow >>= 1;
}
- Array.Copy(y, 0, output, 0, 16);
- }
+ GcmUtilities.AsBytes(y, output);
+ }
private void EnsureAvailable(int bit)
{
int count = lookupPowX2.Count;
if (count <= bit)
{
- byte[] tmp = (byte[])lookupPowX2[count - 1];
+ uint[] tmp = (uint[])lookupPowX2[count - 1];
do
{
tmp = Arrays.Clone(tmp);
diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs
new file mode 100644
index 000000000..ba070f4fc
--- /dev/null
+++ b/crypto/src/crypto/operators/Asn1Signature.cs
@@ -0,0 +1,559 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Operators
+{
+ internal class X509Utilities
+ {
+ private static readonly Asn1Null derNull = DerNull.Instance;
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary exParams = Platform.CreateHashtable();
+ private static readonly ISet noParams = new HashSet();
+
+ static X509Utilities()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384);
+ algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha384);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+ exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+ exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+ exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+ exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather than the algorithm identifier (if possible).
+ */
+ private static string GetDigestAlgName(
+ DerObjectIdentifier digestAlgOID)
+ {
+ if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.Id;
+ }
+ }
+
+ internal static string GetSignatureName(AlgorithmIdentifier sigAlgId)
+ {
+ Asn1Encodable parameters = sigAlgId.Parameters;
+
+ if (parameters != null && !derNull.Equals(parameters))
+ {
+ if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters);
+
+ return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1";
+ }
+ if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
+ {
+ Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters);
+
+ return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.ObjectID.Id;
+ }
+
+ private static RsassaPssParameters CreatePssParams(
+ AlgorithmIdentifier hashAlgId,
+ int saltSize)
+ {
+ return new RsassaPssParameters(
+ hashAlgId,
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+ new DerInteger(saltSize),
+ new DerInteger(1));
+ }
+
+ internal static DerObjectIdentifier GetAlgorithmOid(
+ string algorithmName)
+ {
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (algorithms.Contains(algorithmName))
+ {
+ return (DerObjectIdentifier) algorithms[algorithmName];
+ }
+
+ return new DerObjectIdentifier(algorithmName);
+ }
+
+ internal static AlgorithmIdentifier GetSigAlgID(
+ DerObjectIdentifier sigOid,
+ string algorithmName)
+ {
+ if (noParams.Contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (exParams.Contains(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+ }
+
+ return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+ }
+
+ internal static IEnumerable GetAlgNames()
+ {
+ return new EnumerableProxy(algorithms.Keys);
+ }
+ }
+
+ internal class SignerBucket
+ : Stream
+ {
+ protected readonly ISigner signer;
+
+ public SignerBucket(
+ ISigner signer)
+ {
+ this.signer = signer;
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override int ReadByte()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (count > 0)
+ {
+ signer.BlockUpdate(buffer, offset, count);
+ }
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ signer.Update(b);
+ }
+
+ public override bool CanRead
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override long Length
+ {
+ get { return 0; }
+ }
+
+ public override long Position
+ {
+ get { throw new NotImplementedException (); }
+ set { throw new NotImplementedException (); }
+ }
+
+ public override void Close()
+ {
+ }
+
+ public override void Flush()
+ {
+ }
+
+ public override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void SetLength(
+ long length)
+ {
+ throw new NotImplementedException ();
+ }
+ }
+
+ /// <summary>
+ /// Calculator class for signature generation in ASN.1 based profiles that use an AlgorithmIdentifier to preserve
+ /// signature algorithm details.
+ /// </summary>
+ public class Asn1SignatureCalculator: ISignatureCalculator
+ {
+ private readonly AlgorithmIdentifier algID;
+ private readonly string algorithm;
+ private readonly AsymmetricKeyParameter privateKey;
+ private readonly SecureRandom random;
+
+ /// <summary>
+ /// Base constructor.
+ /// </summary>
+ /// <param name="algorithm">The name of the signature algorithm to use.</param>
+ /// <param name="privateKey">The private key to be used in the signing operation.</param>
+ public Asn1SignatureCalculator (string algorithm, AsymmetricKeyParameter privateKey): this(algorithm, privateKey, null)
+ {
+ }
+
+ /// <summary>
+ /// Constructor which also specifies a source of randomness to be used if one is required.
+ /// </summary>
+ /// <param name="algorithm">The name of the signature algorithm to use.</param>
+ /// <param name="privateKey">The private key to be used in the signing operation.</param>
+ /// <param name="random">The source of randomness to be used in signature calculation.</param>
+ public Asn1SignatureCalculator (string algorithm, AsymmetricKeyParameter privateKey, SecureRandom random)
+ {
+ DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm);
+
+ this.algorithm = algorithm;
+ this.privateKey = privateKey;
+ this.random = random;
+ this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm);
+ }
+
+ public Object AlgorithmDetails
+ {
+ get { return this.algID; }
+ }
+
+ public IStreamCalculator CreateCalculator()
+ {
+ ISigner sig = SignerUtilities.GetSigner(algorithm);
+
+ if (random != null)
+ {
+ sig.Init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.Init(true, privateKey);
+ }
+
+ return new SigCalculator(sig);
+ }
+
+ /// <summary>
+ /// Allows enumeration of the signature names supported by the verifier provider.
+ /// </summary>
+ public static IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+
+ internal class SigCalculator : IStreamCalculator
+ {
+ private readonly ISigner sig;
+ private readonly Stream stream;
+
+ internal SigCalculator(ISigner sig)
+ {
+ this.sig = sig;
+ this.stream = new SignerBucket(sig);
+ }
+
+ public Stream Stream
+ {
+ get { return stream; }
+ }
+
+ public object GetResult()
+ {
+ return new SigResult(sig);
+ }
+ }
+
+ internal class SigResult : IBlockResult
+ {
+ private readonly ISigner sig;
+
+ internal SigResult(ISigner sig)
+ {
+ this.sig = sig;
+ }
+
+ public byte[] DoFinal()
+ {
+ return sig.GenerateSignature();
+ }
+
+ public int DoFinal(byte[] destination, int offset)
+ {
+ byte[] signature = DoFinal();
+
+ Array.Copy(signature, 0, destination, offset, signature.Length);
+
+ return signature.Length;
+ }
+ }
+
+ /// <summary>
+ /// Verifier class for signature verification in ASN.1 based profiles that use an AlgorithmIdentifier to preserve
+ /// signature algorithm details.
+ /// </summary>
+ public class Asn1SignatureVerifier: ISignatureVerifier
+ {
+ private readonly AlgorithmIdentifier algID;
+ private readonly AsymmetricKeyParameter publicKey;
+
+ /// <summary>
+ /// Base constructor.
+ /// </summary>
+ /// <param name="algorithm">The name of the signature algorithm to use.</param>
+ /// <param name="publicKey">The public key to be used in the verification operation.</param>
+ public Asn1SignatureVerifier (String algorithm, AsymmetricKeyParameter publicKey)
+ {
+ DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm);
+
+ this.publicKey = publicKey;
+ this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm);
+ }
+
+ public Asn1SignatureVerifier (AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey)
+ {
+ this.publicKey = publicKey;
+ this.algID = algorithm;
+ }
+
+ public Object AlgorithmDetails
+ {
+ get { return this.algID; }
+ }
+
+ public IStreamCalculator CreateCalculator()
+ {
+ ISigner sig = SignerUtilities.GetSigner(X509Utilities.GetSignatureName(algID));
+
+ sig.Init(false, publicKey);
+
+ return new VerifierCalculator(sig);
+ }
+ }
+
+ internal class VerifierCalculator : IStreamCalculator
+ {
+ private readonly ISigner sig;
+ private readonly Stream stream;
+
+ internal VerifierCalculator(ISigner sig)
+ {
+ this.sig = sig;
+ this.stream = new SignerBucket(sig);
+ }
+
+ public Stream Stream
+ {
+ get { return stream; }
+ }
+
+ public object GetResult()
+ {
+ return new VerifierResult(sig);
+ }
+ }
+
+ internal class VerifierResult : IVerifier
+ {
+ private readonly ISigner sig;
+
+ internal VerifierResult(ISigner sig)
+ {
+ this.sig = sig;
+ }
+
+ public bool IsVerified(byte[] signature)
+ {
+ return sig.VerifySignature(signature);
+ }
+
+ public bool IsVerified(byte[] signature, int off, int length)
+ {
+ byte[] sigBytes = new byte[length];
+
+ Array.Copy(signature, 0, sigBytes, off, sigBytes.Length);
+
+ return sig.VerifySignature(signature);
+ }
+ }
+
+ /// <summary>
+ /// Provider class which supports dynamic creation of signature verifiers.
+ /// </summary>
+ public class Asn1SignatureVerifierProvider: ISignatureVerifierProvider
+ {
+ private readonly AsymmetricKeyParameter publicKey;
+
+ /// <summary>
+ /// Base constructor - specify the public key to be used in verification.
+ /// </summary>
+ /// <param name="publicKey">The public key to be used in creating verifiers provided by this object.</param>
+ public Asn1SignatureVerifierProvider(AsymmetricKeyParameter publicKey)
+ {
+ this.publicKey = publicKey;
+ }
+
+ public ISignatureVerifier CreateSignatureVerifier(Object algorithmDetails)
+ {
+ return new Asn1SignatureVerifier ((AlgorithmIdentifier)algorithmDetails, publicKey);
+ }
+
+ /// <summary>
+ /// Allows enumeration of the signature names supported by the verifier provider.
+ /// </summary>
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
+
diff --git a/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs b/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
index fb8a92ba3..5d2f8cf15 100644
--- a/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
+++ b/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
@@ -122,7 +122,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
}
/**
- * process a single byte, producing an output block if neccessary.
+ * process a single byte, producing an output block if necessary.
*
* @param in the input byte.
* @param out the space for any output that might be produced.
@@ -178,10 +178,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
if (outLength > 0)
{
- if ((outOff + outLength) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.OutputLength(output, outOff, outLength, "output buffer too short");
}
int resultLen = 0;
@@ -242,7 +239,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
{
Reset();
- throw new DataLengthException("output buffer too short");
+ throw new OutputLengthException("output buffer too short");
}
resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
diff --git a/crypto/src/crypto/paddings/Pkcs7Padding.cs b/crypto/src/crypto/paddings/Pkcs7Padding.cs
index f3166fd96..11585647a 100644
--- a/crypto/src/crypto/paddings/Pkcs7Padding.cs
+++ b/crypto/src/crypto/paddings/Pkcs7Padding.cs
@@ -9,7 +9,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
* A padder that adds Pkcs7/Pkcs5 padding to a block.
*/
public class Pkcs7Padding
- : IBlockCipherPadding
+ : IBlockCipherPadding
{
/**
* Initialise the padder.
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
* @param random - a SecureRandom if available.
*/
public void Init(
- SecureRandom random)
+ SecureRandom random)
{
// nothing to do.
}
@@ -32,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
get { return "PKCS7"; }
}
- /**
+ /**
* add the pad bytes to the passed in block, returning the
* number of bytes added.
*/
@@ -55,21 +55,18 @@ namespace Org.BouncyCastle.Crypto.Paddings
* return the number of pad bytes present in the block.
*/
public int PadCount(
- byte[] input)
+ byte[] input)
{
- int count = (int) input[input.Length - 1];
+ byte countAsByte = input[input.Length - 1];
+ int count = countAsByte;
- if (count < 1 || count > input.Length)
- {
+ if (count < 1 || count > input.Length)
throw new InvalidCipherTextException("pad block corrupted");
- }
- for (int i = 1; i <= count; i++)
+ for (int i = 2; i <= count; i++)
{
- if (input[input.Length - i] != count)
- {
+ if (input[input.Length - i] != countAsByte)
throw new InvalidCipherTextException("pad block corrupted");
- }
}
return count;
diff --git a/crypto/src/crypto/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs
index a0544e73b..4258df5c5 100644
--- a/crypto/src/crypto/parameters/DHParameters.cs
+++ b/crypto/src/crypto/parameters/DHParameters.cs
@@ -91,6 +91,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
throw new ArgumentException("m value must be < bitlength of p", "m");
if (l != 0)
{
+ // TODO Check this against the Java version, which has 'l > p.BitLength' here
if (l >= p.BitLength)
throw new ArgumentException("when l value specified, it must be less than bitlength(p)", "l");
if (l < m)
diff --git a/crypto/src/crypto/parameters/Srp6GroupParameters.cs b/crypto/src/crypto/parameters/Srp6GroupParameters.cs
new file mode 100644
index 000000000..6762dd31d
--- /dev/null
+++ b/crypto/src/crypto/parameters/Srp6GroupParameters.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Srp6GroupParameters
+ {
+ private readonly BigInteger n, g;
+
+ public Srp6GroupParameters(BigInteger N, BigInteger g)
+ {
+ this.n = N;
+ this.g = g;
+ }
+
+ public BigInteger G
+ {
+ get { return g; }
+ }
+
+ public BigInteger N
+ {
+ get { return n; }
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
index e1a0d4012..521fae33e 100644
--- a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
+++ b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
@@ -5,62 +5,62 @@ using System.Security.Cryptography;
namespace Org.BouncyCastle.Crypto.Prng
{
- /// <summary>
- /// Uses Microsoft's RNGCryptoServiceProvider
- /// </summary>
- public class CryptoApiRandomGenerator
- : IRandomGenerator
- {
- private readonly RandomNumberGenerator rndProv;
+ /// <summary>
+ /// Uses Microsoft's RNGCryptoServiceProvider
+ /// </summary>
+ public class CryptoApiRandomGenerator
+ : IRandomGenerator
+ {
+ private readonly RandomNumberGenerator rndProv;
- public CryptoApiRandomGenerator()
- : this(new RNGCryptoServiceProvider())
- {
- }
+ public CryptoApiRandomGenerator()
+ : this(new RNGCryptoServiceProvider())
+ {
+ }
- public CryptoApiRandomGenerator(RandomNumberGenerator rng)
- {
- this.rndProv = rng;
- }
+ public CryptoApiRandomGenerator(RandomNumberGenerator rng)
+ {
+ this.rndProv = rng;
+ }
- #region IRandomGenerator Members
+ #region IRandomGenerator Members
- public virtual void AddSeedMaterial(byte[] seed)
- {
- // We don't care about the seed
- }
+ public virtual void AddSeedMaterial(byte[] seed)
+ {
+ // We don't care about the seed
+ }
- public virtual void AddSeedMaterial(long seed)
- {
- // We don't care about the seed
- }
+ public virtual void AddSeedMaterial(long seed)
+ {
+ // We don't care about the seed
+ }
- public virtual void NextBytes(byte[] bytes)
- {
- rndProv.GetBytes(bytes);
- }
+ public virtual void NextBytes(byte[] bytes)
+ {
+ rndProv.GetBytes(bytes);
+ }
- public virtual void NextBytes(byte[] bytes, int start, int len)
- {
- if (start < 0)
- throw new ArgumentException("Start offset cannot be negative", "start");
- if (bytes.Length < (start + len))
- throw new ArgumentException("Byte array too small for requested offset and length");
+ public virtual void NextBytes(byte[] bytes, int start, int len)
+ {
+ if (start < 0)
+ throw new ArgumentException("Start offset cannot be negative", "start");
+ if (bytes.Length < (start + len))
+ throw new ArgumentException("Byte array too small for requested offset and length");
- if (bytes.Length == len && start == 0)
- {
- NextBytes(bytes);
- }
- else
- {
- byte[] tmpBuf = new byte[len];
- rndProv.GetBytes(tmpBuf);
- Array.Copy(tmpBuf, 0, bytes, start, len);
- }
- }
+ if (bytes.Length == len && start == 0)
+ {
+ NextBytes(bytes);
+ }
+ else
+ {
+ byte[] tmpBuf = new byte[len];
+ NextBytes(tmpBuf);
+ Array.Copy(tmpBuf, 0, bytes, start, len);
+ }
+ }
- #endregion
- }
+ #endregion
+ }
}
#endif
diff --git a/crypto/src/crypto/signers/DsaDigestSigner.cs b/crypto/src/crypto/signers/DsaDigestSigner.cs
index aee713450..086601481 100644
--- a/crypto/src/crypto/signers/DsaDigestSigner.cs
+++ b/crypto/src/crypto/signers/DsaDigestSigner.cs
@@ -26,12 +26,12 @@ namespace Org.BouncyCastle.Crypto.Signers
this.dsaSigner = signer;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
}
- public void Init(
+ public virtual void Init(
bool forSigning,
ICipherParameters parameters)
{
@@ -62,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Signers
/**
* update the internal digest with the byte b
*/
- public void Update(
+ public virtual void Update(
byte input)
{
digest.Update(input);
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Signers
/**
* update the internal digest with the byte array in
*/
- public void BlockUpdate(
+ public virtual void BlockUpdate(
byte[] input,
int inOff,
int length)
@@ -83,7 +83,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* Generate a signature for the message we've been loaded with using
* the key we were initialised with.
*/
- public byte[] GenerateSignature()
+ public virtual byte[] GenerateSignature()
{
if (!forSigning)
throw new InvalidOperationException("DSADigestSigner not initialised for signature generation.");
@@ -97,7 +97,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
/// <returns>true if the internal state represents the signature described in the passed in array.</returns>
- public bool VerifySignature(
+ public virtual bool VerifySignature(
byte[] signature)
{
if (forSigning)
@@ -118,7 +118,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
/// <summary>Reset the internal state</summary>
- public void Reset()
+ public virtual void Reset()
{
digest.Reset();
}
diff --git a/crypto/src/crypto/signers/DsaSigner.cs b/crypto/src/crypto/signers/DsaSigner.cs
index fc0780a91..bb28addfc 100644
--- a/crypto/src/crypto/signers/DsaSigner.cs
+++ b/crypto/src/crypto/signers/DsaSigner.cs
@@ -1,10 +1,9 @@
using System;
-using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Math.EC;
-using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Crypto;
+
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Signers
{
@@ -15,9 +14,29 @@ namespace Org.BouncyCastle.Crypto.Signers
public class DsaSigner
: IDsa
{
+ protected readonly IDsaKCalculator kCalculator;
+
protected DsaKeyParameters key = null;
protected SecureRandom random = null;
+ /**
+ * Default configuration, random K values.
+ */
+ public DsaSigner()
+ {
+ this.kCalculator = new RandomDsaKCalculator();
+ }
+
+ /**
+ * Configuration with an alternate, possibly deterministic calculator of K.
+ *
+ * @param kCalculator a K value calculator.
+ */
+ public DsaSigner(IDsaKCalculator kCalculator)
+ {
+ this.kCalculator = kCalculator;
+ }
+
public virtual string AlgorithmName
{
get { return "DSA"; }
@@ -50,7 +69,7 @@ namespace Org.BouncyCastle.Crypto.Signers
this.key = (DsaPublicKeyParameters)parameters;
}
- this.random = InitSecureRandom(forSigning, providedRandom);
+ this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
}
/**
@@ -65,18 +84,22 @@ namespace Org.BouncyCastle.Crypto.Signers
DsaParameters parameters = key.Parameters;
BigInteger q = parameters.Q;
BigInteger m = CalculateE(q, message);
- BigInteger k;
+ BigInteger x = ((DsaPrivateKeyParameters)key).X;
- do
+ if (kCalculator.IsDeterministic)
{
- k = new BigInteger(q.BitLength, random);
+ kCalculator.Init(q, x, message);
}
- while (k.CompareTo(q) >= 0);
+ else
+ {
+ kCalculator.Init(q, random);
+ }
+
+ BigInteger k = kCalculator.NextK();
BigInteger r = parameters.G.ModPow(k, parameters.P).Mod(q);
- k = k.ModInverse(q).Multiply(
- m.Add(((DsaPrivateKeyParameters)key).X.Multiply(r)));
+ k = k.ModInverse(q).Multiply(m.Add(x.Multiply(r)));
BigInteger s = k.Mod(q);
diff --git a/crypto/src/crypto/signers/ECDsaSigner.cs b/crypto/src/crypto/signers/ECDsaSigner.cs
index 867520535..9821732c2 100644
--- a/crypto/src/crypto/signers/ECDsaSigner.cs
+++ b/crypto/src/crypto/signers/ECDsaSigner.cs
@@ -1,11 +1,11 @@
using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math.EC.Multiplier;
using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Signers
{
@@ -15,9 +15,29 @@ namespace Org.BouncyCastle.Crypto.Signers
public class ECDsaSigner
: IDsa
{
+ protected readonly IDsaKCalculator kCalculator;
+
protected ECKeyParameters key = null;
protected SecureRandom random = null;
+ /**
+ * Default configuration, random K values.
+ */
+ public ECDsaSigner()
+ {
+ this.kCalculator = new RandomDsaKCalculator();
+ }
+
+ /**
+ * Configuration with an alternate, possibly deterministic calculator of K.
+ *
+ * @param kCalculator a K value calculator.
+ */
+ public ECDsaSigner(IDsaKCalculator kCalculator)
+ {
+ this.kCalculator = kCalculator;
+ }
+
public virtual string AlgorithmName
{
get { return "ECDSA"; }
@@ -50,7 +70,7 @@ namespace Org.BouncyCastle.Crypto.Signers
this.key = (ECPublicKeyParameters)parameters;
}
- this.random = InitSecureRandom(forSigning, providedRandom);
+ this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
}
// 5.3 pg 28
@@ -68,6 +88,15 @@ namespace Org.BouncyCastle.Crypto.Signers
BigInteger e = CalculateE(n, message);
BigInteger d = ((ECPrivateKeyParameters)key).D;
+ if (kCalculator.IsDeterministic)
+ {
+ kCalculator.Init(n, d, message);
+ }
+ else
+ {
+ kCalculator.Init(n, random);
+ }
+
BigInteger r, s;
ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
@@ -78,11 +107,7 @@ namespace Org.BouncyCastle.Crypto.Signers
BigInteger k;
do // Generate r
{
- do
- {
- k = new BigInteger(n.BitLength, random);
- }
- while (k.SignValue == 0 || k.CompareTo(n) >= 0);
+ k = kCalculator.NextK();
ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();
diff --git a/crypto/src/crypto/signers/ECGOST3410Signer.cs b/crypto/src/crypto/signers/ECGOST3410Signer.cs
index 6027aa9b9..28ab79c1c 100644
--- a/crypto/src/crypto/signers/ECGOST3410Signer.cs
+++ b/crypto/src/crypto/signers/ECGOST3410Signer.cs
@@ -18,12 +18,12 @@ namespace Org.BouncyCastle.Crypto.Signers
private ECKeyParameters key;
private SecureRandom random;
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "ECGOST3410"; }
}
- public void Init(
+ public virtual void Init(
bool forSigning,
ICipherParameters parameters)
{
@@ -62,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Signers
*
* @param message the message that will be verified later.
*/
- public BigInteger[] GenerateSignature(
+ public virtual BigInteger[] GenerateSignature(
byte[] message)
{
byte[] mRev = new byte[message.Length]; // conversion is little-endian
@@ -110,7 +110,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* the passed in message (for standard GOST3410 the message should be
* a GOST3411 hash of the real message to be verified).
*/
- public bool VerifySignature(
+ public virtual bool VerifySignature(
byte[] message,
BigInteger r,
BigInteger s)
diff --git a/crypto/src/crypto/signers/ECNRSigner.cs b/crypto/src/crypto/signers/ECNRSigner.cs
index cae15bdbf..bb21a4994 100644
--- a/crypto/src/crypto/signers/ECNRSigner.cs
+++ b/crypto/src/crypto/signers/ECNRSigner.cs
@@ -19,12 +19,12 @@ namespace Org.BouncyCastle.Crypto.Signers
private ECKeyParameters key;
private SecureRandom random;
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "ECNR"; }
}
- public void Init(
+ public virtual void Init(
bool forSigning,
ICipherParameters parameters)
{
@@ -68,7 +68,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* @param digest the digest to be signed.
* @exception DataLengthException if the digest is longer than the key allows
*/
- public BigInteger[] GenerateSignature(
+ public virtual BigInteger[] GenerateSignature(
byte[] message)
{
if (!this.forSigning)
@@ -134,7 +134,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* @param s the s value of the signature.
* @exception DataLengthException if the digest is longer than the key allows
*/
- public bool VerifySignature(
+ public virtual bool VerifySignature(
byte[] message,
BigInteger r,
BigInteger s)
diff --git a/crypto/src/crypto/signers/GOST3410DigestSigner.cs b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
index 58aefa368..bc32808df 100644
--- a/crypto/src/crypto/signers/GOST3410DigestSigner.cs
+++ b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
@@ -26,12 +26,12 @@ namespace Org.BouncyCastle.Crypto.Signers
this.digest = digest;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
}
- public void Init(
+ public virtual void Init(
bool forSigning,
ICipherParameters parameters)
{
@@ -65,7 +65,7 @@ namespace Org.BouncyCastle.Crypto.Signers
/**
* update the internal digest with the byte b
*/
- public void Update(
+ public virtual void Update(
byte input)
{
digest.Update(input);
@@ -74,7 +74,7 @@ namespace Org.BouncyCastle.Crypto.Signers
/**
* update the internal digest with the byte array in
*/
- public void BlockUpdate(
+ public virtual void BlockUpdate(
byte[] input,
int inOff,
int length)
@@ -86,7 +86,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* Generate a signature for the message we've been loaded with using
* the key we were initialised with.
*/
- public byte[] GenerateSignature()
+ public virtual byte[] GenerateSignature()
{
if (!forSigning)
throw new InvalidOperationException("GOST3410DigestSigner not initialised for signature generation.");
@@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
/// <returns>true if the internal state represents the signature described in the passed in array.</returns>
- public bool VerifySignature(
+ public virtual bool VerifySignature(
byte[] signature)
{
if (forSigning)
@@ -137,7 +137,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
/// <summary>Reset the internal state</summary>
- public void Reset()
+ public virtual void Reset()
{
digest.Reset();
}
diff --git a/crypto/src/crypto/signers/GOST3410Signer.cs b/crypto/src/crypto/signers/GOST3410Signer.cs
index 375eeb5cc..f1832ae37 100644
--- a/crypto/src/crypto/signers/GOST3410Signer.cs
+++ b/crypto/src/crypto/signers/GOST3410Signer.cs
@@ -15,12 +15,12 @@ namespace Org.BouncyCastle.Crypto.Signers
private Gost3410KeyParameters key;
private SecureRandom random;
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "GOST3410"; }
}
- public void Init(
+ public virtual void Init(
bool forSigning,
ICipherParameters parameters)
{
@@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Crypto.Signers
*
* @param message the message that will be verified later.
*/
- public BigInteger[] GenerateSignature(
+ public virtual BigInteger[] GenerateSignature(
byte[] message)
{
byte[] mRev = new byte[message.Length]; // conversion is little-endian
@@ -92,7 +92,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* the passed in message for standard Gost3410 the message should be a
* Gost3411 hash of the real message to be verified.
*/
- public bool VerifySignature(
+ public virtual bool VerifySignature(
byte[] message,
BigInteger r,
BigInteger s)
diff --git a/crypto/src/crypto/signers/GenericSigner.cs b/crypto/src/crypto/signers/GenericSigner.cs
index 1a53eee2b..a5512176f 100644
--- a/crypto/src/crypto/signers/GenericSigner.cs
+++ b/crypto/src/crypto/signers/GenericSigner.cs
@@ -6,124 +6,125 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Signers
{
- public class GenericSigner
- : ISigner
- {
- private readonly IAsymmetricBlockCipher engine;
- private readonly IDigest digest;
- private bool forSigning;
-
- public GenericSigner(
- IAsymmetricBlockCipher engine,
- IDigest digest)
- {
- this.engine = engine;
- this.digest = digest;
- }
-
- public string AlgorithmName
- {
- get { return "Generic(" + engine.AlgorithmName + "/" + digest.AlgorithmName + ")"; }
- }
-
- /**
- * initialise the signer for signing or verification.
- *
- * @param forSigning
- * true if for signing, false otherwise
- * @param parameters
- * necessary parameters.
- */
- public void Init(
- bool forSigning,
- ICipherParameters parameters)
- {
- this.forSigning = forSigning;
- AsymmetricKeyParameter k;
-
- if (parameters is ParametersWithRandom)
- {
- k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
- }
- else
- {
- k = (AsymmetricKeyParameter)parameters;
- }
+ public class GenericSigner
+ : ISigner
+ {
+ private readonly IAsymmetricBlockCipher engine;
+ private readonly IDigest digest;
+ private bool forSigning;
+
+ public GenericSigner(
+ IAsymmetricBlockCipher engine,
+ IDigest digest)
+ {
+ this.engine = engine;
+ this.digest = digest;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Generic(" + engine.AlgorithmName + "/" + digest.AlgorithmName + ")"; }
+ }
+
+ /**
+ * initialise the signer for signing or verification.
+ *
+ * @param forSigning
+ * true if for signing, false otherwise
+ * @param parameters
+ * necessary parameters.
+ */
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ AsymmetricKeyParameter k;
+ if (parameters is ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
if (forSigning && !k.IsPrivate)
throw new InvalidKeyException("Signing requires private key.");
- if (!forSigning && k.IsPrivate)
+ if (!forSigning && k.IsPrivate)
throw new InvalidKeyException("Verification requires public key.");
- Reset();
-
- engine.Init(forSigning, parameters);
- }
-
- /**
- * update the internal digest with the byte b
- */
- public void Update(
- byte input)
- {
- digest.Update(input);
- }
-
- /**
- * update the internal digest with the byte array in
- */
- public void BlockUpdate(
- byte[] input,
- int inOff,
- int length)
- {
- digest.BlockUpdate(input, inOff, length);
- }
-
- /**
- * Generate a signature for the message we've been loaded with using the key
- * we were initialised with.
- */
- public byte[] GenerateSignature()
- {
- if (!forSigning)
- throw new InvalidOperationException("GenericSigner not initialised for signature generation.");
-
- byte[] hash = new byte[digest.GetDigestSize()];
- digest.DoFinal(hash, 0);
-
- return engine.ProcessBlock(hash, 0, hash.Length);
- }
-
- /**
- * return true if the internal state represents the signature described in
- * the passed in array.
- */
- public bool VerifySignature(
- byte[] signature)
- {
- if (forSigning)
- throw new InvalidOperationException("GenericSigner not initialised for verification");
-
- byte[] hash = new byte[digest.GetDigestSize()];
- digest.DoFinal(hash, 0);
-
- try
- {
- byte[] sig = engine.ProcessBlock(signature, 0, signature.Length);
-
- return Arrays.ConstantTimeAreEqual(sig, hash);
- }
- catch (Exception)
- {
- return false;
- }
- }
-
- public void Reset()
- {
- digest.Reset();
- }
- }
+ Reset();
+
+ engine.Init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public virtual void Update(byte input)
+ {
+ digest.Update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public virtual void BlockUpdate(byte[] input, int inOff, int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using the key
+ * we were initialised with.
+ */
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("GenericSigner not initialised for signature generation.");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ return engine.ProcessBlock(hash, 0, hash.Length);
+ }
+
+ /**
+ * return true if the internal state represents the signature described in
+ * the passed in array.
+ */
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("GenericSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ try
+ {
+ byte[] sig = engine.ProcessBlock(signature, 0, signature.Length);
+
+ // Extend with leading zeroes to match the digest size, if necessary.
+ if (sig.Length < hash.Length)
+ {
+ byte[] tmp = new byte[hash.Length];
+ Array.Copy(sig, 0, tmp, tmp.Length - sig.Length, sig.Length);
+ sig = tmp;
+ }
+
+ return Arrays.ConstantTimeAreEqual(sig, hash);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+
+ public virtual void Reset()
+ {
+ digest.Reset();
+ }
+ }
}
diff --git a/crypto/src/crypto/signers/HMacDsaKCalculator.cs b/crypto/src/crypto/signers/HMacDsaKCalculator.cs
new file mode 100644
index 000000000..8231197b9
--- /dev/null
+++ b/crypto/src/crypto/signers/HMacDsaKCalculator.cs
@@ -0,0 +1,150 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * A deterministic K calculator based on the algorithm in section 3.2 of RFC 6979.
+ */
+ public class HMacDsaKCalculator
+ : IDsaKCalculator
+ {
+ private readonly HMac hMac;
+ private readonly byte[] K;
+ private readonly byte[] V;
+
+ private BigInteger n;
+
+ /**
+ * Base constructor.
+ *
+ * @param digest digest to build the HMAC on.
+ */
+ public HMacDsaKCalculator(IDigest digest)
+ {
+ this.hMac = new HMac(digest);
+ this.V = new byte[hMac.GetMacSize()];
+ this.K = new byte[hMac.GetMacSize()];
+ }
+
+ public virtual bool IsDeterministic
+ {
+ get { return true; }
+ }
+
+ public virtual void Init(BigInteger n, SecureRandom random)
+ {
+ throw new InvalidOperationException("Operation not supported");
+ }
+
+ public void Init(BigInteger n, BigInteger d, byte[] message)
+ {
+ this.n = n;
+
+ Arrays.Fill(V, (byte)0x01);
+ Arrays.Fill(K, (byte)0);
+
+ byte[] x = new byte[(n.BitLength + 7) / 8];
+ byte[] dVal = BigIntegers.AsUnsignedByteArray(d);
+
+ Array.Copy(dVal, 0, x, x.Length - dVal.Length, dVal.Length);
+
+ byte[] m = new byte[(n.BitLength + 7) / 8];
+
+ BigInteger mInt = BitsToInt(message);
+
+ if (mInt.CompareTo(n) >= 0)
+ {
+ mInt = mInt.Subtract(n);
+ }
+
+ byte[] mVal = BigIntegers.AsUnsignedByteArray(mInt);
+
+ Array.Copy(mVal, 0, m, m.Length - mVal.Length, mVal.Length);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x00);
+ hMac.BlockUpdate(x, 0, x.Length);
+ hMac.BlockUpdate(m, 0, m.Length);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x01);
+ hMac.BlockUpdate(x, 0, x.Length);
+ hMac.BlockUpdate(m, 0, m.Length);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+ }
+
+ public virtual BigInteger NextK()
+ {
+ byte[] t = new byte[((n.BitLength + 7) / 8)];
+
+ for (;;)
+ {
+ int tOff = 0;
+
+ while (tOff < t.Length)
+ {
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+
+ int len = System.Math.Min(t.Length - tOff, V.Length);
+ Array.Copy(V, 0, t, tOff, len);
+ tOff += len;
+ }
+
+ BigInteger k = BitsToInt(t);
+
+ if (k.SignValue > 0 && k.CompareTo(n) < 0)
+ {
+ return k;
+ }
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x00);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+ }
+ }
+
+ private BigInteger BitsToInt(byte[] t)
+ {
+ BigInteger v = new BigInteger(1, t);
+
+ if (t.Length * 8 > n.BitLength)
+ {
+ v = v.ShiftRight(t.Length * 8 - n.BitLength);
+ }
+
+ return v;
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/IDsaKCalculator.cs b/crypto/src/crypto/signers/IDsaKCalculator.cs
new file mode 100644
index 000000000..645186d41
--- /dev/null
+++ b/crypto/src/crypto/signers/IDsaKCalculator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * Interface define calculators of K values for DSA/ECDSA.
+ */
+ public interface IDsaKCalculator
+ {
+ /**
+ * Return true if this calculator is deterministic, false otherwise.
+ *
+ * @return true if deterministic, otherwise false.
+ */
+ bool IsDeterministic { get; }
+
+ /**
+ * Non-deterministic initialiser.
+ *
+ * @param n the order of the DSA group.
+ * @param random a source of randomness.
+ */
+ void Init(BigInteger n, SecureRandom random);
+
+ /**
+ * Deterministic initialiser.
+ *
+ * @param n the order of the DSA group.
+ * @param d the DSA private value.
+ * @param message the message being signed.
+ */
+ void Init(BigInteger n, BigInteger d, byte[] message);
+
+ /**
+ * Return the next valid value of K.
+ *
+ * @return a K value.
+ */
+ BigInteger NextK();
+ }
+}
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index d4f6c5522..fb117c19d 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -26,29 +26,23 @@ namespace Org.BouncyCastle.Crypto.Signers
return recoveredMessage;
}
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerImplicit = 0xBC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerRipeMD160 = 0x31CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerRipeMD128 = 0x32CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerSha1 = 0x33CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerSha256 = 0x34CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerSha512 = 0x35CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerSha384 = 0x36CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerWhirlpool = 0x37CC;
- private static readonly IDictionary trailerMap = Platform.CreateHashtable();
-
- static Iso9796d2PssSigner()
- {
- trailerMap.Add("RIPEMD128", TrailerRipeMD128);
- trailerMap.Add("RIPEMD160", TrailerRipeMD160);
- trailerMap.Add("SHA-1", TrailerSha1);
- trailerMap.Add("SHA-256", TrailerSha256);
- trailerMap.Add("SHA-384", TrailerSha384);
- trailerMap.Add("SHA-512", TrailerSha512);
-
- trailerMap.Add("Whirlpool", TrailerWhirlpool);
- }
-
private IDigest digest;
private IAsymmetricBlockCipher cipher;
@@ -71,8 +65,7 @@ namespace Org.BouncyCastle.Crypto.Signers
private int preTLength;
/// <summary>
- /// Generate a signer for the with either implicit or explicit trailers
- /// for ISO9796-2, scheme 2 or 3.
+ /// Generate a signer with either implicit or explicit trailers for ISO9796-2, scheme 2 or 3.
/// </summary>
/// <param name="cipher">base cipher to use for signature creation/verification</param>
/// <param name="digest">digest to use.</param>
@@ -91,15 +84,15 @@ namespace Org.BouncyCastle.Crypto.Signers
if (isImplicit)
{
- trailer = TrailerImplicit;
+ trailer = IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else if (IsoTrailers.NoTrailerAvailable(digest))
+ {
+ throw new ArgumentException("no valid trailer", "digest");
}
else
{
- string digestAlg = digest.AlgorithmName;
- if (!trailerMap.Contains(digestAlg))
- throw new ArgumentException("no valid trailer for digest");
-
- trailer = (int)trailerMap[digestAlg];
+ trailer = IsoTrailers.GetTrailer(digest);
}
}
@@ -120,7 +113,7 @@ namespace Org.BouncyCastle.Crypto.Signers
{
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "with" + "ISO9796-2S2"; }
}
@@ -180,7 +173,7 @@ namespace Org.BouncyCastle.Crypto.Signers
block = new byte[(keyBits + 7) / 8];
- if (trailer == TrailerImplicit)
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
{
mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1];
}
@@ -247,11 +240,10 @@ namespace Org.BouncyCastle.Crypto.Signers
{
int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
- string digestAlg = digest.AlgorithmName;
- if (!trailerMap.Contains(digestAlg))
+ if (IsoTrailers.NoTrailerAvailable(digest))
throw new ArgumentException("unrecognised hash in signature");
- if (sigTrail != (int)trailerMap[digestAlg])
+ if (sigTrail != IsoTrailers.GetTrailer(digest))
throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
tLength = 2;
@@ -365,7 +357,7 @@ namespace Org.BouncyCastle.Crypto.Signers
/// <summary> Generate a signature for the loaded message using the key we were
/// initialised with.
/// </summary>
- public byte[] GenerateSignature()
+ public virtual byte[] GenerateSignature()
{
int digSize = digest.GetDigestSize();
byte[] m2Hash = new byte[digSize];
@@ -395,7 +387,7 @@ namespace Org.BouncyCastle.Crypto.Signers
digest.DoFinal(hash, 0);
int tLength = 2;
- if (trailer == TrailerImplicit)
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
{
tLength = 1;
}
@@ -415,9 +407,9 @@ namespace Org.BouncyCastle.Crypto.Signers
Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen);
- if (trailer == TrailerImplicit)
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
{
- block[block.Length - 1] = (byte)TrailerImplicit;
+ block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
}
else
{
diff --git a/crypto/src/crypto/signers/Iso9796d2Signer.cs b/crypto/src/crypto/signers/Iso9796d2Signer.cs
index cfb8942e6..b90ed8f0b 100644
--- a/crypto/src/crypto/signers/Iso9796d2Signer.cs
+++ b/crypto/src/crypto/signers/Iso9796d2Signer.cs
@@ -21,30 +21,23 @@ namespace Org.BouncyCastle.Crypto.Signers
return recoveredMessage;
}
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerImplicit = 0xBC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerRipeMD160 = 0x31CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerRipeMD128 = 0x32CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerSha1 = 0x33CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerSha256 = 0x34CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerSha512 = 0x35CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerSha384 = 0x36CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
public const int TrailerWhirlpool = 0x37CC;
- private static IDictionary trailerMap = Platform.CreateHashtable();
-
- static Iso9796d2Signer()
- {
- trailerMap.Add("RIPEMD128", TrailerRipeMD128);
- trailerMap.Add("RIPEMD160", TrailerRipeMD160);
-
- trailerMap.Add("SHA-1", TrailerSha1);
- trailerMap.Add("SHA-256", TrailerSha256);
- trailerMap.Add("SHA-384", TrailerSha384);
- trailerMap.Add("SHA-512", TrailerSha512);
-
- trailerMap.Add("Whirlpool", TrailerWhirlpool);
- }
-
private IDigest digest;
private IAsymmetricBlockCipher cipher;
@@ -60,8 +53,7 @@ namespace Org.BouncyCastle.Crypto.Signers
private byte[] preBlock;
/// <summary>
- /// Generate a signer for the with either implicit or explicit trailers
- /// for ISO9796-2.
+ /// Generate a signer with either implicit or explicit trailers for ISO9796-2.
/// </summary>
/// <param name="cipher">base cipher to use for signature creation/verification</param>
/// <param name="digest">digest to use.</param>
@@ -76,20 +68,15 @@ namespace Org.BouncyCastle.Crypto.Signers
if (isImplicit)
{
- trailer = TrailerImplicit;
+ trailer = IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else if (IsoTrailers.NoTrailerAvailable(digest))
+ {
+ throw new ArgumentException("no valid trailer", "digest");
}
else
{
- string digestName = digest.AlgorithmName;
-
- if (trailerMap.Contains(digestName))
- {
- trailer = (int)trailerMap[digest.AlgorithmName];
- }
- else
- {
- throw new System.ArgumentException("no valid trailer for digest");
- }
+ trailer = IsoTrailers.GetTrailer(digest);
}
}
@@ -105,7 +92,7 @@ namespace Org.BouncyCastle.Crypto.Signers
{
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "with" + "ISO9796-2S1"; }
}
@@ -119,7 +106,7 @@ namespace Org.BouncyCastle.Crypto.Signers
keyBits = kParam.Modulus.BitLength;
block = new byte[(keyBits + 7) / 8];
- if (trailer == TrailerImplicit)
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
{
mBuf = new byte[block.Length - digest.GetDigestSize() - 2];
}
@@ -195,10 +182,10 @@ namespace Org.BouncyCastle.Crypto.Signers
{
int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
- string digestName = digest.AlgorithmName;
- if (!trailerMap.Contains(digestName))
+ if (IsoTrailers.NoTrailerAvailable(digest))
throw new ArgumentException("unrecognised hash in signature");
- if (sigTrail != (int)trailerMap[digestName])
+
+ if (sigTrail != IsoTrailers.GetTrailer(digest))
throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
delta = 2;
@@ -252,7 +239,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
/// <summary> update the internal digest with the byte b</summary>
- public void Update(
+ public virtual void Update(
byte input)
{
digest.Update(input);
@@ -266,7 +253,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
/// <summary> update the internal digest with the byte array in</summary>
- public void BlockUpdate(
+ public virtual void BlockUpdate(
byte[] input,
int inOff,
int length)
@@ -319,12 +306,12 @@ namespace Org.BouncyCastle.Crypto.Signers
int t = 0;
int delta = 0;
- if (trailer == TrailerImplicit)
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
{
t = 8;
delta = block.Length - digSize - 1;
digest.DoFinal(block, delta);
- block[block.Length - 1] = (byte) TrailerImplicit;
+ block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
}
else
{
@@ -424,10 +411,10 @@ namespace Org.BouncyCastle.Crypto.Signers
{
int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
- string digestName = digest.AlgorithmName;
- if (!trailerMap.Contains(digestName))
+ if (IsoTrailers.NoTrailerAvailable(digest))
throw new ArgumentException("unrecognised hash in signature");
- if (sigTrail != (int)trailerMap[digestName])
+
+ if (sigTrail != IsoTrailers.GetTrailer(digest))
throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
delta = 2;
diff --git a/crypto/src/crypto/signers/IsoTrailers.cs b/crypto/src/crypto/signers/IsoTrailers.cs
new file mode 100644
index 000000000..497ffaf78
--- /dev/null
+++ b/crypto/src/crypto/signers/IsoTrailers.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class IsoTrailers
+ {
+ public const int TRAILER_IMPLICIT = 0xBC;
+ public const int TRAILER_RIPEMD160 = 0x31CC;
+ public const int TRAILER_RIPEMD128 = 0x32CC;
+ public const int TRAILER_SHA1 = 0x33CC;
+ public const int TRAILER_SHA256 = 0x34CC;
+ public const int TRAILER_SHA512 = 0x35CC;
+ public const int TRAILER_SHA384 = 0x36CC;
+ public const int TRAILER_WHIRLPOOL = 0x37CC;
+ public const int TRAILER_SHA224 = 0x38CC;
+ public const int TRAILER_SHA512_224 = 0x39CC;
+ public const int TRAILER_SHA512_256 = 0x40CC;
+
+ private static IDictionary CreateTrailerMap()
+ {
+ IDictionary trailers = Platform.CreateHashtable();
+
+ trailers.Add("RIPEMD128", TRAILER_RIPEMD128);
+ trailers.Add("RIPEMD160", TRAILER_RIPEMD160);
+
+ trailers.Add("SHA-1", TRAILER_SHA1);
+ trailers.Add("SHA-224", TRAILER_SHA224);
+ trailers.Add("SHA-256", TRAILER_SHA256);
+ trailers.Add("SHA-384", TRAILER_SHA384);
+ trailers.Add("SHA-512", TRAILER_SHA512);
+ trailers.Add("SHA-512/224", TRAILER_SHA512_224);
+ trailers.Add("SHA-512/256", TRAILER_SHA512_256);
+
+ trailers.Add("Whirlpool", TRAILER_WHIRLPOOL);
+
+ return CollectionUtilities.ReadOnly(trailers);
+ }
+
+ // IDictionary is (string -> Int32)
+ private static readonly IDictionary trailerMap = CreateTrailerMap();
+
+ public static int GetTrailer(IDigest digest)
+ {
+ return (int)trailerMap[digest.AlgorithmName];
+ }
+
+ public static bool NoTrailerAvailable(IDigest digest)
+ {
+ return !trailerMap.Contains(digest.AlgorithmName);
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/PssSigner.cs b/crypto/src/crypto/signers/PssSigner.cs
index 6900224f3..03890902b 100644
--- a/crypto/src/crypto/signers/PssSigner.cs
+++ b/crypto/src/crypto/signers/PssSigner.cs
@@ -115,7 +115,7 @@ namespace Org.BouncyCastle.Crypto.Signers
this.trailer = trailer;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return mgfDigest.AlgorithmName + "withRSAandMGF1"; }
}
diff --git a/crypto/src/crypto/signers/RandomDsaKCalculator.cs b/crypto/src/crypto/signers/RandomDsaKCalculator.cs
new file mode 100644
index 000000000..022cc268d
--- /dev/null
+++ b/crypto/src/crypto/signers/RandomDsaKCalculator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class RandomDsaKCalculator
+ : IDsaKCalculator
+ {
+ private BigInteger q;
+ private SecureRandom random;
+
+ public virtual bool IsDeterministic
+ {
+ get { return false; }
+ }
+
+ public virtual void Init(BigInteger n, SecureRandom random)
+ {
+ this.q = n;
+ this.random = random;
+ }
+
+ public virtual void Init(BigInteger n, BigInteger d, byte[] message)
+ {
+ throw new InvalidOperationException("Operation not supported");
+ }
+
+ public virtual BigInteger NextK()
+ {
+ int qBitLength = q.BitLength;
+
+ BigInteger k;
+ do
+ {
+ k = new BigInteger(qBitLength, random);
+ }
+ while (k.SignValue < 1 || k.CompareTo(q) >= 0);
+
+ return k;
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/RsaDigestSigner.cs b/crypto/src/crypto/signers/RsaDigestSigner.cs
index f57bfc83d..d9b19cf6b 100644
--- a/crypto/src/crypto/signers/RsaDigestSigner.cs
+++ b/crypto/src/crypto/signers/RsaDigestSigner.cs
@@ -19,16 +19,16 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Signers
{
public class RsaDigestSigner
- : ISigner
+ : ISigner
{
private readonly IAsymmetricBlockCipher rsaEngine = new Pkcs1Encoding(new RsaBlindedEngine());
private readonly AlgorithmIdentifier algId;
- private readonly IDigest digest;
- private bool forSigning;
+ private readonly IDigest digest;
+ private bool forSigning;
- private static readonly IDictionary oidMap = Platform.CreateHashtable();
+ private static readonly IDictionary oidMap = Platform.CreateHashtable();
- /// <summary>
+ /// <summary>
/// Load oid table.
/// </summary>
static RsaDigestSigner()
@@ -48,37 +48,36 @@ namespace Org.BouncyCastle.Crypto.Signers
oidMap["MD5"] = PkcsObjectIdentifiers.MD5;
}
- public RsaDigestSigner(
- IDigest digest)
+ public RsaDigestSigner(IDigest digest)
+ : this(digest, (DerObjectIdentifier)oidMap[digest.AlgorithmName])
{
- this.digest = digest;
+ }
- string algName = digest.AlgorithmName;
- if (algName.Equals("NULL"))
- {
- this.algId = null;
- }
- else
- {
- this.algId = new AlgorithmIdentifier(
- (DerObjectIdentifier)oidMap[digest.AlgorithmName], DerNull.Instance);
- }
+ public RsaDigestSigner(IDigest digest, DerObjectIdentifier digestOid)
+ : this(digest, new AlgorithmIdentifier(digestOid, DerNull.Instance))
+ {
}
- public string AlgorithmName
+ public RsaDigestSigner(IDigest digest, AlgorithmIdentifier algId)
+ {
+ this.digest = digest;
+ this.algId = algId;
+ }
+
+ public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "withRSA"; }
}
- /**
+ /**
* Initialise the signer for signing or verification.
*
* @param forSigning true if for signing, false otherwise
* @param param necessary parameters.
*/
- public void Init(
- bool forSigning,
- ICipherParameters parameters)
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
{
this.forSigning = forSigning;
AsymmetricKeyParameter k;
@@ -95,10 +94,10 @@ namespace Org.BouncyCastle.Crypto.Signers
if (forSigning && !k.IsPrivate)
throw new InvalidKeyException("Signing requires private key.");
- if (!forSigning && k.IsPrivate)
+ if (!forSigning && k.IsPrivate)
throw new InvalidKeyException("Verification requires public key.");
- Reset();
+ Reset();
rsaEngine.Init(forSigning, parameters);
}
@@ -106,8 +105,8 @@ namespace Org.BouncyCastle.Crypto.Signers
/**
* update the internal digest with the byte b
*/
- public void Update(
- byte input)
+ public virtual void Update(
+ byte input)
{
digest.Update(input);
}
@@ -115,10 +114,10 @@ namespace Org.BouncyCastle.Crypto.Signers
/**
* update the internal digest with the byte array in
*/
- public void BlockUpdate(
- byte[] input,
- int inOff,
- int length)
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
{
digest.BlockUpdate(input, inOff, length);
}
@@ -127,102 +126,92 @@ namespace Org.BouncyCastle.Crypto.Signers
* Generate a signature for the message we've been loaded with using
* the key we were initialised with.
*/
- public byte[] GenerateSignature()
+ public virtual byte[] GenerateSignature()
{
if (!forSigning)
throw new InvalidOperationException("RsaDigestSigner not initialised for signature generation.");
- byte[] hash = new byte[digest.GetDigestSize()];
+ byte[] hash = new byte[digest.GetDigestSize()];
digest.DoFinal(hash, 0);
- byte[] data = DerEncode(hash);
+ byte[] data = DerEncode(hash);
return rsaEngine.ProcessBlock(data, 0, data.Length);
}
- /**
+ /**
* return true if the internal state represents the signature described
* in the passed in array.
*/
- public bool VerifySignature(
- byte[] signature)
+ public virtual bool VerifySignature(
+ byte[] signature)
{
- if (forSigning)
- throw new InvalidOperationException("RsaDigestSigner not initialised for verification");
-
- byte[] hash = new byte[digest.GetDigestSize()];
- digest.DoFinal(hash, 0);
-
- byte[] sig;
- byte[] expected;
-
- try
- {
- sig = rsaEngine.ProcessBlock(signature, 0, signature.Length);
- expected = DerEncode(hash);
- }
- catch (Exception)
- {
- return false;
- }
-
- if (sig.Length == expected.Length)
- {
- for (int i = 0; i < sig.Length; i++)
- {
- if (sig[i] != expected[i])
- {
- return false;
- }
- }
- }
- else if (sig.Length == expected.Length - 2) // NULL left out
- {
- int sigOffset = sig.Length - hash.Length - 2;
- int expectedOffset = expected.Length - hash.Length - 2;
-
- expected[1] -= 2; // adjust lengths
- expected[3] -= 2;
-
- for (int i = 0; i < hash.Length; i++)
- {
- if (sig[sigOffset + i] != expected[expectedOffset + i]) // check hash
- {
- return false;
- }
- }
-
- for (int i = 0; i < sigOffset; i++)
- {
- if (sig[i] != expected[i]) // check header less NULL
- {
- return false;
- }
- }
- }
- else
- {
- return false;
- }
-
- return true;
+ if (forSigning)
+ throw new InvalidOperationException("RsaDigestSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = rsaEngine.ProcessBlock(signature, 0, signature.Length);
+ expected = DerEncode(hash);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ if (sig.Length == expected.Length)
+ {
+ return Arrays.ConstantTimeAreEqual(sig, expected);
+ }
+ else if (sig.Length == expected.Length - 2) // NULL left out
+ {
+ int sigOffset = sig.Length - hash.Length - 2;
+ int expectedOffset = expected.Length - hash.Length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ int nonEqual = 0;
+
+ for (int i = 0; i < hash.Length; i++)
+ {
+ nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ nonEqual |= (sig[i] ^ expected[i]); // check header less NULL
+ }
+
+ return nonEqual == 0;
+ }
+ else
+ {
+ return false;
+ }
}
- public void Reset()
+ public virtual void Reset()
{
digest.Reset();
}
- private byte[] DerEncode(byte[] hash)
- {
- if (algId == null)
- {
- // For raw RSA, the DigestInfo must be prepared externally
- return hash;
- }
+ private byte[] DerEncode(byte[] hash)
+ {
+ if (algId == null)
+ {
+ // For raw RSA, the DigestInfo must be prepared externally
+ return hash;
+ }
- DigestInfo dInfo = new DigestInfo(algId, hash);
+ DigestInfo dInfo = new DigestInfo(algId, hash);
- return dInfo.GetDerEncoded();
- }
+ return dInfo.GetDerEncoded();
+ }
}
}
diff --git a/crypto/src/crypto/signers/X931Signer.cs b/crypto/src/crypto/signers/X931Signer.cs
new file mode 100644
index 000000000..36483fe17
--- /dev/null
+++ b/crypto/src/crypto/signers/X931Signer.cs
@@ -0,0 +1,225 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * X9.31-1998 - signing using a hash.
+ * <p>
+ * The message digest hash, H, is encapsulated to form a byte string as follows
+ * </p>
+ * <pre>
+ * EB = 06 || PS || 0xBA || H || TRAILER
+ * </pre>
+ * where PS is a string of bytes all of value 0xBB of length such that |EB|=|n|, and TRAILER is the ISO/IEC 10118 part number†for the digest. The byte string, EB, is converted to an integer value, the message representative, f.
+ */
+ public class X931Signer
+ : ISigner
+ {
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_IMPLICIT = 0xBC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_RIPEMD160 = 0x31CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_RIPEMD128 = 0x32CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA1 = 0x33CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA256 = 0x34CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA512 = 0x35CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA384 = 0x36CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_WHIRLPOOL = 0x37CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA224 = 0x38CC;
+
+ private IDigest digest;
+ private IAsymmetricBlockCipher cipher;
+ private RsaKeyParameters kParam;
+
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+
+ /**
+ * Generate a signer with either implicit or explicit trailers for X9.31.
+ *
+ * @param cipher base cipher to use for signature creation/verification
+ * @param digest digest to use.
+ * @param implicit whether or not the trailer is implicit or gives the hash.
+ */
+ public X931Signer(IAsymmetricBlockCipher cipher, IDigest digest, bool isImplicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+
+ if (isImplicit)
+ {
+ trailer = IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else if (IsoTrailers.NoTrailerAvailable(digest))
+ {
+ throw new ArgumentException("no valid trailer", "digest");
+ }
+ else
+ {
+ trailer = IsoTrailers.GetTrailer(digest);
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + cipher.AlgorithmName + "/X9.31"; }
+ }
+
+ /**
+ * Constructor for a signer with an explicit digest trailer.
+ *
+ * @param cipher cipher to use.
+ * @param digest digest to sign with.
+ */
+ public X931Signer(IAsymmetricBlockCipher cipher, IDigest digest)
+ : this(cipher, digest, false)
+ {
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ kParam = (RsaKeyParameters)parameters;
+
+ cipher.Init(forSigning, kParam);
+
+ keyBits = kParam.Modulus.BitLength;
+
+ block = new byte[(keyBits + 7) / 8];
+
+ Reset();
+ }
+
+ /// <summary> clear possible sensitive data</summary>
+ private void ClearBlock(byte[] block)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public virtual void Update(byte b)
+ {
+ digest.Update(b);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public virtual void BlockUpdate(byte[] input, int off, int len)
+ {
+ digest.BlockUpdate(input, off, len);
+ }
+
+ /**
+ * reset the internal state
+ */
+ public virtual void Reset()
+ {
+ digest.Reset();
+ }
+
+ /**
+ * generate a signature for the loaded message using the key we were
+ * initialised with.
+ */
+ public virtual byte[] GenerateSignature()
+ {
+ CreateSignatureBlock();
+
+ BigInteger t = new BigInteger(1, cipher.ProcessBlock(block, 0, block.Length));
+ ClearBlock(block);
+
+ t = t.Min(kParam.Modulus.Subtract(t));
+
+ return BigIntegers.AsUnsignedByteArray((kParam.Modulus.BitLength + 7) / 8, t);
+ }
+
+ private void CreateSignatureBlock()
+ {
+ int digSize = digest.GetDigestSize();
+
+ int delta;
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
+ {
+ delta = block.Length - digSize - 1;
+ digest.DoFinal(block, delta);
+ block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else
+ {
+ delta = block.Length - digSize - 2;
+ digest.DoFinal(block, delta);
+ block[block.Length - 2] = (byte)(trailer >> 8);
+ block[block.Length - 1] = (byte)trailer;
+ }
+
+ block[0] = 0x6b;
+ for (int i = delta - 2; i != 0; i--)
+ {
+ block[i] = (byte)0xbb;
+ }
+ block[delta - 1] = (byte)0xba;
+ }
+
+ /**
+ * return true if the signature represents a ISO9796-2 signature
+ * for the passed in message.
+ */
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ try
+ {
+ block = cipher.ProcessBlock(signature, 0, signature.Length);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ BigInteger t = new BigInteger(block);
+ BigInteger f;
+
+ if ((t.IntValue & 15) == 12)
+ {
+ f = t;
+ }
+ else
+ {
+ t = kParam.Modulus.Subtract(t);
+ if ((t.IntValue & 15) == 12)
+ {
+ f = t;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ CreateSignatureBlock();
+
+ byte[] fBlock = BigIntegers.AsUnsignedByteArray(block.Length, f);
+
+ bool rv = Arrays.ConstantTimeAreEqual(block, fBlock);
+
+ ClearBlock(block);
+ ClearBlock(fBlock);
+
+ return rv;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs b/crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs
new file mode 100644
index 000000000..2d7af80e8
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsAgreementCredentials
+ : AbstractTlsCredentials, TlsAgreementCredentials
+ {
+ /// <exception cref="IOException"></exception>
+ public abstract byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey);
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsCipherFactory.cs b/crypto/src/crypto/tls/AbstractTlsCipherFactory.cs
new file mode 100644
index 000000000..141ee6507
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsCipherFactory.cs
@@ -0,0 +1,15 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class AbstractTlsCipherFactory
+ : TlsCipherFactory
+ {
+ /// <exception cref="IOException"></exception>
+ public virtual TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsClient.cs b/crypto/src/crypto/tls/AbstractTlsClient.cs
new file mode 100644
index 000000000..046feb78c
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsClient.cs
@@ -0,0 +1,258 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsClient
+ : AbstractTlsPeer, TlsClient
+ {
+ protected TlsCipherFactory mCipherFactory;
+
+ protected TlsClientContext mContext;
+
+ protected IList mSupportedSignatureAlgorithms;
+ protected int[] mNamedCurves;
+ protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+ protected int mSelectedCipherSuite;
+ protected short mSelectedCompressionMethod;
+
+ public AbstractTlsClient()
+ : this(new DefaultTlsCipherFactory())
+ {
+ }
+
+ public AbstractTlsClient(TlsCipherFactory cipherFactory)
+ {
+ this.mCipherFactory = cipherFactory;
+ }
+
+ protected virtual bool AllowUnexpectedServerExtension(int extensionType, byte[] extensionData)
+ {
+ switch (extensionType)
+ {
+ case ExtensionType.elliptic_curves:
+ /*
+ * Exception added based on field reports that some servers do send this, although the
+ * Supported Elliptic Curves Extension is clearly intended to be client-only. If
+ * present, we still require that it is a valid EllipticCurveList.
+ */
+ TlsEccUtilities.ReadSupportedEllipticCurvesExtension(extensionData);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected virtual void CheckForUnexpectedServerExtension(IDictionary serverExtensions, int extensionType)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(serverExtensions, extensionType);
+ if (extensionData != null && !AllowUnexpectedServerExtension(extensionType, extensionData))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public virtual void Init(TlsClientContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual TlsSession GetSessionToResume()
+ {
+ return null;
+ }
+
+ /**
+ * RFC 5246 E.1. "TLS clients that wish to negotiate with older servers MAY send any value
+ * {03,XX} as the record layer version number. Typical values would be {03,00}, the lowest
+ * version number supported by the client, and the value of ClientHello.client_version. No
+ * single value will guarantee interoperability with all old servers, but this is a complex
+ * topic beyond the scope of this document."
+ */
+ public virtual ProtocolVersion ClientHelloRecordLayerVersion
+ {
+ get
+ {
+ // "{03,00}"
+ // return ProtocolVersion.SSLv3;
+
+ // "the lowest version number supported by the client"
+ // return getMinimumVersion();
+
+ // "the value of ClientHello.client_version"
+ return ClientVersion;
+ }
+ }
+
+ public virtual ProtocolVersion ClientVersion
+ {
+ get { return ProtocolVersion.TLSv12; }
+ }
+
+ public virtual bool IsFallback
+ {
+ /*
+ * draft-ietf-tls-downgrade-scsv-00 4. [..] is meant for use by clients that repeat a
+ * connection attempt with a downgraded protocol in order to avoid interoperability problems
+ * with legacy servers.
+ */
+ get { return false; }
+ }
+
+ public virtual IDictionary GetClientExtensions()
+ {
+ IDictionary clientExtensions = null;
+
+ ProtocolVersion clientVersion = mContext.ClientVersion;
+
+ /*
+ * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior to 1.2.
+ * Clients MUST NOT offer it if they are offering prior versions.
+ */
+ if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
+ {
+ // TODO Provide a way for the user to specify the acceptable hash/signature algorithms.
+
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
+
+ clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);
+
+ TlsUtilities.AddSignatureAlgorithmsExtension(clientExtensions, mSupportedSignatureAlgorithms);
+ }
+
+ if (TlsEccUtilities.ContainsEccCipherSuites(GetCipherSuites()))
+ {
+ /*
+ * RFC 4492 5.1. A client that proposes ECC cipher suites in its ClientHello message
+ * appends these extensions (along with any others), enumerating the curves it supports
+ * and the point formats it can parse. Clients SHOULD send both the Supported Elliptic
+ * Curves Extension and the Supported Point Formats Extension.
+ */
+ /*
+ * TODO Could just add all the curves since we support them all, but users may not want
+ * to use unnecessarily large fields. Need configuration options.
+ */
+ this.mNamedCurves = new int[]{ NamedCurve.secp256r1, NamedCurve.secp384r1 };
+ this.mClientECPointFormats = new byte[]{ ECPointFormat.uncompressed,
+ ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };
+
+ clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);
+
+ TlsEccUtilities.AddSupportedEllipticCurvesExtension(clientExtensions, mNamedCurves);
+ TlsEccUtilities.AddSupportedPointFormatsExtension(clientExtensions, mClientECPointFormats);
+ }
+
+ return clientExtensions;
+ }
+
+ public virtual ProtocolVersion MinimumVersion
+ {
+ get { return ProtocolVersion.TLSv10; }
+ }
+
+ public virtual void NotifyServerVersion(ProtocolVersion serverVersion)
+ {
+ if (!MinimumVersion.IsEqualOrEarlierVersionOf(serverVersion))
+ throw new TlsFatalAlert(AlertDescription.protocol_version);
+ }
+
+ public abstract int[] GetCipherSuites();
+
+ public virtual byte[] GetCompressionMethods()
+ {
+ return new byte[]{ CompressionMethod.cls_null };
+ }
+
+ public virtual void NotifySessionID(byte[] sessionID)
+ {
+ // Currently ignored
+ }
+
+ public virtual void NotifySelectedCipherSuite(int selectedCipherSuite)
+ {
+ this.mSelectedCipherSuite = selectedCipherSuite;
+ }
+
+ public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
+ {
+ this.mSelectedCompressionMethod = selectedCompressionMethod;
+ }
+
+ public virtual void ProcessServerExtensions(IDictionary serverExtensions)
+ {
+ /*
+ * TlsProtocol implementation validates that any server extensions received correspond to
+ * client extensions sent. By default, we don't send any, and this method is not called.
+ */
+ if (serverExtensions != null)
+ {
+ /*
+ * RFC 5246 7.4.1.4.1. Servers MUST NOT send this extension.
+ */
+ CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.signature_algorithms);
+
+ CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.elliptic_curves);
+
+ if (TlsEccUtilities.IsEccCipherSuite(this.mSelectedCipherSuite))
+ {
+ this.mServerECPointFormats = TlsEccUtilities.GetSupportedPointFormatsExtension(serverExtensions);
+ }
+ else
+ {
+ CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.ec_point_formats);
+ }
+ }
+ }
+
+ public virtual void ProcessServerSupplementalData(IList serverSupplementalData)
+ {
+ if (serverSupplementalData != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public abstract TlsKeyExchange GetKeyExchange();
+
+ public abstract TlsAuthentication GetAuthentication();
+
+ public virtual IList GetClientSupplementalData()
+ {
+ return null;
+ }
+
+ public override TlsCompression GetCompression()
+ {
+ switch (mSelectedCompressionMethod)
+ {
+ case CompressionMethod.cls_null:
+ return new TlsNullCompression();
+
+ case CompressionMethod.DEFLATE:
+ return new TlsDeflateCompression();
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected compression method was in the list of client-offered compression
+ * methods, so if we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsCipher GetCipher()
+ {
+ int encryptionAlgorithm = TlsUtilities.GetEncryptionAlgorithm(mSelectedCipherSuite);
+ int macAlgorithm = TlsUtilities.GetMacAlgorithm(mSelectedCipherSuite);
+
+ return mCipherFactory.CreateCipher(mContext, encryptionAlgorithm, macAlgorithm);
+ }
+
+ public virtual void NotifyNewSessionTicket(NewSessionTicket newSessionTicket)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsContext.cs b/crypto/src/crypto/tls/AbstractTlsContext.cs
new file mode 100644
index 000000000..ae7efc64d
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsContext.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Threading;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal abstract class AbstractTlsContext
+ : TlsContext
+ {
+ private static long counter = Times.NanoTime();
+
+#if NETCF_1_0
+ private static object counterLock = new object();
+ private static long NextCounterValue()
+ {
+ lock (counterLock)
+ {
+ return ++counter;
+ }
+ }
+#else
+ private static long NextCounterValue()
+ {
+ return Interlocked.Increment(ref counter);
+ }
+#endif
+
+ private readonly IRandomGenerator mNonceRandom;
+ private readonly SecureRandom mSecureRandom;
+ private readonly SecurityParameters mSecurityParameters;
+
+ private ProtocolVersion mClientVersion = null;
+ private ProtocolVersion mServerVersion = null;
+ private TlsSession mSession = null;
+ private object mUserObject = null;
+
+ internal AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters)
+ {
+ IDigest d = TlsUtilities.CreateHash(HashAlgorithm.sha256);
+ byte[] seed = new byte[d.GetDigestSize()];
+ secureRandom.NextBytes(seed);
+
+ this.mNonceRandom = new DigestRandomGenerator(d);
+ mNonceRandom.AddSeedMaterial(NextCounterValue());
+ mNonceRandom.AddSeedMaterial(Times.NanoTime());
+ mNonceRandom.AddSeedMaterial(seed);
+
+ this.mSecureRandom = secureRandom;
+ this.mSecurityParameters = securityParameters;
+ }
+
+ public virtual IRandomGenerator NonceRandomGenerator
+ {
+ get { return mNonceRandom; }
+ }
+
+ public virtual SecureRandom SecureRandom
+ {
+ get { return mSecureRandom; }
+ }
+
+ public virtual SecurityParameters SecurityParameters
+ {
+ get { return mSecurityParameters; }
+ }
+
+ public abstract bool IsServer { get; }
+
+ public virtual ProtocolVersion ClientVersion
+ {
+ get { return mClientVersion; }
+ }
+
+ internal virtual void SetClientVersion(ProtocolVersion clientVersion)
+ {
+ this.mClientVersion = clientVersion;
+ }
+
+ public virtual ProtocolVersion ServerVersion
+ {
+ get { return mServerVersion; }
+ }
+
+ internal virtual void SetServerVersion(ProtocolVersion serverVersion)
+ {
+ this.mServerVersion = serverVersion;
+ }
+
+ public virtual TlsSession ResumableSession
+ {
+ get { return mSession; }
+ }
+
+ internal virtual void SetResumableSession(TlsSession session)
+ {
+ this.mSession = session;
+ }
+
+ public virtual object UserObject
+ {
+ get { return mUserObject; }
+ set { this.mUserObject = value; }
+ }
+
+ public virtual byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length)
+ {
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 5.4. If a client or server chooses to continue with a full
+ * handshake without the extended master secret extension, [..] the client or server MUST
+ * NOT export any key material based on the new master secret for any subsequent
+ * application-level authentication. In particular, it MUST disable [RFC5705] [..].
+ */
+
+ if (context_value != null && !TlsUtilities.IsValidUint16(context_value.Length))
+ throw new ArgumentException("must have length less than 2^16 (or be null)", "context_value");
+
+ SecurityParameters sp = SecurityParameters;
+ byte[] cr = sp.ClientRandom, sr = sp.ServerRandom;
+
+ int seedLength = cr.Length + sr.Length;
+ if (context_value != null)
+ {
+ seedLength += (2 + context_value.Length);
+ }
+
+ byte[] seed = new byte[seedLength];
+ int seedPos = 0;
+
+ Array.Copy(cr, 0, seed, seedPos, cr.Length);
+ seedPos += cr.Length;
+ Array.Copy(sr, 0, seed, seedPos, sr.Length);
+ seedPos += sr.Length;
+ if (context_value != null)
+ {
+ TlsUtilities.WriteUint16(context_value.Length, seed, seedPos);
+ seedPos += 2;
+ Array.Copy(context_value, 0, seed, seedPos, context_value.Length);
+ seedPos += context_value.Length;
+ }
+
+ if (seedPos != seedLength)
+ throw new InvalidOperationException("error in calculation of seed for export");
+
+ return TlsUtilities.PRF(this, sp.MasterSecret, asciiLabel, seed, length);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsCredentials.cs b/crypto/src/crypto/tls/AbstractTlsCredentials.cs
new file mode 100644
index 000000000..6411b811c
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsCredentials.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsCredentials
+ : TlsCredentials
+ {
+ public abstract Certificate Certificate { get; }
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs b/crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs
new file mode 100644
index 000000000..05b129c60
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsEncryptionCredentials
+ : AbstractTlsCredentials, TlsEncryptionCredentials
+ {
+ /// <exception cref="IOException"></exception>
+ public abstract byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret);
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
new file mode 100644
index 000000000..c9ec06107
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsKeyExchange
+ : TlsKeyExchange
+ {
+ protected readonly int mKeyExchange;
+ protected IList mSupportedSignatureAlgorithms;
+
+ protected TlsContext mContext;
+
+ protected AbstractTlsKeyExchange(int keyExchange, IList supportedSignatureAlgorithms)
+ {
+ this.mKeyExchange = keyExchange;
+ this.mSupportedSignatureAlgorithms = supportedSignatureAlgorithms;
+ }
+
+ public virtual void Init(TlsContext context)
+ {
+ this.mContext = context;
+
+ ProtocolVersion clientVersion = context.ClientVersion;
+
+ if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
+ {
+ /*
+ * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension,
+ * the server MUST do the following:
+ *
+ * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK,
+ * ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}.
+ *
+ * - If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if
+ * the client had sent the value {sha1,dsa}.
+ *
+ * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA),
+ * behave as if the client had sent value {sha1,ecdsa}.
+ */
+ if (this.mSupportedSignatureAlgorithms == null)
+ {
+ switch (mKeyExchange)
+ {
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.SRP_DSS:
+ {
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultDssSignatureAlgorithms();
+ break;
+ }
+
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ {
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+ break;
+ }
+
+ case KeyExchangeAlgorithm.DH_RSA:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ case KeyExchangeAlgorithm.RSA:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ case KeyExchangeAlgorithm.SRP_RSA:
+ {
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
+ break;
+ }
+
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.SRP:
+ break;
+
+ default:
+ throw new InvalidOperationException("unsupported key exchange algorithm");
+ }
+ }
+
+ }
+ else if (this.mSupportedSignatureAlgorithms != null)
+ {
+ throw new InvalidOperationException("supported_signature_algorithms not allowed for " + clientVersion);
+ }
+ }
+
+ public abstract void SkipServerCredentials();
+
+ public virtual void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (mSupportedSignatureAlgorithms == null)
+ {
+ /*
+ * TODO RFC 2264 7.4.2. Unless otherwise specified, the signing algorithm for the
+ * certificate must be the same as the algorithm for the certificate key.
+ */
+ }
+ else
+ {
+ /*
+ * TODO RFC 5264 7.4.2. If the client provided a "signature_algorithms" extension, then
+ * all certificates provided by the server MUST be signed by a hash/signature algorithm
+ * pair that appears in that extension.
+ */
+ }
+ }
+
+ public virtual void ProcessServerCredentials(TlsCredentials serverCredentials)
+ {
+ ProcessServerCertificate(serverCredentials.Certificate);
+ }
+
+ public virtual bool RequiresServerKeyExchange
+ {
+ get { return false; }
+ }
+
+ public virtual byte[] GenerateServerKeyExchange()
+ {
+ if (RequiresServerKeyExchange)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return null;
+ }
+
+ public virtual void SkipServerKeyExchange()
+ {
+ if (RequiresServerKeyExchange)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public virtual void ProcessServerKeyExchange(Stream input)
+ {
+ if (!RequiresServerKeyExchange)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ public abstract void ValidateCertificateRequest(CertificateRequest certificateRequest);
+
+ public virtual void SkipClientCredentials()
+ {
+ }
+
+ public abstract void ProcessClientCredentials(TlsCredentials clientCredentials);
+
+ public virtual void ProcessClientCertificate(Certificate clientCertificate)
+ {
+ }
+
+ public abstract void GenerateClientKeyExchange(Stream output);
+
+ public virtual void ProcessClientKeyExchange(Stream input)
+ {
+ // Key exchange implementation MUST support client key exchange
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public abstract byte[] GeneratePremasterSecret();
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsPeer.cs b/crypto/src/crypto/tls/AbstractTlsPeer.cs
new file mode 100644
index 000000000..81a53386c
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsPeer.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsPeer
+ : TlsPeer
+ {
+ public virtual bool ShouldUseGmtUnixTime()
+ {
+ /*
+ * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
+ * TLS implementors MUST by default set the entire value the ClientHello.Random and
+ * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
+ * sequence.
+ */
+ return false;
+ }
+
+ public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
+ {
+ if (!secureRenegotiation)
+ {
+ /*
+ * RFC 5746 3.4/3.6. In this case, some clients/servers may want to terminate the handshake instead
+ * of continuing; see Section 4.1/4.3 for discussion.
+ */
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ public abstract TlsCompression GetCompression();
+
+ public abstract TlsCipher GetCipher();
+
+ public virtual void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+ {
+ }
+
+ public virtual void NotifyAlertReceived(byte alertLevel, byte alertDescription)
+ {
+ }
+
+ public virtual void NotifyHandshakeComplete()
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsServer.cs b/crypto/src/crypto/tls/AbstractTlsServer.cs
new file mode 100644
index 000000000..9f549cfd1
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsServer.cs
@@ -0,0 +1,349 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsServer
+ : AbstractTlsPeer, TlsServer
+ {
+ protected TlsCipherFactory mCipherFactory;
+
+ protected TlsServerContext mContext;
+
+ protected ProtocolVersion mClientVersion;
+ protected int[] mOfferedCipherSuites;
+ protected byte[] mOfferedCompressionMethods;
+ protected IDictionary mClientExtensions;
+
+ protected bool mEncryptThenMacOffered;
+ protected short mMaxFragmentLengthOffered;
+ protected bool mTruncatedHMacOffered;
+ protected IList mSupportedSignatureAlgorithms;
+ protected bool mEccCipherSuitesOffered;
+ protected int[] mNamedCurves;
+ protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+ protected ProtocolVersion mServerVersion;
+ protected int mSelectedCipherSuite;
+ protected byte mSelectedCompressionMethod;
+ protected IDictionary mServerExtensions;
+
+ public AbstractTlsServer()
+ : this(new DefaultTlsCipherFactory())
+ {
+ }
+
+ public AbstractTlsServer(TlsCipherFactory cipherFactory)
+ {
+ this.mCipherFactory = cipherFactory;
+ }
+
+ protected virtual bool AllowEncryptThenMac
+ {
+ get { return true; }
+ }
+
+ protected virtual bool AllowTruncatedHMac
+ {
+ get { return false; }
+ }
+
+ protected virtual IDictionary CheckServerExtensions()
+ {
+ return this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mServerExtensions);
+ }
+
+ protected abstract int[] GetCipherSuites();
+
+ protected byte[] GetCompressionMethods()
+ {
+ return new byte[] { CompressionMethod.cls_null };
+ }
+
+ protected virtual ProtocolVersion MaximumVersion
+ {
+ get { return ProtocolVersion.TLSv11; }
+ }
+
+ protected virtual ProtocolVersion MinimumVersion
+ {
+ get { return ProtocolVersion.TLSv10; }
+ }
+
+ protected virtual bool SupportsClientEccCapabilities(int[] namedCurves, byte[] ecPointFormats)
+ {
+ // NOTE: BC supports all the current set of point formats so we don't check them here
+
+ if (namedCurves == null)
+ {
+ /*
+ * RFC 4492 4. A client that proposes ECC cipher suites may choose not to include these
+ * extensions. In this case, the server is free to choose any one of the elliptic curves
+ * or point formats [...].
+ */
+ return TlsEccUtilities.HasAnySupportedNamedCurves();
+ }
+
+ for (int i = 0; i < namedCurves.Length; ++i)
+ {
+ int namedCurve = namedCurves[i];
+ if (NamedCurve.IsValid(namedCurve)
+ && (!NamedCurve.RefersToASpecificNamedCurve(namedCurve) || TlsEccUtilities.IsSupportedNamedCurve(namedCurve)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public virtual void Init(TlsServerContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual void NotifyClientVersion(ProtocolVersion clientVersion)
+ {
+ this.mClientVersion = clientVersion;
+ }
+
+ public virtual void NotifyFallback(bool isFallback)
+ {
+ /*
+ * draft-ietf-tls-downgrade-scsv-00 3. If TLS_FALLBACK_SCSV appears in
+ * ClientHello.cipher_suites and the highest protocol version supported by the server is
+ * higher than the version indicated in ClientHello.client_version, the server MUST respond
+ * with an inappropriate_fallback alert.
+ */
+ if (isFallback && MaximumVersion.IsLaterVersionOf(mClientVersion))
+ throw new TlsFatalAlert(AlertDescription.inappropriate_fallback);
+ }
+
+ public virtual void NotifyOfferedCipherSuites(int[] offeredCipherSuites)
+ {
+ this.mOfferedCipherSuites = offeredCipherSuites;
+ this.mEccCipherSuitesOffered = TlsEccUtilities.ContainsEccCipherSuites(this.mOfferedCipherSuites);
+ }
+
+ public virtual void NotifyOfferedCompressionMethods(byte[] offeredCompressionMethods)
+ {
+ this.mOfferedCompressionMethods = offeredCompressionMethods;
+ }
+
+ public virtual void ProcessClientExtensions(IDictionary clientExtensions)
+ {
+ this.mClientExtensions = clientExtensions;
+
+ if (clientExtensions != null)
+ {
+ this.mEncryptThenMacOffered = TlsExtensionsUtilities.HasEncryptThenMacExtension(clientExtensions);
+
+ this.mMaxFragmentLengthOffered = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions);
+ if (mMaxFragmentLengthOffered >= 0 && !MaxFragmentLength.IsValid((byte)mMaxFragmentLengthOffered))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ this.mTruncatedHMacOffered = TlsExtensionsUtilities.HasTruncatedHMacExtension(clientExtensions);
+
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetSignatureAlgorithmsExtension(clientExtensions);
+ if (this.mSupportedSignatureAlgorithms != null)
+ {
+ /*
+ * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior
+ * to 1.2. Clients MUST NOT offer it if they are offering prior versions.
+ */
+ if (!TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mClientVersion))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ this.mNamedCurves = TlsEccUtilities.GetSupportedEllipticCurvesExtension(clientExtensions);
+ this.mClientECPointFormats = TlsEccUtilities.GetSupportedPointFormatsExtension(clientExtensions);
+ }
+
+ /*
+ * RFC 4429 4. The client MUST NOT include these extensions in the ClientHello message if it
+ * does not propose any ECC cipher suites.
+ *
+ * NOTE: This was overly strict as there may be ECC cipher suites that we don't recognize.
+ * Also, draft-ietf-tls-negotiated-ff-dhe will be overloading the 'elliptic_curves'
+ * extension to explicitly allow FFDHE (i.e. non-ECC) groups.
+ */
+ //if (!this.mEccCipherSuitesOffered && (this.mNamedCurves != null || this.mClientECPointFormats != null))
+ // throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ public virtual ProtocolVersion GetServerVersion()
+ {
+ if (MinimumVersion.IsEqualOrEarlierVersionOf(mClientVersion))
+ {
+ ProtocolVersion maximumVersion = MaximumVersion;
+ if (mClientVersion.IsEqualOrEarlierVersionOf(maximumVersion))
+ {
+ return mServerVersion = mClientVersion;
+ }
+ if (mClientVersion.IsLaterVersionOf(maximumVersion))
+ {
+ return mServerVersion = maximumVersion;
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.protocol_version);
+ }
+
+ public virtual int GetSelectedCipherSuite()
+ {
+ /*
+ * TODO RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate
+ * cipher suites against the "signature_algorithms" extension before selecting them. This is
+ * somewhat inelegant but is a compromise designed to minimize changes to the original
+ * cipher suite design.
+ */
+
+ /*
+ * RFC 4429 5.1. A server that receives a ClientHello containing one or both of these
+ * extensions MUST use the client's enumerated capabilities to guide its selection of an
+ * appropriate cipher suite. One of the proposed ECC cipher suites must be negotiated only
+ * if the server can successfully complete the handshake while using the curves and point
+ * formats supported by the client [...].
+ */
+ bool eccCipherSuitesEnabled = SupportsClientEccCapabilities(this.mNamedCurves, this.mClientECPointFormats);
+
+ int[] cipherSuites = GetCipherSuites();
+ for (int i = 0; i < cipherSuites.Length; ++i)
+ {
+ int cipherSuite = cipherSuites[i];
+
+ if (Arrays.Contains(this.mOfferedCipherSuites, cipherSuite)
+ && (eccCipherSuitesEnabled || !TlsEccUtilities.IsEccCipherSuite(cipherSuite))
+ && TlsUtilities.IsValidCipherSuiteForVersion(cipherSuite, mServerVersion))
+ {
+ return this.mSelectedCipherSuite = cipherSuite;
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ public virtual byte GetSelectedCompressionMethod()
+ {
+ byte[] compressionMethods = GetCompressionMethods();
+ for (int i = 0; i < compressionMethods.Length; ++i)
+ {
+ if (Arrays.Contains(mOfferedCompressionMethods, compressionMethods[i]))
+ {
+ return this.mSelectedCompressionMethod = compressionMethods[i];
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ // IDictionary is (Int32 -> byte[])
+ public virtual IDictionary GetServerExtensions()
+ {
+ if (this.mEncryptThenMacOffered && AllowEncryptThenMac)
+ {
+ /*
+ * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
+ * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
+ * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
+ * client.
+ */
+ if (TlsUtilities.IsBlockCipherSuite(this.mSelectedCipherSuite))
+ {
+ TlsExtensionsUtilities.AddEncryptThenMacExtension(CheckServerExtensions());
+ }
+ }
+
+ if (this.mMaxFragmentLengthOffered >= 0
+ && TlsUtilities.IsValidUint8(mMaxFragmentLengthOffered)
+ && MaxFragmentLength.IsValid((byte)mMaxFragmentLengthOffered))
+ {
+ TlsExtensionsUtilities.AddMaxFragmentLengthExtension(CheckServerExtensions(), (byte)mMaxFragmentLengthOffered);
+ }
+
+ if (this.mTruncatedHMacOffered && AllowTruncatedHMac)
+ {
+ TlsExtensionsUtilities.AddTruncatedHMacExtension(CheckServerExtensions());
+ }
+
+ if (this.mClientECPointFormats != null && TlsEccUtilities.IsEccCipherSuite(this.mSelectedCipherSuite))
+ {
+ /*
+ * RFC 4492 5.2. A server that selects an ECC cipher suite in response to a ClientHello
+ * message including a Supported Point Formats Extension appends this extension (along
+ * with others) to its ServerHello message, enumerating the point formats it can parse.
+ */
+ this.mServerECPointFormats = new byte[]{ ECPointFormat.uncompressed,
+ ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };
+
+ TlsEccUtilities.AddSupportedPointFormatsExtension(CheckServerExtensions(), mServerECPointFormats);
+ }
+
+ return mServerExtensions;
+ }
+
+ public virtual IList GetServerSupplementalData()
+ {
+ return null;
+ }
+
+ public abstract TlsCredentials GetCredentials();
+
+ public virtual CertificateStatus GetCertificateStatus()
+ {
+ return null;
+ }
+
+ public abstract TlsKeyExchange GetKeyExchange();
+
+ public virtual CertificateRequest GetCertificateRequest()
+ {
+ return null;
+ }
+
+ public virtual void ProcessClientSupplementalData(IList clientSupplementalData)
+ {
+ if (clientSupplementalData != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public virtual void NotifyClientCertificate(Certificate clientCertificate)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public override TlsCompression GetCompression()
+ {
+ switch (mSelectedCompressionMethod)
+ {
+ case CompressionMethod.cls_null:
+ return new TlsNullCompression();
+
+ default:
+ /*
+ * Note: internal error here; we selected the compression method, so if we now can't
+ * produce an implementation, we shouldn't have chosen it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsCipher GetCipher()
+ {
+ int encryptionAlgorithm = TlsUtilities.GetEncryptionAlgorithm(mSelectedCipherSuite);
+ int macAlgorithm = TlsUtilities.GetMacAlgorithm(mSelectedCipherSuite);
+
+ return mCipherFactory.CreateCipher(mContext, encryptionAlgorithm, macAlgorithm);
+ }
+
+ public virtual NewSessionTicket GetNewSessionTicket()
+ {
+ /*
+ * RFC 5077 3.3. If the server determines that it does not want to include a ticket after it
+ * has included the SessionTicket extension in the ServerHello, then it sends a zero-length
+ * ticket in the NewSessionTicket handshake message.
+ */
+ return new NewSessionTicket(0L, TlsUtilities.EmptyBytes);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsSigner.cs b/crypto/src/crypto/tls/AbstractTlsSigner.cs
new file mode 100644
index 000000000..1f4aabf74
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsSigner.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsSigner
+ : TlsSigner
+ {
+ protected TlsContext mContext;
+
+ public virtual void Init(TlsContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual byte[] GenerateRawSignature(AsymmetricKeyParameter privateKey, byte[] md5AndSha1)
+ {
+ return GenerateRawSignature(null, privateKey, md5AndSha1);
+ }
+
+ public abstract byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+ AsymmetricKeyParameter privateKey, byte[] hash);
+
+ public virtual bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5AndSha1)
+ {
+ return VerifyRawSignature(null, sigBytes, publicKey, md5AndSha1);
+ }
+
+ public abstract bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+ AsymmetricKeyParameter publicKey, byte[] hash);
+
+ public virtual ISigner CreateSigner(AsymmetricKeyParameter privateKey)
+ {
+ return CreateSigner(null, privateKey);
+ }
+
+ public abstract ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey);
+
+ public virtual ISigner CreateVerifyer(AsymmetricKeyParameter publicKey)
+ {
+ return CreateVerifyer(null, publicKey);
+ }
+
+ public abstract ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey);
+
+ public abstract bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
+ }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs b/crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs
new file mode 100644
index 000000000..886c46c6e
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs
@@ -0,0 +1,20 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsSignerCredentials
+ : AbstractTlsCredentials, TlsSignerCredentials
+ {
+ /// <exception cref="IOException"></exception>
+ public abstract byte[] GenerateCertificateSignature(byte[] hash);
+
+ public virtual SignatureAndHashAlgorithm SignatureAndHashAlgorithm
+ {
+ get
+ {
+ throw new InvalidOperationException("TlsSignerCredentials implementation does not support (D)TLS 1.2+");
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/AlertDescription.cs b/crypto/src/crypto/tls/AlertDescription.cs
index e09da6cab..49de60cea 100644
--- a/crypto/src/crypto/tls/AlertDescription.cs
+++ b/crypto/src/crypto/tls/AlertDescription.cs
@@ -213,5 +213,92 @@ namespace Org.BouncyCastle.Crypto.Tls
* "unknown_psk_identity" alert message.
*/
public const byte unknown_psk_identity = 115;
+
+ /*
+ * draft-ietf-tls-downgrade-scsv-00
+ */
+
+ /**
+ * If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest protocol version
+ * supported by the server is higher than the version indicated in ClientHello.client_version,
+ * the server MUST respond with an inappropriate_fallback alert.
+ */
+ public const byte inappropriate_fallback = 86;
+
+ public static string GetName(byte alertDescription)
+ {
+ switch (alertDescription)
+ {
+ case close_notify:
+ return "close_notify";
+ case unexpected_message:
+ return "unexpected_message";
+ case bad_record_mac:
+ return "bad_record_mac";
+ case decryption_failed:
+ return "decryption_failed";
+ case record_overflow:
+ return "record_overflow";
+ case decompression_failure:
+ return "decompression_failure";
+ case handshake_failure:
+ return "handshake_failure";
+ case no_certificate:
+ return "no_certificate";
+ case bad_certificate:
+ return "bad_certificate";
+ case unsupported_certificate:
+ return "unsupported_certificate";
+ case certificate_revoked:
+ return "certificate_revoked";
+ case certificate_expired:
+ return "certificate_expired";
+ case certificate_unknown:
+ return "certificate_unknown";
+ case illegal_parameter:
+ return "illegal_parameter";
+ case unknown_ca:
+ return "unknown_ca";
+ case access_denied:
+ return "access_denied";
+ case decode_error:
+ return "decode_error";
+ case decrypt_error:
+ return "decrypt_error";
+ case export_restriction:
+ return "export_restriction";
+ case protocol_version:
+ return "protocol_version";
+ case insufficient_security:
+ return "insufficient_security";
+ case internal_error:
+ return "internal_error";
+ case user_canceled:
+ return "user_canceled";
+ case no_renegotiation:
+ return "no_renegotiation";
+ case unsupported_extension:
+ return "unsupported_extension";
+ case certificate_unobtainable:
+ return "certificate_unobtainable";
+ case unrecognized_name:
+ return "unrecognized_name";
+ case bad_certificate_status_response:
+ return "bad_certificate_status_response";
+ case bad_certificate_hash_value:
+ return "bad_certificate_hash_value";
+ case unknown_psk_identity:
+ return "unknown_psk_identity";
+ case inappropriate_fallback:
+ return "inappropriate_fallback";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ public static string GetText(byte alertDescription)
+ {
+ return GetName(alertDescription) + "(" + alertDescription + ")";
+ }
}
}
diff --git a/crypto/src/crypto/tls/AlertLevel.cs b/crypto/src/crypto/tls/AlertLevel.cs
index d77251dfb..9461a0b58 100644
--- a/crypto/src/crypto/tls/AlertLevel.cs
+++ b/crypto/src/crypto/tls/AlertLevel.cs
@@ -7,5 +7,23 @@ namespace Org.BouncyCastle.Crypto.Tls
{
public const byte warning = 1;
public const byte fatal = 2;
+
+ public static string GetName(byte alertDescription)
+ {
+ switch (alertDescription)
+ {
+ case warning:
+ return "warning";
+ case fatal:
+ return "fatal";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ public static string GetText(byte alertDescription)
+ {
+ return GetName(alertDescription) + "(" + alertDescription + ")";
+ }
}
}
diff --git a/crypto/src/crypto/tls/AlwaysValidVerifyer.cs b/crypto/src/crypto/tls/AlwaysValidVerifyer.cs
deleted file mode 100644
index e26c6fc3f..000000000
--- a/crypto/src/crypto/tls/AlwaysValidVerifyer.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-
-using Org.BouncyCastle.Asn1.X509;
-
-namespace Org.BouncyCastle.Crypto.Tls
-{
- /// <remarks>
- /// A certificate verifyer, that will always return true.
- /// <pre>
- /// DO NOT USE THIS FILE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
- /// </pre>
- /// </remarks>
- [Obsolete("Perform certificate verification in TlsAuthentication implementation")]
- public class AlwaysValidVerifyer
- : ICertificateVerifyer
- {
- /// <summary>Return true.</summary>
- public bool IsValid(
- X509CertificateStructure[] certs)
- {
- return true;
- }
- }
-}
diff --git a/crypto/src/crypto/tls/BasicTlsPskIdentity.cs b/crypto/src/crypto/tls/BasicTlsPskIdentity.cs
new file mode 100644
index 000000000..db5954422
--- /dev/null
+++ b/crypto/src/crypto/tls/BasicTlsPskIdentity.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class BasicTlsPskIdentity
+ : TlsPskIdentity
+ {
+ protected byte[] mIdentity;
+ protected byte[] mPsk;
+
+ public BasicTlsPskIdentity(byte[] identity, byte[] psk)
+ {
+ this.mIdentity = Arrays.Clone(identity);
+ this.mPsk = Arrays.Clone(psk);
+ }
+
+ public BasicTlsPskIdentity(string identity, byte[] psk)
+ {
+ this.mIdentity = Strings.ToUtf8ByteArray(identity);
+ this.mPsk = Arrays.Clone(psk);
+ }
+
+ public virtual void SkipIdentityHint()
+ {
+ }
+
+ public virtual void NotifyIdentityHint(byte[] psk_identity_hint)
+ {
+ }
+
+ public virtual byte[] GetPskIdentity()
+ {
+ return mIdentity;
+ }
+
+ public virtual byte[] GetPsk()
+ {
+ return mPsk;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/ByteQueueStream.cs b/crypto/src/crypto/tls/ByteQueueStream.cs
new file mode 100644
index 000000000..bf603e006
--- /dev/null
+++ b/crypto/src/crypto/tls/ByteQueueStream.cs
@@ -0,0 +1,114 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ByteQueueStream
+ : Stream
+ {
+ private readonly ByteQueue buffer;
+
+ public ByteQueueStream()
+ {
+ this.buffer = new ByteQueue();
+ }
+
+ public virtual int Available
+ {
+ get { return buffer.Available; }
+ }
+
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+
+ public override void Close()
+ {
+ }
+
+ public override void Flush()
+ {
+ }
+
+ public override long Length
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public virtual int Peek(byte[] buf)
+ {
+ int bytesToRead = System.Math.Min(buffer.Available, buf.Length);
+ buffer.Read(buf, 0, bytesToRead, 0);
+ return bytesToRead;
+ }
+
+ public override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+
+ public virtual int Read(byte[] buf)
+ {
+ return Read(buf, 0, buf.Length);
+ }
+
+ public override int Read(byte[] buf, int off, int len)
+ {
+ int bytesToRead = System.Math.Min(buffer.Available, len);
+ buffer.RemoveData(buf, off, bytesToRead, 0);
+ return bytesToRead;
+ }
+
+ public override int ReadByte()
+ {
+ if (buffer.Available == 0)
+ return -1;
+
+ return buffer.RemoveData(1, 0)[0] & 0xFF;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException();
+ }
+
+ public virtual int Skip(int n)
+ {
+ int bytesToSkip = System.Math.Min(buffer.Available, n);
+ buffer.RemoveData(bytesToSkip);
+ return bytesToSkip;
+ }
+
+ public virtual void Write(byte[] buf)
+ {
+ buffer.AddData(buf, 0, buf.Length);
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ buffer.AddData(buf, off, len);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ buffer.AddData(new byte[]{ b }, 0, 1);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/CertChainType.cs b/crypto/src/crypto/tls/CertChainType.cs
index b526a79a7..cbb183441 100644
--- a/crypto/src/crypto/tls/CertChainType.cs
+++ b/crypto/src/crypto/tls/CertChainType.cs
@@ -7,10 +7,10 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
public abstract class CertChainType
{
- public const short individual_certs = 0;
- public const short pkipath = 1;
+ public const byte individual_certs = 0;
+ public const byte pkipath = 1;
- public static bool IsValid(short certChainType)
+ public static bool IsValid(byte certChainType)
{
return certChainType >= individual_certs && certChainType <= pkipath;
}
diff --git a/crypto/src/crypto/tls/Certificate.cs b/crypto/src/crypto/tls/Certificate.cs
index 12bfa9214..c59616c95 100644
--- a/crypto/src/crypto/tls/Certificate.cs
+++ b/crypto/src/crypto/tls/Certificate.cs
@@ -38,13 +38,6 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mCertificateList = certificateList;
}
- /// <returns>An array which contains the certs, this chain contains.</returns>
- [Obsolete("Use 'GetCertificateList' instead")]
- public virtual X509CertificateStructure[] GetCerts()
- {
- return GetCertificateList();
- }
-
/**
* @return an array of {@link org.bouncycastle.asn1.x509.Certificate} representing a certificate
* chain.
diff --git a/crypto/src/crypto/tls/CertificateRequest.cs b/crypto/src/crypto/tls/CertificateRequest.cs
index 8ab265513..f3dcb3bbd 100644
--- a/crypto/src/crypto/tls/CertificateRequest.cs
+++ b/crypto/src/crypto/tls/CertificateRequest.cs
@@ -100,7 +100,7 @@ namespace Org.BouncyCastle.Crypto.Tls
{
byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der);
derEncodings.Add(derEncoding);
- totalLength += derEncoding.Length;
+ totalLength += derEncoding.Length + 2;
}
TlsUtilities.CheckUint16(totalLength);
@@ -108,7 +108,7 @@ namespace Org.BouncyCastle.Crypto.Tls
foreach (byte[] derEncoding in derEncodings)
{
- output.Write(derEncoding, 0, derEncoding.Length);
+ TlsUtilities.WriteOpaque16(derEncoding, output);
}
}
}
@@ -123,8 +123,7 @@ namespace Org.BouncyCastle.Crypto.Tls
* @return a {@link CertificateRequest} object.
* @throws IOException
*/
- public static CertificateRequest Parse(//TlsContext context,
- Stream input)
+ public static CertificateRequest Parse(TlsContext context, Stream input)
{
int numTypes = TlsUtilities.ReadUint8(input);
byte[] certificateTypes = new byte[numTypes];
@@ -133,13 +132,12 @@ namespace Org.BouncyCastle.Crypto.Tls
certificateTypes[i] = TlsUtilities.ReadUint8(input);
}
- // TODO Add TLS 1.2 support here
IList supportedSignatureAlgorithms = null;
- //if (TlsUtilities.IsTLSv12(context))
- //{
- // // TODO Check whether SignatureAlgorithm.anonymous is allowed here
- // supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(false, input);
- //}
+ if (TlsUtilities.IsTlsV12(context))
+ {
+ // TODO Check whether SignatureAlgorithm.anonymous is allowed here
+ supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(false, input);
+ }
IList certificateAuthorities = Platform.CreateArrayList();
byte[] certAuthData = TlsUtilities.ReadOpaque16(input);
diff --git a/crypto/src/crypto/tls/CertificateStatus.cs b/crypto/src/crypto/tls/CertificateStatus.cs
new file mode 100644
index 000000000..0f95475b9
--- /dev/null
+++ b/crypto/src/crypto/tls/CertificateStatus.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class CertificateStatus
+ {
+ protected readonly byte mStatusType;
+ protected readonly object mResponse;
+
+ public CertificateStatus(byte statusType, object response)
+ {
+ if (!IsCorrectType(statusType, response))
+ throw new ArgumentException("not an instance of the correct type", "response");
+
+ this.mStatusType = statusType;
+ this.mResponse = response;
+ }
+
+ public virtual byte StatusType
+ {
+ get { return mStatusType; }
+ }
+
+ public virtual object Response
+ {
+ get { return mResponse; }
+ }
+
+ public virtual OcspResponse GetOcspResponse()
+ {
+ if (!IsCorrectType(CertificateStatusType.ocsp, mResponse))
+ throw new InvalidOperationException("'response' is not an OcspResponse");
+
+ return (OcspResponse)mResponse;
+ }
+
+ /**
+ * Encode this {@link CertificateStatus} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(mStatusType, output);
+
+ switch (mStatusType)
+ {
+ case CertificateStatusType.ocsp:
+ byte[] derEncoding = ((OcspResponse)mResponse).GetEncoded(Asn1Encodable.Der);
+ TlsUtilities.WriteOpaque24(derEncoding, output);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ /**
+ * Parse a {@link CertificateStatus} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link CertificateStatus} object.
+ * @throws IOException
+ */
+ public static CertificateStatus Parse(Stream input)
+ {
+ byte status_type = TlsUtilities.ReadUint8(input);
+ object response;
+
+ switch (status_type)
+ {
+ case CertificateStatusType.ocsp:
+ {
+ byte[] derEncoding = TlsUtilities.ReadOpaque24(input);
+ response = OcspResponse.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ return new CertificateStatus(status_type, response);
+ }
+
+ protected static bool IsCorrectType(byte statusType, object response)
+ {
+ switch (statusType)
+ {
+ case CertificateStatusType.ocsp:
+ return response is OcspResponse;
+ default:
+ throw new ArgumentException("unsupported value", "statusType");
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/CertificateStatusRequest.cs b/crypto/src/crypto/tls/CertificateStatusRequest.cs
new file mode 100644
index 000000000..9587d7df8
--- /dev/null
+++ b/crypto/src/crypto/tls/CertificateStatusRequest.cs
@@ -0,0 +1,95 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class CertificateStatusRequest
+ {
+ protected readonly byte mStatusType;
+ protected readonly object mRequest;
+
+ public CertificateStatusRequest(byte statusType, Object request)
+ {
+ if (!IsCorrectType(statusType, request))
+ throw new ArgumentException("not an instance of the correct type", "request");
+
+ this.mStatusType = statusType;
+ this.mRequest = request;
+ }
+
+ public virtual byte StatusType
+ {
+ get { return mStatusType; }
+ }
+
+ public virtual object Request
+ {
+ get { return mRequest; }
+ }
+
+ public virtual OcspStatusRequest GetOcspStatusRequest()
+ {
+ if (!IsCorrectType(CertificateStatusType.ocsp, mRequest))
+ throw new InvalidOperationException("'request' is not an OCSPStatusRequest");
+
+ return (OcspStatusRequest)mRequest;
+ }
+
+ /**
+ * Encode this {@link CertificateStatusRequest} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(mStatusType, output);
+
+ switch (mStatusType)
+ {
+ case CertificateStatusType.ocsp:
+ ((OcspStatusRequest)mRequest).Encode(output);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ /**
+ * Parse a {@link CertificateStatusRequest} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link CertificateStatusRequest} object.
+ * @throws IOException
+ */
+ public static CertificateStatusRequest Parse(Stream input)
+ {
+ byte status_type = TlsUtilities.ReadUint8(input);
+ object result;
+
+ switch (status_type)
+ {
+ case CertificateStatusType.ocsp:
+ result = OcspStatusRequest.Parse(input);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ return new CertificateStatusRequest(status_type, result);
+ }
+
+ protected static bool IsCorrectType(byte statusType, object request)
+ {
+ switch (statusType)
+ {
+ case CertificateStatusType.ocsp:
+ return request is OcspStatusRequest;
+ default:
+ throw new ArgumentException("unsupported value", "statusType");
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/CertificateStatusType.cs b/crypto/src/crypto/tls/CertificateStatusType.cs
index 222d31635..54b741b42 100644
--- a/crypto/src/crypto/tls/CertificateStatusType.cs
+++ b/crypto/src/crypto/tls/CertificateStatusType.cs
@@ -7,6 +7,6 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 3546 3.6
*/
- public const short ocsp = 1;
+ public const byte ocsp = 1;
}
}
diff --git a/crypto/src/crypto/tls/CertificateUrl.cs b/crypto/src/crypto/tls/CertificateUrl.cs
new file mode 100644
index 000000000..a951b8063
--- /dev/null
+++ b/crypto/src/crypto/tls/CertificateUrl.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /*
+ * RFC 3546 3.3
+ */
+ public class CertificateUrl
+ {
+ protected readonly byte mType;
+ protected readonly IList mUrlAndHashList;
+
+ /**
+ * @param type
+ * see {@link CertChainType} for valid constants.
+ * @param urlAndHashList
+ * a {@link IList} of {@link UrlAndHash}.
+ */
+ public CertificateUrl(byte type, IList urlAndHashList)
+ {
+ if (!CertChainType.IsValid(type))
+ throw new ArgumentException("not a valid CertChainType value", "type");
+ if (urlAndHashList == null || urlAndHashList.Count < 1)
+ throw new ArgumentException("must have length > 0", "urlAndHashList");
+
+ this.mType = type;
+ this.mUrlAndHashList = urlAndHashList;
+ }
+
+ /**
+ * @return {@link CertChainType}
+ */
+ public virtual byte Type
+ {
+ get { return mType; }
+ }
+
+ /**
+ * @return an {@link IList} of {@link UrlAndHash}
+ */
+ public virtual IList UrlAndHashList
+ {
+ get { return mUrlAndHashList; }
+ }
+
+ /**
+ * Encode this {@link CertificateUrl} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(this.mType, output);
+
+ ListBuffer16 buf = new ListBuffer16();
+ foreach (UrlAndHash urlAndHash in this.mUrlAndHashList)
+ {
+ urlAndHash.Encode(buf);
+ }
+ buf.EncodeTo(output);
+ }
+
+ /**
+ * Parse a {@link CertificateUrl} from a {@link Stream}.
+ *
+ * @param context
+ * the {@link TlsContext} of the current connection.
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link CertificateUrl} object.
+ * @throws IOException
+ */
+ public static CertificateUrl parse(TlsContext context, Stream input)
+ {
+ byte type = TlsUtilities.ReadUint8(input);
+ if (!CertChainType.IsValid(type))
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int totalLength = TlsUtilities.ReadUint16(input);
+ if (totalLength < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] urlAndHashListData = TlsUtilities.ReadFully(totalLength, input);
+
+ MemoryStream buf = new MemoryStream(urlAndHashListData, false);
+
+ IList url_and_hash_list = Platform.CreateArrayList();
+ while (buf.Position < buf.Length)
+ {
+ UrlAndHash url_and_hash = UrlAndHash.Parse(context, buf);
+ url_and_hash_list.Add(url_and_hash);
+ }
+
+ return new CertificateUrl(type, url_and_hash_list);
+ }
+
+ // TODO Could be more generally useful
+ internal class ListBuffer16
+ : MemoryStream
+ {
+ internal ListBuffer16()
+ {
+ // Reserve space for length
+ TlsUtilities.WriteUint16(0, this);
+ }
+
+ internal void EncodeTo(Stream output)
+ {
+ // Patch actual length back in
+ long length = Length - 2;
+ TlsUtilities.CheckUint16(length);
+ this.Position = 0;
+ TlsUtilities.WriteUint16((int)length, this);
+ this.WriteTo(output);
+ this.Close();
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/Chacha20Poly1305.cs b/crypto/src/crypto/tls/Chacha20Poly1305.cs
new file mode 100644
index 000000000..e4e4c7ee2
--- /dev/null
+++ b/crypto/src/crypto/tls/Chacha20Poly1305.cs
@@ -0,0 +1,153 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class Chacha20Poly1305
+ : TlsCipher
+ {
+ protected readonly TlsContext context;
+
+ protected readonly ChaChaEngine encryptCipher;
+ protected readonly ChaChaEngine decryptCipher;
+
+ /// <exception cref="IOException"></exception>
+ public Chacha20Poly1305(TlsContext context)
+ {
+ if (!TlsUtilities.IsTlsV12(context))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.context = context;
+
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, 64);
+
+ KeyParameter client_write_key = new KeyParameter(key_block, 0, 32);
+ KeyParameter server_write_key = new KeyParameter(key_block, 32, 32);
+
+ this.encryptCipher = new ChaChaEngine(20);
+ this.decryptCipher = new ChaChaEngine(20);
+
+ KeyParameter encryptKey, decryptKey;
+ if (context.IsServer)
+ {
+ encryptKey = server_write_key;
+ decryptKey = client_write_key;
+ }
+ else
+ {
+ encryptKey = client_write_key;
+ decryptKey = server_write_key;
+ }
+
+ byte[] dummyNonce = new byte[8];
+
+ this.encryptCipher.Init(true, new ParametersWithIV(encryptKey, dummyNonce));
+ this.decryptCipher.Init(false, new ParametersWithIV(decryptKey, dummyNonce));
+ }
+
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
+ {
+ return ciphertextLimit - 16;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+ {
+ int ciphertextLength = len + 16;
+
+ KeyParameter macKey = InitRecordMac(encryptCipher, true, seqNo);
+
+ byte[] output = new byte[ciphertextLength];
+ encryptCipher.ProcessBytes(plaintext, offset, len, output, 0);
+
+ byte[] additionalData = GetAdditionalData(seqNo, type, len);
+ byte[] mac = CalculateRecordMac(macKey, additionalData, output, 0, len);
+ Array.Copy(mac, 0, output, len, mac.Length);
+
+ return output;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+ {
+ if (GetPlaintextLimit(len) < 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int plaintextLength = len - 16;
+
+ byte[] receivedMAC = Arrays.CopyOfRange(ciphertext, offset + plaintextLength, offset + len);
+
+ KeyParameter macKey = InitRecordMac(decryptCipher, false, seqNo);
+
+ byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+ byte[] calculatedMAC = CalculateRecordMac(macKey, additionalData, ciphertext, offset, plaintextLength);
+
+ if (!Arrays.ConstantTimeAreEqual(calculatedMAC, receivedMAC))
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+
+ byte[] output = new byte[plaintextLength];
+ decryptCipher.ProcessBytes(ciphertext, offset, plaintextLength, output, 0);
+
+ return output;
+ }
+
+ protected virtual KeyParameter InitRecordMac(ChaChaEngine cipher, bool forEncryption, long seqNo)
+ {
+ byte[] nonce = new byte[8];
+ TlsUtilities.WriteUint64(seqNo, nonce, 0);
+
+ cipher.Init(forEncryption, new ParametersWithIV(null, nonce));
+
+ byte[] firstBlock = new byte[64];
+ cipher.ProcessBytes(firstBlock, 0, firstBlock.Length, firstBlock, 0);
+
+ // NOTE: The BC implementation puts 'r' after 'k'
+ Array.Copy(firstBlock, 0, firstBlock, 32, 16);
+ KeyParameter macKey = new KeyParameter(firstBlock, 16, 32);
+ Poly1305KeyGenerator.Clamp(macKey.GetKey());
+ return macKey;
+ }
+
+ protected virtual byte[] CalculateRecordMac(KeyParameter macKey, byte[] additionalData, byte[] buf, int off, int len)
+ {
+ IMac mac = new Poly1305();
+ mac.Init(macKey);
+
+ UpdateRecordMac(mac, additionalData, 0, additionalData.Length);
+ UpdateRecordMac(mac, buf, off, len);
+ return MacUtilities.DoFinal(mac);
+ }
+
+ protected virtual void UpdateRecordMac(IMac mac, byte[] buf, int off, int len)
+ {
+ mac.BlockUpdate(buf, off, len);
+
+ byte[] longLen = Pack.UInt64_To_LE((ulong)len);
+ mac.BlockUpdate(longLen, 0, longLen.Length);
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual byte[] GetAdditionalData(long seqNo, byte type, int len)
+ {
+ /*
+ * additional_data = seq_num + TLSCompressed.type + TLSCompressed.version +
+ * TLSCompressed.length
+ */
+ byte[] additional_data = new byte[13];
+ TlsUtilities.WriteUint64(seqNo, additional_data, 0);
+ TlsUtilities.WriteUint8(type, additional_data, 8);
+ TlsUtilities.WriteVersion(context.ServerVersion, additional_data, 9);
+ TlsUtilities.WriteUint16(len, additional_data, 11);
+
+ return additional_data;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/ChangeCipherSpec.cs b/crypto/src/crypto/tls/ChangeCipherSpec.cs
index 2ef4c3b34..323de9162 100644
--- a/crypto/src/crypto/tls/ChangeCipherSpec.cs
+++ b/crypto/src/crypto/tls/ChangeCipherSpec.cs
@@ -4,6 +4,6 @@ namespace Org.BouncyCastle.Crypto.Tls
{
public abstract class ChangeCipherSpec
{
- public const short change_cipher_spec = 1;
+ public const byte change_cipher_spec = 1;
}
}
diff --git a/crypto/src/crypto/tls/CipherSuite.cs b/crypto/src/crypto/tls/CipherSuite.cs
index 2c5077780..5ec36aee8 100644
--- a/crypto/src/crypto/tls/CipherSuite.cs
+++ b/crypto/src/crypto/tls/CipherSuite.cs
@@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A;
/*
- * RFC 4132
+ * RFC 5932
*/
public const int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041;
public const int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042;
@@ -64,6 +64,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044;
public const int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045;
public const int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046;
+
public const int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084;
public const int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085;
public const int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086;
@@ -71,6 +72,20 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088;
public const int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089;
+ public const int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BA;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BB;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BC;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BD;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BE;
+ public const int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BF;
+
+ public const int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C0;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C1;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C2;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4;
+ public const int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5;
+
/*
* RFC 4162
*/
@@ -240,6 +255,54 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF;
/*
+ * RFC 6367
+ */
+ public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC072;
+ public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC073;
+ public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC074;
+ public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC075;
+ public const int TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC076;
+ public const int TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC077;
+ public const int TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC078;
+ public const int TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC079;
+
+ public const int TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07A;
+ public const int TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07B;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07C;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07D;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07E;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07F;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC080;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC081;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC082;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC083;
+ public const int TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = 0xC084;
+ public const int TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = 0xC085;
+ public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC086;
+ public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC087;
+ public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC088;
+ public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC089;
+ public const int TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08A;
+ public const int TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08B;
+ public const int TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08C;
+ public const int TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08D;
+
+ public const int TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08E;
+ public const int TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08F;
+ public const int TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC090;
+ public const int TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC091;
+ public const int TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC092;
+ public const int TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC093;
+ public const int TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC094;
+ public const int TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC095;
+ public const int TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC096;
+ public const int TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC097;
+ public const int TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC098;
+ public const int TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC099;
+ public const int TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC09A;
+ public const int TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC09B;
+
+ /*
* RFC 6655
*/
public const int TLS_RSA_WITH_AES_128_CCM = 0xC09C;
@@ -260,39 +323,55 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int TLS_PSK_DHE_WITH_AES_256_CCM_8 = 0xC0AB;
/*
- * TBD[draft-josefsson-salsa20-tls-02]
+ * RFC 7251
+ */
+ public const int TLS_ECDHE_ECDSA_WITH_AES_128_CCM = 0xC0AC;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_256_CCM = 0xC0AD;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = 0xC0AF;
+
+ /*
+ * draft-agl-tls-chacha20poly1305-04
+ */
+ public const int TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC13;
+ public const int TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC14;
+ public const int TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC15;
+
+ /*
+ * draft-josefsson-salsa20-tls-04
*/
- const int TLS_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xFF00;
- const int TLS_RSA_WITH_SALSA20_SHA1 = 0xFF01;
- const int TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xFF02;
- const int TLS_DHE_RSA_WITH_SALSA20_SHA1 = 0xFF03;
- const int TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xFF04;
- const int TLS_ECDHE_RSA_WITH_SALSA20_SHA1 = 0xFF05;
- const int TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1 = 0xFF06;
- const int TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1 = 0xFF07;
- const int TLS_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xFF08;
- const int TLS_PSK_WITH_SALSA20_SHA1 = 0xFF09;
- const int TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xFF0A;
- const int TLS_DHE_PSK_WITH_SALSA20_SHA1 = 0xFF0B;
- const int TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xFF0C;
- const int TLS_RSA_PSK_WITH_SALSA20_SHA1 = 0xFF0D;
- const int TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xFF0E;
- const int TLS_ECDHE_PSK_WITH_SALSA20_SHA1 = 0xFF0F;
- const int TLS_RSA_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF10;
- const int TLS_RSA_WITH_SALSA20_UMAC96 = 0xFF11;
- const int TLS_DHE_RSA_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF12;
- const int TLS_DHE_RSA_WITH_SALSA20_UMAC96 = 0xFF13;
- const int TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF14;
- const int TLS_ECDHE_RSA_WITH_SALSA20_UMAC96 = 0xFF15;
- const int TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF16;
- const int TLS_ECDHE_ECDSA_WITH_SALSA20_UMAC96 = 0xFF17;
- const int TLS_PSK_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF18;
- const int TLS_PSK_WITH_SALSA20_UMAC96 = 0xFF19;
- const int TLS_DHE_PSK_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF1A;
- const int TLS_DHE_PSK_WITH_SALSA20_UMAC96 = 0xFF1B;
- const int TLS_RSA_PSK_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF1C;
- const int TLS_RSA_PSK_WITH_SALSA20_UMAC96 = 0xFF1D;
- const int TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF1E;
- const int TLS_ECDHE_PSK_WITH_SALSA20_UMAC96 = 0xFF1F;
+ public const int TLS_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE410;
+ public const int TLS_RSA_WITH_SALSA20_SHA1 = 0xE411;
+ public const int TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE412;
+ public const int TLS_ECDHE_RSA_WITH_SALSA20_SHA1 = 0xE413;
+ public const int TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE414;
+ public const int TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1 = 0xE415;
+ public const int TLS_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE416;
+ public const int TLS_PSK_WITH_SALSA20_SHA1 = 0xE417;
+ public const int TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE418;
+ public const int TLS_ECDHE_PSK_WITH_SALSA20_SHA1 = 0xE419;
+ public const int TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE41A;
+ public const int TLS_RSA_PSK_WITH_SALSA20_SHA1 = 0xE41B;
+ public const int TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE41C;
+ public const int TLS_DHE_PSK_WITH_SALSA20_SHA1 = 0xE41D;
+ public const int TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE41E;
+ public const int TLS_DHE_RSA_WITH_SALSA20_SHA1 = 0xE41F;
+
+ /*
+ * draft-ietf-tls-downgrade-scsv-00
+ */
+ public const int TLS_FALLBACK_SCSV = 0x5600;
+
+ public static bool IsScsv(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
+ case TLS_FALLBACK_SCSV:
+ return true;
+ default:
+ return false;
+ }
+ }
}
}
diff --git a/crypto/src/crypto/tls/ClientAuthenticationType.cs b/crypto/src/crypto/tls/ClientAuthenticationType.cs
index 51e6e5005..dd248f3df 100644
--- a/crypto/src/crypto/tls/ClientAuthenticationType.cs
+++ b/crypto/src/crypto/tls/ClientAuthenticationType.cs
@@ -7,8 +7,8 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 5077 4
*/
- public const short anonymous = 0;
- public const short certificate_based = 1;
- public const short psk = 2;
+ public const byte anonymous = 0;
+ public const byte certificate_based = 1;
+ public const byte psk = 2;
}
}
diff --git a/crypto/src/crypto/tls/CombinedHash.cs b/crypto/src/crypto/tls/CombinedHash.cs
index 59ad87a7b..74a52d598 100644
--- a/crypto/src/crypto/tls/CombinedHash.cs
+++ b/crypto/src/crypto/tls/CombinedHash.cs
@@ -1,82 +1,133 @@
using System;
-using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Tls
{
- /// <remarks>A combined hash, which implements md5(m) || sha1(m).</remarks>
- internal class CombinedHash
- : IDigest
- {
- private readonly MD5Digest md5;
- private readonly Sha1Digest sha1;
-
- internal CombinedHash()
- {
- this.md5 = new MD5Digest();
- this.sha1 = new Sha1Digest();
- }
-
- internal CombinedHash(CombinedHash t)
- {
- this.md5 = new MD5Digest(t.md5);
- this.sha1 = new Sha1Digest(t.sha1);
- }
-
- /// <seealso cref="IDigest.AlgorithmName"/>
- public string AlgorithmName
- {
- get
- {
- return md5.AlgorithmName + " and " + sha1.AlgorithmName + " for TLS 1.0";
- }
- }
-
- /// <seealso cref="IDigest.GetByteLength"/>
- public int GetByteLength()
- {
- return System.Math.Max(md5.GetByteLength(), sha1.GetByteLength());
- }
-
- /// <seealso cref="IDigest.GetDigestSize"/>
- public int GetDigestSize()
- {
- return md5.GetDigestSize() + sha1.GetDigestSize();
- }
-
- /// <seealso cref="IDigest.Update"/>
- public void Update(
- byte input)
- {
- md5.Update(input);
- sha1.Update(input);
- }
-
- /// <seealso cref="IDigest.BlockUpdate"/>
- public void BlockUpdate(
- byte[] input,
- int inOff,
- int len)
- {
- md5.BlockUpdate(input, inOff, len);
- sha1.BlockUpdate(input, inOff, len);
- }
-
- /// <seealso cref="IDigest.DoFinal"/>
- public int DoFinal(
- byte[] output,
- int outOff)
- {
- int i1 = md5.DoFinal(output, outOff);
- int i2 = sha1.DoFinal(output, outOff + i1);
- return i1 + i2;
- }
-
- /// <seealso cref="IDigest.Reset"/>
- public void Reset()
- {
- md5.Reset();
- sha1.Reset();
- }
- }
+ /**
+ * A combined hash, which implements md5(m) || sha1(m).
+ */
+ internal class CombinedHash
+ : TlsHandshakeHash
+ {
+ protected TlsContext mContext;
+ protected IDigest mMd5;
+ protected IDigest mSha1;
+
+ internal CombinedHash()
+ {
+ this.mMd5 = TlsUtilities.CreateHash(HashAlgorithm.md5);
+ this.mSha1 = TlsUtilities.CreateHash(HashAlgorithm.sha1);
+ }
+
+ internal CombinedHash(CombinedHash t)
+ {
+ this.mContext = t.mContext;
+ this.mMd5 = TlsUtilities.CloneHash(HashAlgorithm.md5, t.mMd5);
+ this.mSha1 = TlsUtilities.CloneHash(HashAlgorithm.sha1, t.mSha1);
+ }
+
+ public virtual void Init(TlsContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual TlsHandshakeHash NotifyPrfDetermined()
+ {
+ return this;
+ }
+
+ public virtual void TrackHashAlgorithm(byte hashAlgorithm)
+ {
+ throw new InvalidOperationException("CombinedHash only supports calculating the legacy PRF for handshake hash");
+ }
+
+ public virtual void SealHashAlgorithms()
+ {
+ }
+
+ public virtual TlsHandshakeHash StopTracking()
+ {
+ return new CombinedHash(this);
+ }
+
+ public virtual IDigest ForkPrfHash()
+ {
+ return new CombinedHash(this);
+ }
+
+ public virtual byte[] GetFinalHash(byte hashAlgorithm)
+ {
+ throw new InvalidOperationException("CombinedHash doesn't support multiple hashes");
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return mMd5.AlgorithmName + " and " + mSha1.AlgorithmName; }
+ }
+
+ public virtual int GetByteLength()
+ {
+ return System.Math.Max(mMd5.GetByteLength(), mSha1.GetByteLength());
+ }
+
+ public virtual int GetDigestSize()
+ {
+ return mMd5.GetDigestSize() + mSha1.GetDigestSize();
+ }
+
+ public virtual void Update(byte input)
+ {
+ mMd5.Update(input);
+ mSha1.Update(input);
+ }
+
+ /**
+ * @see org.bouncycastle.crypto.Digest#update(byte[], int, int)
+ */
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ mMd5.BlockUpdate(input, inOff, len);
+ mSha1.BlockUpdate(input, inOff, len);
+ }
+
+ /**
+ * @see org.bouncycastle.crypto.Digest#doFinal(byte[], int)
+ */
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ if (mContext != null && TlsUtilities.IsSsl(mContext))
+ {
+ Ssl3Complete(mMd5, Ssl3Mac.IPAD, Ssl3Mac.OPAD, 48);
+ Ssl3Complete(mSha1, Ssl3Mac.IPAD, Ssl3Mac.OPAD, 40);
+ }
+
+ int i1 = mMd5.DoFinal(output, outOff);
+ int i2 = mSha1.DoFinal(output, outOff + i1);
+ return i1 + i2;
+ }
+
+ /**
+ * @see org.bouncycastle.crypto.Digest#reset()
+ */
+ public virtual void Reset()
+ {
+ mMd5.Reset();
+ mSha1.Reset();
+ }
+
+ protected virtual void Ssl3Complete(IDigest d, byte[] ipad, byte[] opad, int padLength)
+ {
+ byte[] master_secret = mContext.SecurityParameters.masterSecret;
+
+ d.BlockUpdate(master_secret, 0, master_secret.Length);
+ d.BlockUpdate(ipad, 0, padLength);
+
+ byte[] tmp = DigestUtilities.DoFinal(d);
+
+ d.BlockUpdate(master_secret, 0, master_secret.Length);
+ d.BlockUpdate(opad, 0, padLength);
+ d.BlockUpdate(tmp, 0, tmp.Length);
+ }
+ }
}
diff --git a/crypto/src/crypto/tls/CompressionMethod.cs b/crypto/src/crypto/tls/CompressionMethod.cs
index e4ee9666f..89c1f5ff4 100644
--- a/crypto/src/crypto/tls/CompressionMethod.cs
+++ b/crypto/src/crypto/tls/CompressionMethod.cs
@@ -7,7 +7,7 @@ namespace Org.BouncyCastle.Crypto.Tls
/// </summary>
public abstract class CompressionMethod
{
- public const byte NULL = 0;
+ public const byte cls_null = 0;
/*
* RFC 3749 2
diff --git a/crypto/src/crypto/tls/DatagramTransport.cs b/crypto/src/crypto/tls/DatagramTransport.cs
new file mode 100644
index 000000000..524a8b181
--- /dev/null
+++ b/crypto/src/crypto/tls/DatagramTransport.cs
@@ -0,0 +1,23 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface DatagramTransport
+ {
+ /// <exception cref="IOException"/>
+ int GetReceiveLimit();
+
+ /// <exception cref="IOException"/>
+ int GetSendLimit();
+
+ /// <exception cref="IOException"/>
+ int Receive(byte[] buf, int off, int len, int waitMillis);
+
+ /// <exception cref="IOException"/>
+ void Send(byte[] buf, int off, int len);
+
+ /// <exception cref="IOException"/>
+ void Close();
+ }
+}
diff --git a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
index 2bd2f40bf..5147a1990 100644
--- a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Parameters;
@@ -8,69 +9,61 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
public class DefaultTlsAgreementCredentials
- : TlsAgreementCredentials
+ : AbstractTlsAgreementCredentials
{
- protected Certificate clientCert;
- protected AsymmetricKeyParameter clientPrivateKey;
+ protected readonly Certificate mCertificate;
+ protected readonly AsymmetricKeyParameter mPrivateKey;
- protected IBasicAgreement basicAgreement;
- protected bool truncateAgreement;
+ protected readonly IBasicAgreement mBasicAgreement;
+ protected readonly bool mTruncateAgreement;
- public DefaultTlsAgreementCredentials(Certificate clientCertificate, AsymmetricKeyParameter clientPrivateKey)
+ public DefaultTlsAgreementCredentials(Certificate certificate, AsymmetricKeyParameter privateKey)
{
- if (clientCertificate == null)
- {
- throw new ArgumentNullException("clientCertificate");
- }
- if (clientCertificate.Length == 0)
- {
- throw new ArgumentException("cannot be empty", "clientCertificate");
- }
- if (clientPrivateKey == null)
- {
- throw new ArgumentNullException("clientPrivateKey");
- }
- if (!clientPrivateKey.IsPrivate)
- {
- throw new ArgumentException("must be private", "clientPrivateKey");
- }
+ if (certificate == null)
+ throw new ArgumentNullException("certificate");
+ if (certificate.IsEmpty)
+ throw new ArgumentException("cannot be empty", "certificate");
+ if (privateKey == null)
+ throw new ArgumentNullException("privateKey");
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("must be private", "privateKey");
- if (clientPrivateKey is DHPrivateKeyParameters)
+ if (privateKey is DHPrivateKeyParameters)
{
- basicAgreement = new DHBasicAgreement();
- truncateAgreement = true;
+ mBasicAgreement = new DHBasicAgreement();
+ mTruncateAgreement = true;
}
- else if (clientPrivateKey is ECPrivateKeyParameters)
+ else if (privateKey is ECPrivateKeyParameters)
{
- basicAgreement = new ECDHBasicAgreement();
- truncateAgreement = false;
+ mBasicAgreement = new ECDHBasicAgreement();
+ mTruncateAgreement = false;
}
else
{
- throw new ArgumentException("type not supported: "
- + clientPrivateKey.GetType().FullName, "clientPrivateKey");
+ throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
}
- this.clientCert = clientCertificate;
- this.clientPrivateKey = clientPrivateKey;
+ this.mCertificate = certificate;
+ this.mPrivateKey = privateKey;
}
- public virtual Certificate Certificate
+ public override Certificate Certificate
{
- get { return clientCert; }
+ get { return mCertificate; }
}
- public virtual byte[] GenerateAgreement(AsymmetricKeyParameter serverPublicKey)
+ /// <exception cref="IOException"></exception>
+ public override byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey)
{
- basicAgreement.Init(clientPrivateKey);
- BigInteger agreementValue = basicAgreement.CalculateAgreement(serverPublicKey);
+ mBasicAgreement.Init(mPrivateKey);
+ BigInteger agreementValue = mBasicAgreement.CalculateAgreement(peerPublicKey);
- if (truncateAgreement)
+ if (mTruncateAgreement)
{
return BigIntegers.AsUnsignedByteArray(agreementValue);
}
- return BigIntegers.AsUnsignedByteArray(basicAgreement.GetFieldSize(), agreementValue);
+ return BigIntegers.AsUnsignedByteArray(mBasicAgreement.GetFieldSize(), agreementValue);
}
}
}
diff --git a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
index 18b23a67b..7c4213c25 100644
--- a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
+++ b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
@@ -1,53 +1,146 @@
using System;
using System.IO;
-using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
namespace Org.BouncyCastle.Crypto.Tls
{
public class DefaultTlsCipherFactory
- : TlsCipherFactory
+ : AbstractTlsCipherFactory
{
- public virtual TlsCipher CreateCipher(TlsClientContext context,
- int encryptionAlgorithm, DigestAlgorithm digestAlgorithm)
+ /// <exception cref="IOException"></exception>
+ public override TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm)
{
switch (encryptionAlgorithm)
{
- case EncryptionAlgorithm.cls_3DES_EDE_CBC:
- return CreateDesEdeCipher(context, 24, digestAlgorithm);
- case EncryptionAlgorithm.AES_128_CBC:
- return CreateAesCipher(context, 16, digestAlgorithm);
- case EncryptionAlgorithm.AES_256_CBC:
- return CreateAesCipher(context, 32, digestAlgorithm);
- case EncryptionAlgorithm.RC4_128:
- return CreateRC4Cipher(context, 16, digestAlgorithm);
- default:
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ case EncryptionAlgorithm.cls_3DES_EDE_CBC:
+ return CreateDesEdeCipher(context, macAlgorithm);
+ case EncryptionAlgorithm.AEAD_CHACHA20_POLY1305:
+ // NOTE: Ignores macAlgorithm
+ return CreateChaCha20Poly1305(context);
+ case EncryptionAlgorithm.AES_128_CBC:
+ return CreateAESCipher(context, 16, macAlgorithm);
+ case EncryptionAlgorithm.AES_128_CCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ccm(context, 16, 16);
+ case EncryptionAlgorithm.AES_128_CCM_8:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ccm(context, 16, 8);
+ case EncryptionAlgorithm.AES_256_CCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ccm(context, 32, 16);
+ case EncryptionAlgorithm.AES_256_CCM_8:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ccm(context, 32, 8);
+ case EncryptionAlgorithm.AES_128_GCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Gcm(context, 16, 16);
+ case EncryptionAlgorithm.AES_256_CBC:
+ return CreateAESCipher(context, 32, macAlgorithm);
+ case EncryptionAlgorithm.AES_256_GCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Gcm(context, 32, 16);
+ case EncryptionAlgorithm.CAMELLIA_128_CBC:
+ return CreateCamelliaCipher(context, 16, macAlgorithm);
+ case EncryptionAlgorithm.CAMELLIA_128_GCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Camellia_Gcm(context, 16, 16);
+ case EncryptionAlgorithm.CAMELLIA_256_CBC:
+ return CreateCamelliaCipher(context, 32, macAlgorithm);
+ case EncryptionAlgorithm.CAMELLIA_256_GCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Camellia_Gcm(context, 32, 16);
+ case EncryptionAlgorithm.ESTREAM_SALSA20:
+ return CreateSalsa20Cipher(context, 12, 32, macAlgorithm);
+ case EncryptionAlgorithm.NULL:
+ return CreateNullCipher(context, macAlgorithm);
+ case EncryptionAlgorithm.RC4_128:
+ return CreateRC4Cipher(context, 16, macAlgorithm);
+ case EncryptionAlgorithm.SALSA20:
+ return CreateSalsa20Cipher(context, 20, 32, macAlgorithm);
+ case EncryptionAlgorithm.SEED_CBC:
+ return CreateSeedCipher(context, macAlgorithm);
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
/// <exception cref="IOException"></exception>
- protected virtual TlsCipher CreateRC4Cipher(TlsClientContext context, int cipherKeySize, DigestAlgorithm digestAlgorithm)
+ protected virtual TlsBlockCipher CreateAESCipher(TlsContext context, int cipherKeySize, int macAlgorithm)
{
- return new TlsStreamCipher(context, CreateRC4StreamCipher(), CreateRC4StreamCipher(), CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize);
+ return new TlsBlockCipher(context, CreateAesBlockCipher(), CreateAesBlockCipher(),
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), cipherKeySize);
}
/// <exception cref="IOException"></exception>
- protected virtual TlsCipher CreateAesCipher(TlsClientContext context, int cipherKeySize,
- DigestAlgorithm digestAlgorithm)
+ protected virtual TlsBlockCipher CreateCamelliaCipher(TlsContext context, int cipherKeySize, int macAlgorithm)
{
- return new TlsBlockCipher(context, CreateAesBlockCipher(), CreateAesBlockCipher(),
- CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize);
+ return new TlsBlockCipher(context, CreateCamelliaBlockCipher(),
+ CreateCamelliaBlockCipher(), CreateHMacDigest(macAlgorithm),
+ CreateHMacDigest(macAlgorithm), cipherKeySize);
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual TlsCipher CreateChaCha20Poly1305(TlsContext context)
+ {
+ return new Chacha20Poly1305(context);
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual TlsAeadCipher CreateCipher_Aes_Ccm(TlsContext context, int cipherKeySize, int macSize)
+ {
+ return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Ccm(),
+ CreateAeadBlockCipher_Aes_Ccm(), cipherKeySize, macSize);
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual TlsAeadCipher CreateCipher_Aes_Gcm(TlsContext context, int cipherKeySize, int macSize)
+ {
+ return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Gcm(),
+ CreateAeadBlockCipher_Aes_Gcm(), cipherKeySize, macSize);
}
/// <exception cref="IOException"></exception>
- protected virtual TlsCipher CreateDesEdeCipher(TlsClientContext context, int cipherKeySize,
- DigestAlgorithm digestAlgorithm)
+ protected virtual TlsAeadCipher CreateCipher_Camellia_Gcm(TlsContext context, int cipherKeySize, int macSize)
+ {
+ return new TlsAeadCipher(context, CreateAeadBlockCipher_Camellia_Gcm(),
+ CreateAeadBlockCipher_Camellia_Gcm(), cipherKeySize, macSize);
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual TlsBlockCipher CreateDesEdeCipher(TlsContext context, int macAlgorithm)
{
return new TlsBlockCipher(context, CreateDesEdeBlockCipher(), CreateDesEdeBlockCipher(),
- CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize);
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), 24);
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual TlsNullCipher CreateNullCipher(TlsContext context, int macAlgorithm)
+ {
+ return new TlsNullCipher(context, CreateHMacDigest(macAlgorithm),
+ CreateHMacDigest(macAlgorithm));
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual TlsStreamCipher CreateRC4Cipher(TlsContext context, int cipherKeySize, int macAlgorithm)
+ {
+ return new TlsStreamCipher(context, CreateRC4StreamCipher(), CreateRC4StreamCipher(),
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), cipherKeySize, false);
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual TlsStreamCipher CreateSalsa20Cipher(TlsContext context, int rounds, int cipherKeySize, int macAlgorithm)
+ {
+ return new TlsStreamCipher(context, CreateSalsa20StreamCipher(rounds), CreateSalsa20StreamCipher(rounds),
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), cipherKeySize, true);
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual TlsBlockCipher CreateSeedCipher(TlsContext context, int macAlgorithm)
+ {
+ return new TlsBlockCipher(context, CreateSeedBlockCipher(), CreateSeedBlockCipher(),
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), 16);
}
protected virtual IBlockCipher CreateAesEngine()
@@ -55,11 +148,38 @@ namespace Org.BouncyCastle.Crypto.Tls
return new AesEngine();
}
+ protected virtual IBlockCipher CreateCamelliaEngine()
+ {
+ return new CamelliaEngine();
+ }
+
protected virtual IBlockCipher CreateAesBlockCipher()
{
return new CbcBlockCipher(CreateAesEngine());
}
+ protected virtual IAeadBlockCipher CreateAeadBlockCipher_Aes_Ccm()
+ {
+ return new CcmBlockCipher(CreateAesEngine());
+ }
+
+ protected virtual IAeadBlockCipher CreateAeadBlockCipher_Aes_Gcm()
+ {
+ // TODO Consider allowing custom configuration of multiplier
+ return new GcmBlockCipher(CreateAesEngine());
+ }
+
+ protected virtual IAeadBlockCipher CreateAeadBlockCipher_Camellia_Gcm()
+ {
+ // TODO Consider allowing custom configuration of multiplier
+ return new GcmBlockCipher(CreateCamelliaEngine());
+ }
+
+ protected virtual IBlockCipher CreateCamelliaBlockCipher()
+ {
+ return new CbcBlockCipher(CreateCamelliaEngine());
+ }
+
protected virtual IBlockCipher CreateDesEdeBlockCipher()
{
return new CbcBlockCipher(new DesEdeEngine());
@@ -70,21 +190,35 @@ namespace Org.BouncyCastle.Crypto.Tls
return new RC4Engine();
}
+ protected virtual IStreamCipher CreateSalsa20StreamCipher(int rounds)
+ {
+ return new Salsa20Engine(rounds);
+ }
+
+ protected virtual IBlockCipher CreateSeedBlockCipher()
+ {
+ return new CbcBlockCipher(new SeedEngine());
+ }
+
/// <exception cref="IOException"></exception>
- protected virtual IDigest CreateDigest(DigestAlgorithm digestAlgorithm)
+ protected virtual IDigest CreateHMacDigest(int macAlgorithm)
{
- switch (digestAlgorithm)
+ switch (macAlgorithm)
{
- case DigestAlgorithm.MD5:
- return new MD5Digest();
- case DigestAlgorithm.SHA:
- return new Sha1Digest();
- case DigestAlgorithm.SHA256:
- return new Sha256Digest();
- case DigestAlgorithm.SHA384:
- return new Sha384Digest();
- default:
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ case MacAlgorithm.cls_null:
+ return null;
+ case MacAlgorithm.hmac_md5:
+ return TlsUtilities.CreateHash(HashAlgorithm.md5);
+ case MacAlgorithm.hmac_sha1:
+ return TlsUtilities.CreateHash(HashAlgorithm.sha1);
+ case MacAlgorithm.hmac_sha256:
+ return TlsUtilities.CreateHash(HashAlgorithm.sha256);
+ case MacAlgorithm.hmac_sha384:
+ return TlsUtilities.CreateHash(HashAlgorithm.sha384);
+ case MacAlgorithm.hmac_sha512:
+ return TlsUtilities.CreateHash(HashAlgorithm.sha512);
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
}
diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs
index d59fae164..ff7e6da85 100644
--- a/crypto/src/crypto/tls/DefaultTlsClient.cs
+++ b/crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -12,272 +12,100 @@ using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Tls
{
public abstract class DefaultTlsClient
- : TlsClient
+ : AbstractTlsClient
{
- protected TlsCipherFactory cipherFactory;
-
- protected TlsClientContext context;
-
- protected byte selectedCompressionMethod;
- protected int selectedCipherSuite;
-
public DefaultTlsClient()
- : this(new DefaultTlsCipherFactory())
+ : base()
{
}
public DefaultTlsClient(TlsCipherFactory cipherFactory)
+ : base(cipherFactory)
{
- this.cipherFactory = cipherFactory;
- }
-
- public virtual void Init(TlsClientContext context)
- {
- this.context = context;
}
- public virtual bool ShouldUseGmtUnixTime()
+ public override int[] GetCipherSuites()
{
- /*
- * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
- * TLS implementors MUST by default set the entire value the ClientHello.Random and
- * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
- * sequence.
- */
- return false;
- }
-
- public virtual int[] GetCipherSuites()
- {
- return new int[] {
- CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
- CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
- CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ return new int[]
+ {
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
- CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
- CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- CipherSuite.TLS_RSA_WITH_RC4_128_SHA,
};
}
- public virtual byte[] GetCompressionMethods()
- {
- /*
- * To offer DEFLATE compression, override this method:
- * return new byte[] { CompressionMethod.DEFLATE, CompressionMethod.NULL };
- */
-
- return new byte[] { CompressionMethod.NULL };
- }
-
- public virtual IDictionary GetClientExtensions()
- {
- return null;
- }
-
- public virtual void NotifySessionID(byte[] sessionID)
+ public override TlsKeyExchange GetKeyExchange()
{
- // Currently ignored
- }
-
- public virtual void NotifySelectedCipherSuite(int selectedCipherSuite)
- {
- this.selectedCipherSuite = selectedCipherSuite;
- }
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
- public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
- {
- this.selectedCompressionMethod = selectedCompressionMethod;
- }
-
- public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
- {
- if (!secureRenegotiation)
+ switch (keyExchangeAlgorithm)
{
- /*
- * RFC 5746 3.4.
- * If the extension is not present, the server does not support
- * secure renegotiation; set secure_renegotiation flag to FALSE.
- * In this case, some clients may want to terminate the handshake
- * instead of continuing; see Section 4.1 for discussion.
- */
-// throw new TlsFatalAlert(AlertDescription.handshake_failure);
- }
- }
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DH_RSA:
+ return CreateDHKeyExchange(keyExchangeAlgorithm);
- public virtual void ProcessServerExtensions(IDictionary serverExtensions)
- {
- }
-
- public virtual TlsKeyExchange GetKeyExchange()
- {
- switch (selectedCipherSuite)
- {
- case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
- return CreateRsaKeyExchange();
-
- case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
- return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS);
-
- case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
- return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA);
-
- case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
- return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ return CreateDheKeyExchange(keyExchangeAlgorithm);
- case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA);
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ return CreateECDHKeyExchange(keyExchangeAlgorithm);
- case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- return CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_ECDSA);
-
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_ECDSA);
-
- case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
- return CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_RSA);
-
- case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA);
-
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected cipher suite was in the list of client-offered cipher
- * suites, so if we now can't produce an implementation, we shouldn't have
- * offered it!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- }
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return CreateECDheKeyExchange(keyExchangeAlgorithm);
- public abstract TlsAuthentication GetAuthentication();
+ case KeyExchangeAlgorithm.RSA:
+ return CreateRsaKeyExchange();
- public virtual TlsCompression GetCompression()
- {
- switch (selectedCompressionMethod)
- {
- case CompressionMethod.NULL:
- return new TlsNullCompression();
-
- case CompressionMethod.DEFLATE:
- return new TlsDeflateCompression();
-
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected compression method was in the list of client-offered compression
- * methods, so if we now can't produce an implementation, we shouldn't have
- * offered it!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- }
-
- public virtual TlsCipher GetCipher()
- {
- switch (selectedCipherSuite)
- {
- case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA);
-
- case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.RC4_128, DigestAlgorithm.SHA);
-
- case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
-
- case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
-
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected cipher suite was in the list of client-offered cipher
- * suites, so if we now can't produce an implementation, we shouldn't have
- * offered it!
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
*/
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange)
{
- return new TlsDHKeyExchange(context, keyExchange);
+ return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null);
}
protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange)
{
- return new TlsDheKeyExchange(context, keyExchange);
+ return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null);
}
protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange)
{
- return new TlsECDHKeyExchange(context, keyExchange);
+ return new TlsECDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+ mServerECPointFormats);
}
protected virtual TlsKeyExchange CreateECDheKeyExchange(int keyExchange)
{
- return new TlsECDheKeyExchange(context, keyExchange);
+ return new TlsECDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+ mServerECPointFormats);
}
protected virtual TlsKeyExchange CreateRsaKeyExchange()
{
- return new TlsRsaKeyExchange(context);
+ return new TlsRsaKeyExchange(mSupportedSignatureAlgorithms);
}
}
}
diff --git a/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs b/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
new file mode 100644
index 000000000..34d15d146
--- /dev/null
+++ b/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
@@ -0,0 +1,51 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DefaultTlsEncryptionCredentials
+ : AbstractTlsEncryptionCredentials
+ {
+ protected readonly TlsContext mContext;
+ protected readonly Certificate mCertificate;
+ protected readonly AsymmetricKeyParameter mPrivateKey;
+
+ public DefaultTlsEncryptionCredentials(TlsContext context, Certificate certificate,
+ AsymmetricKeyParameter privateKey)
+ {
+ if (certificate == null)
+ throw new ArgumentNullException("certificate");
+ if (certificate.IsEmpty)
+ throw new ArgumentException("cannot be empty", "certificate");
+ if (privateKey == null)
+ throw new ArgumentNullException("'privateKey' cannot be null");
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("must be private", "privateKey");
+
+ if (privateKey is RsaKeyParameters)
+ {
+ }
+ else
+ {
+ throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
+ }
+
+ this.mContext = context;
+ this.mCertificate = certificate;
+ this.mPrivateKey = privateKey;
+ }
+
+ public override Certificate Certificate
+ {
+ get { return mCertificate; }
+ }
+
+ /// <exception cref="IOException"></exception>
+ public override byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret)
+ {
+ return TlsRsaUtilities.SafeDecryptPreMasterSecret(mContext, (RsaKeyParameters)mPrivateKey, encryptedPreMasterSecret);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DefaultTlsServer.cs b/crypto/src/crypto/tls/DefaultTlsServer.cs
new file mode 100644
index 000000000..77cd5f1cc
--- /dev/null
+++ b/crypto/src/crypto/tls/DefaultTlsServer.cs
@@ -0,0 +1,162 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class DefaultTlsServer
+ : AbstractTlsServer
+ {
+ public DefaultTlsServer()
+ : base()
+ {
+ }
+
+ public DefaultTlsServer(TlsCipherFactory cipherFactory)
+ : base(cipherFactory)
+ {
+ }
+
+ protected virtual TlsSignerCredentials GetDsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsSignerCredentials GetECDsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsEncryptionCredentials GetRsaEncryptionCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsSignerCredentials GetRsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual DHParameters GetDHParameters()
+ {
+ return DHStandardGroups.rfc5114_2048_256;
+ }
+
+ protected override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+ };
+ }
+
+ public override TlsCredentials GetCredentials()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DHE_DSS:
+ return GetDsaSignerCredentials();
+
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ return GetECDsaSignerCredentials();
+
+ case KeyExchangeAlgorithm.DHE_RSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return GetRsaSignerCredentials();
+
+ case KeyExchangeAlgorithm.RSA:
+ return GetRsaEncryptionCredentials();
+
+ default:
+ /* Note: internal error here; selected a key exchange we don't implement! */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DH_RSA:
+ return CreateDHKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ return CreateDheKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ return CreateECDHKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return CreateECDheKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.RSA:
+ return CreateRsaKeyExchange();
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange)
+ {
+ return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, GetDHParameters());
+ }
+
+ protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange)
+ {
+ return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, GetDHParameters());
+ }
+
+ protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange)
+ {
+ return new TlsECDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+ mServerECPointFormats);
+ }
+
+ protected virtual TlsKeyExchange CreateECDheKeyExchange(int keyExchange)
+ {
+ return new TlsECDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+ mServerECPointFormats);
+ }
+
+ protected virtual TlsKeyExchange CreateRsaKeyExchange()
+ {
+ return new TlsRsaKeyExchange(mSupportedSignatureAlgorithms);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
index 2c5aa3524..c7a136573 100644
--- a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
@@ -1,76 +1,92 @@
using System;
+using System.IO;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Tls
{
public class DefaultTlsSignerCredentials
- : TlsSignerCredentials
+ : AbstractTlsSignerCredentials
{
- protected TlsClientContext context;
- protected Certificate clientCert;
- protected AsymmetricKeyParameter clientPrivateKey;
+ protected readonly TlsContext mContext;
+ protected readonly Certificate mCertificate;
+ protected readonly AsymmetricKeyParameter mPrivateKey;
+ protected readonly SignatureAndHashAlgorithm mSignatureAndHashAlgorithm;
- protected TlsSigner clientSigner;
+ protected readonly TlsSigner mSigner;
- public DefaultTlsSignerCredentials(TlsClientContext context,
- Certificate clientCertificate, AsymmetricKeyParameter clientPrivateKey)
+ public DefaultTlsSignerCredentials(TlsContext context, Certificate certificate, AsymmetricKeyParameter privateKey)
+ : this(context, certificate, privateKey, null)
{
- if (clientCertificate == null)
- {
- throw new ArgumentNullException("clientCertificate");
- }
- if (clientCertificate.Length == 0)
- {
+ }
+
+ public DefaultTlsSignerCredentials(TlsContext context, Certificate certificate, AsymmetricKeyParameter privateKey,
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+ {
+ if (certificate == null)
+ throw new ArgumentNullException("certificate");
+ if (certificate.IsEmpty)
throw new ArgumentException("cannot be empty", "clientCertificate");
- }
- if (clientPrivateKey == null)
- {
- throw new ArgumentNullException("clientPrivateKey");
- }
- if (!clientPrivateKey.IsPrivate)
- {
- throw new ArgumentException("must be private", "clientPrivateKey");
- }
+ if (privateKey == null)
+ throw new ArgumentNullException("privateKey");
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("must be private", "privateKey");
+ if (TlsUtilities.IsTlsV12(context) && signatureAndHashAlgorithm == null)
+ throw new ArgumentException("cannot be null for (D)TLS 1.2+", "signatureAndHashAlgorithm");
- if (clientPrivateKey is RsaKeyParameters)
+ if (privateKey is RsaKeyParameters)
{
- clientSigner = new TlsRsaSigner();
+ mSigner = new TlsRsaSigner();
}
- else if (clientPrivateKey is DsaPrivateKeyParameters)
+ else if (privateKey is DsaPrivateKeyParameters)
{
- clientSigner = new TlsDssSigner();
+ mSigner = new TlsDssSigner();
}
- else if (clientPrivateKey is ECPrivateKeyParameters)
+ else if (privateKey is ECPrivateKeyParameters)
{
- clientSigner = new TlsECDsaSigner();
+ mSigner = new TlsECDsaSigner();
}
else
{
- throw new ArgumentException("type not supported: "
- + clientPrivateKey.GetType().FullName, "clientPrivateKey");
+ throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
}
- this.context = context;
- this.clientCert = clientCertificate;
- this.clientPrivateKey = clientPrivateKey;
+ this.mSigner.Init(context);
+
+ this.mContext = context;
+ this.mCertificate = certificate;
+ this.mPrivateKey = privateKey;
+ this.mSignatureAndHashAlgorithm = signatureAndHashAlgorithm;
}
- public virtual Certificate Certificate
+ public override Certificate Certificate
{
- get { return clientCert; }
+ get { return mCertificate; }
}
- public virtual byte[] GenerateCertificateSignature(byte[] md5andsha1)
+ /// <exception cref="IOException"></exception>
+ public override byte[] GenerateCertificateSignature(byte[] hash)
{
try
{
- return clientSigner.GenerateRawSignature(context.SecureRandom, clientPrivateKey, md5andsha1);
+ if (TlsUtilities.IsTlsV12(mContext))
+ {
+ return mSigner.GenerateRawSignature(mSignatureAndHashAlgorithm, mPrivateKey, hash);
+ }
+ else
+ {
+ return mSigner.GenerateRawSignature(mPrivateKey, hash);
+ }
}
- catch (CryptoException)
+ catch (CryptoException e)
{
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
}
}
+
+ public override SignatureAndHashAlgorithm SignatureAndHashAlgorithm
+ {
+ get { return mSignatureAndHashAlgorithm; }
+ }
}
}
diff --git a/crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs b/crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs
new file mode 100644
index 000000000..cc933bff9
--- /dev/null
+++ b/crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DefaultTlsSrpGroupVerifier
+ : TlsSrpGroupVerifier
+ {
+ protected static readonly IList DefaultGroups = Platform.CreateArrayList();
+
+ static DefaultTlsSrpGroupVerifier()
+ {
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_1024);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_1536);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_2048);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_3072);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_4096);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_6144);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_8192);
+ }
+
+ // Vector is (SRP6GroupParameters)
+ protected readonly IList mGroups;
+
+ /**
+ * Accept only the group parameters specified in RFC 5054 Appendix A.
+ */
+ public DefaultTlsSrpGroupVerifier()
+ : this(DefaultGroups)
+ {
+ }
+
+ /**
+ * Specify a custom set of acceptable group parameters.
+ *
+ * @param groups a {@link Vector} of acceptable {@link SRP6GroupParameters}
+ */
+ public DefaultTlsSrpGroupVerifier(IList groups)
+ {
+ this.mGroups = groups;
+ }
+
+ public virtual bool Accept(Srp6GroupParameters group)
+ {
+ foreach (Srp6GroupParameters entry in mGroups)
+ {
+ if (AreGroupsEqual(group, entry))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected virtual bool AreGroupsEqual(Srp6GroupParameters a, Srp6GroupParameters b)
+ {
+ return a == b || (AreParametersEqual(a.N, b.N) && AreParametersEqual(a.G, b.G));
+ }
+
+ protected virtual bool AreParametersEqual(BigInteger a, BigInteger b)
+ {
+ return a == b || a.Equals(b);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DeferredHash.cs b/crypto/src/crypto/tls/DeferredHash.cs
new file mode 100644
index 000000000..1112d4a3c
--- /dev/null
+++ b/crypto/src/crypto/tls/DeferredHash.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * Buffers input until the hash algorithm is determined.
+ */
+ internal class DeferredHash
+ : TlsHandshakeHash
+ {
+ protected const int BUFFERING_HASH_LIMIT = 4;
+
+ protected TlsContext mContext;
+
+ private DigestInputBuffer mBuf;
+ private IDictionary mHashes;
+ private int mPrfHashAlgorithm;
+
+ internal DeferredHash()
+ {
+ this.mBuf = new DigestInputBuffer();
+ this.mHashes = Platform.CreateHashtable();
+ this.mPrfHashAlgorithm = -1;
+ }
+
+ private DeferredHash(byte prfHashAlgorithm, IDigest prfHash)
+ {
+ this.mBuf = null;
+ this.mHashes = Platform.CreateHashtable();
+ this.mPrfHashAlgorithm = prfHashAlgorithm;
+ mHashes[prfHashAlgorithm] = prfHash;
+ }
+
+ public virtual void Init(TlsContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual TlsHandshakeHash NotifyPrfDetermined()
+ {
+ int prfAlgorithm = mContext.SecurityParameters.PrfAlgorithm;
+ if (prfAlgorithm == PrfAlgorithm.tls_prf_legacy)
+ {
+ CombinedHash legacyHash = new CombinedHash();
+ legacyHash.Init(mContext);
+ mBuf.UpdateDigest(legacyHash);
+ return legacyHash.NotifyPrfDetermined();
+ }
+
+ this.mPrfHashAlgorithm = TlsUtilities.GetHashAlgorithmForPrfAlgorithm(prfAlgorithm);
+
+ CheckTrackingHash((byte)mPrfHashAlgorithm);
+
+ return this;
+ }
+
+ public virtual void TrackHashAlgorithm(byte hashAlgorithm)
+ {
+ if (mBuf == null)
+ throw new InvalidOperationException("Too late to track more hash algorithms");
+
+ CheckTrackingHash(hashAlgorithm);
+ }
+
+ public virtual void SealHashAlgorithms()
+ {
+ CheckStopBuffering();
+ }
+
+ public virtual TlsHandshakeHash StopTracking()
+ {
+ byte prfHashAlgorithm = (byte)mPrfHashAlgorithm;
+ IDigest prfHash = TlsUtilities.CloneHash(prfHashAlgorithm, (IDigest)mHashes[prfHashAlgorithm]);
+ if (mBuf != null)
+ {
+ mBuf.UpdateDigest(prfHash);
+ }
+ DeferredHash result = new DeferredHash(prfHashAlgorithm, prfHash);
+ result.Init(mContext);
+ return result;
+ }
+
+ public virtual IDigest ForkPrfHash()
+ {
+ CheckStopBuffering();
+
+ byte prfHashAlgorithm = (byte)mPrfHashAlgorithm;
+ if (mBuf != null)
+ {
+ IDigest prfHash = TlsUtilities.CreateHash(prfHashAlgorithm);
+ mBuf.UpdateDigest(prfHash);
+ return prfHash;
+ }
+
+ return TlsUtilities.CloneHash(prfHashAlgorithm, (IDigest)mHashes[prfHashAlgorithm]);
+ }
+
+ public virtual byte[] GetFinalHash(byte hashAlgorithm)
+ {
+ IDigest d = (IDigest)mHashes[hashAlgorithm];
+ if (d == null)
+ throw new InvalidOperationException("HashAlgorithm " + hashAlgorithm + " is not being tracked");
+
+ d = TlsUtilities.CloneHash(hashAlgorithm, d);
+ if (mBuf != null)
+ {
+ mBuf.UpdateDigest(d);
+ }
+
+ return DigestUtilities.DoFinal(d);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { throw new InvalidOperationException("Use Fork() to get a definite IDigest"); }
+ }
+
+ public virtual int GetByteLength()
+ {
+ throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+ }
+
+ public virtual int GetDigestSize()
+ {
+ throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+ }
+
+ public virtual void Update(byte input)
+ {
+ if (mBuf != null)
+ {
+ mBuf.WriteByte(input);
+ return;
+ }
+
+ foreach (IDigest hash in mHashes.Values)
+ {
+ hash.Update(input);
+ }
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ if (mBuf != null)
+ {
+ mBuf.Write(input, inOff, len);
+ return;
+ }
+
+ foreach (IDigest hash in mHashes.Values)
+ {
+ hash.BlockUpdate(input, inOff, len);
+ }
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+ }
+
+ public virtual void Reset()
+ {
+ if (mBuf != null)
+ {
+ mBuf.SetLength(0);
+ return;
+ }
+
+ foreach (IDigest hash in mHashes.Values)
+ {
+ hash.Reset();
+ }
+ }
+
+ protected virtual void CheckStopBuffering()
+ {
+ if (mBuf != null && mHashes.Count <= BUFFERING_HASH_LIMIT)
+ {
+ foreach (IDigest hash in mHashes.Values)
+ {
+ mBuf.UpdateDigest(hash);
+ }
+
+ this.mBuf = null;
+ }
+ }
+
+ protected virtual void CheckTrackingHash(byte hashAlgorithm)
+ {
+ if (!mHashes.Contains(hashAlgorithm))
+ {
+ IDigest hash = TlsUtilities.CreateHash(hashAlgorithm);
+ mHashes[hashAlgorithm] = hash;
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DigestAlgorithm.cs b/crypto/src/crypto/tls/DigestAlgorithm.cs
deleted file mode 100644
index 745bea448..000000000
--- a/crypto/src/crypto/tls/DigestAlgorithm.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-
-namespace Org.BouncyCastle.Crypto.Tls
-{
- /// <summary>RFC 2246</summary>
- /// <remarks>
- /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
- /// depend on the particular values (e.g. serialization).
- /// </remarks>
- [Obsolete("Use MacAlgorithm constants instead")]
- public enum DigestAlgorithm
- {
- NULL,
- MD5,
- SHA,
-
- /*
- * RFC 5246
- */
- SHA256,
- SHA384,
- SHA512,
- }
-}
diff --git a/crypto/src/crypto/tls/DigitallySigned.cs b/crypto/src/crypto/tls/DigitallySigned.cs
new file mode 100644
index 000000000..8b7344fd9
--- /dev/null
+++ b/crypto/src/crypto/tls/DigitallySigned.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DigitallySigned
+ {
+ protected readonly SignatureAndHashAlgorithm mAlgorithm;
+ protected readonly byte[] mSignature;
+
+ public DigitallySigned(SignatureAndHashAlgorithm algorithm, byte[] signature)
+ {
+ if (signature == null)
+ throw new ArgumentNullException("signature");
+
+ this.mAlgorithm = algorithm;
+ this.mSignature = signature;
+ }
+
+ /**
+ * @return a {@link SignatureAndHashAlgorithm} (or null before TLS 1.2).
+ */
+ public virtual SignatureAndHashAlgorithm Algorithm
+ {
+ get { return mAlgorithm; }
+ }
+
+ public virtual byte[] Signature
+ {
+ get { return mSignature; }
+ }
+
+ /**
+ * Encode this {@link DigitallySigned} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ if (mAlgorithm != null)
+ {
+ mAlgorithm.Encode(output);
+ }
+ TlsUtilities.WriteOpaque16(mSignature, output);
+ }
+
+ /**
+ * Parse a {@link DigitallySigned} from a {@link Stream}.
+ *
+ * @param context
+ * the {@link TlsContext} of the current connection.
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link DigitallySigned} object.
+ * @throws IOException
+ */
+ public static DigitallySigned Parse(TlsContext context, Stream input)
+ {
+ SignatureAndHashAlgorithm algorithm = null;
+ if (TlsUtilities.IsTlsV12(context))
+ {
+ algorithm = SignatureAndHashAlgorithm.Parse(input);
+ }
+ byte[] signature = TlsUtilities.ReadOpaque16(input);
+ return new DigitallySigned(algorithm, signature);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs
new file mode 100644
index 000000000..411e7cca2
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs
@@ -0,0 +1,839 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DtlsClientProtocol
+ : DtlsProtocol
+ {
+ public DtlsClientProtocol(SecureRandom secureRandom)
+ : base(secureRandom)
+ {
+ }
+
+ public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport)
+ {
+ if (client == null)
+ throw new ArgumentNullException("client");
+ if (transport == null)
+ throw new ArgumentNullException("transport");
+
+ SecurityParameters securityParameters = new SecurityParameters();
+ securityParameters.entity = ConnectionEnd.client;
+
+ ClientHandshakeState state = new ClientHandshakeState();
+ state.client = client;
+ state.clientContext = new TlsClientContextImpl(mSecureRandom, securityParameters);
+
+ securityParameters.clientRandom = TlsProtocol.CreateRandomBlock(client.ShouldUseGmtUnixTime(),
+ state.clientContext.NonceRandomGenerator);
+
+ client.Init(state.clientContext);
+
+ DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.clientContext, client, ContentType.handshake);
+
+ TlsSession sessionToResume = state.client.GetSessionToResume();
+ if (sessionToResume != null && sessionToResume.IsResumable)
+ {
+ SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
+ if (sessionParameters != null)
+ {
+ state.tlsSession = sessionToResume;
+ state.sessionParameters = sessionParameters;
+ }
+ }
+
+ try
+ {
+ return ClientHandshake(state, recordLayer);
+ }
+ catch (TlsFatalAlert fatalAlert)
+ {
+ recordLayer.Fail(fatalAlert.AlertDescription);
+ throw fatalAlert;
+ }
+ catch (IOException e)
+ {
+ recordLayer.Fail(AlertDescription.internal_error);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ recordLayer.Fail(AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer)
+ {
+ SecurityParameters securityParameters = state.clientContext.SecurityParameters;
+ DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.clientContext, recordLayer);
+
+ byte[] clientHelloBody = GenerateClientHello(state, state.client);
+ handshake.SendMessage(HandshakeType.client_hello, clientHelloBody);
+
+ DtlsReliableHandshake.Message serverMessage = handshake.ReceiveMessage();
+
+ while (serverMessage.Type == HandshakeType.hello_verify_request)
+ {
+ ProtocolVersion recordLayerVersion = recordLayer.ResetDiscoveredPeerVersion();
+ ProtocolVersion client_version = state.clientContext.ClientVersion;
+
+ /*
+ * RFC 6347 4.2.1 DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of
+ * the version of TLS that is expected to be negotiated. DTLS 1.2 and 1.0 clients MUST use
+ * the version solely to indicate packet formatting (which is the same in both DTLS 1.2 and
+ * 1.0) and not as part of version negotiation.
+ */
+ if (!recordLayerVersion.IsEqualOrEarlierVersionOf(client_version))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ byte[] cookie = ProcessHelloVerifyRequest(state, serverMessage.Body);
+ byte[] patched = PatchClientHelloWithCookie(clientHelloBody, cookie);
+
+ handshake.ResetHandshakeMessagesDigest();
+ handshake.SendMessage(HandshakeType.client_hello, patched);
+
+ serverMessage = handshake.ReceiveMessage();
+ }
+
+ if (serverMessage.Type == HandshakeType.server_hello)
+ {
+ ReportServerVersion(state, recordLayer.DiscoveredPeerVersion);
+
+ ProcessServerHello(state, serverMessage.Body);
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ handshake.NotifyHelloComplete();
+
+ ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
+
+ if (state.resumedSession)
+ {
+ securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret);
+ recordLayer.InitPendingEpoch(state.client.GetCipher());
+
+ // NOTE: Calculated exclusive of the actual Finished message from the server
+ byte[] resExpectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
+ TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
+ ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), resExpectedServerVerifyData);
+
+ // NOTE: Calculated exclusive of the Finished message itself
+ byte[] resClientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
+ TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
+ handshake.SendMessage(HandshakeType.finished, resClientVerifyData);
+
+ handshake.Finish();
+
+ state.clientContext.SetResumableSession(state.tlsSession);
+
+ state.client.NotifyHandshakeComplete();
+
+ return new DtlsTransport(recordLayer);
+ }
+
+ InvalidateSession(state);
+
+ if (state.selectedSessionID.Length > 0)
+ {
+ state.tlsSession = new TlsSessionImpl(state.selectedSessionID, null);
+ }
+
+ serverMessage = handshake.ReceiveMessage();
+
+ if (serverMessage.Type == HandshakeType.supplemental_data)
+ {
+ ProcessServerSupplementalData(state, serverMessage.Body);
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ state.client.ProcessServerSupplementalData(null);
+ }
+
+ state.keyExchange = state.client.GetKeyExchange();
+ state.keyExchange.Init(state.clientContext);
+
+ Certificate serverCertificate = null;
+
+ if (serverMessage.Type == HandshakeType.certificate)
+ {
+ serverCertificate = ProcessServerCertificate(state, serverMessage.Body);
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ // Okay, Certificate is optional
+ state.keyExchange.SkipServerCredentials();
+ }
+
+ // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+ if (serverCertificate == null || serverCertificate.IsEmpty)
+ {
+ state.allowCertificateStatus = false;
+ }
+
+ if (serverMessage.Type == HandshakeType.certificate_status)
+ {
+ ProcessCertificateStatus(state, serverMessage.Body);
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ // Okay, CertificateStatus is optional
+ }
+
+ if (serverMessage.Type == HandshakeType.server_key_exchange)
+ {
+ ProcessServerKeyExchange(state, serverMessage.Body);
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ // Okay, ServerKeyExchange is optional
+ state.keyExchange.SkipServerKeyExchange();
+ }
+
+ if (serverMessage.Type == HandshakeType.certificate_request)
+ {
+ ProcessCertificateRequest(state, serverMessage.Body);
+
+ /*
+ * TODO Give the client a chance to immediately select the CertificateVerify hash
+ * algorithm here to avoid tracking the other hash algorithms unnecessarily?
+ */
+ TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
+ state.certificateRequest.SupportedSignatureAlgorithms);
+
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ // Okay, CertificateRequest is optional
+ }
+
+ if (serverMessage.Type == HandshakeType.server_hello_done)
+ {
+ if (serverMessage.Body.Length != 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ handshake.HandshakeHash.SealHashAlgorithms();
+
+ IList clientSupplementalData = state.client.GetClientSupplementalData();
+ if (clientSupplementalData != null)
+ {
+ byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData);
+ handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
+ }
+
+ if (state.certificateRequest != null)
+ {
+ state.clientCredentials = state.authentication.GetClientCredentials(state.certificateRequest);
+
+ /*
+ * RFC 5246 If no suitable certificate is available, the client MUST send a certificate
+ * message containing no certificates.
+ *
+ * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+ */
+ Certificate clientCertificate = null;
+ if (state.clientCredentials != null)
+ {
+ clientCertificate = state.clientCredentials.Certificate;
+ }
+ if (clientCertificate == null)
+ {
+ clientCertificate = Certificate.EmptyChain;
+ }
+
+ byte[] certificateBody = GenerateCertificate(clientCertificate);
+ handshake.SendMessage(HandshakeType.certificate, certificateBody);
+ }
+
+ if (state.clientCredentials != null)
+ {
+ state.keyExchange.ProcessClientCredentials(state.clientCredentials);
+ }
+ else
+ {
+ state.keyExchange.SkipClientCredentials();
+ }
+
+ byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state);
+ handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody);
+
+ TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();
+ securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.clientContext, prepareFinishHash, null);
+
+ TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange);
+ recordLayer.InitPendingEpoch(state.client.GetCipher());
+
+ if (state.clientCredentials != null && state.clientCredentials is TlsSignerCredentials)
+ {
+ TlsSignerCredentials signerCredentials = (TlsSignerCredentials)state.clientCredentials;
+
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ state.clientContext, signerCredentials);
+
+ byte[] hash;
+ if (signatureAndHashAlgorithm == null)
+ {
+ hash = securityParameters.SessionHash;
+ }
+ else
+ {
+ hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
+ }
+
+ byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
+ DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify);
+ handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
+ }
+
+ // NOTE: Calculated exclusive of the Finished message itself
+ byte[] clientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
+ TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
+ handshake.SendMessage(HandshakeType.finished, clientVerifyData);
+
+ if (state.expectSessionTicket)
+ {
+ serverMessage = handshake.ReceiveMessage();
+ if (serverMessage.Type == HandshakeType.session_ticket)
+ {
+ ProcessNewSessionTicket(state, serverMessage.Body);
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ // NOTE: Calculated exclusive of the actual Finished message from the server
+ byte[] expectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
+ TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
+ ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedServerVerifyData);
+
+ handshake.Finish();
+
+ if (state.tlsSession != null)
+ {
+ state.sessionParameters = new SessionParameters.Builder()
+ .SetCipherSuite(securityParameters.CipherSuite)
+ .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
+ .SetMasterSecret(securityParameters.MasterSecret)
+ .SetPeerCertificate(serverCertificate)
+ .SetPskIdentity(securityParameters.PskIdentity)
+ .SetSrpIdentity(securityParameters.SrpIdentity)
+ // TODO Consider filtering extensions that aren't relevant to resumed sessions
+ .SetServerExtensions(state.serverExtensions)
+ .Build();
+
+ state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters);
+
+ state.clientContext.SetResumableSession(state.tlsSession);
+ }
+
+ state.client.NotifyHandshakeComplete();
+
+ return new DtlsTransport(recordLayer);
+ }
+
+ protected virtual byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
+ {
+ MemoryStream buf = new MemoryStream();
+ certificateVerify.Encode(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ ProtocolVersion client_version = client.ClientVersion;
+ if (!client_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ TlsClientContextImpl context = state.clientContext;
+
+ context.SetClientVersion(client_version);
+ TlsUtilities.WriteVersion(client_version, buf);
+
+ SecurityParameters securityParameters = context.SecurityParameters;
+ buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);
+
+ // Session ID
+ byte[] session_id = TlsUtilities.EmptyBytes;
+ if (state.tlsSession != null)
+ {
+ session_id = state.tlsSession.SessionID;
+ if (session_id == null || session_id.Length > 32)
+ {
+ session_id = TlsUtilities.EmptyBytes;
+ }
+ }
+ TlsUtilities.WriteOpaque8(session_id, buf);
+
+ // Cookie
+ TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);
+
+ bool fallback = client.IsFallback;
+
+ /*
+ * Cipher suites
+ */
+ state.offeredCipherSuites = client.GetCipherSuites();
+
+ // Integer -> byte[]
+ state.clientExtensions = client.GetClientExtensions();
+
+ // Cipher Suites (and SCSV)
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+ * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+ * ClientHello. Including both is NOT RECOMMENDED.
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
+ bool noRenegExt = (null == renegExtData);
+
+ bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+
+ if (noRenegExt && noRenegSCSV)
+ {
+ // TODO Consider whether to default to a client extension instead
+ state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+ }
+
+ /*
+ * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version
+ * containing a lower value than the latest (highest-valued) version supported by the
+ * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in
+ * ClientHello.cipher_suites.
+ */
+ if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
+ {
+ state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
+ }
+
+ TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf);
+ }
+
+ // TODO Add support for compression
+ // Compression methods
+ // state.offeredCompressionMethods = client.getCompressionMethods();
+ state.offeredCompressionMethods = new byte[]{ CompressionMethod.cls_null };
+
+ TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf);
+
+ // Extensions
+ if (state.clientExtensions != null)
+ {
+ TlsProtocol.WriteExtensions(buf, state.clientExtensions);
+ }
+
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateClientKeyExchange(ClientHandshakeState state)
+ {
+ MemoryStream buf = new MemoryStream();
+ state.keyExchange.GenerateClientKeyExchange(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual void InvalidateSession(ClientHandshakeState state)
+ {
+ if (state.sessionParameters != null)
+ {
+ state.sessionParameters.Clear();
+ state.sessionParameters = null;
+ }
+
+ if (state.tlsSession != null)
+ {
+ state.tlsSession.Invalidate();
+ state.tlsSession = null;
+ }
+ }
+
+ protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
+ {
+ if (state.authentication == null)
+ {
+ /*
+ * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server to
+ * request client identification.
+ */
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ MemoryStream buf = new MemoryStream(body, false);
+
+ state.certificateRequest = CertificateRequest.Parse(state.clientContext, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
+ }
+
+ protected virtual void ProcessCertificateStatus(ClientHandshakeState state, byte[] body)
+ {
+ if (!state.allowCertificateStatus)
+ {
+ /*
+ * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
+ * server MUST have included an extension of type "status_request" with empty
+ * "extension_data" in the extended server hello..
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ MemoryStream buf = new MemoryStream(body, false);
+
+ state.certificateStatus = CertificateStatus.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
+ }
+
+ protected virtual byte[] ProcessHelloVerifyRequest(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+ byte[] cookie = TlsUtilities.ReadOpaque8(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ // TODO Seems this behaviour is not yet in line with OpenSSL for DTLS 1.2
+ // reportServerVersion(state, server_version);
+ if (!server_version.IsEqualOrEarlierVersionOf(state.clientContext.ClientVersion))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ /*
+ * RFC 6347 This specification increases the cookie size limit to 255 bytes for greater
+ * future flexibility. The limit remains 32 for previous versions of DTLS.
+ */
+ if (!ProtocolVersion.DTLSv12.IsEqualOrEarlierVersionOf(server_version) && cookie.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return cookie;
+ }
+
+ protected virtual void ProcessNewSessionTicket(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ state.client.NotifyNewSessionTicket(newSessionTicket);
+ }
+
+ protected virtual Certificate ProcessServerCertificate(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ Certificate serverCertificate = Certificate.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ state.keyExchange.ProcessServerCertificate(serverCertificate);
+ state.authentication = state.client.GetAuthentication();
+ state.authentication.NotifyServerCertificate(serverCertificate);
+
+ return serverCertificate;
+ }
+
+ protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] body)
+ {
+ SecurityParameters securityParameters = state.clientContext.SecurityParameters;
+
+ MemoryStream buf = new MemoryStream(body, false);
+
+ {
+ ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+ ReportServerVersion(state, server_version);
+ }
+
+ securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
+
+ state.selectedSessionID = TlsUtilities.ReadOpaque8(buf);
+ if (state.selectedSessionID.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ state.client.NotifySessionID(state.selectedSessionID);
+ state.resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null
+ && Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);
+
+ int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
+ if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+ || CipherSuite.IsScsv(selectedCipherSuite)
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.clientContext.ServerVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.illegal_parameter);
+ state.client.NotifySelectedCipherSuite(selectedCipherSuite);
+
+ byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
+ if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ state.client.NotifySelectedCompressionMethod(selectedCompressionMethod);
+
+ /*
+ * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
+ * hello message when the client has requested extended functionality via the extended
+ * client hello message specified in Section 2.1. ... Note that the extended server hello
+ * message is only sent in response to an extended client hello message. This prevents the
+ * possibility that the extended server hello message could "break" existing TLS 1.0
+ * clients.
+ */
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and send a server hello containing no
+ * extensions.
+ */
+
+ // Integer -> byte[]
+ state.serverExtensions = TlsProtocol.ReadExtensions(buf);
+
+ /*
+ * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
+ * extended client hello message. However, see RFC 5746 exception below. We always include
+ * the SCSV, so an Extended Server Hello is always allowed.
+ */
+ if (state.serverExtensions != null)
+ {
+ foreach (int extType in state.serverExtensions.Keys)
+ {
+ /*
+ * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
+ * ClientHello containing only the SCSV is an explicit exception to the prohibition
+ * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is
+ * only allowed because the client is signaling its willingness to receive the
+ * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+ */
+ if (extType == ExtensionType.renegotiation_info)
+ continue;
+
+ /*
+ * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
+ * same extension type appeared in the corresponding ClientHello. If a client
+ * receives an extension type in ServerHello that it did not request in the
+ * associated ClientHello, it MUST abort the handshake with an unsupported_extension
+ * fatal alert.
+ */
+ if (null == TlsUtilities.GetExtensionData(state.clientExtensions, extType))
+ throw new TlsFatalAlert(AlertDescription.unsupported_extension);
+
+ /*
+ * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and send a server hello containing no
+ * extensions[.]
+ */
+ if (state.resumedSession)
+ {
+ // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
+ // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
+ // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
+ //throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ /*
+ * RFC 5746 3.4. Client Behavior: Initial Handshake
+ */
+ {
+ /*
+ * When a ServerHello is received, the client MUST check if it includes the
+ * "renegotiation_info" extension:
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
+ if (renegExtData != null)
+ {
+ /*
+ * If the extension is present, set the secure_renegotiation flag to TRUE. The
+ * client MUST then verify that the length of the "renegotiated_connection"
+ * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
+ * handshake_failure alert).
+ */
+ state.secure_renegotiation = true;
+
+ if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
+ state.client.NotifySecureRenegotiation(state.secure_renegotiation);
+
+ IDictionary sessionClientExtensions = state.clientExtensions, sessionServerExtensions = state.serverExtensions;
+ if (state.resumedSession)
+ {
+ if (selectedCipherSuite != state.sessionParameters.CipherSuite
+ || selectedCompressionMethod != state.sessionParameters.CompressionAlgorithm)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ sessionClientExtensions = null;
+ sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
+ }
+
+ securityParameters.cipherSuite = selectedCipherSuite;
+ securityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+ if (sessionServerExtensions != null)
+ {
+ {
+ /*
+ * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
+ * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
+ * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
+ * client.
+ */
+ bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
+ if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(securityParameters.CipherSuite))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ securityParameters.encryptThenMac = serverSentEncryptThenMAC;
+ }
+
+ securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
+
+ securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
+ sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
+
+ securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
+
+ /*
+ * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be
+ * sent in a session resumption handshake.
+ */
+ state.allowCertificateStatus = !state.resumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
+ AlertDescription.illegal_parameter);
+
+ state.expectSessionTicket = !state.resumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
+ AlertDescription.illegal_parameter);
+ }
+
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
+ * that do not use the extended master secret [..]. (and see 5.2, 5.3)
+ */
+
+ if (sessionClientExtensions != null)
+ {
+ state.client.ProcessServerExtensions(sessionServerExtensions);
+ }
+
+ securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext,
+ securityParameters.CipherSuite);
+
+ /*
+ * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
+ * a verify_data_length equal to 12. This includes all existing cipher suites.
+ */
+ securityParameters.verifyDataLength = 12;
+ }
+
+ protected virtual void ProcessServerKeyExchange(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ state.keyExchange.ProcessServerKeyExchange(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+ }
+
+ protected virtual void ProcessServerSupplementalData(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+ IList serverSupplementalData = TlsProtocol.ReadSupplementalDataMessage(buf);
+ state.client.ProcessServerSupplementalData(serverSupplementalData);
+ }
+
+ protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
+ {
+ TlsClientContextImpl clientContext = state.clientContext;
+ ProtocolVersion currentServerVersion = clientContext.ServerVersion;
+ if (null == currentServerVersion)
+ {
+ clientContext.SetServerVersion(server_version);
+ state.client.NotifyServerVersion(server_version);
+ }
+ else if (!currentServerVersion.Equals(server_version))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ protected static byte[] PatchClientHelloWithCookie(byte[] clientHelloBody, byte[] cookie)
+ {
+ int sessionIDPos = 34;
+ int sessionIDLength = TlsUtilities.ReadUint8(clientHelloBody, sessionIDPos);
+
+ int cookieLengthPos = sessionIDPos + 1 + sessionIDLength;
+ int cookiePos = cookieLengthPos + 1;
+
+ byte[] patched = new byte[clientHelloBody.Length + cookie.Length];
+ Array.Copy(clientHelloBody, 0, patched, 0, cookieLengthPos);
+ TlsUtilities.CheckUint8(cookie.Length);
+ TlsUtilities.WriteUint8((byte)cookie.Length, patched, cookieLengthPos);
+ Array.Copy(cookie, 0, patched, cookiePos, cookie.Length);
+ Array.Copy(clientHelloBody, cookiePos, patched, cookiePos + cookie.Length, clientHelloBody.Length - cookiePos);
+
+ return patched;
+ }
+
+ protected internal class ClientHandshakeState
+ {
+ internal TlsClient client = null;
+ internal TlsClientContextImpl clientContext = null;
+ internal TlsSession tlsSession = null;
+ internal SessionParameters sessionParameters = null;
+ internal SessionParameters.Builder sessionParametersBuilder = null;
+ internal int[] offeredCipherSuites = null;
+ internal byte[] offeredCompressionMethods = null;
+ internal IDictionary clientExtensions = null;
+ internal IDictionary serverExtensions = null;
+ internal byte[] selectedSessionID = null;
+ internal bool resumedSession = false;
+ internal bool secure_renegotiation = false;
+ internal bool allowCertificateStatus = false;
+ internal bool expectSessionTicket = false;
+ internal TlsKeyExchange keyExchange = null;
+ internal TlsAuthentication authentication = null;
+ internal CertificateStatus certificateStatus = null;
+ internal CertificateRequest certificateRequest = null;
+ internal TlsCredentials clientCredentials = null;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsEpoch.cs b/crypto/src/crypto/tls/DtlsEpoch.cs
new file mode 100644
index 000000000..91fffa5e1
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsEpoch.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class DtlsEpoch
+ {
+ private readonly DtlsReplayWindow mReplayWindow = new DtlsReplayWindow();
+
+ private readonly int mEpoch;
+ private readonly TlsCipher mCipher;
+
+ private long mSequenceNumber = 0;
+
+ internal DtlsEpoch(int epoch, TlsCipher cipher)
+ {
+ if (epoch < 0)
+ throw new ArgumentException("must be >= 0", "epoch");
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+
+ this.mEpoch = epoch;
+ this.mCipher = cipher;
+ }
+
+ internal long AllocateSequenceNumber()
+ {
+ // TODO Check for overflow
+ return mSequenceNumber++;
+ }
+
+ internal TlsCipher Cipher
+ {
+ get { return mCipher; }
+ }
+
+ internal int Epoch
+ {
+ get { return mEpoch; }
+ }
+
+ internal DtlsReplayWindow ReplayWindow
+ {
+ get { return mReplayWindow; }
+ }
+
+ internal long SequenceNumber
+ {
+ get { return mSequenceNumber; }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsHandshakeRetransmit.cs b/crypto/src/crypto/tls/DtlsHandshakeRetransmit.cs
new file mode 100644
index 000000000..8bfae78b1
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsHandshakeRetransmit.cs
@@ -0,0 +1,11 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ interface DtlsHandshakeRetransmit
+ {
+ /// <exception cref="IOException"/>
+ void ReceivedHandshakeRecord(int epoch, byte[] buf, int off, int len);
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsProtocol.cs b/crypto/src/crypto/tls/DtlsProtocol.cs
new file mode 100644
index 000000000..e4ebd436c
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsProtocol.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class DtlsProtocol
+ {
+ protected readonly SecureRandom mSecureRandom;
+
+ protected DtlsProtocol(SecureRandom secureRandom)
+ {
+ if (secureRandom == null)
+ throw new ArgumentNullException("secureRandom");
+
+ this.mSecureRandom = secureRandom;
+ }
+
+ /// <exception cref="IOException"/>
+ protected virtual void ProcessFinished(byte[] body, byte[] expected_verify_data)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ byte[] verify_data = TlsUtilities.ReadFully(expected_verify_data.Length, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ if (!Arrays.ConstantTimeAreEqual(expected_verify_data, verify_data))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ /// <exception cref="IOException"/>
+ internal static void ApplyMaxFragmentLengthExtension(DtlsRecordLayer recordLayer, short maxFragmentLength)
+ {
+ if (maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)maxFragmentLength))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ int plainTextLimit = 1 << (8 + maxFragmentLength);
+ recordLayer.SetPlaintextLimit(plainTextLimit);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ protected static short EvaluateMaxFragmentLengthExtension(bool resumedSession, IDictionary clientExtensions,
+ IDictionary serverExtensions, byte alertDescription)
+ {
+ short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
+ if (maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)maxFragmentLength)
+ || (!resumedSession && maxFragmentLength != TlsExtensionsUtilities
+ .GetMaxFragmentLengthExtension(clientExtensions)))
+ {
+ throw new TlsFatalAlert(alertDescription);
+ }
+ }
+ return maxFragmentLength;
+ }
+
+ /// <exception cref="IOException"/>
+ protected static byte[] GenerateCertificate(Certificate certificate)
+ {
+ MemoryStream buf = new MemoryStream();
+ certificate.Encode(buf);
+ return buf.ToArray();
+ }
+
+ /// <exception cref="IOException"/>
+ protected static byte[] GenerateSupplementalData(IList supplementalData)
+ {
+ MemoryStream buf = new MemoryStream();
+ TlsProtocol.WriteSupplementalData(buf, supplementalData);
+ return buf.ToArray();
+ }
+
+ /// <exception cref="IOException"/>
+ protected static void ValidateSelectedCipherSuite(int selectedCipherSuite, byte alertDescription)
+ {
+ switch (TlsUtilities.GetEncryptionAlgorithm(selectedCipherSuite))
+ {
+ case EncryptionAlgorithm.RC4_40:
+ case EncryptionAlgorithm.RC4_128:
+ throw new TlsFatalAlert(alertDescription);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsReassembler.cs b/crypto/src/crypto/tls/DtlsReassembler.cs
new file mode 100644
index 000000000..11fe609cf
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsReassembler.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ class DtlsReassembler
+ {
+ private readonly byte mMsgType;
+ private readonly byte[] mBody;
+
+ private readonly IList mMissing = Platform.CreateArrayList();
+
+ internal DtlsReassembler(byte msg_type, int length)
+ {
+ this.mMsgType = msg_type;
+ this.mBody = new byte[length];
+ this.mMissing.Add(new Range(0, length));
+ }
+
+ internal byte MsgType
+ {
+ get { return mMsgType; }
+ }
+
+ internal byte[] GetBodyIfComplete()
+ {
+ return mMissing.Count == 0 ? mBody : null;
+ }
+
+ internal void ContributeFragment(byte msg_type, int length, byte[] buf, int off, int fragment_offset,
+ int fragment_length)
+ {
+ int fragment_end = fragment_offset + fragment_length;
+
+ if (this.mMsgType != msg_type || this.mBody.Length != length || fragment_end > length)
+ {
+ return;
+ }
+
+ if (fragment_length == 0)
+ {
+ // NOTE: Empty messages still require an empty fragment to complete it
+ if (fragment_offset == 0 && mMissing.Count > 0)
+ {
+ Range firstRange = (Range)mMissing[0];
+ if (firstRange.End == 0)
+ {
+ mMissing.RemoveAt(0);
+ }
+ }
+ return;
+ }
+
+ for (int i = 0; i < mMissing.Count; ++i)
+ {
+ Range range = (Range)mMissing[i];
+ if (range.Start >= fragment_end)
+ {
+ break;
+ }
+ if (range.End > fragment_offset)
+ {
+
+ int copyStart = System.Math.Max(range.Start, fragment_offset);
+ int copyEnd = System.Math.Min(range.End, fragment_end);
+ int copyLength = copyEnd - copyStart;
+
+ Array.Copy(buf, off + copyStart - fragment_offset, mBody, copyStart,
+ copyLength);
+
+ if (copyStart == range.Start)
+ {
+ if (copyEnd == range.End)
+ {
+ mMissing.RemoveAt(i--);
+ }
+ else
+ {
+ range.Start = copyEnd;
+ }
+ }
+ else
+ {
+ if (copyEnd != range.End)
+ {
+ mMissing.Insert(++i, new Range(copyEnd, range.End));
+ }
+ range.End = copyStart;
+ }
+ }
+ }
+ }
+
+ internal void Reset()
+ {
+ this.mMissing.Clear();
+ this.mMissing.Add(new Range(0, mBody.Length));
+ }
+
+ private class Range
+ {
+ private int mStart, mEnd;
+
+ internal Range(int start, int end)
+ {
+ this.mStart = start;
+ this.mEnd = end;
+ }
+
+ public int Start
+ {
+ get { return mStart; }
+ set { this.mStart = value; }
+ }
+
+ public int End
+ {
+ get { return mEnd; }
+ set { this.mEnd = value; }
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsRecordLayer.cs b/crypto/src/crypto/tls/DtlsRecordLayer.cs
new file mode 100644
index 000000000..70befd9e4
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsRecordLayer.cs
@@ -0,0 +1,507 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class DtlsRecordLayer
+ : DatagramTransport
+ {
+ private const int RECORD_HEADER_LENGTH = 13;
+ private const int MAX_FRAGMENT_LENGTH = 1 << 14;
+ private const long TCP_MSL = 1000L * 60 * 2;
+ private const long RETRANSMIT_TIMEOUT = TCP_MSL * 2;
+
+ private readonly DatagramTransport mTransport;
+ private readonly TlsContext mContext;
+ private readonly TlsPeer mPeer;
+
+ private readonly ByteQueue mRecordQueue = new ByteQueue();
+
+ private volatile bool mClosed = false;
+ private volatile bool mFailed = false;
+ private volatile ProtocolVersion mDiscoveredPeerVersion = null;
+ private volatile bool mInHandshake;
+ private volatile int mPlaintextLimit;
+ private DtlsEpoch mCurrentEpoch, mPendingEpoch;
+ private DtlsEpoch mReadEpoch, mWriteEpoch;
+
+ private DtlsHandshakeRetransmit mRetransmit = null;
+ private DtlsEpoch mRetransmitEpoch = null;
+ private long mRetransmitExpiry = 0;
+
+ internal DtlsRecordLayer(DatagramTransport transport, TlsContext context, TlsPeer peer, byte contentType)
+ {
+ this.mTransport = transport;
+ this.mContext = context;
+ this.mPeer = peer;
+
+ this.mInHandshake = true;
+
+ this.mCurrentEpoch = new DtlsEpoch(0, new TlsNullCipher(context));
+ this.mPendingEpoch = null;
+ this.mReadEpoch = mCurrentEpoch;
+ this.mWriteEpoch = mCurrentEpoch;
+
+ SetPlaintextLimit(MAX_FRAGMENT_LENGTH);
+ }
+
+ internal virtual void SetPlaintextLimit(int plaintextLimit)
+ {
+ this.mPlaintextLimit = plaintextLimit;
+ }
+
+ internal virtual ProtocolVersion DiscoveredPeerVersion
+ {
+ get { return mDiscoveredPeerVersion; }
+ }
+
+ internal virtual ProtocolVersion ResetDiscoveredPeerVersion()
+ {
+ ProtocolVersion result = mDiscoveredPeerVersion;
+ mDiscoveredPeerVersion = null;
+ return result;
+ }
+
+ internal virtual void InitPendingEpoch(TlsCipher pendingCipher)
+ {
+ if (mPendingEpoch != null)
+ throw new InvalidOperationException();
+
+ /*
+ * TODO "In order to ensure that any given sequence/epoch pair is unique, implementations
+ * MUST NOT allow the same epoch value to be reused within two times the TCP maximum segment
+ * lifetime."
+ */
+
+ // TODO Check for overflow
+ this.mPendingEpoch = new DtlsEpoch(mWriteEpoch.Epoch + 1, pendingCipher);
+ }
+
+ internal virtual void HandshakeSuccessful(DtlsHandshakeRetransmit retransmit)
+ {
+ if (mReadEpoch == mCurrentEpoch || mWriteEpoch == mCurrentEpoch)
+ {
+ // TODO
+ throw new InvalidOperationException();
+ }
+
+ if (retransmit != null)
+ {
+ this.mRetransmit = retransmit;
+ this.mRetransmitEpoch = mCurrentEpoch;
+ this.mRetransmitExpiry = DateTimeUtilities.CurrentUnixMs() + RETRANSMIT_TIMEOUT;
+ }
+
+ this.mInHandshake = false;
+ this.mCurrentEpoch = mPendingEpoch;
+ this.mPendingEpoch = null;
+ }
+
+ internal virtual void ResetWriteEpoch()
+ {
+ if (mRetransmitEpoch != null)
+ {
+ this.mWriteEpoch = mRetransmitEpoch;
+ }
+ else
+ {
+ this.mWriteEpoch = mCurrentEpoch;
+ }
+ }
+
+ public virtual int GetReceiveLimit()
+ {
+ return System.Math.Min(this.mPlaintextLimit,
+ mReadEpoch.Cipher.GetPlaintextLimit(mTransport.GetReceiveLimit() - RECORD_HEADER_LENGTH));
+ }
+
+ public virtual int GetSendLimit()
+ {
+ return System.Math.Min(this.mPlaintextLimit,
+ mWriteEpoch.Cipher.GetPlaintextLimit(mTransport.GetSendLimit() - RECORD_HEADER_LENGTH));
+ }
+
+ public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
+ {
+ byte[] record = null;
+
+ for (;;)
+ {
+ int receiveLimit = System.Math.Min(len, GetReceiveLimit()) + RECORD_HEADER_LENGTH;
+ if (record == null || record.Length < receiveLimit)
+ {
+ record = new byte[receiveLimit];
+ }
+
+ try
+ {
+ if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry)
+ {
+ mRetransmit = null;
+ mRetransmitEpoch = null;
+ }
+
+ int received = ReceiveRecord(record, 0, receiveLimit, waitMillis);
+ if (received < 0)
+ {
+ return received;
+ }
+ if (received < RECORD_HEADER_LENGTH)
+ {
+ continue;
+ }
+ int length = TlsUtilities.ReadUint16(record, 11);
+ if (received != (length + RECORD_HEADER_LENGTH))
+ {
+ continue;
+ }
+
+ byte type = TlsUtilities.ReadUint8(record, 0);
+
+ // TODO Support user-specified custom protocols?
+ switch (type)
+ {
+ case ContentType.alert:
+ case ContentType.application_data:
+ case ContentType.change_cipher_spec:
+ case ContentType.handshake:
+ case ContentType.heartbeat:
+ break;
+ default:
+ // TODO Exception?
+ continue;
+ }
+
+ int epoch = TlsUtilities.ReadUint16(record, 3);
+
+ DtlsEpoch recordEpoch = null;
+ if (epoch == mReadEpoch.Epoch)
+ {
+ recordEpoch = mReadEpoch;
+ }
+ else if (type == ContentType.handshake && mRetransmitEpoch != null
+ && epoch == mRetransmitEpoch.Epoch)
+ {
+ recordEpoch = mRetransmitEpoch;
+ }
+
+ if (recordEpoch == null)
+ {
+ continue;
+ }
+
+ long seq = TlsUtilities.ReadUint48(record, 5);
+ if (recordEpoch.ReplayWindow.ShouldDiscard(seq))
+ {
+ continue;
+ }
+
+ ProtocolVersion version = TlsUtilities.ReadVersion(record, 1);
+ if (mDiscoveredPeerVersion != null && !mDiscoveredPeerVersion.Equals(version))
+ {
+ continue;
+ }
+
+ byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext(
+ GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH,
+ received - RECORD_HEADER_LENGTH);
+
+ recordEpoch.ReplayWindow.ReportAuthenticated(seq);
+
+ if (plaintext.Length > this.mPlaintextLimit)
+ {
+ continue;
+ }
+
+ if (mDiscoveredPeerVersion == null)
+ {
+ mDiscoveredPeerVersion = version;
+ }
+
+ switch (type)
+ {
+ case ContentType.alert:
+ {
+ if (plaintext.Length == 2)
+ {
+ byte alertLevel = plaintext[0];
+ byte alertDescription = plaintext[1];
+
+ mPeer.NotifyAlertReceived(alertLevel, alertDescription);
+
+ if (alertLevel == AlertLevel.fatal)
+ {
+ Fail(alertDescription);
+ throw new TlsFatalAlert(alertDescription);
+ }
+
+ // TODO Can close_notify be a fatal alert?
+ if (alertDescription == AlertDescription.close_notify)
+ {
+ CloseTransport();
+ }
+ }
+
+ continue;
+ }
+ case ContentType.application_data:
+ {
+ if (mInHandshake)
+ {
+ // TODO Consider buffering application data for new epoch that arrives
+ // out-of-order with the Finished message
+ continue;
+ }
+ break;
+ }
+ case ContentType.change_cipher_spec:
+ {
+ // Implicitly receive change_cipher_spec and change to pending cipher state
+
+ for (int i = 0; i < plaintext.Length; ++i)
+ {
+ byte message = TlsUtilities.ReadUint8(plaintext, i);
+ if (message != ChangeCipherSpec.change_cipher_spec)
+ {
+ continue;
+ }
+
+ if (mPendingEpoch != null)
+ {
+ mReadEpoch = mPendingEpoch;
+ }
+ }
+
+ continue;
+ }
+ case ContentType.handshake:
+ {
+ if (!mInHandshake)
+ {
+ if (mRetransmit != null)
+ {
+ mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length);
+ }
+
+ // TODO Consider support for HelloRequest
+ continue;
+ }
+ break;
+ }
+ case ContentType.heartbeat:
+ {
+ // TODO[RFC 6520]
+ continue;
+ }
+ }
+
+ /*
+ * NOTE: If we receive any non-handshake data in the new epoch implies the peer has
+ * received our final flight.
+ */
+ if (!mInHandshake && mRetransmit != null)
+ {
+ this.mRetransmit = null;
+ this.mRetransmitEpoch = null;
+ }
+
+ Array.Copy(plaintext, 0, buf, off, plaintext.Length);
+ return plaintext.Length;
+ }
+ catch (IOException e)
+ {
+ // NOTE: Assume this is a timeout for the moment
+ throw e;
+ }
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual void Send(byte[] buf, int off, int len)
+ {
+ byte contentType = ContentType.application_data;
+
+ if (this.mInHandshake || this.mWriteEpoch == this.mRetransmitEpoch)
+ {
+ contentType = ContentType.handshake;
+
+ byte handshakeType = TlsUtilities.ReadUint8(buf, off);
+ if (handshakeType == HandshakeType.finished)
+ {
+ DtlsEpoch nextEpoch = null;
+ if (this.mInHandshake)
+ {
+ nextEpoch = mPendingEpoch;
+ }
+ else if (this.mWriteEpoch == this.mRetransmitEpoch)
+ {
+ nextEpoch = mCurrentEpoch;
+ }
+
+ if (nextEpoch == null)
+ {
+ // TODO
+ throw new InvalidOperationException();
+ }
+
+ // Implicitly send change_cipher_spec and change to pending cipher state
+
+ // TODO Send change_cipher_spec and finished records in single datagram?
+ byte[] data = new byte[]{ 1 };
+ SendRecord(ContentType.change_cipher_spec, data, 0, data.Length);
+
+ mWriteEpoch = nextEpoch;
+ }
+ }
+
+ SendRecord(contentType, buf, off, len);
+ }
+
+ public virtual void Close()
+ {
+ if (!mClosed)
+ {
+ if (mInHandshake)
+ {
+ Warn(AlertDescription.user_canceled, "User canceled handshake");
+ }
+ CloseTransport();
+ }
+ }
+
+ internal virtual void Fail(byte alertDescription)
+ {
+ if (!mClosed)
+ {
+ try
+ {
+ RaiseAlert(AlertLevel.fatal, alertDescription, null, null);
+ }
+ catch (Exception)
+ {
+ // Ignore
+ }
+
+ mFailed = true;
+
+ CloseTransport();
+ }
+ }
+
+ internal virtual void Warn(byte alertDescription, string message)
+ {
+ RaiseAlert(AlertLevel.warning, alertDescription, message, null);
+ }
+
+ private void CloseTransport()
+ {
+ if (!mClosed)
+ {
+ /*
+ * RFC 5246 7.2.1. Unless some other fatal alert has been transmitted, each party is
+ * required to send a close_notify alert before closing the write side of the
+ * connection. The other party MUST respond with a close_notify alert of its own and
+ * close down the connection immediately, discarding any pending writes.
+ */
+
+ try
+ {
+ if (!mFailed)
+ {
+ Warn(AlertDescription.close_notify, null);
+ }
+ mTransport.Close();
+ }
+ catch (Exception)
+ {
+ // Ignore
+ }
+
+ mClosed = true;
+ }
+ }
+
+ private void RaiseAlert(byte alertLevel, byte alertDescription, string message, Exception cause)
+ {
+ mPeer.NotifyAlertRaised(alertLevel, alertDescription, message, cause);
+
+ byte[] error = new byte[2];
+ error[0] = (byte)alertLevel;
+ error[1] = (byte)alertDescription;
+
+ SendRecord(ContentType.alert, error, 0, 2);
+ }
+
+ private int ReceiveRecord(byte[] buf, int off, int len, int waitMillis)
+ {
+ if (mRecordQueue.Available > 0)
+ {
+ int length = 0;
+ if (mRecordQueue.Available >= RECORD_HEADER_LENGTH)
+ {
+ byte[] lengthBytes = new byte[2];
+ mRecordQueue.Read(lengthBytes, 0, 2, 11);
+ length = TlsUtilities.ReadUint16(lengthBytes, 0);
+ }
+
+ int received = System.Math.Min(mRecordQueue.Available, RECORD_HEADER_LENGTH + length);
+ mRecordQueue.RemoveData(buf, off, received, 0);
+ return received;
+ }
+
+ {
+ int received = mTransport.Receive(buf, off, len, waitMillis);
+ if (received >= RECORD_HEADER_LENGTH)
+ {
+ int fragmentLength = TlsUtilities.ReadUint16(buf, off + 11);
+ int recordLength = RECORD_HEADER_LENGTH + fragmentLength;
+ if (received > recordLength)
+ {
+ mRecordQueue.AddData(buf, off + recordLength, received - recordLength);
+ received = recordLength;
+ }
+ }
+ return received;
+ }
+ }
+
+ private void SendRecord(byte contentType, byte[] buf, int off, int len)
+ {
+ if (len > this.mPlaintextLimit)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ /*
+ * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+ * or ChangeCipherSpec content types.
+ */
+ if (len < 1 && contentType != ContentType.application_data)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ int recordEpoch = mWriteEpoch.Epoch;
+ long recordSequenceNumber = mWriteEpoch.AllocateSequenceNumber();
+
+ byte[] ciphertext = mWriteEpoch.Cipher.EncodePlaintext(
+ GetMacSequenceNumber(recordEpoch, recordSequenceNumber), contentType, buf, off, len);
+
+ // TODO Check the ciphertext length?
+
+ byte[] record = new byte[ciphertext.Length + RECORD_HEADER_LENGTH];
+ TlsUtilities.WriteUint8(contentType, record, 0);
+ ProtocolVersion version = mDiscoveredPeerVersion != null ? mDiscoveredPeerVersion : mContext.ClientVersion;
+ TlsUtilities.WriteVersion(version, record, 1);
+ TlsUtilities.WriteUint16(recordEpoch, record, 3);
+ TlsUtilities.WriteUint48(recordSequenceNumber, record, 5);
+ TlsUtilities.WriteUint16(ciphertext.Length, record, 11);
+ Array.Copy(ciphertext, 0, record, RECORD_HEADER_LENGTH, ciphertext.Length);
+
+ mTransport.Send(record, 0, record.Length);
+ }
+
+ private static long GetMacSequenceNumber(int epoch, long sequence_number)
+ {
+ return ((epoch & 0xFFFFFFFFL) << 48) | sequence_number;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsReliableHandshake.cs b/crypto/src/crypto/tls/DtlsReliableHandshake.cs
new file mode 100644
index 000000000..8e4439e67
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsReliableHandshake.cs
@@ -0,0 +1,443 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class DtlsReliableHandshake
+ {
+ private const int MAX_RECEIVE_AHEAD = 10;
+
+ private readonly DtlsRecordLayer mRecordLayer;
+
+ private TlsHandshakeHash mHandshakeHash;
+
+ private IDictionary mCurrentInboundFlight = Platform.CreateHashtable();
+ private IDictionary mPreviousInboundFlight = null;
+ private IList mOutboundFlight = Platform.CreateArrayList();
+ private bool mSending = true;
+
+ private int mMessageSeq = 0, mNextReceiveSeq = 0;
+
+ internal DtlsReliableHandshake(TlsContext context, DtlsRecordLayer transport)
+ {
+ this.mRecordLayer = transport;
+ this.mHandshakeHash = new DeferredHash();
+ this.mHandshakeHash.Init(context);
+ }
+
+ internal void NotifyHelloComplete()
+ {
+ this.mHandshakeHash = mHandshakeHash.NotifyPrfDetermined();
+ }
+
+ internal TlsHandshakeHash HandshakeHash
+ {
+ get { return mHandshakeHash; }
+ }
+
+ internal TlsHandshakeHash PrepareToFinish()
+ {
+ TlsHandshakeHash result = mHandshakeHash;
+ this.mHandshakeHash = mHandshakeHash.StopTracking();
+ return result;
+ }
+
+ internal void SendMessage(byte msg_type, byte[] body)
+ {
+ TlsUtilities.CheckUint24(body.Length);
+
+ if (!mSending)
+ {
+ CheckInboundFlight();
+ mSending = true;
+ mOutboundFlight.Clear();
+ }
+
+ Message message = new Message(mMessageSeq++, msg_type, body);
+
+ mOutboundFlight.Add(message);
+
+ WriteMessage(message);
+ UpdateHandshakeMessagesDigest(message);
+ }
+
+ internal byte[] ReceiveMessageBody(byte msg_type)
+ {
+ Message message = ReceiveMessage();
+ if (message.Type != msg_type)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ return message.Body;
+ }
+
+ internal Message ReceiveMessage()
+ {
+ if (mSending)
+ {
+ mSending = false;
+ PrepareInboundFlight();
+ }
+
+ // Check if we already have the next message waiting
+ {
+ DtlsReassembler next = (DtlsReassembler)mCurrentInboundFlight[mNextReceiveSeq];
+ if (next != null)
+ {
+ byte[] body = next.GetBodyIfComplete();
+ if (body != null)
+ {
+ mPreviousInboundFlight = null;
+ return UpdateHandshakeMessagesDigest(new Message(mNextReceiveSeq++, next.MsgType, body));
+ }
+ }
+ }
+
+ byte[] buf = null;
+
+ // TODO Check the conditions under which we should reset this
+ int readTimeoutMillis = 1000;
+
+ for (;;)
+ {
+ int receiveLimit = mRecordLayer.GetReceiveLimit();
+ if (buf == null || buf.Length < receiveLimit)
+ {
+ buf = new byte[receiveLimit];
+ }
+
+ // TODO Handle records containing multiple handshake messages
+
+ try
+ {
+ for (; ; )
+ {
+ int received = mRecordLayer.Receive(buf, 0, receiveLimit, readTimeoutMillis);
+ if (received < 0)
+ {
+ break;
+ }
+ if (received < 12)
+ {
+ continue;
+ }
+ int fragment_length = TlsUtilities.ReadUint24(buf, 9);
+ if (received != (fragment_length + 12))
+ {
+ continue;
+ }
+ int seq = TlsUtilities.ReadUint16(buf, 4);
+ if (seq > (mNextReceiveSeq + MAX_RECEIVE_AHEAD))
+ {
+ continue;
+ }
+ byte msg_type = TlsUtilities.ReadUint8(buf, 0);
+ int length = TlsUtilities.ReadUint24(buf, 1);
+ int fragment_offset = TlsUtilities.ReadUint24(buf, 6);
+ if (fragment_offset + fragment_length > length)
+ {
+ continue;
+ }
+
+ if (seq < mNextReceiveSeq)
+ {
+ /*
+ * NOTE: If we Receive the previous flight of incoming messages in full
+ * again, retransmit our last flight
+ */
+ if (mPreviousInboundFlight != null)
+ {
+ DtlsReassembler reassembler = (DtlsReassembler)mPreviousInboundFlight[seq];
+ if (reassembler != null)
+ {
+ reassembler.ContributeFragment(msg_type, length, buf, 12, fragment_offset,
+ fragment_length);
+
+ if (CheckAll(mPreviousInboundFlight))
+ {
+ ResendOutboundFlight();
+
+ /*
+ * TODO[DTLS] implementations SHOULD back off handshake packet
+ * size during the retransmit backoff.
+ */
+ readTimeoutMillis = System.Math.Min(readTimeoutMillis * 2, 60000);
+
+ ResetAll(mPreviousInboundFlight);
+ }
+ }
+ }
+ }
+ else
+ {
+ DtlsReassembler reassembler = (DtlsReassembler)mCurrentInboundFlight[seq];
+ if (reassembler == null)
+ {
+ reassembler = new DtlsReassembler(msg_type, length);
+ mCurrentInboundFlight[seq] = reassembler;
+ }
+
+ reassembler.ContributeFragment(msg_type, length, buf, 12, fragment_offset, fragment_length);
+
+ if (seq == mNextReceiveSeq)
+ {
+ byte[] body = reassembler.GetBodyIfComplete();
+ if (body != null)
+ {
+ mPreviousInboundFlight = null;
+ return UpdateHandshakeMessagesDigest(new Message(mNextReceiveSeq++,
+ reassembler.MsgType, body));
+ }
+ }
+ }
+ }
+ }
+ catch (IOException)
+ {
+ // NOTE: Assume this is a timeout for the moment
+ }
+
+ ResendOutboundFlight();
+
+ /*
+ * TODO[DTLS] implementations SHOULD back off handshake packet size during the
+ * retransmit backoff.
+ */
+ readTimeoutMillis = System.Math.Min(readTimeoutMillis * 2, 60000);
+ }
+ }
+
+ internal void Finish()
+ {
+ DtlsHandshakeRetransmit retransmit = null;
+ if (!mSending)
+ {
+ CheckInboundFlight();
+ }
+ else if (mCurrentInboundFlight != null)
+ {
+ /*
+ * RFC 6347 4.2.4. In addition, for at least twice the default MSL defined for [TCP],
+ * when in the FINISHED state, the node that transmits the last flight (the server in an
+ * ordinary handshake or the client in a resumed handshake) MUST respond to a retransmit
+ * of the peer's last flight with a retransmit of the last flight.
+ */
+ retransmit = new Retransmit(this);
+ }
+
+ mRecordLayer.HandshakeSuccessful(retransmit);
+ }
+
+ internal void ResetHandshakeMessagesDigest()
+ {
+ mHandshakeHash.Reset();
+ }
+
+ private void HandleRetransmittedHandshakeRecord(int epoch, byte[] buf, int off, int len)
+ {
+ /*
+ * TODO Need to handle the case where the previous inbound flight contains
+ * messages from two epochs.
+ */
+ if (len < 12)
+ return;
+ int fragment_length = TlsUtilities.ReadUint24(buf, off + 9);
+ if (len != (fragment_length + 12))
+ return;
+ int seq = TlsUtilities.ReadUint16(buf, off + 4);
+ if (seq >= mNextReceiveSeq)
+ return;
+
+ byte msg_type = TlsUtilities.ReadUint8(buf, off);
+
+ // TODO This is a hack that only works until we try to support renegotiation
+ int expectedEpoch = msg_type == HandshakeType.finished ? 1 : 0;
+ if (epoch != expectedEpoch)
+ return;
+
+ int length = TlsUtilities.ReadUint24(buf, off + 1);
+ int fragment_offset = TlsUtilities.ReadUint24(buf, off + 6);
+ if (fragment_offset + fragment_length > length)
+ return;
+
+ DtlsReassembler reassembler = (DtlsReassembler)mCurrentInboundFlight[seq];
+ if (reassembler != null)
+ {
+ reassembler.ContributeFragment(msg_type, length, buf, off + 12, fragment_offset,
+ fragment_length);
+ if (CheckAll(mCurrentInboundFlight))
+ {
+ ResendOutboundFlight();
+ ResetAll(mCurrentInboundFlight);
+ }
+ }
+ }
+
+ /**
+ * Check that there are no "extra" messages left in the current inbound flight
+ */
+ private void CheckInboundFlight()
+ {
+ foreach (int key in mCurrentInboundFlight.Keys)
+ {
+ if (key >= mNextReceiveSeq)
+ {
+ // TODO Should this be considered an error?
+ }
+ }
+ }
+
+ private void PrepareInboundFlight()
+ {
+ ResetAll(mCurrentInboundFlight);
+ mPreviousInboundFlight = mCurrentInboundFlight;
+ mCurrentInboundFlight = Platform.CreateHashtable();
+ }
+
+ private void ResendOutboundFlight()
+ {
+ mRecordLayer.ResetWriteEpoch();
+ for (int i = 0; i < mOutboundFlight.Count; ++i)
+ {
+ WriteMessage((Message)mOutboundFlight[i]);
+ }
+ }
+
+ private Message UpdateHandshakeMessagesDigest(Message message)
+ {
+ if (message.Type != HandshakeType.hello_request)
+ {
+ byte[] body = message.Body;
+ byte[] buf = new byte[12];
+ TlsUtilities.WriteUint8(message.Type, buf, 0);
+ TlsUtilities.WriteUint24(body.Length, buf, 1);
+ TlsUtilities.WriteUint16(message.Seq, buf, 4);
+ TlsUtilities.WriteUint24(0, buf, 6);
+ TlsUtilities.WriteUint24(body.Length, buf, 9);
+ mHandshakeHash.BlockUpdate(buf, 0, buf.Length);
+ mHandshakeHash.BlockUpdate(body, 0, body.Length);
+ }
+ return message;
+ }
+
+ private void WriteMessage(Message message)
+ {
+ int sendLimit = mRecordLayer.GetSendLimit();
+ int fragmentLimit = sendLimit - 12;
+
+ // TODO Support a higher minimum fragment size?
+ if (fragmentLimit < 1)
+ {
+ // TODO Should we be throwing an exception here?
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ int length = message.Body.Length;
+
+ // NOTE: Must still send a fragment if body is empty
+ int fragment_offset = 0;
+ do
+ {
+ int fragment_length = System.Math.Min(length - fragment_offset, fragmentLimit);
+ WriteHandshakeFragment(message, fragment_offset, fragment_length);
+ fragment_offset += fragment_length;
+ }
+ while (fragment_offset < length);
+ }
+
+ private void WriteHandshakeFragment(Message message, int fragment_offset, int fragment_length)
+ {
+ RecordLayerBuffer fragment = new RecordLayerBuffer(12 + fragment_length);
+ TlsUtilities.WriteUint8(message.Type, fragment);
+ TlsUtilities.WriteUint24(message.Body.Length, fragment);
+ TlsUtilities.WriteUint16(message.Seq, fragment);
+ TlsUtilities.WriteUint24(fragment_offset, fragment);
+ TlsUtilities.WriteUint24(fragment_length, fragment);
+ fragment.Write(message.Body, fragment_offset, fragment_length);
+
+ fragment.SendToRecordLayer(mRecordLayer);
+ }
+
+ private static bool CheckAll(IDictionary inboundFlight)
+ {
+ foreach (DtlsReassembler r in inboundFlight.Values)
+ {
+ if (r.GetBodyIfComplete() == null)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static void ResetAll(IDictionary inboundFlight)
+ {
+ foreach (DtlsReassembler r in inboundFlight.Values)
+ {
+ r.Reset();
+ }
+ }
+
+ internal class Message
+ {
+ private readonly int mMessageSeq;
+ private readonly byte mMsgType;
+ private readonly byte[] mBody;
+
+ internal Message(int message_seq, byte msg_type, byte[] body)
+ {
+ this.mMessageSeq = message_seq;
+ this.mMsgType = msg_type;
+ this.mBody = body;
+ }
+
+ public int Seq
+ {
+ get { return mMessageSeq; }
+ }
+
+ public byte Type
+ {
+ get { return mMsgType; }
+ }
+
+ public byte[] Body
+ {
+ get { return mBody; }
+ }
+ }
+
+ internal class RecordLayerBuffer
+ : MemoryStream
+ {
+ internal RecordLayerBuffer(int size)
+ : base(size)
+ {
+ }
+
+ internal void SendToRecordLayer(DtlsRecordLayer recordLayer)
+ {
+ recordLayer.Send(GetBuffer(), 0, (int)Length);
+ this.Close();
+ }
+ }
+
+ internal class Retransmit
+ : DtlsHandshakeRetransmit
+ {
+ private readonly DtlsReliableHandshake mOuter;
+
+ internal Retransmit(DtlsReliableHandshake outer)
+ {
+ this.mOuter = outer;
+ }
+
+ public void ReceivedHandshakeRecord(int epoch, byte[] buf, int off, int len)
+ {
+ mOuter.HandleRetransmittedHandshakeRecord(epoch, buf, off, len);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsReplayWindow.cs b/crypto/src/crypto/tls/DtlsReplayWindow.cs
new file mode 100644
index 000000000..ea18e805e
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsReplayWindow.cs
@@ -0,0 +1,85 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 4347 4.1.2.5 Anti-replay
+ * <p/>
+ * Support fast rejection of duplicate records by maintaining a sliding receive window
+ */
+ internal class DtlsReplayWindow
+ {
+ private const long VALID_SEQ_MASK = 0x0000FFFFFFFFFFFFL;
+
+ private const long WINDOW_SIZE = 64L;
+
+ private long mLatestConfirmedSeq = -1;
+ private long mBitmap = 0;
+
+ /**
+ * Check whether a received record with the given sequence number should be rejected as a duplicate.
+ *
+ * @param seq the 48-bit DTLSPlainText.sequence_number field of a received record.
+ * @return true if the record should be discarded without further processing.
+ */
+ internal bool ShouldDiscard(long seq)
+ {
+ if ((seq & VALID_SEQ_MASK) != seq)
+ return true;
+
+ if (seq <= mLatestConfirmedSeq)
+ {
+ long diff = mLatestConfirmedSeq - seq;
+ if (diff >= WINDOW_SIZE)
+ return true;
+ if ((mBitmap & (1L << (int)diff)) != 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Report that a received record with the given sequence number passed authentication checks.
+ *
+ * @param seq the 48-bit DTLSPlainText.sequence_number field of an authenticated record.
+ */
+ internal void ReportAuthenticated(long seq)
+ {
+ if ((seq & VALID_SEQ_MASK) != seq)
+ throw new ArgumentException("out of range", "seq");
+
+ if (seq <= mLatestConfirmedSeq)
+ {
+ long diff = mLatestConfirmedSeq - seq;
+ if (diff < WINDOW_SIZE)
+ {
+ mBitmap |= (1L << (int)diff);
+ }
+ }
+ else
+ {
+ long diff = seq - mLatestConfirmedSeq;
+ if (diff >= WINDOW_SIZE)
+ {
+ mBitmap = 1;
+ }
+ else
+ {
+ mBitmap <<= (int)diff;
+ mBitmap |= 1;
+ }
+ mLatestConfirmedSeq = seq;
+ }
+ }
+
+ /**
+ * When a new epoch begins, sequence numbers begin again at 0
+ */
+ internal void Reset()
+ {
+ mLatestConfirmedSeq = -1;
+ mBitmap = 0;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs
new file mode 100644
index 000000000..9c7caf290
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs
@@ -0,0 +1,655 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DtlsServerProtocol
+ : DtlsProtocol
+ {
+ protected bool mVerifyRequests = true;
+
+ public DtlsServerProtocol(SecureRandom secureRandom)
+ : base(secureRandom)
+ {
+ }
+
+ public virtual bool VerifyRequests
+ {
+ get { return mVerifyRequests; }
+ set { this.mVerifyRequests = value; }
+ }
+
+ public virtual DtlsTransport Accept(TlsServer server, DatagramTransport transport)
+ {
+ if (server == null)
+ throw new ArgumentNullException("server");
+ if (transport == null)
+ throw new ArgumentNullException("transport");
+
+ SecurityParameters securityParameters = new SecurityParameters();
+ securityParameters.entity = ConnectionEnd.server;
+
+ ServerHandshakeState state = new ServerHandshakeState();
+ state.server = server;
+ state.serverContext = new TlsServerContextImpl(mSecureRandom, securityParameters);
+
+ securityParameters.serverRandom = TlsProtocol.CreateRandomBlock(server.ShouldUseGmtUnixTime(),
+ state.serverContext.NonceRandomGenerator);
+
+ server.Init(state.serverContext);
+
+ DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.serverContext, server, ContentType.handshake);
+
+ // TODO Need to handle sending of HelloVerifyRequest without entering a full connection
+
+ try
+ {
+ return ServerHandshake(state, recordLayer);
+ }
+ catch (TlsFatalAlert fatalAlert)
+ {
+ recordLayer.Fail(fatalAlert.AlertDescription);
+ throw fatalAlert;
+ }
+ catch (IOException e)
+ {
+ recordLayer.Fail(AlertDescription.internal_error);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ recordLayer.Fail(AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer)
+ {
+ SecurityParameters securityParameters = state.serverContext.SecurityParameters;
+ DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.serverContext, recordLayer);
+
+ DtlsReliableHandshake.Message clientMessage = handshake.ReceiveMessage();
+
+ {
+ // NOTE: After receiving a record from the client, we discover the record layer version
+ ProtocolVersion client_version = recordLayer.DiscoveredPeerVersion;
+ // TODO Read RFCs for guidance on the expected record layer version number
+ state.serverContext.SetClientVersion(client_version);
+ }
+
+ if (clientMessage.Type == HandshakeType.client_hello)
+ {
+ ProcessClientHello(state, clientMessage.Body);
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ {
+ byte[] serverHelloBody = GenerateServerHello(state);
+
+ ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
+
+ handshake.SendMessage(HandshakeType.server_hello, serverHelloBody);
+ }
+
+ handshake.NotifyHelloComplete();
+
+ IList serverSupplementalData = state.server.GetServerSupplementalData();
+ if (serverSupplementalData != null)
+ {
+ byte[] supplementalDataBody = GenerateSupplementalData(serverSupplementalData);
+ handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
+ }
+
+ state.keyExchange = state.server.GetKeyExchange();
+ state.keyExchange.Init(state.serverContext);
+
+ state.serverCredentials = state.server.GetCredentials();
+
+ Certificate serverCertificate = null;
+
+ if (state.serverCredentials == null)
+ {
+ state.keyExchange.SkipServerCredentials();
+ }
+ else
+ {
+ state.keyExchange.ProcessServerCredentials(state.serverCredentials);
+
+ serverCertificate = state.serverCredentials.Certificate;
+ byte[] certificateBody = GenerateCertificate(serverCertificate);
+ handshake.SendMessage(HandshakeType.certificate, certificateBody);
+ }
+
+ // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+ if (serverCertificate == null || serverCertificate.IsEmpty)
+ {
+ state.allowCertificateStatus = false;
+ }
+
+ if (state.allowCertificateStatus)
+ {
+ CertificateStatus certificateStatus = state.server.GetCertificateStatus();
+ if (certificateStatus != null)
+ {
+ byte[] certificateStatusBody = GenerateCertificateStatus(state, certificateStatus);
+ handshake.SendMessage(HandshakeType.certificate_status, certificateStatusBody);
+ }
+ }
+
+ byte[] serverKeyExchange = state.keyExchange.GenerateServerKeyExchange();
+ if (serverKeyExchange != null)
+ {
+ handshake.SendMessage(HandshakeType.server_key_exchange, serverKeyExchange);
+ }
+
+ if (state.serverCredentials != null)
+ {
+ state.certificateRequest = state.server.GetCertificateRequest();
+ if (state.certificateRequest != null)
+ {
+ state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
+
+ byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest);
+ handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody);
+
+ TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
+ state.certificateRequest.SupportedSignatureAlgorithms);
+ }
+ }
+
+ handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes);
+
+ handshake.HandshakeHash.SealHashAlgorithms();
+
+ clientMessage = handshake.ReceiveMessage();
+
+ if (clientMessage.Type == HandshakeType.supplemental_data)
+ {
+ ProcessClientSupplementalData(state, clientMessage.Body);
+ clientMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ state.server.ProcessClientSupplementalData(null);
+ }
+
+ if (state.certificateRequest == null)
+ {
+ state.keyExchange.SkipClientCredentials();
+ }
+ else
+ {
+ if (clientMessage.Type == HandshakeType.certificate)
+ {
+ ProcessClientCertificate(state, clientMessage.Body);
+ clientMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ if (TlsUtilities.IsTlsV12(state.serverContext))
+ {
+ /*
+ * RFC 5246 If no suitable certificate is available, the client MUST send a
+ * certificate message containing no certificates.
+ *
+ * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ NotifyClientCertificate(state, Certificate.EmptyChain);
+ }
+ }
+
+ if (clientMessage.Type == HandshakeType.client_key_exchange)
+ {
+ ProcessClientKeyExchange(state, clientMessage.Body);
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();
+ securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.serverContext, prepareFinishHash, null);
+
+ TlsProtocol.EstablishMasterSecret(state.serverContext, state.keyExchange);
+ recordLayer.InitPendingEpoch(state.server.GetCipher());
+
+ /*
+ * RFC 5246 7.4.8 This message is only sent following a client certificate that has signing
+ * capability (i.e., all certificates except those containing fixed Diffie-Hellman
+ * parameters).
+ */
+ if (ExpectCertificateVerifyMessage(state))
+ {
+ byte[] certificateVerifyBody = handshake.ReceiveMessageBody(HandshakeType.certificate_verify);
+ ProcessCertificateVerify(state, certificateVerifyBody, prepareFinishHash);
+ }
+
+ // NOTE: Calculated exclusive of the actual Finished message from the client
+ byte[] expectedClientVerifyData = TlsUtilities.CalculateVerifyData(state.serverContext, ExporterLabel.client_finished,
+ TlsProtocol.GetCurrentPrfHash(state.serverContext, handshake.HandshakeHash, null));
+ ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedClientVerifyData);
+
+ if (state.expectSessionTicket)
+ {
+ NewSessionTicket newSessionTicket = state.server.GetNewSessionTicket();
+ byte[] newSessionTicketBody = GenerateNewSessionTicket(state, newSessionTicket);
+ handshake.SendMessage(HandshakeType.session_ticket, newSessionTicketBody);
+ }
+
+ // NOTE: Calculated exclusive of the Finished message itself
+ byte[] serverVerifyData = TlsUtilities.CalculateVerifyData(state.serverContext, ExporterLabel.server_finished,
+ TlsProtocol.GetCurrentPrfHash(state.serverContext, handshake.HandshakeHash, null));
+ handshake.SendMessage(HandshakeType.finished, serverVerifyData);
+
+ handshake.Finish();
+
+ state.server.NotifyHandshakeComplete();
+
+ return new DtlsTransport(recordLayer);
+ }
+
+ protected virtual byte[] GenerateCertificateRequest(ServerHandshakeState state, CertificateRequest certificateRequest)
+ {
+ MemoryStream buf = new MemoryStream();
+ certificateRequest.Encode(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateCertificateStatus(ServerHandshakeState state, CertificateStatus certificateStatus)
+ {
+ MemoryStream buf = new MemoryStream();
+ certificateStatus.Encode(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateNewSessionTicket(ServerHandshakeState state, NewSessionTicket newSessionTicket)
+ {
+ MemoryStream buf = new MemoryStream();
+ newSessionTicket.Encode(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
+ {
+ SecurityParameters securityParameters = state.serverContext.SecurityParameters;
+
+ MemoryStream buf = new MemoryStream();
+
+ {
+ ProtocolVersion server_version = state.server.GetServerVersion();
+ if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ // TODO Read RFCs for guidance on the expected record layer version number
+ // recordStream.setReadVersion(server_version);
+ // recordStream.setWriteVersion(server_version);
+ // recordStream.setRestrictReadVersion(true);
+ state.serverContext.SetServerVersion(server_version);
+
+ TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);
+ }
+
+ buf.Write(securityParameters.ServerRandom, 0, securityParameters.ServerRandom.Length);
+
+ /*
+ * The server may return an empty session_id to indicate that the session will not be cached
+ * and therefore cannot be resumed.
+ */
+ TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);
+
+ int selectedCipherSuite = state.server.GetSelectedCipherSuite();
+ if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+ || CipherSuite.IsScsv(selectedCipherSuite)
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.serverContext.ServerVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.internal_error);
+ securityParameters.cipherSuite = selectedCipherSuite;
+
+ byte selectedCompressionMethod = state.server.GetSelectedCompressionMethod();
+ if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ securityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+ TlsUtilities.WriteUint16(selectedCipherSuite, buf);
+ TlsUtilities.WriteUint8(selectedCompressionMethod, buf);
+
+ state.serverExtensions = state.server.GetServerExtensions();
+
+ /*
+ * RFC 5746 3.6. Server Behavior: Initial Handshake
+ */
+ if (state.secure_renegotiation)
+ {
+ byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
+ bool noRenegExt = (null == renegExtData);
+
+ if (noRenegExt)
+ {
+ /*
+ * Note that sending a "renegotiation_info" extension in response to a ClientHello
+ * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
+ * Section 7.4.1.4, on the server sending unsolicited extensions and is only allowed
+ * because the client is signaling its willingness to receive the extension via the
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+ */
+
+ /*
+ * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
+ * "renegotiation_info" extension in the ServerHello message.
+ */
+ state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
+ state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
+ }
+ }
+
+ if (securityParameters.extendedMasterSecret)
+ {
+ state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
+ TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions);
+ }
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and send a server hello containing no
+ * extensions.
+ */
+
+ if (state.serverExtensions != null)
+ {
+ securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);
+
+ securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
+ state.clientExtensions, state.serverExtensions, AlertDescription.internal_error);
+
+ securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions);
+
+ /*
+ * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+ * a session resumption handshake.
+ */
+ state.allowCertificateStatus = !state.resumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.status_request,
+ AlertDescription.internal_error);
+
+ state.expectSessionTicket = !state.resumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.session_ticket,
+ AlertDescription.internal_error);
+
+ TlsProtocol.WriteExtensions(buf, state.serverExtensions);
+ }
+
+ securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.serverContext,
+ securityParameters.CipherSuite);
+
+ /*
+ * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length
+ * has a verify_data_length equal to 12. This includes all existing cipher suites.
+ */
+ securityParameters.verifyDataLength = 12;
+
+ return buf.ToArray();
+ }
+
+ protected virtual void NotifyClientCertificate(ServerHandshakeState state, Certificate clientCertificate)
+ {
+ if (state.certificateRequest == null)
+ throw new InvalidOperationException();
+
+ if (state.clientCertificate != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ state.clientCertificate = clientCertificate;
+
+ if (clientCertificate.IsEmpty)
+ {
+ state.keyExchange.SkipClientCredentials();
+ }
+ else
+ {
+
+ /*
+ * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request
+ * message was non-empty, one of the certificates in the certificate chain SHOULD be
+ * issued by one of the listed CAs.
+ */
+
+ state.clientCertificateType = TlsUtilities.GetClientCertificateType(clientCertificate,
+ state.serverCredentials.Certificate);
+
+ state.keyExchange.ProcessClientCertificate(clientCertificate);
+ }
+
+ /*
+ * RFC 5246 7.4.6. If the client does not send any certificates, the server MAY at its
+ * discretion either continue the handshake without client authentication, or respond with a
+ * fatal handshake_failure alert. Also, if some aspect of the certificate chain was
+ * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its
+ * discretion either continue the handshake (considering the client unauthenticated) or send
+ * a fatal alert.
+ */
+ state.server.NotifyClientCertificate(clientCertificate);
+ }
+
+ protected virtual void ProcessClientCertificate(ServerHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ Certificate clientCertificate = Certificate.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ NotifyClientCertificate(state, clientCertificate);
+ }
+
+ protected virtual void ProcessCertificateVerify(ServerHandshakeState state, byte[] body, TlsHandshakeHash prepareFinishHash)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ TlsServerContextImpl context = state.serverContext;
+ DigitallySigned clientCertificateVerify = DigitallySigned.Parse(context, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ // Verify the CertificateVerify message contains a correct signature.
+ bool verified = false;
+ try
+ {
+ byte[] hash;
+ if (TlsUtilities.IsTlsV12(context))
+ {
+ hash = prepareFinishHash.GetFinalHash(clientCertificateVerify.Algorithm.Hash);
+ }
+ else
+ {
+ hash = context.SecurityParameters.SessionHash;
+ }
+
+ X509CertificateStructure x509Cert = state.clientCertificate.GetCertificateAt(0);
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
+
+ TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)state.clientCertificateType);
+ tlsSigner.Init(context);
+ verified = tlsSigner.VerifyRawSignature(clientCertificateVerify.Algorithm,
+ clientCertificateVerify.Signature, publicKey, hash);
+ }
+ catch (Exception)
+ {
+ }
+
+ if (!verified)
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+ }
+
+ protected virtual void ProcessClientHello(ServerHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ // TODO Read RFCs for guidance on the expected record layer version number
+ ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);
+ if (!client_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ /*
+ * Read the client random
+ */
+ byte[] client_random = TlsUtilities.ReadFully(32, buf);
+
+ byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
+ if (sessionID.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ // TODO RFC 4347 has the cookie length restricted to 32, but not in RFC 6347
+ byte[] cookie = TlsUtilities.ReadOpaque8(buf);
+
+ int cipher_suites_length = TlsUtilities.ReadUint16(buf);
+ if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ /*
+ * NOTE: "If the session_id field is not empty (implying a session resumption request) this
+ * vector must include at least the cipher_suite from that session."
+ */
+ state.offeredCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);
+
+ int compression_methods_length = TlsUtilities.ReadUint8(buf);
+ if (compression_methods_length < 1)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ state.offeredCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and send a server hello containing no
+ * extensions.
+ */
+ state.clientExtensions = TlsProtocol.ReadExtensions(buf);
+
+ TlsServerContextImpl context = state.serverContext;
+ SecurityParameters securityParameters = context.SecurityParameters;
+
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
+ * that do not use the extended master secret [..]. (and see 5.2, 5.3)
+ */
+ securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions);
+
+ context.SetClientVersion(client_version);
+
+ state.server.NotifyClientVersion(client_version);
+ state.server.NotifyFallback(Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));
+
+ securityParameters.clientRandom = client_random;
+
+ state.server.NotifyOfferedCipherSuites(state.offeredCipherSuites);
+ state.server.NotifyOfferedCompressionMethods(state.offeredCompressionMethods);
+
+ /*
+ * RFC 5746 3.6. Server Behavior: Initial Handshake
+ */
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+ * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+ * ClientHello. Including both is NOT RECOMMENDED.
+ */
+
+ /*
+ * When a ClientHello is received, the server MUST check if it includes the
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
+ * to TRUE.
+ */
+ if (Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
+ {
+ state.secure_renegotiation = true;
+ }
+
+ /*
+ * The server MUST check if the "renegotiation_info" extension is included in the
+ * ClientHello.
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
+ if (renegExtData != null)
+ {
+ /*
+ * If the extension is present, set secure_renegotiation flag to TRUE. The
+ * server MUST then verify that the length of the "renegotiated_connection"
+ * field is zero, and if it is not, MUST abort the handshake.
+ */
+ state.secure_renegotiation = true;
+
+ if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ state.server.NotifySecureRenegotiation(state.secure_renegotiation);
+
+ if (state.clientExtensions != null)
+ {
+ state.server.ProcessClientExtensions(state.clientExtensions);
+ }
+ }
+
+ protected virtual void ProcessClientKeyExchange(ServerHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ state.keyExchange.ProcessClientKeyExchange(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+ }
+
+ protected virtual void ProcessClientSupplementalData(ServerHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+ IList clientSupplementalData = TlsProtocol.ReadSupplementalDataMessage(buf);
+ state.server.ProcessClientSupplementalData(clientSupplementalData);
+ }
+
+ protected virtual bool ExpectCertificateVerifyMessage(ServerHandshakeState state)
+ {
+ return state.clientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)state.clientCertificateType);
+ }
+
+ protected internal class ServerHandshakeState
+ {
+ internal TlsServer server = null;
+ internal TlsServerContextImpl serverContext = null;
+ internal int[] offeredCipherSuites = null;
+ internal byte[] offeredCompressionMethods = null;
+ internal IDictionary clientExtensions = null;
+ internal IDictionary serverExtensions = null;
+ internal bool resumedSession = false;
+ internal bool secure_renegotiation = false;
+ internal bool allowCertificateStatus = false;
+ internal bool expectSessionTicket = false;
+ internal TlsKeyExchange keyExchange = null;
+ internal TlsCredentials serverCredentials = null;
+ internal CertificateRequest certificateRequest = null;
+ internal short clientCertificateType = -1;
+ internal Certificate clientCertificate = null;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/DtlsTransport.cs b/crypto/src/crypto/tls/DtlsTransport.cs
new file mode 100644
index 000000000..5c607336b
--- /dev/null
+++ b/crypto/src/crypto/tls/DtlsTransport.cs
@@ -0,0 +1,77 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DtlsTransport
+ : DatagramTransport
+ {
+ private readonly DtlsRecordLayer mRecordLayer;
+
+ internal DtlsTransport(DtlsRecordLayer recordLayer)
+ {
+ this.mRecordLayer = recordLayer;
+ }
+
+ public virtual int GetReceiveLimit()
+ {
+ return mRecordLayer.GetReceiveLimit();
+ }
+
+ public virtual int GetSendLimit()
+ {
+ return mRecordLayer.GetSendLimit();
+ }
+
+ public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
+ {
+ try
+ {
+ return mRecordLayer.Receive(buf, off, len, waitMillis);
+ }
+ catch (TlsFatalAlert fatalAlert)
+ {
+ mRecordLayer.Fail(fatalAlert.AlertDescription);
+ throw fatalAlert;
+ }
+ catch (IOException e)
+ {
+ mRecordLayer.Fail(AlertDescription.internal_error);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ mRecordLayer.Fail(AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ public virtual void Send(byte[] buf, int off, int len)
+ {
+ try
+ {
+ mRecordLayer.Send(buf, off, len);
+ }
+ catch (TlsFatalAlert fatalAlert)
+ {
+ mRecordLayer.Fail(fatalAlert.AlertDescription);
+ throw fatalAlert;
+ }
+ catch (IOException e)
+ {
+ mRecordLayer.Fail(AlertDescription.internal_error);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ mRecordLayer.Fail(AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ public virtual void Close()
+ {
+ mRecordLayer.Close();
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/ECBasisType.cs b/crypto/src/crypto/tls/ECBasisType.cs
index b7c9c6bd7..5416e17c0 100644
--- a/crypto/src/crypto/tls/ECBasisType.cs
+++ b/crypto/src/crypto/tls/ECBasisType.cs
@@ -5,10 +5,10 @@ namespace Org.BouncyCastle.Crypto.Tls
/// <summary>RFC 4492 5.4. (Errata ID: 2389)</summary>
public abstract class ECBasisType
{
- public const short ec_basis_trinomial = 1;
- public const short ec_basis_pentanomial = 2;
+ public const byte ec_basis_trinomial = 1;
+ public const byte ec_basis_pentanomial = 2;
- public static bool IsValid(short ecBasisType)
+ public static bool IsValid(byte ecBasisType)
{
return ecBasisType >= ec_basis_trinomial && ecBasisType <= ec_basis_pentanomial;
}
diff --git a/crypto/src/crypto/tls/EncryptionAlgorithm.cs b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
index dbeaa3356..05d1c5d7a 100644
--- a/crypto/src/crypto/tls/EncryptionAlgorithm.cs
+++ b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
@@ -50,9 +50,20 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int AES_256_CCM_8 = 18;
/*
- * TBD[draft-josefsson-salsa20-tls-02]
+ * RFC 6367
*/
- const int ESTREAM_SALSA20 = 100;
- const int SALSA20 = 101;
+ public const int CAMELLIA_128_GCM = 19;
+ public const int CAMELLIA_256_GCM = 20;
+
+ /*
+ * draft-josefsson-salsa20-tls-04
+ */
+ public const int ESTREAM_SALSA20 = 100;
+ public const int SALSA20 = 101;
+
+ /*
+ * draft-agl-tls-chacha20poly1305-04
+ */
+ public const int AEAD_CHACHA20_POLY1305 = 102;
}
}
diff --git a/crypto/src/crypto/tls/ExporterLabel.cs b/crypto/src/crypto/tls/ExporterLabel.cs
index c186d410b..5970769d7 100644
--- a/crypto/src/crypto/tls/ExporterLabel.cs
+++ b/crypto/src/crypto/tls/ExporterLabel.cs
@@ -6,12 +6,6 @@ namespace Org.BouncyCastle.Crypto.Tls
public abstract class ExporterLabel
{
/*
- * BC-specific
- */
- internal const string client_random = "client random";
- internal const string server_random = "server random";
-
- /*
* RFC 5246
*/
public const string client_finished = "client finished";
@@ -34,5 +28,10 @@ namespace Org.BouncyCastle.Crypto.Tls
* RFC 5764
*/
public const string dtls_srtp = "EXTRACTOR-dtls_srtp";
+
+ /*
+ * draft-ietf-tls-session-hash-04
+ */
+ public static readonly string extended_master_secret = "extended master secret";
}
}
diff --git a/crypto/src/crypto/tls/ExtensionType.cs b/crypto/src/crypto/tls/ExtensionType.cs
index 4e265c358..b4b24f7c3 100644
--- a/crypto/src/crypto/tls/ExtensionType.cs
+++ b/crypto/src/crypto/tls/ExtensionType.cs
@@ -44,16 +44,28 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int heartbeat = 15;
/*
+ * RFC 7366
+ */
+ public const int encrypt_then_mac = 22;
+
+ /*
+ * draft-ietf-tls-session-hash-04
+ *
+ * NOTE: Early code-point assignment
+ */
+ public const int extended_master_secret = 23;
+
+ /*
* RFC 5077 7.
*/
public const int session_ticket = 35;
/*
- * draft-gutmann-tls-encrypt-then-mac-05
+ * draft-ietf-tls-negotiated-ff-dhe-01
*
- * NOTE: This value has not yet been reserved by the IETF
+ * WARNING: Placeholder value; the real value is TBA
*/
- public static readonly int encrypt_then_mac = 66;
+ public static readonly int negotiated_ff_dhe_groups = 101;
/*
* RFC 5746 3.2.
diff --git a/crypto/src/crypto/tls/FiniteFieldDheGroup.cs b/crypto/src/crypto/tls/FiniteFieldDheGroup.cs
new file mode 100644
index 000000000..437504941
--- /dev/null
+++ b/crypto/src/crypto/tls/FiniteFieldDheGroup.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /*
+ * draft-ietf-tls-negotiated-ff-dhe-01
+ */
+ public abstract class FiniteFieldDheGroup
+ {
+ public const byte ffdhe2432 = 0;
+ public const byte ffdhe3072 = 1;
+ public const byte ffdhe4096 = 2;
+ public const byte ffdhe6144 = 3;
+ public const byte ffdhe8192 = 4;
+
+ public static bool IsValid(byte group)
+ {
+ return group >= ffdhe2432 && group <= ffdhe8192;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/HeartbeatExtension.cs b/crypto/src/crypto/tls/HeartbeatExtension.cs
new file mode 100644
index 000000000..049837266
--- /dev/null
+++ b/crypto/src/crypto/tls/HeartbeatExtension.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class HeartbeatExtension
+ {
+ protected readonly byte mMode;
+
+ public HeartbeatExtension(byte mode)
+ {
+ if (!HeartbeatMode.IsValid(mode))
+ throw new ArgumentException("not a valid HeartbeatMode value", "mode");
+
+ this.mMode = mode;
+ }
+
+ public virtual byte Mode
+ {
+ get { return mMode; }
+ }
+
+ /**
+ * Encode this {@link HeartbeatExtension} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(mMode, output);
+ }
+
+ /**
+ * Parse a {@link HeartbeatExtension} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link HeartbeatExtension} object.
+ * @throws IOException
+ */
+ public static HeartbeatExtension Parse(Stream input)
+ {
+ byte mode = TlsUtilities.ReadUint8(input);
+ if (!HeartbeatMode.IsValid(mode))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return new HeartbeatExtension(mode);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/HeartbeatMessage.cs b/crypto/src/crypto/tls/HeartbeatMessage.cs
new file mode 100644
index 000000000..f64a7baa4
--- /dev/null
+++ b/crypto/src/crypto/tls/HeartbeatMessage.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class HeartbeatMessage
+ {
+ protected readonly byte mType;
+ protected readonly byte[] mPayload;
+ protected readonly int mPaddingLength;
+
+ public HeartbeatMessage(byte type, byte[] payload, int paddingLength)
+ {
+ if (!HeartbeatMessageType.IsValid(type))
+ throw new ArgumentException("not a valid HeartbeatMessageType value", "type");
+ if (payload == null || payload.Length >= (1 << 16))
+ throw new ArgumentException("must have length < 2^16", "payload");
+ if (paddingLength < 16)
+ throw new ArgumentException("must be at least 16", "paddingLength");
+
+ this.mType = type;
+ this.mPayload = payload;
+ this.mPaddingLength = paddingLength;
+ }
+
+ /**
+ * Encode this {@link HeartbeatMessage} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(TlsContext context, Stream output)
+ {
+ TlsUtilities.WriteUint8(mType, output);
+
+ TlsUtilities.CheckUint16(mPayload.Length);
+ TlsUtilities.WriteUint16(mPayload.Length, output);
+ output.Write(mPayload, 0, mPayload.Length);
+
+ byte[] padding = new byte[mPaddingLength];
+ context.NonceRandomGenerator.NextBytes(padding);
+ output.Write(padding, 0, padding.Length);
+ }
+
+ /**
+ * Parse a {@link HeartbeatMessage} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link HeartbeatMessage} object.
+ * @throws IOException
+ */
+ public static HeartbeatMessage Parse(Stream input)
+ {
+ byte type = TlsUtilities.ReadUint8(input);
+ if (!HeartbeatMessageType.IsValid(type))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ int payload_length = TlsUtilities.ReadUint16(input);
+
+ PayloadBuffer buf = new PayloadBuffer();
+ Streams.PipeAll(input, buf);
+
+ byte[] payload = buf.ToTruncatedByteArray(payload_length);
+ if (payload == null)
+ {
+ /*
+ * RFC 6520 4. If the payload_length of a received HeartbeatMessage is too large, the
+ * received HeartbeatMessage MUST be discarded silently.
+ */
+ return null;
+ }
+
+ TlsUtilities.CheckUint16(buf.Length);
+ int padding_length = (int)buf.Length - payload.Length;
+
+ /*
+ * RFC 6520 4. The padding of a received HeartbeatMessage message MUST be ignored
+ */
+ return new HeartbeatMessage(type, payload, padding_length);
+ }
+
+ internal class PayloadBuffer
+ : MemoryStream
+ {
+ internal byte[] ToTruncatedByteArray(int payloadLength)
+ {
+ /*
+ * RFC 6520 4. The padding_length MUST be at least 16.
+ */
+ int minimumCount = payloadLength + 16;
+ if (Length < minimumCount)
+ return null;
+ return Arrays.CopyOf(GetBuffer(), payloadLength);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/HeartbeatMessageType.cs b/crypto/src/crypto/tls/HeartbeatMessageType.cs
index 9e3ad213c..57a4b86be 100644
--- a/crypto/src/crypto/tls/HeartbeatMessageType.cs
+++ b/crypto/src/crypto/tls/HeartbeatMessageType.cs
@@ -7,10 +7,10 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
public abstract class HeartbeatMessageType
{
- public const short heartbeat_request = 1;
- public const short heartbeat_response = 2;
+ public const byte heartbeat_request = 1;
+ public const byte heartbeat_response = 2;
- public static bool IsValid(short heartbeatMessageType)
+ public static bool IsValid(byte heartbeatMessageType)
{
return heartbeatMessageType >= heartbeat_request && heartbeatMessageType <= heartbeat_response;
}
diff --git a/crypto/src/crypto/tls/HeartbeatMode.cs b/crypto/src/crypto/tls/HeartbeatMode.cs
index 0968f6e10..f1570a84d 100644
--- a/crypto/src/crypto/tls/HeartbeatMode.cs
+++ b/crypto/src/crypto/tls/HeartbeatMode.cs
@@ -7,10 +7,10 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
public abstract class HeartbeatMode
{
- public const short peer_allowed_to_send = 1;
- public const short peer_not_allowed_to_send = 2;
+ public const byte peer_allowed_to_send = 1;
+ public const byte peer_not_allowed_to_send = 2;
- public static bool IsValid(short heartbeatMode)
+ public static bool IsValid(byte heartbeatMode)
{
return heartbeatMode >= peer_allowed_to_send && heartbeatMode <= peer_not_allowed_to_send;
}
diff --git a/crypto/src/crypto/tls/ICertificateVerifyer.cs b/crypto/src/crypto/tls/ICertificateVerifyer.cs
deleted file mode 100644
index df5ea51d7..000000000
--- a/crypto/src/crypto/tls/ICertificateVerifyer.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-
-using Org.BouncyCastle.Asn1.X509;
-
-namespace Org.BouncyCastle.Crypto.Tls
-{
- /// <remarks>
- /// This should be implemented by any class which can find out, if a given
- /// certificate chain is being accepted by an client.
- /// </remarks>
- [Obsolete("Perform certificate verification in TlsAuthentication implementation")]
- public interface ICertificateVerifyer
- {
- /// <param name="certs">The certs, which are part of the chain.</param>
- /// <returns>True, if the chain is accepted, false otherwise</returns>
- bool IsValid(X509CertificateStructure[] certs);
- }
-}
diff --git a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
deleted file mode 100644
index bce31c0b0..000000000
--- a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-
-namespace Org.BouncyCastle.Crypto.Tls
-{
- /// <summary>
- /// A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication.
- /// </summary>
- [Obsolete]
- public class LegacyTlsAuthentication
- : TlsAuthentication
- {
- protected ICertificateVerifyer verifyer;
-
- public LegacyTlsAuthentication(ICertificateVerifyer verifyer)
- {
- this.verifyer = verifyer;
- }
-
- public virtual void NotifyServerCertificate(Certificate serverCertificate)
- {
- if (!this.verifyer.IsValid(serverCertificate.GetCertificateList()))
- throw new TlsFatalAlert(AlertDescription.user_canceled);
- }
-
- public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
- {
- return null;
- }
- }
-}
diff --git a/crypto/src/crypto/tls/LegacyTlsClient.cs b/crypto/src/crypto/tls/LegacyTlsClient.cs
deleted file mode 100644
index fbb9a732e..000000000
--- a/crypto/src/crypto/tls/LegacyTlsClient.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-
-namespace Org.BouncyCastle.Crypto.Tls
-{
- /// <summary>
- /// A temporary class to use LegacyTlsAuthentication
- /// </summary>
- [Obsolete]
- public class LegacyTlsClient
- : DefaultTlsClient
- {
- [Obsolete]
- protected ICertificateVerifyer verifyer;
-
- [Obsolete]
- public LegacyTlsClient(ICertificateVerifyer verifyer)
- {
- this.verifyer = verifyer;
- }
-
- public override TlsAuthentication GetAuthentication()
- {
- return new LegacyTlsAuthentication(verifyer);
- }
- }
-}
\ No newline at end of file
diff --git a/crypto/src/crypto/tls/MaxFragmentLength.cs b/crypto/src/crypto/tls/MaxFragmentLength.cs
index adb6d129c..5b10b35dd 100644
--- a/crypto/src/crypto/tls/MaxFragmentLength.cs
+++ b/crypto/src/crypto/tls/MaxFragmentLength.cs
@@ -7,12 +7,12 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 3546 3.2.
*/
- public const short pow2_9 = 1;
- public const short pow2_10 = 2;
- public const short pow2_11 = 3;
- public const short pow2_12 = 4;
+ public const byte pow2_9 = 1;
+ public const byte pow2_10 = 2;
+ public const byte pow2_11 = 3;
+ public const byte pow2_12 = 4;
- public static bool IsValid(short maxFragmentLength)
+ public static bool IsValid(byte maxFragmentLength)
{
return maxFragmentLength >= pow2_9 && maxFragmentLength <= pow2_12;
}
diff --git a/crypto/src/crypto/tls/NameType.cs b/crypto/src/crypto/tls/NameType.cs
index ffcb639d0..25f6046fc 100644
--- a/crypto/src/crypto/tls/NameType.cs
+++ b/crypto/src/crypto/tls/NameType.cs
@@ -7,6 +7,6 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 3546 3.1.
*/
- public const short host_name = 0;
+ public const byte host_name = 0;
}
}
diff --git a/crypto/src/crypto/tls/NamedCurve.cs b/crypto/src/crypto/tls/NamedCurve.cs
index 8ef395069..b8aa0ecde 100644
--- a/crypto/src/crypto/tls/NamedCurve.cs
+++ b/crypto/src/crypto/tls/NamedCurve.cs
@@ -58,7 +58,8 @@ namespace Org.BouncyCastle.Crypto.Tls
public static bool IsValid(int namedCurve)
{
- return namedCurve >= sect163k1 && namedCurve <= brainpoolP512r1;
+ return (namedCurve >= sect163k1 && namedCurve <= brainpoolP512r1)
+ || (namedCurve >= arbitrary_explicit_prime_curves && namedCurve <= arbitrary_explicit_char2_curves);
}
public static bool RefersToASpecificNamedCurve(int namedCurve)
@@ -73,24 +74,4 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
}
-
- internal class NamedCurveHelper
- {
- internal static ECDomainParameters GetECParameters(int namedCurve)
- {
- if (!NamedCurve.IsValid(namedCurve))
- return null;
-
- string curveName = namedCurve.ToString();
-
- // Lazily created the first time a particular curve is accessed
- X9ECParameters ecP = SecNamedCurves.GetByName(curveName);
-
- if (ecP == null)
- return null;
-
- // It's a bit inefficient to do this conversion every time
- return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
- }
- }
}
diff --git a/crypto/src/crypto/tls/NewSessionTicket.cs b/crypto/src/crypto/tls/NewSessionTicket.cs
new file mode 100644
index 000000000..a84026b8c
--- /dev/null
+++ b/crypto/src/crypto/tls/NewSessionTicket.cs
@@ -0,0 +1,53 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class NewSessionTicket
+ {
+ protected readonly long mTicketLifetimeHint;
+ protected readonly byte[] mTicket;
+
+ public NewSessionTicket(long ticketLifetimeHint, byte[] ticket)
+ {
+ this.mTicketLifetimeHint = ticketLifetimeHint;
+ this.mTicket = ticket;
+ }
+
+ public virtual long TicketLifetimeHint
+ {
+ get { return mTicketLifetimeHint; }
+ }
+
+ public virtual byte[] Ticket
+ {
+ get { return mTicket; }
+ }
+
+ /**
+ * Encode this {@link NewSessionTicket} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint32(mTicketLifetimeHint, output);
+ TlsUtilities.WriteOpaque16(mTicket, output);
+ }
+
+ /**
+ * Parse a {@link NewSessionTicket} from a {@link Stream}.
+ *
+ * @param input the {@link Stream} to parse from.
+ * @return a {@link NewSessionTicket} object.
+ * @throws IOException
+ */
+ public static NewSessionTicket Parse(Stream input)
+ {
+ long ticketLifetimeHint = TlsUtilities.ReadUint32(input);
+ byte[] ticket = TlsUtilities.ReadOpaque16(input);
+ return new NewSessionTicket(ticketLifetimeHint, ticket);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/OcspStatusRequest.cs b/crypto/src/crypto/tls/OcspStatusRequest.cs
new file mode 100644
index 000000000..2dd8371e5
--- /dev/null
+++ b/crypto/src/crypto/tls/OcspStatusRequest.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 3546 3.6
+ */
+ public class OcspStatusRequest
+ {
+ protected readonly IList mResponderIDList;
+ protected readonly X509Extensions mRequestExtensions;
+
+ /**
+ * @param responderIDList
+ * an {@link IList} of {@link ResponderID}, specifying the list of trusted OCSP
+ * responders. An empty list has the special meaning that the responders are
+ * implicitly known to the server - e.g., by prior arrangement.
+ * @param requestExtensions
+ * OCSP request extensions. A null value means that there are no extensions.
+ */
+ public OcspStatusRequest(IList responderIDList, X509Extensions requestExtensions)
+ {
+ this.mResponderIDList = responderIDList;
+ this.mRequestExtensions = requestExtensions;
+ }
+
+ /**
+ * @return an {@link IList} of {@link ResponderID}
+ */
+ public virtual IList ResponderIDList
+ {
+ get { return mResponderIDList; }
+ }
+
+ /**
+ * @return OCSP request extensions
+ */
+ public virtual X509Extensions RequestExtensions
+ {
+ get { return mRequestExtensions; }
+ }
+
+ /**
+ * Encode this {@link OcspStatusRequest} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ if (mResponderIDList == null || mResponderIDList.Count < 1)
+ {
+ TlsUtilities.WriteUint16(0, output);
+ }
+ else
+ {
+ MemoryStream buf = new MemoryStream();
+ for (int i = 0; i < mResponderIDList.Count; ++i)
+ {
+ ResponderID responderID = (ResponderID)mResponderIDList[i];
+ byte[] derEncoding = responderID.GetEncoded(Asn1Encodable.Der);
+ TlsUtilities.WriteOpaque16(derEncoding, buf);
+ }
+ TlsUtilities.CheckUint16(buf.Length);
+ TlsUtilities.WriteUint16((int)buf.Length, output);
+ buf.WriteTo(output);
+ }
+
+ if (mRequestExtensions == null)
+ {
+ TlsUtilities.WriteUint16(0, output);
+ }
+ else
+ {
+ byte[] derEncoding = mRequestExtensions.GetEncoded(Asn1Encodable.Der);
+ TlsUtilities.CheckUint16(derEncoding.Length);
+ TlsUtilities.WriteUint16(derEncoding.Length, output);
+ output.Write(derEncoding, 0, derEncoding.Length);
+ }
+ }
+
+ /**
+ * Parse a {@link OcspStatusRequest} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return an {@link OcspStatusRequest} object.
+ * @throws IOException
+ */
+ public static OcspStatusRequest Parse(Stream input)
+ {
+ IList responderIDList = Platform.CreateArrayList();
+ {
+ int length = TlsUtilities.ReadUint16(input);
+ if (length > 0)
+ {
+ byte[] data = TlsUtilities.ReadFully(length, input);
+ MemoryStream buf = new MemoryStream(data, false);
+ do
+ {
+ byte[] derEncoding = TlsUtilities.ReadOpaque16(buf);
+ ResponderID responderID = ResponderID.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+ responderIDList.Add(responderID);
+ }
+ while (buf.Position < buf.Length);
+ }
+ }
+
+ X509Extensions requestExtensions = null;
+ {
+ int length = TlsUtilities.ReadUint16(input);
+ if (length > 0)
+ {
+ byte[] derEncoding = TlsUtilities.ReadFully(length, input);
+ requestExtensions = X509Extensions.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+ }
+ }
+
+ return new OcspStatusRequest(responderIDList, requestExtensions);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/PskTlsClient.cs b/crypto/src/crypto/tls/PskTlsClient.cs
index e60688155..2ef80dcfd 100644
--- a/crypto/src/crypto/tls/PskTlsClient.cs
+++ b/crypto/src/crypto/tls/PskTlsClient.cs
@@ -3,200 +3,68 @@ using System.Collections;
namespace Org.BouncyCastle.Crypto.Tls
{
- public abstract class PskTlsClient
- :TlsClient
+ public class PskTlsClient
+ : AbstractTlsClient
{
- protected TlsCipherFactory cipherFactory;
- protected TlsPskIdentity pskIdentity;
-
- protected TlsClientContext context;
-
- protected byte selectedCompressionMethod;
- protected int selectedCipherSuite;
+ protected TlsPskIdentity mPskIdentity;
public PskTlsClient(TlsPskIdentity pskIdentity)
- : this(new DefaultTlsCipherFactory(), pskIdentity)
+ : this(new DefaultTlsCipherFactory(), pskIdentity)
{
}
public PskTlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity)
+ : base(cipherFactory)
{
- this.cipherFactory = cipherFactory;
- this.pskIdentity = pskIdentity;
- }
-
- public virtual void Init(TlsClientContext context)
- {
- this.context = context;
- }
-
- public virtual bool ShouldUseGmtUnixTime()
- {
- /*
- * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
- * TLS implementors MUST by default set the entire value the ClientHello.Random and
- * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
- * sequence.
- */
- return false;
- }
-
- public virtual int[] GetCipherSuites()
- {
- return new int[] {
- CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
- CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
- CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA,
- CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
- CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
- CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA,
- CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA,
- CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA,
- CipherSuite.TLS_PSK_WITH_RC4_128_SHA,
- };
- }
-
- public virtual IDictionary GetClientExtensions()
- {
- return null;
- }
-
- public virtual byte[] GetCompressionMethods()
- {
- return new byte[] { CompressionMethod.NULL };
- }
-
- public virtual void NotifySessionID(byte[] sessionID)
- {
- // Currently ignored
- }
-
- public virtual void NotifySelectedCipherSuite(int selectedCipherSuite)
- {
- this.selectedCipherSuite = selectedCipherSuite;
+ this.mPskIdentity = pskIdentity;
}
- public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
+ public override int[] GetCipherSuites()
{
- this.selectedCompressionMethod = selectedCompressionMethod;
- }
-
- public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
- {
- if (!secureRenegotiation)
+ return new int[]
{
- /*
- * RFC 5746 3.4. If the extension is not present, the server does not support
- * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
- * some clients may want to terminate the handshake instead of continuing; see
- * Section 4.1 for discussion.
- */
-// throw new TlsFatalAlert(AlertDescription.handshake_failure);
- }
- }
-
- public virtual void ProcessServerExtensions(IDictionary serverExtensions)
- {
+ CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ };
}
- public virtual TlsKeyExchange GetKeyExchange()
+ public override TlsKeyExchange GetKeyExchange()
{
- switch (selectedCipherSuite)
- {
- case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
- return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK);
-
- case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
- return CreatePskKeyExchange(KeyExchangeAlgorithm.RSA_PSK);
-
- case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
- return CreatePskKeyExchange(KeyExchangeAlgorithm.DHE_PSK);
-
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected cipher suite was in the list of client-offered cipher
- * suites, so if we now can't produce an implementation, we shouldn't have
- * offered it!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- }
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
- public abstract TlsAuthentication GetAuthentication();
-
- public virtual TlsCompression GetCompression()
- {
- switch (selectedCompressionMethod)
+ switch (keyExchangeAlgorithm)
{
- case CompressionMethod.NULL:
- return new TlsNullCompression();
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ return CreatePskKeyExchange(keyExchangeAlgorithm);
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected compression method was in the list of client-offered compression
- * methods, so if we now can't produce an implementation, we shouldn't have
- * offered it!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
- public virtual TlsCipher GetCipher()
+ public override TlsAuthentication GetAuthentication()
{
- switch (selectedCipherSuite)
- {
- case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC,
- DigestAlgorithm.SHA);
-
- case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC,
- DigestAlgorithm.SHA);
-
- case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC,
- DigestAlgorithm.SHA);
-
- case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.RC4_128,
- DigestAlgorithm.SHA);
-
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected cipher suite was in the list of client-offered cipher
- * suites, so if we now can't produce an implementation, we shouldn't have
- * offered it!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
+ /*
+ * Note: This method is not called unless a server certificate is sent, which may be the
+ * case e.g. for RSA_PSK key exchange.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange)
{
- return new TlsPskKeyExchange(context, keyExchange, pskIdentity);
+ return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mPskIdentity, null, null, mNamedCurves,
+ mClientECPointFormats, mServerECPointFormats);
}
}
}
diff --git a/crypto/src/crypto/tls/PskTlsServer.cs b/crypto/src/crypto/tls/PskTlsServer.cs
new file mode 100644
index 000000000..85f3055fb
--- /dev/null
+++ b/crypto/src/crypto/tls/PskTlsServer.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class PskTlsServer
+ : AbstractTlsServer
+ {
+ protected TlsPskIdentityManager mPskIdentityManager;
+
+ public PskTlsServer(TlsPskIdentityManager pskIdentityManager)
+ : this(new DefaultTlsCipherFactory(), pskIdentityManager)
+ {
+ }
+
+ public PskTlsServer(TlsCipherFactory cipherFactory, TlsPskIdentityManager pskIdentityManager)
+ : base(cipherFactory)
+ {
+ this.mPskIdentityManager = pskIdentityManager;
+ }
+
+ protected virtual TlsEncryptionCredentials GetRsaEncryptionCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual DHParameters GetDHParameters()
+ {
+ return DHStandardGroups.rfc5114_2048_256;
+ }
+
+ protected override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ };
+ }
+
+ public override TlsCredentials GetCredentials()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ return null;
+
+ case KeyExchangeAlgorithm.RSA_PSK:
+ return GetRsaEncryptionCredentials();
+
+ default:
+ /* Note: internal error here; selected a key exchange we don't implement! */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ return CreatePskKeyExchange(keyExchangeAlgorithm);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange)
+ {
+ return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null, mPskIdentityManager,
+ GetDHParameters(), mNamedCurves, mClientECPointFormats, mServerECPointFormats);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/RecordStream.cs b/crypto/src/crypto/tls/RecordStream.cs
index ce8882cbe..6f3fc41c6 100644
--- a/crypto/src/crypto/tls/RecordStream.cs
+++ b/crypto/src/crypto/tls/RecordStream.cs
@@ -3,164 +3,336 @@ using System.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- /// <remarks>An implementation of the TLS 1.0 record layer.</remarks>
+ /// <summary>An implementation of the TLS 1.0/1.1/1.2 record layer, allowing downgrade to SSLv3.</summary>
internal class RecordStream
{
- private TlsProtocolHandler handler;
- private Stream inStr;
- private Stream outStr;
- private CombinedHash hash;
- private TlsCompression readCompression = null;
- private TlsCompression writeCompression = null;
- private TlsCipher readCipher = null;
- private TlsCipher writeCipher = null;
- private MemoryStream buffer = new MemoryStream();
+ private const int DEFAULT_PLAINTEXT_LIMIT = (1 << 14);
- internal RecordStream(
- TlsProtocolHandler handler,
- Stream inStr,
- Stream outStr)
+ internal const int TLS_HEADER_SIZE = 5;
+ internal const int TLS_HEADER_TYPE_OFFSET = 0;
+ internal const int TLS_HEADER_VERSION_OFFSET = 1;
+ internal const int TLS_HEADER_LENGTH_OFFSET = 3;
+
+ private TlsProtocol mHandler;
+ private Stream mInput;
+ private Stream mOutput;
+ private TlsCompression mPendingCompression = null, mReadCompression = null, mWriteCompression = null;
+ private TlsCipher mPendingCipher = null, mReadCipher = null, mWriteCipher = null;
+ private long mReadSeqNo = 0, mWriteSeqNo = 0;
+ private MemoryStream mBuffer = new MemoryStream();
+
+ private TlsHandshakeHash mHandshakeHash = null;
+
+ private ProtocolVersion mReadVersion = null, mWriteVersion = null;
+ private bool mRestrictReadVersion = true;
+
+ private int mPlaintextLimit, mCompressedLimit, mCiphertextLimit;
+
+ internal RecordStream(TlsProtocol handler, Stream input, Stream output)
+ {
+ this.mHandler = handler;
+ this.mInput = input;
+ this.mOutput = output;
+ this.mReadCompression = new TlsNullCompression();
+ this.mWriteCompression = this.mReadCompression;
+ }
+
+ internal virtual void Init(TlsContext context)
+ {
+ this.mReadCipher = new TlsNullCipher(context);
+ this.mWriteCipher = this.mReadCipher;
+ this.mHandshakeHash = new DeferredHash();
+ this.mHandshakeHash.Init(context);
+
+ SetPlaintextLimit(DEFAULT_PLAINTEXT_LIMIT);
+ }
+
+ internal virtual int GetPlaintextLimit()
+ {
+ return mPlaintextLimit;
+ }
+
+ internal virtual void SetPlaintextLimit(int plaintextLimit)
+ {
+ this.mPlaintextLimit = plaintextLimit;
+ this.mCompressedLimit = this.mPlaintextLimit + 1024;
+ this.mCiphertextLimit = this.mCompressedLimit + 1024;
+ }
+
+ internal virtual ProtocolVersion ReadVersion
{
- this.handler = handler;
- this.inStr = inStr;
- this.outStr = outStr;
- this.hash = new CombinedHash();
- this.readCompression = new TlsNullCompression();
- this.writeCompression = this.readCompression;
- this.readCipher = new TlsNullCipher();
- this.writeCipher = this.readCipher;
+ get { return mReadVersion; }
+ set { this.mReadVersion = value; }
}
- internal void ClientCipherSpecDecided(TlsCompression tlsCompression, TlsCipher tlsCipher)
+ internal virtual void SetWriteVersion(ProtocolVersion writeVersion)
{
- this.writeCompression = tlsCompression;
- this.writeCipher = tlsCipher;
+ this.mWriteVersion = writeVersion;
}
- internal void ServerClientSpecReceived()
+ /**
+ * RFC 5246 E.1. "Earlier versions of the TLS specification were not fully clear on what the
+ * record layer version number (TLSPlaintext.version) should contain when sending ClientHello
+ * (i.e., before it is known which version of the protocol will be employed). Thus, TLS servers
+ * compliant with this specification MUST accept any value {03,XX} as the record layer version
+ * number for ClientHello."
+ */
+ internal virtual void SetRestrictReadVersion(bool enabled)
{
- this.readCompression = this.writeCompression;
- this.readCipher = this.writeCipher;
+ this.mRestrictReadVersion = enabled;
}
- public void ReadData()
+ internal virtual void SetPendingConnectionState(TlsCompression tlsCompression, TlsCipher tlsCipher)
{
- byte contentType = TlsUtilities.ReadUint8(inStr);
- TlsUtilities.CheckVersion(inStr);
- int size = TlsUtilities.ReadUint16(inStr);
- byte[] buf = DecodeAndVerify(contentType, inStr, size);
- handler.ProcessData(contentType, buf, 0, buf.Length);
+ this.mPendingCompression = tlsCompression;
+ this.mPendingCipher = tlsCipher;
}
- internal byte[] DecodeAndVerify(
- byte contentType,
- Stream inStr,
- int len)
+ internal virtual void SentWriteCipherSpec()
{
- byte[] buf = new byte[len];
- TlsUtilities.ReadFully(buf, inStr);
- byte[] decoded = readCipher.DecodeCiphertext(contentType, buf, 0, buf.Length);
+ if (mPendingCompression == null || mPendingCipher == null)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
- Stream cOut = readCompression.Decompress(buffer);
+ this.mWriteCompression = this.mPendingCompression;
+ this.mWriteCipher = this.mPendingCipher;
+ this.mWriteSeqNo = 0;
+ }
+
+ internal virtual void ReceivedReadCipherSpec()
+ {
+ if (mPendingCompression == null || mPendingCipher == null)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ this.mReadCompression = this.mPendingCompression;
+ this.mReadCipher = this.mPendingCipher;
+ this.mReadSeqNo = 0;
+ }
- if (cOut == buffer)
+ internal virtual void FinaliseHandshake()
+ {
+ if (mReadCompression != mPendingCompression || mWriteCompression != mPendingCompression
+ || mReadCipher != mPendingCipher || mWriteCipher != mPendingCipher)
{
- return decoded;
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
}
+ this.mPendingCompression = null;
+ this.mPendingCipher = null;
+ }
- cOut.Write(decoded, 0, decoded.Length);
- cOut.Flush();
- byte[] contents = buffer.ToArray();
- buffer.SetLength(0);
- return contents;
+ internal virtual bool ReadRecord()
+ {
+ byte[] recordHeader = TlsUtilities.ReadAllOrNothing(TLS_HEADER_SIZE, mInput);
+ if (recordHeader == null)
+ return false;
+
+ byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET);
+
+ /*
+ * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
+ * unexpected_message alert.
+ */
+ CheckType(type, AlertDescription.unexpected_message);
+
+ if (!mRestrictReadVersion)
+ {
+ int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET);
+ if ((version & 0xffffff00) != 0x0300)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ else
+ {
+ ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET);
+ if (mReadVersion == null)
+ {
+ mReadVersion = version;
+ }
+ else if (!version.Equals(mReadVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);
+ byte[] plaintext = DecodeAndVerify(type, mInput, length);
+ mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length);
+ return true;
}
- internal void WriteMessage(
- byte type,
- byte[] message,
- int offset,
- int len)
+ internal virtual byte[] DecodeAndVerify(byte type, Stream input, int len)
{
+ CheckLength(len, mCiphertextLimit, AlertDescription.record_overflow);
+
+ byte[] buf = TlsUtilities.ReadFully(len, input);
+ byte[] decoded = mReadCipher.DecodeCiphertext(mReadSeqNo++, type, buf, 0, buf.Length);
+
+ CheckLength(decoded.Length, mCompressedLimit, AlertDescription.record_overflow);
+
+ /*
+ * TODO RFC5264 6.2.2. Implementation note: Decompression functions are responsible for
+ * ensuring that messages cannot cause internal buffer overflows.
+ */
+ Stream cOut = mReadCompression.Decompress(mBuffer);
+ if (cOut != mBuffer)
+ {
+ cOut.Write(decoded, 0, decoded.Length);
+ cOut.Flush();
+ decoded = GetBufferContents();
+ }
+
+ /*
+ * RFC 5264 6.2.2. If the decompression function encounters a TLSCompressed.fragment that
+ * would decompress to a length in excess of 2^14 bytes, it should report a fatal
+ * decompression failure error.
+ */
+ CheckLength(decoded.Length, mPlaintextLimit, AlertDescription.decompression_failure);
+
+ /*
+ * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+ * or ChangeCipherSpec content types.
+ */
+ if (decoded.Length < 1 && type != ContentType.application_data)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return decoded;
+ }
+
+ internal virtual void WriteRecord(byte type, byte[] plaintext, int plaintextOffset, int plaintextLength)
+ {
+ // Never send anything until a valid ClientHello has been received
+ if (mWriteVersion == null)
+ return;
+
+ /*
+ * RFC 5264 6. Implementations MUST NOT send record types not defined in this document
+ * unless negotiated by some extension.
+ */
+ CheckType(type, AlertDescription.internal_error);
+
+ /*
+ * RFC 5264 6.2.1 The length should not exceed 2^14.
+ */
+ CheckLength(plaintextLength, mPlaintextLimit, AlertDescription.internal_error);
+
+ /*
+ * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+ * or ChangeCipherSpec content types.
+ */
+ if (plaintextLength < 1 && type != ContentType.application_data)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
if (type == ContentType.handshake)
{
- UpdateHandshakeData(message, offset, len);
+ UpdateHandshakeData(plaintext, plaintextOffset, plaintextLength);
}
- Stream cOut = writeCompression.Compress(buffer);
+ Stream cOut = mWriteCompression.Compress(mBuffer);
byte[] ciphertext;
- if (cOut == buffer)
+ if (cOut == mBuffer)
{
- ciphertext = writeCipher.EncodePlaintext(type, message, offset, len);
+ ciphertext = mWriteCipher.EncodePlaintext(mWriteSeqNo++, type, plaintext, plaintextOffset, plaintextLength);
}
else
{
- cOut.Write(message, offset, len);
+ cOut.Write(plaintext, plaintextOffset, plaintextLength);
cOut.Flush();
- ciphertext = writeCipher.EncodePlaintext(type, buffer.GetBuffer(), 0, (int)buffer.Position);
- buffer.SetLength(0);
+ byte[] compressed = GetBufferContents();
+
+ /*
+ * RFC5264 6.2.2. Compression must be lossless and may not increase the content length
+ * by more than 1024 bytes.
+ */
+ CheckLength(compressed.Length, plaintextLength + 1024, AlertDescription.internal_error);
+
+ ciphertext = mWriteCipher.EncodePlaintext(mWriteSeqNo++, type, compressed, 0, compressed.Length);
}
- byte[] writeMessage = new byte[ciphertext.Length + 5];
- TlsUtilities.WriteUint8((byte)type, writeMessage, 0);
- TlsUtilities.WriteVersion(writeMessage, 1);
- TlsUtilities.WriteUint16(ciphertext.Length, writeMessage, 3);
- Array.Copy(ciphertext, 0, writeMessage, 5, ciphertext.Length);
- outStr.Write(writeMessage, 0, writeMessage.Length);
- outStr.Flush();
+ /*
+ * RFC 5264 6.2.3. The length may not exceed 2^14 + 2048.
+ */
+ CheckLength(ciphertext.Length, mCiphertextLimit, AlertDescription.internal_error);
+
+ byte[] record = new byte[ciphertext.Length + TLS_HEADER_SIZE];
+ TlsUtilities.WriteUint8(type, record, TLS_HEADER_TYPE_OFFSET);
+ TlsUtilities.WriteVersion(mWriteVersion, record, TLS_HEADER_VERSION_OFFSET);
+ TlsUtilities.WriteUint16(ciphertext.Length, record, TLS_HEADER_LENGTH_OFFSET);
+ Array.Copy(ciphertext, 0, record, TLS_HEADER_SIZE, ciphertext.Length);
+ mOutput.Write(record, 0, record.Length);
+ mOutput.Flush();
}
- internal void UpdateHandshakeData(
- byte[] message,
- int offset,
- int len)
+ internal virtual void NotifyHelloComplete()
{
- hash.BlockUpdate(message, offset, len);
+ this.mHandshakeHash = mHandshakeHash.NotifyPrfDetermined();
}
- internal byte[] GetCurrentHash()
+ internal virtual TlsHandshakeHash HandshakeHash
{
- return DoFinal(new CombinedHash(hash));
+ get { return mHandshakeHash; }
}
- internal void Close()
+ internal virtual TlsHandshakeHash PrepareToFinish()
+ {
+ TlsHandshakeHash result = mHandshakeHash;
+ this.mHandshakeHash = mHandshakeHash.StopTracking();
+ return result;
+ }
+
+ internal virtual void UpdateHandshakeData(byte[] message, int offset, int len)
+ {
+ mHandshakeHash.BlockUpdate(message, offset, len);
+ }
+
+ internal virtual void SafeClose()
{
- IOException e = null;
try
{
- inStr.Close();
+ mInput.Close();
}
- catch (IOException ex)
+ catch (IOException)
{
- e = ex;
}
try
{
- // NB: This is harmless if outStr == inStr
- outStr.Close();
+ mOutput.Close();
}
- catch (IOException ex)
+ catch (IOException)
{
- e = ex;
}
+ }
- if (e != null)
- {
- throw e;
- }
+ internal virtual void Flush()
+ {
+ mOutput.Flush();
+ }
+
+ private byte[] GetBufferContents()
+ {
+ byte[] contents = mBuffer.ToArray();
+ mBuffer.SetLength(0);
+ return contents;
}
- internal void Flush()
+ private static void CheckType(byte type, byte alertDescription)
{
- outStr.Flush();
+ switch (type)
+ {
+ case ContentType.application_data:
+ case ContentType.alert:
+ case ContentType.change_cipher_spec:
+ case ContentType.handshake:
+ case ContentType.heartbeat:
+ break;
+ default:
+ throw new TlsFatalAlert(alertDescription);
+ }
}
- private static byte[] DoFinal(CombinedHash ch)
+ private static void CheckLength(int length, int limit, byte alertDescription)
{
- byte[] bs = new byte[ch.GetDigestSize()];
- ch.DoFinal(bs, 0);
- return bs;
+ if (length > limit)
+ throw new TlsFatalAlert(alertDescription);
}
}
}
diff --git a/crypto/src/crypto/tls/SecurityParameters.cs b/crypto/src/crypto/tls/SecurityParameters.cs
index 9ed3969eb..3b851587d 100644
--- a/crypto/src/crypto/tls/SecurityParameters.cs
+++ b/crypto/src/crypto/tls/SecurityParameters.cs
@@ -1,26 +1,103 @@
using System;
+using Org.BouncyCastle.Utilities;
+
namespace Org.BouncyCastle.Crypto.Tls
{
- public class SecurityParameters
- {
- internal byte[] clientRandom = null;
- internal byte[] serverRandom = null;
- internal byte[] masterSecret = null;
-
- public byte[] ClientRandom
- {
- get { return clientRandom; }
- }
-
- public byte[] ServerRandom
- {
- get { return serverRandom; }
- }
-
- public byte[] MasterSecret
- {
- get { return masterSecret; }
- }
- }
+ public class SecurityParameters
+ {
+ internal int entity = -1;
+ internal int cipherSuite = -1;
+ internal byte compressionAlgorithm = CompressionMethod.cls_null;
+ internal int prfAlgorithm = -1;
+ internal int verifyDataLength = -1;
+ internal byte[] masterSecret = null;
+ internal byte[] clientRandom = null;
+ internal byte[] serverRandom = null;
+ internal byte[] sessionHash = null;
+ internal byte[] pskIdentity = null;
+ internal byte[] srpIdentity = null;
+
+ // TODO Keep these internal, since it's maybe not the ideal place for them
+ internal short maxFragmentLength = -1;
+ internal bool truncatedHMac = false;
+ internal bool encryptThenMac = false;
+ internal bool extendedMasterSecret = false;
+
+ internal virtual void Clear()
+ {
+ if (this.masterSecret != null)
+ {
+ Arrays.Fill(this.masterSecret, (byte)0);
+ this.masterSecret = null;
+ }
+ }
+
+ /**
+ * @return {@link ConnectionEnd}
+ */
+ public virtual int Entity
+ {
+ get { return entity; }
+ }
+
+ /**
+ * @return {@link CipherSuite}
+ */
+ public virtual int CipherSuite
+ {
+ get { return cipherSuite; }
+ }
+
+ /**
+ * @return {@link CompressionMethod}
+ */
+ public byte CompressionAlgorithm
+ {
+ get { return compressionAlgorithm; }
+ }
+
+ /**
+ * @return {@link PRFAlgorithm}
+ */
+ public virtual int PrfAlgorithm
+ {
+ get { return prfAlgorithm; }
+ }
+
+ public virtual int VerifyDataLength
+ {
+ get { return verifyDataLength; }
+ }
+
+ public virtual byte[] MasterSecret
+ {
+ get { return masterSecret; }
+ }
+
+ public virtual byte[] ClientRandom
+ {
+ get { return clientRandom; }
+ }
+
+ public virtual byte[] ServerRandom
+ {
+ get { return serverRandom; }
+ }
+
+ public virtual byte[] SessionHash
+ {
+ get { return sessionHash; }
+ }
+
+ public virtual byte[] PskIdentity
+ {
+ get { return pskIdentity; }
+ }
+
+ public virtual byte[] SrpIdentity
+ {
+ get { return srpIdentity; }
+ }
+ }
}
diff --git a/crypto/src/crypto/tls/ServerDHParams.cs b/crypto/src/crypto/tls/ServerDHParams.cs
new file mode 100644
index 000000000..b09262771
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerDHParams.cs
@@ -0,0 +1,61 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ServerDHParams
+ {
+ protected readonly DHPublicKeyParameters mPublicKey;
+
+ public ServerDHParams(DHPublicKeyParameters publicKey)
+ {
+ if (publicKey == null)
+ throw new ArgumentNullException("publicKey");
+
+ this.mPublicKey = publicKey;
+ }
+
+ public virtual DHPublicKeyParameters PublicKey
+ {
+ get { return mPublicKey; }
+ }
+
+ /**
+ * Encode this {@link ServerDHParams} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ DHParameters dhParameters = mPublicKey.Parameters;
+ BigInteger Ys = mPublicKey.Y;
+
+ TlsDHUtilities.WriteDHParameter(dhParameters.P, output);
+ TlsDHUtilities.WriteDHParameter(dhParameters.G, output);
+ TlsDHUtilities.WriteDHParameter(Ys, output);
+ }
+
+ /**
+ * Parse a {@link ServerDHParams} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link ServerDHParams} object.
+ * @throws IOException
+ */
+ public static ServerDHParams Parse(Stream input)
+ {
+ BigInteger p = TlsDHUtilities.ReadDHParameter(input);
+ BigInteger g = TlsDHUtilities.ReadDHParameter(input);
+ BigInteger Ys = TlsDHUtilities.ReadDHParameter(input);
+
+ return new ServerDHParams(
+ TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Ys, new DHParameters(p, g))));
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/ServerName.cs b/crypto/src/crypto/tls/ServerName.cs
new file mode 100644
index 000000000..3d1e8f844
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerName.cs
@@ -0,0 +1,105 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ServerName
+ {
+ protected readonly byte mNameType;
+ protected readonly object mName;
+
+ public ServerName(byte nameType, object name)
+ {
+ if (!IsCorrectType(nameType, name))
+ throw new ArgumentException("not an instance of the correct type", "name");
+
+ this.mNameType = nameType;
+ this.mName = name;
+ }
+
+ public virtual byte NameType
+ {
+ get { return mNameType; }
+ }
+
+ public virtual object Name
+ {
+ get { return mName; }
+ }
+
+ public virtual string GetHostName()
+ {
+ if (!IsCorrectType(Tls.NameType.host_name, mName))
+ throw new InvalidOperationException("'name' is not a HostName string");
+
+ return (string)mName;
+ }
+
+ /**
+ * Encode this {@link ServerName} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(mNameType, output);
+
+ switch (mNameType)
+ {
+ case Tls.NameType.host_name:
+ byte[] utf8Encoding = Strings.ToUtf8ByteArray((string)mName);
+ if (utf8Encoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ TlsUtilities.WriteOpaque16(utf8Encoding, output);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ /**
+ * Parse a {@link ServerName} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link ServerName} object.
+ * @throws IOException
+ */
+ public static ServerName Parse(Stream input)
+ {
+ byte name_type = TlsUtilities.ReadUint8(input);
+ object name;
+
+ switch (name_type)
+ {
+ case Tls.NameType.host_name:
+ {
+ byte[] utf8Encoding = TlsUtilities.ReadOpaque16(input);
+ if (utf8Encoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ name = Strings.FromUtf8ByteArray(utf8Encoding);
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ return new ServerName(name_type, name);
+ }
+
+ protected static bool IsCorrectType(byte nameType, object name)
+ {
+ switch (nameType)
+ {
+ case Tls.NameType.host_name:
+ return name is string;
+ default:
+ throw new ArgumentException("unsupported value", "name");
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/ServerNameList.cs b/crypto/src/crypto/tls/ServerNameList.cs
new file mode 100644
index 000000000..13da79bf6
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerNameList.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ServerNameList
+ {
+ protected readonly IList mServerNameList;
+
+ /**
+ * @param serverNameList an {@link IList} of {@link ServerName}.
+ */
+ public ServerNameList(IList serverNameList)
+ {
+ if (serverNameList == null || serverNameList.Count < 1)
+ throw new ArgumentException("must not be null or empty", "serverNameList");
+
+ this.mServerNameList = serverNameList;
+ }
+
+ /**
+ * @return an {@link IList} of {@link ServerName}.
+ */
+ public virtual IList ServerNames
+ {
+ get { return mServerNameList; }
+ }
+
+ /**
+ * Encode this {@link ServerNameList} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ foreach (ServerName entry in ServerNames)
+ {
+ entry.Encode(buf);
+ }
+
+ TlsUtilities.CheckUint16(buf.Length);
+ TlsUtilities.WriteUint16((int)buf.Length, output);
+ buf.WriteTo(output);
+ }
+
+ /**
+ * Parse a {@link ServerNameList} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link ServerNameList} object.
+ * @throws IOException
+ */
+ public static ServerNameList Parse(Stream input)
+ {
+ int length = TlsUtilities.ReadUint16(input);
+ if (length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] data = TlsUtilities.ReadFully(length, input);
+
+ MemoryStream buf = new MemoryStream(data, false);
+
+ IList server_name_list = Platform.CreateArrayList();
+ while (buf.Position < buf.Length)
+ {
+ ServerName entry = ServerName.Parse(buf);
+ server_name_list.Add(entry);
+ }
+
+ return new ServerNameList(server_name_list);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs b/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs
new file mode 100644
index 000000000..485889709
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class ServerOnlyTlsAuthentication
+ : TlsAuthentication
+ {
+ public abstract void NotifyServerCertificate(Certificate serverCertificate);
+
+ public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
+ {
+ return null;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/ServerSrpParams.cs b/crypto/src/crypto/tls/ServerSrpParams.cs
new file mode 100644
index 000000000..556ac5310
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerSrpParams.cs
@@ -0,0 +1,75 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ServerSrpParams
+ {
+ protected BigInteger m_N, m_g, m_B;
+ protected byte[] m_s;
+
+ public ServerSrpParams(BigInteger N, BigInteger g, byte[] s, BigInteger B)
+ {
+ this.m_N = N;
+ this.m_g = g;
+ this.m_s = Arrays.Clone(s);
+ this.m_B = B;
+ }
+
+ public virtual BigInteger B
+ {
+ get { return m_B; }
+ }
+
+ public virtual BigInteger G
+ {
+ get { return m_g; }
+ }
+
+ public virtual BigInteger N
+ {
+ get { return m_N; }
+ }
+
+ public virtual byte[] S
+ {
+ get { return m_s; }
+ }
+
+ /**
+ * Encode this {@link ServerSRPParams} to an {@link OutputStream}.
+ *
+ * @param output
+ * the {@link OutputStream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsSrpUtilities.WriteSrpParameter(m_N, output);
+ TlsSrpUtilities.WriteSrpParameter(m_g, output);
+ TlsUtilities.WriteOpaque8(m_s, output);
+ TlsSrpUtilities.WriteSrpParameter(m_B, output);
+ }
+
+ /**
+ * Parse a {@link ServerSRPParams} from an {@link InputStream}.
+ *
+ * @param input
+ * the {@link InputStream} to parse from.
+ * @return a {@link ServerSRPParams} object.
+ * @throws IOException
+ */
+ public static ServerSrpParams Parse(Stream input)
+ {
+ BigInteger N = TlsSrpUtilities.ReadSrpParameter(input);
+ BigInteger g = TlsSrpUtilities.ReadSrpParameter(input);
+ byte[] s = TlsUtilities.ReadOpaque8(input);
+ BigInteger B = TlsSrpUtilities.ReadSrpParameter(input);
+
+ return new ServerSrpParams(N, g, s, B);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/SessionParameters.cs b/crypto/src/crypto/tls/SessionParameters.cs
new file mode 100644
index 000000000..a1eb5f27c
--- /dev/null
+++ b/crypto/src/crypto/tls/SessionParameters.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public sealed class SessionParameters
+ {
+ public sealed class Builder
+ {
+ private int mCipherSuite = -1;
+ private short mCompressionAlgorithm = -1;
+ private byte[] mMasterSecret = null;
+ private Certificate mPeerCertificate = null;
+ private byte[] mPskIdentity = null;
+ private byte[] mSrpIdentity = null;
+ private byte[] mEncodedServerExtensions = null;
+
+ public Builder()
+ {
+ }
+
+ public SessionParameters Build()
+ {
+ Validate(this.mCipherSuite >= 0, "cipherSuite");
+ Validate(this.mCompressionAlgorithm >= 0, "compressionAlgorithm");
+ Validate(this.mMasterSecret != null, "masterSecret");
+ return new SessionParameters(mCipherSuite, (byte)mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
+ mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
+ }
+
+ public Builder SetCipherSuite(int cipherSuite)
+ {
+ this.mCipherSuite = cipherSuite;
+ return this;
+ }
+
+ public Builder SetCompressionAlgorithm(byte compressionAlgorithm)
+ {
+ this.mCompressionAlgorithm = compressionAlgorithm;
+ return this;
+ }
+
+ public Builder SetMasterSecret(byte[] masterSecret)
+ {
+ this.mMasterSecret = masterSecret;
+ return this;
+ }
+
+ public Builder SetPeerCertificate(Certificate peerCertificate)
+ {
+ this.mPeerCertificate = peerCertificate;
+ return this;
+ }
+
+ public Builder SetPskIdentity(byte[] pskIdentity)
+ {
+ this.mPskIdentity = pskIdentity;
+ return this;
+ }
+
+ public Builder SetSrpIdentity(byte[] srpIdentity)
+ {
+ this.mSrpIdentity = srpIdentity;
+ return this;
+ }
+
+ public Builder SetServerExtensions(IDictionary serverExtensions)
+ {
+ if (serverExtensions == null)
+ {
+ mEncodedServerExtensions = null;
+ }
+ else
+ {
+ MemoryStream buf = new MemoryStream();
+ TlsProtocol.WriteExtensions(buf, serverExtensions);
+ mEncodedServerExtensions = buf.ToArray();
+ }
+ return this;
+ }
+
+ private void Validate(bool condition, string parameter)
+ {
+ if (!condition)
+ throw new InvalidOperationException("Required session parameter '" + parameter + "' not configured");
+ }
+ }
+
+ private int mCipherSuite;
+ private byte mCompressionAlgorithm;
+ private byte[] mMasterSecret;
+ private Certificate mPeerCertificate;
+ private byte[] mPskIdentity;
+ private byte[] mSrpIdentity;
+ private byte[] mEncodedServerExtensions;
+
+ private SessionParameters(int cipherSuite, byte compressionAlgorithm, byte[] masterSecret,
+ Certificate peerCertificate, byte[] pskIdentity, byte[] srpIdentity, byte[] encodedServerExtensions)
+ {
+ this.mCipherSuite = cipherSuite;
+ this.mCompressionAlgorithm = compressionAlgorithm;
+ this.mMasterSecret = Arrays.Clone(masterSecret);
+ this.mPeerCertificate = peerCertificate;
+ this.mPskIdentity = Arrays.Clone(pskIdentity);
+ this.mSrpIdentity = Arrays.Clone(srpIdentity);
+ this.mEncodedServerExtensions = encodedServerExtensions;
+ }
+
+ public void Clear()
+ {
+ if (this.mMasterSecret != null)
+ {
+ Arrays.Fill(this.mMasterSecret, (byte)0);
+ }
+ }
+
+ public SessionParameters Copy()
+ {
+ return new SessionParameters(mCipherSuite, mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
+ mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
+ }
+
+ public int CipherSuite
+ {
+ get { return mCipherSuite; }
+ }
+
+ public byte CompressionAlgorithm
+ {
+ get { return mCompressionAlgorithm; }
+ }
+
+ public byte[] MasterSecret
+ {
+ get { return mMasterSecret; }
+ }
+
+ public Certificate PeerCertificate
+ {
+ get { return mPeerCertificate; }
+ }
+
+ public byte[] PskIdentity
+ {
+ get { return mPskIdentity; }
+ }
+
+ public byte[] SrpIdentity
+ {
+ get { return mSrpIdentity; }
+ }
+
+ public IDictionary ReadServerExtensions()
+ {
+ if (mEncodedServerExtensions == null)
+ return null;
+
+ MemoryStream buf = new MemoryStream(mEncodedServerExtensions, false);
+ return TlsProtocol.ReadExtensions(buf);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs b/crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs
new file mode 100644
index 000000000..3e9737cd7
--- /dev/null
+++ b/crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * An implementation of {@link TlsSRPIdentityManager} that simulates the existence of "unknown" identities
+ * to obscure the fact that there is no verifier for them.
+ */
+ public class SimulatedTlsSrpIdentityManager
+ : TlsSrpIdentityManager
+ {
+ private static readonly byte[] PREFIX_PASSWORD = Strings.ToByteArray("password");
+ private static readonly byte[] PREFIX_SALT = Strings.ToByteArray("salt");
+
+ /**
+ * Create a {@link SimulatedTlsSRPIdentityManager} that implements the algorithm from RFC 5054 2.5.1.3
+ *
+ * @param group the {@link SRP6GroupParameters} defining the group that SRP is operating in
+ * @param seedKey the secret "seed key" referred to in RFC 5054 2.5.1.3
+ * @return an instance of {@link SimulatedTlsSRPIdentityManager}
+ */
+ public static SimulatedTlsSrpIdentityManager GetRfc5054Default(Srp6GroupParameters group, byte[] seedKey)
+ {
+ Srp6VerifierGenerator verifierGenerator = new Srp6VerifierGenerator();
+ verifierGenerator.Init(group, TlsUtilities.CreateHash(HashAlgorithm.sha1));
+
+ HMac mac = new HMac(TlsUtilities.CreateHash(HashAlgorithm.sha1));
+ mac.Init(new KeyParameter(seedKey));
+
+ return new SimulatedTlsSrpIdentityManager(group, verifierGenerator, mac);
+ }
+
+ protected readonly Srp6GroupParameters mGroup;
+ protected readonly Srp6VerifierGenerator mVerifierGenerator;
+ protected readonly IMac mMac;
+
+ public SimulatedTlsSrpIdentityManager(Srp6GroupParameters group, Srp6VerifierGenerator verifierGenerator, IMac mac)
+ {
+ this.mGroup = group;
+ this.mVerifierGenerator = verifierGenerator;
+ this.mMac = mac;
+ }
+
+ public virtual TlsSrpLoginParameters GetLoginParameters(byte[] identity)
+ {
+ mMac.BlockUpdate(PREFIX_SALT, 0, PREFIX_SALT.Length);
+ mMac.BlockUpdate(identity, 0, identity.Length);
+
+ byte[] salt = new byte[mMac.GetMacSize()];
+ mMac.DoFinal(salt, 0);
+
+ mMac.BlockUpdate(PREFIX_PASSWORD, 0, PREFIX_PASSWORD.Length);
+ mMac.BlockUpdate(identity, 0, identity.Length);
+
+ byte[] password = new byte[mMac.GetMacSize()];
+ mMac.DoFinal(password, 0);
+
+ BigInteger verifier = mVerifierGenerator.GenerateVerifier(salt, identity, password);
+
+ return new TlsSrpLoginParameters(mGroup, verifier, salt);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/SrpTlsClient.cs b/crypto/src/crypto/tls/SrpTlsClient.cs
index 3769fc85d..df1607751 100644
--- a/crypto/src/crypto/tls/SrpTlsClient.cs
+++ b/crypto/src/crypto/tls/SrpTlsClient.cs
@@ -6,194 +6,99 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
- public abstract class SrpTlsClient
- : TlsClient
+ public class SrpTlsClient
+ : AbstractTlsClient
{
- protected TlsCipherFactory cipherFactory;
- protected byte[] identity;
- protected byte[] password;
+ protected TlsSrpGroupVerifier mGroupVerifier;
- protected TlsClientContext context;
-
- protected byte selectedCompressionMethod;
- protected int selectedCipherSuite;
+ protected byte[] mIdentity;
+ protected byte[] mPassword;
public SrpTlsClient(byte[] identity, byte[] password)
- : this(new DefaultTlsCipherFactory(), identity, password)
+ : this(new DefaultTlsCipherFactory(), new DefaultTlsSrpGroupVerifier(), identity, password)
{
}
public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password)
+ : this(cipherFactory, new DefaultTlsSrpGroupVerifier(), identity, password)
{
- this.cipherFactory = cipherFactory;
- this.identity = Arrays.Clone(identity);
- this.password = Arrays.Clone(password);
}
- public virtual void Init(TlsClientContext context)
+ public SrpTlsClient(TlsCipherFactory cipherFactory, TlsSrpGroupVerifier groupVerifier,
+ byte[] identity, byte[] password)
+ : base(cipherFactory)
{
- this.context = context;
+ this.mGroupVerifier = groupVerifier;
+ this.mIdentity = Arrays.Clone(identity);
+ this.mPassword = Arrays.Clone(password);
}
- public virtual bool ShouldUseGmtUnixTime()
+ protected virtual bool RequireSrpServerExtension
{
- /*
- * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
- * TLS implementors MUST by default set the entire value the ClientHello.Random and
- * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
- * sequence.
- */
- return false;
+ // No explicit guidance in RFC 5054; by default an (empty) extension from server is optional
+ get { return false; }
}
- public virtual int[] GetCipherSuites()
+ public override int[] GetCipherSuites()
{
- return new int[] {
- CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
- CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
- CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
- CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
- CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
- CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+ return new int[]
+ {
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA
};
}
- public virtual IDictionary GetClientExtensions()
+ public override IDictionary GetClientExtensions()
{
- IDictionary clientExtensions = Platform.CreateHashtable();
-
- MemoryStream srpData = new MemoryStream();
- TlsUtilities.WriteOpaque8(this.identity, srpData);
- clientExtensions[ExtensionType.srp] = srpData.ToArray();
-
+ IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions());
+ TlsSrpUtilities.AddSrpExtension(clientExtensions, this.mIdentity);
return clientExtensions;
}
- public virtual byte[] GetCompressionMethods()
- {
- return new byte[] { CompressionMethod.NULL };
- }
-
- public virtual void NotifySessionID(byte[] sessionID)
+ public override void ProcessServerExtensions(IDictionary serverExtensions)
{
- // Currently ignored
- }
-
- public virtual void NotifySelectedCipherSuite(int selectedCipherSuite)
- {
- this.selectedCipherSuite = selectedCipherSuite;
- }
-
- public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
- {
- this.selectedCompressionMethod = selectedCompressionMethod;
- }
-
- public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
- {
- if (!secureRenegotiation)
+ if (!TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions, ExtensionType.srp,
+ AlertDescription.illegal_parameter))
{
- /*
- * RFC 5746 3.4. If the extension is not present, the server does not support
- * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
- * some clients may want to terminate the handshake instead of continuing; see
- * Section 4.1 for discussion.
- */
-// throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ if (RequireSrpServerExtension)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
- }
- public virtual void ProcessServerExtensions(IDictionary serverExtensions)
- {
- // There is no server response for the SRP extension
+ base.ProcessServerExtensions(serverExtensions);
}
- public virtual TlsKeyExchange GetKeyExchange()
+ public override TlsKeyExchange GetKeyExchange()
{
- switch (selectedCipherSuite)
- {
- case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
- return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP);
-
- case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
- return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA);
-
- case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
- return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS);
-
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected cipher suite was in the list of client-offered cipher
- * suites, so if we now can't produce an implementation, we shouldn't have
- * offered it!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- }
-
- public abstract TlsAuthentication GetAuthentication();
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
- public virtual TlsCompression GetCompression()
- {
- switch (selectedCompressionMethod)
+ switch (keyExchangeAlgorithm)
{
- case CompressionMethod.NULL:
- return new TlsNullCompression();
-
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected compression method was in the list of client-offered compression
- * methods, so if we now can't produce an implementation, we shouldn't have
- * offered it!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ case KeyExchangeAlgorithm.SRP:
+ case KeyExchangeAlgorithm.SRP_DSS:
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return CreateSrpKeyExchange(keyExchangeAlgorithm);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
- public virtual TlsCipher GetCipher()
+ public override TlsAuthentication GetAuthentication()
{
- switch (selectedCipherSuite)
- {
- case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA);
-
- case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
-
- case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
- return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
-
- default:
- /*
- * Note: internal error here; the TlsProtocolHandler verifies that the
- * server-selected cipher suite was in the list of client-offered cipher
- * suites, so if we now can't produce an implementation, we shouldn't have
- * offered it!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
+ /*
+ * Note: This method is not called unless a server certificate is sent, which may be the
+ * case e.g. for SRP_DSS or SRP_RSA key exchange.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
protected virtual TlsKeyExchange CreateSrpKeyExchange(int keyExchange)
{
- return new TlsSrpKeyExchange(context, keyExchange, identity, password);
+ return new TlsSrpKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mGroupVerifier, mIdentity, mPassword);
}
}
}
diff --git a/crypto/src/crypto/tls/SrpTlsServer.cs b/crypto/src/crypto/tls/SrpTlsServer.cs
new file mode 100644
index 000000000..f97878380
--- /dev/null
+++ b/crypto/src/crypto/tls/SrpTlsServer.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class SrpTlsServer
+ : AbstractTlsServer
+ {
+ protected TlsSrpIdentityManager mSrpIdentityManager;
+
+ protected byte[] mSrpIdentity = null;
+ protected TlsSrpLoginParameters mLoginParameters = null;
+
+ public SrpTlsServer(TlsSrpIdentityManager srpIdentityManager)
+ : this(new DefaultTlsCipherFactory(), srpIdentityManager)
+ {
+ }
+
+ public SrpTlsServer(TlsCipherFactory cipherFactory, TlsSrpIdentityManager srpIdentityManager)
+ : base(cipherFactory)
+ {
+ this.mSrpIdentityManager = srpIdentityManager;
+ }
+
+ protected virtual TlsSignerCredentials GetDsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsSignerCredentials GetRsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA
+ };
+ }
+
+ public override void ProcessClientExtensions(IDictionary clientExtensions)
+ {
+ base.ProcessClientExtensions(clientExtensions);
+
+ this.mSrpIdentity = TlsSrpUtilities.GetSrpExtension(clientExtensions);
+ }
+
+ public override int GetSelectedCipherSuite()
+ {
+ int cipherSuite = base.GetSelectedCipherSuite();
+
+ if (TlsSrpUtilities.IsSrpCipherSuite(cipherSuite))
+ {
+ if (mSrpIdentity != null)
+ {
+ this.mLoginParameters = mSrpIdentityManager.GetLoginParameters(mSrpIdentity);
+ }
+
+ if (mLoginParameters == null)
+ throw new TlsFatalAlert(AlertDescription.unknown_psk_identity);
+ }
+
+ return cipherSuite;
+ }
+
+ public override TlsCredentials GetCredentials()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ return null;
+
+ case KeyExchangeAlgorithm.SRP_DSS:
+ return GetDsaSignerCredentials();
+
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return GetRsaSignerCredentials();
+
+ default:
+ /* Note: internal error here; selected a key exchange we don't implement! */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ case KeyExchangeAlgorithm.SRP_DSS:
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return CreateSrpKeyExchange(keyExchangeAlgorithm);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected virtual TlsKeyExchange CreateSrpKeyExchange(int keyExchange)
+ {
+ return new TlsSrpKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mSrpIdentity, mLoginParameters);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/Ssl3Mac.cs b/crypto/src/crypto/tls/Ssl3Mac.cs
index b2f3f309e..8bdb342dc 100644
--- a/crypto/src/crypto/tls/Ssl3Mac.cs
+++ b/crypto/src/crypto/tls/Ssl3Mac.cs
@@ -6,109 +6,105 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
- /**
- * HMAC implementation based on original internet draft for HMAC (RFC 2104)
- *
- * The difference is that padding is concatentated versus XORed with the key
- *
- * H(K + opad, H(K + ipad, text))
- */
- public class Ssl3Mac
- : IMac
- {
- private const byte IPAD = 0x36;
- private const byte OPAD = 0x5C;
-
- internal static readonly byte[] MD5_IPAD = GenPad(IPAD, 48);
- internal static readonly byte[] MD5_OPAD = GenPad(OPAD, 48);
- internal static readonly byte[] SHA1_IPAD = GenPad(IPAD, 40);
- internal static readonly byte[] SHA1_OPAD = GenPad(OPAD, 40);
-
- private IDigest digest;
-
- private byte[] secret;
- private byte[] ipad, opad;
-
- /**
- * Base constructor for one of the standard digest algorithms that the byteLength of
- * the algorithm is know for. Behaviour is undefined for digests other than MD5 or SHA1.
- *
- * @param digest the digest.
- */
- public Ssl3Mac(IDigest digest)
- {
- this.digest = digest;
-
- if (digest.GetDigestSize() == 20)
- {
- this.ipad = SHA1_IPAD;
- this.opad = SHA1_OPAD;
- }
- else
- {
- this.ipad = MD5_IPAD;
- this.opad = MD5_OPAD;
- }
- }
-
- public virtual string AlgorithmName
- {
- get { return digest.AlgorithmName + "/SSL3MAC"; }
- }
-
- public virtual void Init(ICipherParameters parameters)
- {
- secret = Arrays.Clone(((KeyParameter)parameters).GetKey());
-
- Reset();
- }
-
- public virtual int GetMacSize()
- {
- return digest.GetDigestSize();
- }
-
- public virtual void Update(byte input)
- {
- digest.Update(input);
- }
-
- public virtual void BlockUpdate(byte[] input, int inOff, int len)
- {
- digest.BlockUpdate(input, inOff, len);
- }
-
- public virtual int DoFinal(byte[] output, int outOff)
- {
- byte[] tmp = new byte[digest.GetDigestSize()];
- digest.DoFinal(tmp, 0);
-
- digest.BlockUpdate(secret, 0, secret.Length);
- digest.BlockUpdate(opad, 0, opad.Length);
- digest.BlockUpdate(tmp, 0, tmp.Length);
-
- int len = digest.DoFinal(output, outOff);
-
- Reset();
-
- return len;
- }
-
- /**
- * Reset the mac generator.
- */
- public virtual void Reset()
- {
- digest.Reset();
- digest.BlockUpdate(secret, 0, secret.Length);
- digest.BlockUpdate(ipad, 0, ipad.Length);
- }
-
- private static byte[] GenPad(byte b, int count)
- {
- byte[] padding = new byte[count];
- Arrays.Fill(padding, b);
- return padding;
- }
- }
+ /**
+ * HMAC implementation based on original internet draft for HMAC (RFC 2104)
+ *
+ * The difference is that padding is concatentated versus XORed with the key
+ *
+ * H(K + opad, H(K + ipad, text))
+ */
+ public class Ssl3Mac
+ : IMac
+ {
+ private const byte IPAD_BYTE = 0x36;
+ private const byte OPAD_BYTE = 0x5C;
+
+ internal static readonly byte[] IPAD = GenPad(IPAD_BYTE, 48);
+ internal static readonly byte[] OPAD = GenPad(OPAD_BYTE, 48);
+
+ private readonly IDigest digest;
+ private readonly int padLength;
+
+ private byte[] secret;
+
+ /**
+ * Base constructor for one of the standard digest algorithms that the byteLength of
+ * the algorithm is know for. Behaviour is undefined for digests other than MD5 or SHA1.
+ *
+ * @param digest the digest.
+ */
+ public Ssl3Mac(IDigest digest)
+ {
+ this.digest = digest;
+
+ if (digest.GetDigestSize() == 20)
+ {
+ this.padLength = 40;
+ }
+ else
+ {
+ this.padLength = 48;
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "/SSL3MAC"; }
+ }
+
+ public virtual void Init(ICipherParameters parameters)
+ {
+ secret = Arrays.Clone(((KeyParameter)parameters).GetKey());
+
+ Reset();
+ }
+
+ public virtual int GetMacSize()
+ {
+ return digest.GetDigestSize();
+ }
+
+ public virtual void Update(byte input)
+ {
+ digest.Update(input);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ digest.BlockUpdate(input, inOff, len);
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ byte[] tmp = new byte[digest.GetDigestSize()];
+ digest.DoFinal(tmp, 0);
+
+ digest.BlockUpdate(secret, 0, secret.Length);
+ digest.BlockUpdate(OPAD, 0, padLength);
+ digest.BlockUpdate(tmp, 0, tmp.Length);
+
+ int len = digest.DoFinal(output, outOff);
+
+ Reset();
+
+ return len;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public virtual void Reset()
+ {
+ digest.Reset();
+ digest.BlockUpdate(secret, 0, secret.Length);
+ digest.BlockUpdate(IPAD, 0, padLength);
+ }
+
+ private static byte[] GenPad(byte b, int count)
+ {
+ byte[] padding = new byte[count];
+ Arrays.Fill(padding, b);
+ return padding;
+ }
+ }
}
diff --git a/crypto/src/crypto/tls/SupplementalDataEntry.cs b/crypto/src/crypto/tls/SupplementalDataEntry.cs
new file mode 100644
index 000000000..5adc4fa52
--- /dev/null
+++ b/crypto/src/crypto/tls/SupplementalDataEntry.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class SupplementalDataEntry
+ {
+ protected readonly int mDataType;
+ protected readonly byte[] mData;
+
+ public SupplementalDataEntry(int dataType, byte[] data)
+ {
+ this.mDataType = dataType;
+ this.mData = data;
+ }
+
+ public virtual int DataType
+ {
+ get { return mDataType; }
+ }
+
+ public virtual byte[] Data
+ {
+ get { return mData; }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsAeadCipher.cs b/crypto/src/crypto/tls/TlsAeadCipher.cs
new file mode 100644
index 000000000..951e8663b
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsAeadCipher.cs
@@ -0,0 +1,189 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsAeadCipher
+ : TlsCipher
+ {
+ protected readonly TlsContext context;
+ protected readonly int macSize;
+ protected readonly int nonce_explicit_length;
+
+ protected readonly IAeadBlockCipher encryptCipher;
+ protected readonly IAeadBlockCipher decryptCipher;
+
+ protected readonly byte[] encryptImplicitNonce, decryptImplicitNonce;
+
+ /// <exception cref="IOException"></exception>
+ public TlsAeadCipher(TlsContext context, IAeadBlockCipher clientWriteCipher, IAeadBlockCipher serverWriteCipher,
+ int cipherKeySize, int macSize)
+ {
+ if (!TlsUtilities.IsTlsV12(context))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.context = context;
+ this.macSize = macSize;
+
+ // NOTE: Valid for RFC 5288/6655 ciphers but may need review for other AEAD ciphers
+ this.nonce_explicit_length = 8;
+
+ // TODO SecurityParameters.fixed_iv_length
+ int fixed_iv_length = 4;
+
+ int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length);
+
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+ int offset = 0;
+
+ KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ byte[] client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
+ offset += fixed_iv_length;
+ byte[] server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
+ offset += fixed_iv_length;
+
+ if (offset != key_block_size)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ KeyParameter encryptKey, decryptKey;
+ if (context.IsServer)
+ {
+ this.encryptCipher = serverWriteCipher;
+ this.decryptCipher = clientWriteCipher;
+ this.encryptImplicitNonce = server_write_IV;
+ this.decryptImplicitNonce = client_write_IV;
+ encryptKey = server_write_key;
+ decryptKey = client_write_key;
+ }
+ else
+ {
+ this.encryptCipher = clientWriteCipher;
+ this.decryptCipher = serverWriteCipher;
+ this.encryptImplicitNonce = client_write_IV;
+ this.decryptImplicitNonce = server_write_IV;
+ encryptKey = client_write_key;
+ decryptKey = server_write_key;
+ }
+
+ byte[] dummyNonce = new byte[fixed_iv_length + nonce_explicit_length];
+
+ this.encryptCipher.Init(true, new AeadParameters(encryptKey, 8 * macSize, dummyNonce));
+ this.decryptCipher.Init(false, new AeadParameters(decryptKey, 8 * macSize, dummyNonce));
+ }
+
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
+ {
+ // TODO We ought to be able to ask the decryptCipher (independently of it's current state!)
+ return ciphertextLimit - macSize - nonce_explicit_length;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+ {
+ byte[] nonce = new byte[this.encryptImplicitNonce.Length + nonce_explicit_length];
+ Array.Copy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.Length);
+
+ /*
+ * RFC 5288/6655 The nonce_explicit MAY be the 64-bit sequence number.
+ *
+ * (May need review for other AEAD ciphers).
+ */
+ TlsUtilities.WriteUint64(seqNo, nonce, encryptImplicitNonce.Length);
+
+ int plaintextOffset = offset;
+ int plaintextLength = len;
+ int ciphertextLength = encryptCipher.GetOutputSize(plaintextLength);
+
+ byte[] output = new byte[nonce_explicit_length + ciphertextLength];
+ Array.Copy(nonce, encryptImplicitNonce.Length, output, 0, nonce_explicit_length);
+ int outputPos = nonce_explicit_length;
+
+ byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+ AeadParameters parameters = new AeadParameters(null, 8 * macSize, nonce, additionalData);
+
+ try
+ {
+ encryptCipher.Init(true, parameters);
+ outputPos += encryptCipher.ProcessBytes(plaintext, plaintextOffset, plaintextLength, output, outputPos);
+ outputPos += encryptCipher.DoFinal(output, outputPos);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+
+ if (outputPos != output.Length)
+ {
+ // NOTE: Existing AEAD cipher implementations all give exact output lengths
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ return output;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+ {
+ if (GetPlaintextLimit(len) < 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] nonce = new byte[this.decryptImplicitNonce.Length + nonce_explicit_length];
+ Array.Copy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.Length);
+ Array.Copy(ciphertext, offset, nonce, decryptImplicitNonce.Length, nonce_explicit_length);
+
+ int ciphertextOffset = offset + nonce_explicit_length;
+ int ciphertextLength = len - nonce_explicit_length;
+ int plaintextLength = decryptCipher.GetOutputSize(ciphertextLength);
+
+ byte[] output = new byte[plaintextLength];
+ int outputPos = 0;
+
+ byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+ AeadParameters parameters = new AeadParameters(null, 8 * macSize, nonce, additionalData);
+
+ try
+ {
+ decryptCipher.Init(false, parameters);
+ outputPos += decryptCipher.ProcessBytes(ciphertext, ciphertextOffset, ciphertextLength, output, outputPos);
+ outputPos += decryptCipher.DoFinal(output, outputPos);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac, e);
+ }
+
+ if (outputPos != output.Length)
+ {
+ // NOTE: Existing AEAD cipher implementations all give exact output lengths
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ return output;
+ }
+
+ /// <exception cref="IOException"></exception>
+ protected virtual byte[] GetAdditionalData(long seqNo, byte type, int len)
+ {
+ /*
+ * additional_data = seq_num + TLSCompressed.type + TLSCompressed.version +
+ * TLSCompressed.length
+ */
+
+ byte[] additional_data = new byte[13];
+ TlsUtilities.WriteUint64(seqNo, additional_data, 0);
+ TlsUtilities.WriteUint8(type, additional_data, 8);
+ TlsUtilities.WriteVersion(context.ServerVersion, additional_data, 9);
+ TlsUtilities.WriteUint16(len, additional_data, 11);
+
+ return additional_data;
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsAgreementCredentials.cs b/crypto/src/crypto/tls/TlsAgreementCredentials.cs
index 46ee4f90e..7c64072e8 100644
--- a/crypto/src/crypto/tls/TlsAgreementCredentials.cs
+++ b/crypto/src/crypto/tls/TlsAgreementCredentials.cs
@@ -3,9 +3,10 @@ using System.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- public interface TlsAgreementCredentials : TlsCredentials
- {
- /// <exception cref="IOException"></exception>
- byte[] GenerateAgreement(AsymmetricKeyParameter serverPublicKey);
- }
+ public interface TlsAgreementCredentials
+ : TlsCredentials
+ {
+ /// <exception cref="IOException"></exception>
+ byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey);
+ }
}
diff --git a/crypto/src/crypto/tls/TlsBlockCipher.cs b/crypto/src/crypto/tls/TlsBlockCipher.cs
index cfbceb25e..d81b881fc 100644
--- a/crypto/src/crypto/tls/TlsBlockCipher.cs
+++ b/crypto/src/crypto/tls/TlsBlockCipher.cs
@@ -1,8 +1,6 @@
using System;
using System.IO;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
@@ -10,169 +8,310 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
/// <summary>
- /// A generic TLS 1.0 block cipher. This can be used for AES or 3DES for example.
+ /// A generic TLS 1.0-1.2 / SSLv3 block cipher. This can be used for AES or 3DES for example.
/// </summary>
public class TlsBlockCipher
- : TlsCipher
+ : TlsCipher
{
- protected TlsClientContext context;
- protected byte[] randomData;
+ protected readonly TlsContext context;
+ protected readonly byte[] randomData;
+ protected readonly bool useExplicitIV;
+ protected readonly bool encryptThenMac;
- protected IBlockCipher encryptCipher;
- protected IBlockCipher decryptCipher;
+ protected readonly IBlockCipher encryptCipher;
+ protected readonly IBlockCipher decryptCipher;
- protected TlsMac wMac;
- protected TlsMac rMac;
+ protected readonly TlsMac mWriteMac;
+ protected readonly TlsMac mReadMac;
public virtual TlsMac WriteMac
{
- get { return wMac; }
+ get { return mWriteMac; }
}
public virtual TlsMac ReadMac
{
- get { return rMac; }
+ get { return mReadMac; }
}
- public TlsBlockCipher(TlsClientContext context, IBlockCipher encryptCipher,
- IBlockCipher decryptCipher, IDigest writeDigest, IDigest readDigest, int cipherKeySize)
+ /// <exception cref="IOException"></exception>
+ public TlsBlockCipher(TlsContext context, IBlockCipher clientWriteCipher, IBlockCipher serverWriteCipher,
+ IDigest clientWriteDigest, IDigest serverWriteDigest, int cipherKeySize)
{
this.context = context;
this.randomData = new byte[256];
- context.SecureRandom.NextBytes(randomData);
+ context.NonceRandomGenerator.NextBytes(randomData);
- this.encryptCipher = encryptCipher;
- this.decryptCipher = decryptCipher;
+ this.useExplicitIV = TlsUtilities.IsTlsV11(context);
+ this.encryptThenMac = context.SecurityParameters.encryptThenMac;
- int prfSize = (2 * cipherKeySize) + writeDigest.GetDigestSize()
- + readDigest.GetDigestSize() + encryptCipher.GetBlockSize()
- + decryptCipher.GetBlockSize();
+ int key_block_size = (2 * cipherKeySize) + clientWriteDigest.GetDigestSize()
+ + serverWriteDigest.GetDigestSize();
- SecurityParameters securityParameters = context.SecurityParameters;
+ // From TLS 1.1 onwards, block ciphers don't need client_write_IV
+ if (!useExplicitIV)
+ {
+ key_block_size += clientWriteCipher.GetBlockSize() + serverWriteCipher.GetBlockSize();
+ }
- byte[] keyBlock = TlsUtilities.PRF(securityParameters.masterSecret, "key expansion",
- TlsUtilities.Concat(securityParameters.serverRandom, securityParameters.clientRandom),
- prfSize);
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
int offset = 0;
- // Init MACs
- wMac = CreateTlsMac(writeDigest, keyBlock, ref offset);
- rMac = CreateTlsMac(readDigest, keyBlock, ref offset);
+ TlsMac clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+ clientWriteDigest.GetDigestSize());
+ offset += clientWriteDigest.GetDigestSize();
+ TlsMac serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+ serverWriteDigest.GetDigestSize());
+ offset += serverWriteDigest.GetDigestSize();
- // Build keys
- KeyParameter encryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize);
- KeyParameter decryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize);
+ KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
- // Add IVs
- ParametersWithIV encryptParams = CreateParametersWithIV(encryptKey,
- keyBlock, ref offset, encryptCipher.GetBlockSize());
- ParametersWithIV decryptParams = CreateParametersWithIV(decryptKey,
- keyBlock, ref offset, decryptCipher.GetBlockSize());
+ byte[] client_write_IV, server_write_IV;
+ if (useExplicitIV)
+ {
+ client_write_IV = new byte[clientWriteCipher.GetBlockSize()];
+ server_write_IV = new byte[serverWriteCipher.GetBlockSize()];
+ }
+ else
+ {
+ client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + clientWriteCipher.GetBlockSize());
+ offset += clientWriteCipher.GetBlockSize();
+ server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + serverWriteCipher.GetBlockSize());
+ offset += serverWriteCipher.GetBlockSize();
+ }
- if (offset != prfSize)
+ if (offset != key_block_size)
+ {
throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
- // Init Ciphers
- encryptCipher.Init(true, encryptParams);
- decryptCipher.Init(false, decryptParams);
- }
+ ICipherParameters encryptParams, decryptParams;
+ if (context.IsServer)
+ {
+ this.mWriteMac = serverWriteMac;
+ this.mReadMac = clientWriteMac;
+ this.encryptCipher = serverWriteCipher;
+ this.decryptCipher = clientWriteCipher;
+ encryptParams = new ParametersWithIV(server_write_key, server_write_IV);
+ decryptParams = new ParametersWithIV(client_write_key, client_write_IV);
+ }
+ else
+ {
+ this.mWriteMac = clientWriteMac;
+ this.mReadMac = serverWriteMac;
+ this.encryptCipher = clientWriteCipher;
+ this.decryptCipher = serverWriteCipher;
+ encryptParams = new ParametersWithIV(client_write_key, client_write_IV);
+ decryptParams = new ParametersWithIV(server_write_key, server_write_IV);
+ }
- protected virtual TlsMac CreateTlsMac(IDigest digest, byte[] buf, ref int off)
- {
- int len = digest.GetDigestSize();
- TlsMac mac = new TlsMac(digest, buf, off, len);
- off += len;
- return mac;
+ this.encryptCipher.Init(true, encryptParams);
+ this.decryptCipher.Init(false, decryptParams);
}
- protected virtual KeyParameter CreateKeyParameter(byte[] buf, ref int off, int len)
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
{
- KeyParameter key = new KeyParameter(buf, off, len);
- off += len;
- return key;
- }
+ int blockSize = encryptCipher.GetBlockSize();
+ int macSize = mWriteMac.Size;
- protected virtual ParametersWithIV CreateParametersWithIV(KeyParameter key,
- byte[] buf, ref int off, int len)
- {
- ParametersWithIV ivParams = new ParametersWithIV(key, buf, off, len);
- off += len;
- return ivParams;
+ int plaintextLimit = ciphertextLimit;
+
+ // An explicit IV consumes 1 block
+ if (useExplicitIV)
+ {
+ plaintextLimit -= blockSize;
+ }
+
+ // Leave room for the MAC, and require block-alignment
+ if (encryptThenMac)
+ {
+ plaintextLimit -= macSize;
+ plaintextLimit -= plaintextLimit % blockSize;
+ }
+ else
+ {
+ plaintextLimit -= plaintextLimit % blockSize;
+ plaintextLimit -= macSize;
+ }
+
+ // Minimum 1 byte of padding
+ --plaintextLimit;
+
+ return plaintextLimit;
}
- public virtual byte[] EncodePlaintext(byte type, byte[] plaintext, int offset, int len)
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
{
- int blocksize = encryptCipher.GetBlockSize();
- int padding_length = blocksize - 1 - ((len + wMac.Size) % blocksize);
+ int blockSize = encryptCipher.GetBlockSize();
+ int macSize = mWriteMac.Size;
+
+ ProtocolVersion version = context.ServerVersion;
+
+ int enc_input_length = len;
+ if (!encryptThenMac)
+ {
+ enc_input_length += macSize;
+ }
- //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion;
- bool isTls = true;
+ int padding_length = blockSize - 1 - (enc_input_length % blockSize);
- if (isTls)
+ // TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though)
+ if (!version.IsDtls && !version.IsSsl)
{
// Add a random number of extra blocks worth of padding
- int maxExtraPadBlocks = (255 - padding_length) / blocksize;
+ int maxExtraPadBlocks = (255 - padding_length) / blockSize;
int actualExtraPadBlocks = ChooseExtraPadBlocks(context.SecureRandom, maxExtraPadBlocks);
- padding_length += actualExtraPadBlocks * blocksize;
+ padding_length += actualExtraPadBlocks * blockSize;
+ }
+
+ int totalSize = len + macSize + padding_length + 1;
+ if (useExplicitIV)
+ {
+ totalSize += blockSize;
+ }
+
+ byte[] outBuf = new byte[totalSize];
+ int outOff = 0;
+
+ if (useExplicitIV)
+ {
+ byte[] explicitIV = new byte[blockSize];
+ context.NonceRandomGenerator.NextBytes(explicitIV);
+
+ encryptCipher.Init(true, new ParametersWithIV(null, explicitIV));
+
+ Array.Copy(explicitIV, 0, outBuf, outOff, blockSize);
+ outOff += blockSize;
+ }
+
+ int blocks_start = outOff;
+
+ Array.Copy(plaintext, offset, outBuf, outOff, len);
+ outOff += len;
+
+ if (!encryptThenMac)
+ {
+ byte[] mac = mWriteMac.CalculateMac(seqNo, type, plaintext, offset, len);
+ Array.Copy(mac, 0, outBuf, outOff, mac.Length);
+ outOff += mac.Length;
}
- int totalsize = len + wMac.Size + padding_length + 1;
- byte[] outbuf = new byte[totalsize];
- Array.Copy(plaintext, offset, outbuf, 0, len);
- byte[] mac = wMac.CalculateMac(type, plaintext, offset, len);
- Array.Copy(mac, 0, outbuf, len, mac.Length);
- int paddoffset = len + mac.Length;
for (int i = 0; i <= padding_length; i++)
{
- outbuf[i + paddoffset] = (byte)padding_length;
+ outBuf[outOff++] = (byte)padding_length;
}
- for (int i = 0; i < totalsize; i += blocksize)
+
+ for (int i = blocks_start; i < outOff; i += blockSize)
+ {
+ encryptCipher.ProcessBlock(outBuf, i, outBuf, i);
+ }
+
+ if (encryptThenMac)
{
- encryptCipher.ProcessBlock(outbuf, i, outbuf, i);
+ byte[] mac = mWriteMac.CalculateMac(seqNo, type, outBuf, 0, outOff);
+ Array.Copy(mac, 0, outBuf, outOff, mac.Length);
+ outOff += mac.Length;
}
- return outbuf;
+
+ // assert outBuf.length == outOff;
+
+ return outBuf;
}
- public virtual byte[] DecodeCiphertext(byte type, byte[] ciphertext, int offset, int len)
+ /// <exception cref="IOException"></exception>
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
{
int blockSize = decryptCipher.GetBlockSize();
- int macSize = rMac.Size;
+ int macSize = mReadMac.Size;
+
+ int minLen = blockSize;
+ if (encryptThenMac)
+ {
+ minLen += macSize;
+ }
+ else
+ {
+ minLen = System.Math.Max(minLen, macSize + 1);
+ }
- /*
- * TODO[TLS 1.1] Explicit IV implies minLen = blockSize + max(blockSize, macSize + 1),
- * and will need further changes to offset and plen variables below.
- */
+ if (useExplicitIV)
+ {
+ minLen += blockSize;
+ }
- int minLen = System.Math.Max(blockSize, macSize + 1);
if (len < minLen)
throw new TlsFatalAlert(AlertDescription.decode_error);
- if (len % blockSize != 0)
+ int blocks_length = len;
+ if (encryptThenMac)
+ {
+ blocks_length -= macSize;
+ }
+
+ if (blocks_length % blockSize != 0)
throw new TlsFatalAlert(AlertDescription.decryption_failed);
- for (int i = 0; i < len; i += blockSize)
+ if (encryptThenMac)
{
- decryptCipher.ProcessBlock(ciphertext, offset + i, ciphertext, offset + i);
+ int end = offset + len;
+ byte[] receivedMac = Arrays.CopyOfRange(ciphertext, end - macSize, end);
+ byte[] calculatedMac = mReadMac.CalculateMac(seqNo, type, ciphertext, offset, len - macSize);
+
+ bool badMacEtm = !Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac);
+ if (badMacEtm)
+ {
+ /*
+ * RFC 7366 3. The MAC SHALL be evaluated before any further processing such as
+ * decryption is performed, and if the MAC verification fails, then processing SHALL
+ * terminate immediately. For TLS, a fatal bad_record_mac MUST be generated [2]. For
+ * DTLS, the record MUST be discarded, and a fatal bad_record_mac MAY be generated
+ * [4]. This immediate response to a bad MAC eliminates any timing channels that may
+ * be available through the use of manipulated packet data.
+ */
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+ }
}
- int plen = len;
+ if (useExplicitIV)
+ {
+ decryptCipher.Init(false, new ParametersWithIV(null, ciphertext, offset, blockSize));
- // If there's anything wrong with the padding, this will return zero
- int totalPad = CheckPaddingConstantTime(ciphertext, offset, plen, blockSize, macSize);
+ offset += blockSize;
+ blocks_length -= blockSize;
+ }
- int macInputLen = plen - totalPad - macSize;
+ for (int i = 0; i < blocks_length; i += blockSize)
+ {
+ decryptCipher.ProcessBlock(ciphertext, offset + i, ciphertext, offset + i);
+ }
+
+ // If there's anything wrong with the padding, this will return zero
+ int totalPad = CheckPaddingConstantTime(ciphertext, offset, blocks_length, blockSize, encryptThenMac ? 0 : macSize);
+ bool badMac = (totalPad == 0);
- byte[] decryptedMac = Arrays.Copy(ciphertext, offset + macInputLen, macSize);
- byte[] calculatedMac = rMac.CalculateMacConstantTime(type, ciphertext, offset, macInputLen, plen - macSize, randomData);
+ int dec_output_length = blocks_length - totalPad;
- bool badMac = !Arrays.ConstantTimeAreEqual(calculatedMac, decryptedMac);
+ if (!encryptThenMac)
+ {
+ dec_output_length -= macSize;
+ int macInputLen = dec_output_length;
+ int macOff = offset + macInputLen;
+ byte[] receivedMac = Arrays.CopyOfRange(ciphertext, macOff, macOff + macSize);
+ byte[] calculatedMac = mReadMac.CalculateMacConstantTime(seqNo, type, ciphertext, offset, macInputLen,
+ blocks_length - macSize, randomData);
+
+ badMac |= !Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac);
+ }
- if (badMac || totalPad == 0)
+ if (badMac)
throw new TlsFatalAlert(AlertDescription.bad_record_mac);
- return Arrays.Copy(ciphertext, offset, macInputLen);
+ return Arrays.CopyOfRange(ciphertext, offset, offset + dec_output_length);
}
protected virtual int CheckPaddingConstantTime(byte[] buf, int off, int len, int blockSize, int macSize)
@@ -185,10 +324,7 @@ namespace Org.BouncyCastle.Crypto.Tls
int dummyIndex = 0;
byte padDiff = 0;
- //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion;
- bool isTls = true;
-
- if ((!isTls && totalPad > blockSize) || (macSize + totalPad > len))
+ if ((TlsUtilities.IsSsl(context) && totalPad > blockSize) || (macSize + totalPad > len))
{
totalPad = 0;
}
@@ -225,25 +361,24 @@ namespace Org.BouncyCastle.Crypto.Tls
protected virtual int ChooseExtraPadBlocks(SecureRandom r, int max)
{
-// return r.NextInt(max + 1);
+ // return r.NextInt(max + 1);
- uint x = (uint)r.NextInt();
+ int x = r.NextInt();
int n = LowestBitSet(x);
return System.Math.Min(n, max);
}
- private int LowestBitSet(uint x)
+ protected virtual int LowestBitSet(int x)
{
if (x == 0)
- {
return 32;
- }
+ uint ux = (uint)x;
int n = 0;
- while ((x & 1) == 0)
+ while ((ux & 1U) == 0)
{
++n;
- x >>= 1;
+ ux >>= 1;
}
return n;
}
diff --git a/crypto/src/crypto/tls/TlsCipher.cs b/crypto/src/crypto/tls/TlsCipher.cs
index a58f4943f..7bd8573ac 100644
--- a/crypto/src/crypto/tls/TlsCipher.cs
+++ b/crypto/src/crypto/tls/TlsCipher.cs
@@ -5,10 +5,12 @@ namespace Org.BouncyCastle.Crypto.Tls
{
public interface TlsCipher
{
+ int GetPlaintextLimit(int ciphertextLimit);
+
/// <exception cref="IOException"></exception>
- byte[] EncodePlaintext(byte type, byte[] plaintext, int offset, int len);
+ byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len);
/// <exception cref="IOException"></exception>
- byte[] DecodeCiphertext(byte type, byte[] ciphertext, int offset, int len);
+ byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len);
}
}
diff --git a/crypto/src/crypto/tls/TlsCipherFactory.cs b/crypto/src/crypto/tls/TlsCipherFactory.cs
index bd65f8b4b..4e1fe0eb9 100644
--- a/crypto/src/crypto/tls/TlsCipherFactory.cs
+++ b/crypto/src/crypto/tls/TlsCipherFactory.cs
@@ -6,7 +6,6 @@ namespace Org.BouncyCastle.Crypto.Tls
public interface TlsCipherFactory
{
/// <exception cref="IOException"></exception>
- TlsCipher CreateCipher(TlsClientContext context, int encryptionAlgorithm,
- DigestAlgorithm digestAlgorithm);
+ TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm);
}
}
diff --git a/crypto/src/crypto/tls/TlsClient.cs b/crypto/src/crypto/tls/TlsClient.cs
index a4cdc647d..116f6a779 100644
--- a/crypto/src/crypto/tls/TlsClient.cs
+++ b/crypto/src/crypto/tls/TlsClient.cs
@@ -15,6 +15,20 @@ namespace Org.BouncyCastle.Crypto.Tls
/// </param>
void Init(TlsClientContext context);
+ /// <summary>Return the session this client wants to resume, if any.</summary>
+ /// <remarks>Note that the peer's certificate chain for the session (if any) may need to be periodically revalidated.</remarks>
+ /// <returns>
+ /// A <see cref="TlsSession"/> representing the resumable session to be used for this connection,
+ /// or null to use a new session.
+ /// </returns>
+ TlsSession GetSessionToResume();
+
+ ProtocolVersion ClientHelloRecordLayerVersion { get; }
+
+ ProtocolVersion ClientVersion { get; }
+
+ bool IsFallback { get; }
+
/// <summary>
/// Get the list of cipher suites that this client supports.
/// </summary>
@@ -40,12 +54,13 @@ namespace Org.BouncyCastle.Crypto.Tls
/// <exception cref="IOException"></exception>
IDictionary GetClientExtensions();
+ /// <exception cref="IOException"></exception>
+ void NotifyServerVersion(ProtocolVersion selectedVersion);
+
/// <summary>
- /// Reports the session ID once it has been determined.
+ /// Notifies the client of the session_id sent in the ServerHello.
/// </summary>
- /// <param name="sessionID">
- /// A <see cref="System.Byte"/>
- /// </param>
+ /// <param name="sessionID">An array of <see cref="System.Byte"/></param>
void NotifySessionID(byte[] sessionID);
/// <summary>
@@ -73,18 +88,6 @@ namespace Org.BouncyCastle.Crypto.Tls
void NotifySelectedCompressionMethod(byte selectedCompressionMethod);
/// <summary>
- /// Report whether the server supports secure renegotiation
- /// </summary>
- /// <remarks>
- /// The protocol handler automatically processes the relevant extensions
- /// </remarks>
- /// <param name="secureRenegotiation">
- /// A <see cref="System.Boolean"/>, true if the server supports secure renegotiation
- /// </param>
- /// <exception cref="IOException"></exception>
- void NotifySecureRenegotiation(bool secureRenegotiation);
-
- /// <summary>
/// Report the extensions from an extended server hello.
/// </summary>
/// <remarks>
@@ -95,6 +98,10 @@ namespace Org.BouncyCastle.Crypto.Tls
/// </param>
void ProcessServerExtensions(IDictionary serverExtensions);
+ /// <param name="serverSupplementalData">A <see cref="IList">list</see> of <see cref="SupplementalDataEntry"/></param>
+ /// <exception cref="IOException"/>
+ void ProcessServerSupplementalData(IList serverSupplementalData);
+
/// <summary>
/// Return an implementation of <see cref="TlsKeyExchange"/> to negotiate the key exchange
/// part of the protocol.
@@ -112,19 +119,18 @@ namespace Org.BouncyCastle.Crypto.Tls
/// <exception cref="IOException"/>
TlsAuthentication GetAuthentication();
- /// <summary>
- /// Return an implementation of <see cref="TlsCompression"/> to handle record compression.
- /// </summary>
+ /// <returns>A <see cref="IList">list</see> of <see cref="SupplementalDataEntry"/></returns>
/// <exception cref="IOException"/>
- TlsCompression GetCompression();
+ IList GetClientSupplementalData();
- /// <summary>
- /// Return an implementation of <see cref="TlsCipher"/> to use for encryption/decryption.
- /// </summary>
- /// <returns>
- /// A <see cref="TlsCipher"/>
- /// </returns>
+ /// <summary>RFC 5077 3.3. NewSessionTicket Handshake Message</summary>
+ /// <remarks>
+ /// This method will be called (only) when a NewSessionTicket handshake message is received. The
+ /// ticket is opaque to the client and clients MUST NOT examine the ticket under the assumption
+ /// that it complies with e.g. <i>RFC 5077 4. Recommended Ticket Construction</i>.
+ /// </remarks>
+ /// <param name="newSessionTicket">The <see cref="NewSessionTicket">ticket</see></param>
/// <exception cref="IOException"/>
- TlsCipher GetCipher();
+ void NotifyNewSessionTicket(NewSessionTicket newSessionTicket);
}
}
diff --git a/crypto/src/crypto/tls/TlsClientContext.cs b/crypto/src/crypto/tls/TlsClientContext.cs
index dbb10aa76..b077d0aaf 100644
--- a/crypto/src/crypto/tls/TlsClientContext.cs
+++ b/crypto/src/crypto/tls/TlsClientContext.cs
@@ -4,12 +4,8 @@ using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Tls
{
- public interface TlsClientContext
- {
- SecureRandom SecureRandom { get; }
-
- SecurityParameters SecurityParameters { get; }
-
- object UserObject { get; set; }
- }
+ public interface TlsClientContext
+ : TlsContext
+ {
+ }
}
diff --git a/crypto/src/crypto/tls/TlsClientContextImpl.cs b/crypto/src/crypto/tls/TlsClientContextImpl.cs
index 9d5dee232..674d68937 100644
--- a/crypto/src/crypto/tls/TlsClientContextImpl.cs
+++ b/crypto/src/crypto/tls/TlsClientContextImpl.cs
@@ -4,34 +4,17 @@ using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Tls
{
- internal class TlsClientContextImpl
- : TlsClientContext
- {
- private readonly SecureRandom secureRandom;
- private readonly SecurityParameters securityParameters;
+ internal class TlsClientContextImpl
+ : AbstractTlsContext, TlsClientContext
+ {
+ internal TlsClientContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
+ : base(secureRandom, securityParameters)
+ {
+ }
- private object userObject = null;
-
- internal TlsClientContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
- {
- this.secureRandom = secureRandom;
- this.securityParameters = securityParameters;
- }
-
- public virtual SecureRandom SecureRandom
- {
- get { return secureRandom; }
- }
-
- public virtual SecurityParameters SecurityParameters
- {
- get { return securityParameters; }
- }
-
- public virtual object UserObject
- {
- get { return userObject; }
- set { this.userObject = value; }
- }
- }
+ public override bool IsServer
+ {
+ get { return false; }
+ }
+ }
}
diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs
new file mode 100644
index 000000000..14c1cf4a4
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -0,0 +1,906 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsClientProtocol
+ : TlsProtocol
+ {
+ protected TlsClient mTlsClient = null;
+ internal TlsClientContextImpl mTlsClientContext = null;
+
+ protected byte[] mSelectedSessionID = null;
+
+ protected TlsKeyExchange mKeyExchange = null;
+ protected TlsAuthentication mAuthentication = null;
+
+ protected CertificateStatus mCertificateStatus = null;
+ protected CertificateRequest mCertificateRequest = null;
+
+ /**
+ * Constructor for blocking mode.
+ * @param stream The bi-directional stream of data to/from the server
+ * @param secureRandom Random number generator for various cryptographic functions
+ */
+ public TlsClientProtocol(Stream stream, SecureRandom secureRandom)
+ : base(stream, secureRandom)
+ {
+ }
+
+ /**
+ * Constructor for blocking mode.
+ * @param input The stream of data from the server
+ * @param output The stream of data to the server
+ * @param secureRandom Random number generator for various cryptographic functions
+ */
+ public TlsClientProtocol(Stream input, Stream output, SecureRandom secureRandom)
+ : base(input, output, secureRandom)
+ {
+ }
+
+ /**
+ * Constructor for non-blocking mode.<br>
+ * <br>
+ * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
+ * provide the received ciphertext, then use
+ * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br>
+ * <br>
+ * Similarly, when data needs to be sent, use
+ * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
+ * {@link #readOutput(byte[], int, int)} to get the corresponding
+ * ciphertext.
+ *
+ * @param secureRandom
+ * Random number generator for various cryptographic functions
+ */
+ public TlsClientProtocol(SecureRandom secureRandom)
+ : base(secureRandom)
+ {
+ }
+
+ /**
+ * Initiates a TLS handshake in the role of client.<br>
+ * <br>
+ * In blocking mode, this will not return until the handshake is complete.
+ * In non-blocking mode, use {@link TlsPeer#NotifyHandshakeComplete()} to
+ * receive a callback when the handshake is complete.
+ *
+ * @param tlsClient The {@link TlsClient} to use for the handshake.
+ * @throws IOException If in blocking mode and handshake was not successful.
+ */
+ public virtual void Connect(TlsClient tlsClient)
+ {
+ if (tlsClient == null)
+ throw new ArgumentNullException("tlsClient");
+ if (this.mTlsClient != null)
+ throw new InvalidOperationException("'Connect' can only be called once");
+
+ this.mTlsClient = tlsClient;
+
+ this.mSecurityParameters = new SecurityParameters();
+ this.mSecurityParameters.entity = ConnectionEnd.client;
+
+ this.mTlsClientContext = new TlsClientContextImpl(mSecureRandom, mSecurityParameters);
+
+ this.mSecurityParameters.clientRandom = CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(),
+ mTlsClientContext.NonceRandomGenerator);
+
+ this.mTlsClient.Init(mTlsClientContext);
+ this.mRecordStream.Init(mTlsClientContext);
+
+ TlsSession sessionToResume = tlsClient.GetSessionToResume();
+ if (sessionToResume != null && sessionToResume.IsResumable)
+ {
+ SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
+ if (sessionParameters != null)
+ {
+ this.mTlsSession = sessionToResume;
+ this.mSessionParameters = sessionParameters;
+ }
+ }
+
+ SendClientHelloMessage();
+ this.mConnectionState = CS_CLIENT_HELLO;
+
+ BlockForHandshake();
+ }
+
+ protected override void CleanupHandshake()
+ {
+ base.CleanupHandshake();
+
+ this.mSelectedSessionID = null;
+ this.mKeyExchange = null;
+ this.mAuthentication = null;
+ this.mCertificateStatus = null;
+ this.mCertificateRequest = null;
+ }
+
+ protected override TlsContext Context
+ {
+ get { return mTlsClientContext; }
+ }
+
+ internal override AbstractTlsContext ContextAdmin
+ {
+ get { return mTlsClientContext; }
+ }
+
+ protected override TlsPeer Peer
+ {
+ get { return mTlsClient; }
+ }
+
+ protected override void HandleHandshakeMessage(byte type, byte[] data)
+ {
+ MemoryStream buf = new MemoryStream(data, false);
+
+ if (this.mResumedSession)
+ {
+ if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ ProcessFinishedMessage(buf);
+ this.mConnectionState = CS_SERVER_FINISHED;
+
+ SendFinishedMessage();
+ this.mConnectionState = CS_CLIENT_FINISHED;
+ this.mConnectionState = CS_END;
+
+ CompleteHandshake();
+ return;
+ }
+
+ switch (type)
+ {
+ case HandshakeType.certificate:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO:
+ case CS_SERVER_SUPPLEMENTAL_DATA:
+ {
+ if (this.mConnectionState == CS_SERVER_HELLO)
+ {
+ HandleSupplementalData(null);
+ }
+
+ // Parse the Certificate message and Send to cipher suite
+
+ this.mPeerCertificate = Certificate.Parse(buf);
+
+ AssertEmpty(buf);
+
+ // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+ if (this.mPeerCertificate == null || this.mPeerCertificate.IsEmpty)
+ {
+ this.mAllowCertificateStatus = false;
+ }
+
+ this.mKeyExchange.ProcessServerCertificate(this.mPeerCertificate);
+
+ this.mAuthentication = mTlsClient.GetAuthentication();
+ this.mAuthentication.NotifyServerCertificate(this.mPeerCertificate);
+
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_SERVER_CERTIFICATE;
+ break;
+ }
+ case HandshakeType.certificate_status:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_CERTIFICATE:
+ {
+ if (!this.mAllowCertificateStatus)
+ {
+ /*
+ * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
+ * server MUST have included an extension of type "status_request" with empty
+ * "extension_data" in the extended server hello..
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mCertificateStatus = CertificateStatus.Parse(buf);
+
+ AssertEmpty(buf);
+
+ // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
+
+ this.mConnectionState = CS_CERTIFICATE_STATUS;
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.finished:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_FINISHED:
+ case CS_SERVER_SESSION_TICKET:
+ {
+ if (this.mConnectionState == CS_CLIENT_FINISHED && this.mExpectSessionTicket)
+ {
+ /*
+ * RFC 5077 3.3. This message MUST be sent if the server included a
+ * SessionTicket extension in the ServerHello.
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ ProcessFinishedMessage(buf);
+ this.mConnectionState = CS_SERVER_FINISHED;
+ this.mConnectionState = CS_END;
+
+ CompleteHandshake();
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.server_hello:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_HELLO:
+ {
+ ReceiveServerHelloMessage(buf);
+ this.mConnectionState = CS_SERVER_HELLO;
+
+ this.mRecordStream.NotifyHelloComplete();
+
+ ApplyMaxFragmentLengthExtension();
+
+ if (this.mResumedSession)
+ {
+ this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
+ this.mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+ SendChangeCipherSpecMessage();
+ }
+ else
+ {
+ InvalidateSession();
+
+ if (this.mSelectedSessionID.Length > 0)
+ {
+ this.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null);
+ }
+ }
+
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.supplemental_data:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO:
+ {
+ HandleSupplementalData(ReadSupplementalDataMessage(buf));
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.server_hello_done:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO:
+ case CS_SERVER_SUPPLEMENTAL_DATA:
+ case CS_SERVER_CERTIFICATE:
+ case CS_CERTIFICATE_STATUS:
+ case CS_SERVER_KEY_EXCHANGE:
+ case CS_CERTIFICATE_REQUEST:
+ {
+ if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
+ {
+ HandleSupplementalData(null);
+ }
+
+ if (mConnectionState < CS_SERVER_CERTIFICATE)
+ {
+ // There was no server certificate message; check it's OK
+ this.mKeyExchange.SkipServerCredentials();
+ this.mAuthentication = null;
+ }
+
+ if (mConnectionState < CS_SERVER_KEY_EXCHANGE)
+ {
+ // There was no server key exchange message; check it's OK
+ this.mKeyExchange.SkipServerKeyExchange();
+ }
+
+ AssertEmpty(buf);
+
+ this.mConnectionState = CS_SERVER_HELLO_DONE;
+
+ this.mRecordStream.HandshakeHash.SealHashAlgorithms();
+
+ IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
+ if (clientSupplementalData != null)
+ {
+ SendSupplementalDataMessage(clientSupplementalData);
+ }
+ this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
+
+ TlsCredentials clientCreds = null;
+ if (mCertificateRequest == null)
+ {
+ this.mKeyExchange.SkipClientCredentials();
+ }
+ else
+ {
+ clientCreds = this.mAuthentication.GetClientCredentials(mCertificateRequest);
+
+ if (clientCreds == null)
+ {
+ this.mKeyExchange.SkipClientCredentials();
+
+ /*
+ * RFC 5246 If no suitable certificate is available, the client MUST Send a
+ * certificate message containing no certificates.
+ *
+ * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+ */
+ SendCertificateMessage(Certificate.EmptyChain);
+ }
+ else
+ {
+ this.mKeyExchange.ProcessClientCredentials(clientCreds);
+
+ SendCertificateMessage(clientCreds.Certificate);
+ }
+ }
+
+ this.mConnectionState = CS_CLIENT_CERTIFICATE;
+
+ /*
+ * Send the client key exchange message, depending on the key exchange we are using
+ * in our CipherSuite.
+ */
+ SendClientKeyExchangeMessage();
+ this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
+
+ TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish();
+ this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null);
+
+ EstablishMasterSecret(Context, mKeyExchange);
+ mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+ if (clientCreds != null && clientCreds is TlsSignerCredentials)
+ {
+ TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds;
+
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ Context, signerCredentials);
+
+ byte[] hash;
+ if (signatureAndHashAlgorithm == null)
+ {
+ hash = mSecurityParameters.SessionHash;
+ }
+ else
+ {
+ hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
+ }
+
+ byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
+ DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ SendCertificateVerifyMessage(certificateVerify);
+
+ this.mConnectionState = CS_CERTIFICATE_VERIFY;
+ }
+
+ SendChangeCipherSpecMessage();
+ SendFinishedMessage();
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ this.mConnectionState = CS_CLIENT_FINISHED;
+ break;
+ }
+ case HandshakeType.server_key_exchange:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO:
+ case CS_SERVER_SUPPLEMENTAL_DATA:
+ case CS_SERVER_CERTIFICATE:
+ case CS_CERTIFICATE_STATUS:
+ {
+ if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
+ {
+ HandleSupplementalData(null);
+ }
+
+ if (mConnectionState < CS_SERVER_CERTIFICATE)
+ {
+ // There was no server certificate message; check it's OK
+ this.mKeyExchange.SkipServerCredentials();
+ this.mAuthentication = null;
+ }
+
+ this.mKeyExchange.ProcessServerKeyExchange(buf);
+
+ AssertEmpty(buf);
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
+ break;
+ }
+ case HandshakeType.certificate_request:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_CERTIFICATE:
+ case CS_CERTIFICATE_STATUS:
+ case CS_SERVER_KEY_EXCHANGE:
+ {
+ if (this.mConnectionState != CS_SERVER_KEY_EXCHANGE)
+ {
+ // There was no server key exchange message; check it's OK
+ this.mKeyExchange.SkipServerKeyExchange();
+ }
+
+ if (this.mAuthentication == null)
+ {
+ /*
+ * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server
+ * to request client identification.
+ */
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ this.mCertificateRequest = CertificateRequest.Parse(Context, buf);
+
+ AssertEmpty(buf);
+
+ this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);
+
+ /*
+ * TODO Give the client a chance to immediately select the CertificateVerify hash
+ * algorithm here to avoid tracking the other hash algorithms unnecessarily?
+ */
+ TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
+ this.mCertificateRequest.SupportedSignatureAlgorithms);
+
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_CERTIFICATE_REQUEST;
+ break;
+ }
+ case HandshakeType.session_ticket:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_FINISHED:
+ {
+ if (!this.mExpectSessionTicket)
+ {
+ /*
+ * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a
+ * SessionTicket extension in the ServerHello.
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ /*
+ * RFC 5077 3.4. If the client receives a session ticket from the server, then it
+ * discards any Session ID that was sent in the ServerHello.
+ */
+ InvalidateSession();
+
+ ReceiveNewSessionTicketMessage(buf);
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_SERVER_SESSION_TICKET;
+ break;
+ }
+ case HandshakeType.hello_request:
+ {
+ AssertEmpty(buf);
+
+ /*
+ * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the
+ * client is currently negotiating a session. This message may be ignored by the client
+ * if it does not wish to renegotiate a session, or the client may, if it wishes,
+ * respond with a no_renegotiation alert.
+ */
+ if (this.mConnectionState == CS_END)
+ {
+ RefuseRenegotiation();
+ }
+ break;
+ }
+ case HandshakeType.client_hello:
+ case HandshakeType.client_key_exchange:
+ case HandshakeType.certificate_verify:
+ case HandshakeType.hello_verify_request:
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ protected virtual void HandleSupplementalData(IList serverSupplementalData)
+ {
+ this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
+ this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
+
+ this.mKeyExchange = mTlsClient.GetKeyExchange();
+ this.mKeyExchange.Init(Context);
+ }
+
+ protected virtual void ReceiveNewSessionTicketMessage(MemoryStream buf)
+ {
+ NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
+
+ AssertEmpty(buf);
+
+ mTlsClient.NotifyNewSessionTicket(newSessionTicket);
+ }
+
+ protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
+ {
+ {
+ ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+ if (server_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ // Check that this matches what the server is Sending in the record layer
+ if (!server_version.Equals(this.mRecordStream.ReadVersion))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ ProtocolVersion client_version = Context.ClientVersion;
+ if (!server_version.IsEqualOrEarlierVersionOf(client_version))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ this.mRecordStream.SetWriteVersion(server_version);
+ ContextAdmin.SetServerVersion(server_version);
+ this.mTlsClient.NotifyServerVersion(server_version);
+ }
+
+ /*
+ * Read the server random
+ */
+ this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
+
+ this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
+ if (this.mSelectedSessionID.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
+ this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null
+ && Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);
+
+ /*
+ * Find out which CipherSuite the server has chosen and check that it was one of the offered
+ * ones, and is a valid selection for the negotiated version.
+ */
+ int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
+ if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+ || CipherSuite.IsScsv(selectedCipherSuite)
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
+
+ /*
+ * Find out which CompressionMethod the server has chosen and check that it was one of the
+ * offered ones.
+ */
+ byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
+ if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
+
+ /*
+ * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
+ * hello message when the client has requested extended functionality via the extended
+ * client hello message specified in Section 2.1. ... Note that the extended server hello
+ * message is only sent in response to an extended client hello message. This prevents the
+ * possibility that the extended server hello message could "break" existing TLS 1.0
+ * clients.
+ */
+ this.mServerExtensions = ReadExtensions(buf);
+
+ /*
+ * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
+ * extended client hello message.
+ *
+ * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server
+ * Hello is always allowed.
+ */
+ if (this.mServerExtensions != null)
+ {
+ foreach (int extType in this.mServerExtensions.Keys)
+ {
+ /*
+ * RFC 5746 3.6. Note that Sending a "renegotiation_info" extension in response to a
+ * ClientHello containing only the SCSV is an explicit exception to the prohibition
+ * in RFC 5246, Section 7.4.1.4, on the server Sending unsolicited extensions and is
+ * only allowed because the client is signaling its willingness to receive the
+ * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+ */
+ if (extType == ExtensionType.renegotiation_info)
+ continue;
+
+ /*
+ * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
+ * same extension type appeared in the corresponding ClientHello. If a client
+ * receives an extension type in ServerHello that it did not request in the
+ * associated ClientHello, it MUST abort the handshake with an unsupported_extension
+ * fatal alert.
+ */
+ if (null == TlsUtilities.GetExtensionData(this.mClientExtensions, extType))
+ throw new TlsFatalAlert(AlertDescription.unsupported_extension);
+
+ /*
+ * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and Send a server hello containing no
+ * extensions[.]
+ */
+ if (this.mResumedSession)
+ {
+ // TODO[compat-gnutls] GnuTLS test server Sends server extensions e.g. ec_point_formats
+ // TODO[compat-openssl] OpenSSL test server Sends server extensions e.g. ec_point_formats
+ // TODO[compat-polarssl] PolarSSL test server Sends server extensions e.g. ec_point_formats
+ // throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ /*
+ * RFC 5746 3.4. Client Behavior: Initial Handshake
+ */
+ {
+ /*
+ * When a ServerHello is received, the client MUST check if it includes the
+ * "renegotiation_info" extension:
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
+ if (renegExtData != null)
+ {
+ /*
+ * If the extension is present, set the secure_renegotiation flag to TRUE. The
+ * client MUST then verify that the length of the "renegotiated_connection"
+ * field is zero, and if it is not, MUST abort the handshake (by Sending a fatal
+ * handshake_failure alert).
+ */
+ this.mSecureRenegotiation = true;
+
+ if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming
+ this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation);
+
+ IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions;
+ if (this.mResumedSession)
+ {
+ if (selectedCipherSuite != this.mSessionParameters.CipherSuite
+ || selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ sessionClientExtensions = null;
+ sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
+ }
+
+ this.mSecurityParameters.cipherSuite = selectedCipherSuite;
+ this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+ if (sessionServerExtensions != null)
+ {
+ {
+ /*
+ * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
+ * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
+ * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
+ * client.
+ */
+ bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
+ if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
+ }
+
+ this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
+
+ this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
+ sessionServerExtensions, AlertDescription.illegal_parameter);
+
+ this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
+
+ /*
+ * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+ * a session resumption handshake.
+ */
+ this.mAllowCertificateStatus = !this.mResumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
+ AlertDescription.illegal_parameter);
+
+ this.mExpectSessionTicket = !this.mResumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
+ AlertDescription.illegal_parameter);
+ }
+
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
+ * that do not use the extended master secret [..]. (and see 5.2, 5.3)
+ */
+
+ if (sessionClientExtensions != null)
+ {
+ this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
+ }
+
+ this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite);
+
+ /*
+ * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
+ * verify_data_length has a verify_data_length equal to 12. This includes all
+ * existing cipher suites.
+ */
+ this.mSecurityParameters.verifyDataLength = 12;
+ }
+
+ protected virtual void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_verify);
+
+ certificateVerify.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendClientHelloMessage()
+ {
+ this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion);
+
+ ProtocolVersion client_version = this.mTlsClient.ClientVersion;
+ if (client_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ContextAdmin.SetClientVersion(client_version);
+
+ /*
+ * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
+ * Session ID in the TLS ClientHello.
+ */
+ byte[] session_id = TlsUtilities.EmptyBytes;
+ if (this.mTlsSession != null)
+ {
+ session_id = this.mTlsSession.SessionID;
+ if (session_id == null || session_id.Length > 32)
+ {
+ session_id = TlsUtilities.EmptyBytes;
+ }
+ }
+
+ bool fallback = this.mTlsClient.IsFallback;
+
+ this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();
+
+ this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();
+
+ if (session_id.Length > 0 && this.mSessionParameters != null)
+ {
+ if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite)
+ || !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
+ {
+ session_id = TlsUtilities.EmptyBytes;
+ }
+ }
+
+ this.mClientExtensions = this.mTlsClient.GetClientExtensions();
+
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
+
+ TlsUtilities.WriteVersion(client_version, message);
+
+ message.Write(this.mSecurityParameters.ClientRandom);
+
+ TlsUtilities.WriteOpaque8(session_id, message);
+
+ // Cipher Suites (and SCSV)
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+ * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+ * ClientHello. Including both is NOT RECOMMENDED.
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
+ bool noRenegExt = (null == renegExtData);
+
+ bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+
+ if (noRenegExt && noRenegScsv)
+ {
+ // TODO Consider whether to default to a client extension instead
+ // this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions);
+ // this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
+ this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+ }
+
+ /*
+ * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version
+ * containing a lower value than the latest (highest-valued) version supported by the
+ * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in
+ * ClientHello.cipher_suites.
+ */
+ if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
+ {
+ this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
+ }
+
+ TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
+ }
+
+ TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);
+
+ if (mClientExtensions != null)
+ {
+ WriteExtensions(message, mClientExtensions);
+ }
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendClientKeyExchangeMessage()
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.client_key_exchange);
+
+ this.mKeyExchange.GenerateClientKeyExchange(message);
+
+ message.WriteToRecordStream(this);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsContext.cs b/crypto/src/crypto/tls/TlsContext.cs
new file mode 100644
index 000000000..d066723fc
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsContext.cs
@@ -0,0 +1,45 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsContext
+ {
+ IRandomGenerator NonceRandomGenerator { get; }
+
+ SecureRandom SecureRandom { get; }
+
+ SecurityParameters SecurityParameters { get; }
+
+ bool IsServer { get; }
+
+ ProtocolVersion ClientVersion { get; }
+
+ ProtocolVersion ServerVersion { get; }
+
+ /**
+ * Used to get the resumable session, if any, used by this connection. Only available after the
+ * handshake has successfully completed.
+ *
+ * @return A {@link TlsSession} representing the resumable session used by this connection, or
+ * null if no resumable session available.
+ * @see TlsPeer#NotifyHandshakeComplete()
+ */
+ TlsSession ResumableSession { get; }
+
+ object UserObject { get; set; }
+
+ /**
+ * Export keying material according to RFC 5705: "Keying Material Exporters for TLS".
+ *
+ * @param asciiLabel indicates which application will use the exported keys.
+ * @param context_value allows the application using the exporter to mix its own data with the TLS PRF for
+ * the exporter output.
+ * @param length the number of bytes to generate
+ * @return a pseudorandom bit string of 'length' bytes generated from the master_secret.
+ */
+ byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length);
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
index 26d76fd3d..93ef1fa4a 100644
--- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -1,86 +1,98 @@
using System;
+using System.Collections;
using System.IO;
-using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Tls
{
- /// <summary>
- /// TLS 1.0 DH key exchange.
- /// </summary>
- internal class TlsDHKeyExchange
- : TlsKeyExchange
+ /// <summary>(D)TLS DH key exchange.</summary>
+ public class TlsDHKeyExchange
+ : AbstractTlsKeyExchange
{
- protected TlsClientContext context;
- protected int keyExchange;
- protected TlsSigner tlsSigner;
+ protected TlsSigner mTlsSigner;
+ protected DHParameters mDHParameters;
- protected AsymmetricKeyParameter serverPublicKey = null;
- protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
- protected TlsAgreementCredentials agreementCredentials;
- protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
+ protected AsymmetricKeyParameter mServerPublicKey;
+ protected TlsAgreementCredentials mAgreementCredentials;
- internal TlsDHKeyExchange(TlsClientContext context, int keyExchange)
+ protected DHPrivateKeyParameters mDHAgreePrivateKey;
+ protected DHPublicKeyParameters mDHAgreePublicKey;
+
+ public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
+ : base(keyExchange, supportedSignatureAlgorithms)
{
switch (keyExchange)
{
- case KeyExchangeAlgorithm.DH_RSA:
- case KeyExchangeAlgorithm.DH_DSS:
- this.tlsSigner = null;
- break;
- case KeyExchangeAlgorithm.DHE_RSA:
- this.tlsSigner = new TlsRsaSigner();
- break;
- case KeyExchangeAlgorithm.DHE_DSS:
- this.tlsSigner = new TlsDssSigner();
- break;
- default:
- throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
+ case KeyExchangeAlgorithm.DH_RSA:
+ case KeyExchangeAlgorithm.DH_DSS:
+ this.mTlsSigner = null;
+ break;
+ case KeyExchangeAlgorithm.DHE_RSA:
+ this.mTlsSigner = new TlsRsaSigner();
+ break;
+ case KeyExchangeAlgorithm.DHE_DSS:
+ this.mTlsSigner = new TlsDssSigner();
+ break;
+ default:
+ throw new InvalidOperationException("unsupported key exchange algorithm");
}
- this.context = context;
- this.keyExchange = keyExchange;
+ this.mDHParameters = dhParameters;
+ }
+
+ public override void Init(TlsContext context)
+ {
+ base.Init(context);
+
+ if (this.mTlsSigner != null)
+ {
+ this.mTlsSigner.Init(context);
+ }
}
- public virtual void SkipServerCertificate()
+ public override void SkipServerCredentials()
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
- public virtual void ProcessServerCertificate(Certificate serverCertificate)
+ public override void ProcessServerCertificate(Certificate serverCertificate)
{
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
- SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
try
{
- this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
}
- catch (Exception)
+ catch (Exception e)
{
- throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
}
- if (tlsSigner == null)
+ if (mTlsSigner == null)
{
try
{
- this.dhAgreeServerPublicKey = ValidateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey);
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey((DHPublicKeyParameters)this.mServerPublicKey);
+ this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters);
}
- catch (InvalidCastException)
+ catch (InvalidCastException e)
{
- throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
}
TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
}
else
{
- if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
+ if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
{
throw new TlsFatalAlert(AlertDescription.certificate_unknown);
}
@@ -88,55 +100,51 @@ namespace Org.BouncyCastle.Crypto.Tls
TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
}
- // TODO
- /*
- * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
- * signing algorithm for the certificate must be the same as the algorithm for the
- * certificate key."
- */
+ base.ProcessServerCertificate(serverCertificate);
}
- public virtual void SkipServerKeyExchange()
+ public override bool RequiresServerKeyExchange
{
- // OK
- }
-
- public virtual void ProcessServerKeyExchange(Stream input)
- {
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ get
+ {
+ switch (mKeyExchange)
+ {
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ case KeyExchangeAlgorithm.DH_anon:
+ return true;
+ default:
+ return false;
+ }
+ }
}
- public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
{
byte[] types = certificateRequest.CertificateTypes;
- foreach (byte type in types)
+ for (int i = 0; i < types.Length; ++i)
{
- switch (type)
+ switch (types[i])
{
- case ClientCertificateType.rsa_sign:
- case ClientCertificateType.dss_sign:
- case ClientCertificateType.rsa_fixed_dh:
- case ClientCertificateType.dss_fixed_dh:
- case ClientCertificateType.ecdsa_sign:
- break;
- default:
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.rsa_fixed_dh:
+ case ClientCertificateType.dss_fixed_dh:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
}
}
- public virtual void SkipClientCredentials()
- {
- this.agreementCredentials = null;
- }
-
- public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
{
if (clientCredentials is TlsAgreementCredentials)
{
// TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
- this.agreementCredentials = (TlsAgreementCredentials)clientCredentials;
+ this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
}
else if (clientCredentials is TlsSignerCredentials)
{
@@ -148,54 +156,69 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
- public virtual void GenerateClientKeyExchange(Stream output)
+ public override void GenerateClientKeyExchange(Stream output)
{
/*
- * RFC 2246 7.4.7.2 If the client certificate already contains a suitable
- * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In
- * this case, the Client Key Exchange message will be sent, but will be empty.
+ * RFC 2246 7.4.7.2 If the client certificate already contains a suitable Diffie-Hellman
+ * key, then Yc is implicit and does not need to be sent again. In this case, the Client Key
+ * Exchange message will be sent, but will be empty.
*/
- if (agreementCredentials == null)
+ if (mAgreementCredentials == null)
{
- GenerateEphemeralClientKeyExchange(dhAgreeServerPublicKey.Parameters, output);
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mDHParameters, output);
}
}
- public virtual byte[] GeneratePremasterSecret()
+ public override void ProcessClientCertificate(Certificate clientCertificate)
{
- if (agreementCredentials != null)
- {
- return agreementCredentials.GenerateAgreement(dhAgreeServerPublicKey);
- }
+ // TODO Extract the public key and validate
- return CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
- }
-
- protected virtual bool AreCompatibleParameters(DHParameters a, DHParameters b)
- {
- return a.P.Equals(b.P) && a.G.Equals(b.G);
+ /*
+ * TODO If the certificate is 'fixed', take the public key as dhAgreePublicKey and check
+ * that the parameters match the server's (see 'areCompatibleParameters').
+ */
}
- protected virtual byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
- DHPrivateKeyParameters privateKey)
+ public override void ProcessClientKeyExchange(Stream input)
{
- return TlsDHUtilities.CalculateDHBasicAgreement(publicKey, privateKey);
+ if (mDHAgreePublicKey != null)
+ {
+ // For dss_fixed_dh and rsa_fixed_dh, the key arrived in the client certificate
+ return;
+ }
+
+ BigInteger Yc = TlsDHUtilities.ReadDHParameter(input);
+
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters));
}
- protected virtual AsymmetricCipherKeyPair GenerateDHKeyPair(DHParameters dhParams)
+ public override byte[] GeneratePremasterSecret()
{
- return TlsDHUtilities.GenerateDHKeyPair(context.SecureRandom, dhParams);
+ if (mAgreementCredentials != null)
+ {
+ return mAgreementCredentials.GenerateAgreement(mDHAgreePublicKey);
+ }
+
+ if (mDHAgreePrivateKey != null)
+ {
+ return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey);
+ }
+
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
- protected virtual void GenerateEphemeralClientKeyExchange(DHParameters dhParams, Stream output)
+ protected virtual int MinimumPrimeBits
{
- this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(
- context.SecureRandom, dhParams, output);
+ get { return 1024; }
}
- protected virtual DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
+ protected virtual DHParameters ValidateDHParameters(DHParameters parameters)
{
- return TlsDHUtilities.ValidateDHPublicKey(key);
+ if (parameters.P.BitLength < MinimumPrimeBits)
+ throw new TlsFatalAlert(AlertDescription.insufficient_security);
+
+ return TlsDHUtilities.ValidateDHParameters(parameters);
}
}
}
diff --git a/crypto/src/crypto/tls/TlsDHUtilities.cs b/crypto/src/crypto/tls/TlsDHUtilities.cs
index b5deb8b84..727587135 100644
--- a/crypto/src/crypto/tls/TlsDHUtilities.cs
+++ b/crypto/src/crypto/tls/TlsDHUtilities.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.IO;
using Org.BouncyCastle.Crypto.Agreement;
@@ -7,11 +8,391 @@ using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Crypto.Tls
{
public abstract class TlsDHUtilities
{
+ internal static readonly BigInteger Two = BigInteger.Two;
+
+ /*
+ * TODO[draft-ietf-tls-negotiated-ff-dhe-01] Move these groups to DHStandardGroups once reaches RFC
+ */
+ private static BigInteger FromHex(String hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ private static DHParameters FromSafeP(String hexP)
+ {
+ BigInteger p = FromHex(hexP), q = p.ShiftRight(1);
+ return new DHParameters(p, Two, q);
+ }
+
+ private static readonly string draft_ffdhe2432_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE13098533C8B3FFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe2432 = FromSafeP(draft_ffdhe2432_p);
+
+ private static readonly string draft_ffdhe3072_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D"
+ + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe3072 = FromSafeP(draft_ffdhe3072_p);
+
+ private static readonly string draft_ffdhe4096_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D"
+ + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB"
+ + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832"
+ + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF"
+ + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A"
+ + "FFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe4096 = FromSafeP(draft_ffdhe4096_p);
+
+ private static readonly string draft_ffdhe6144_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D"
+ + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB"
+ + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832"
+ + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF"
+ + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902"
+ + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6"
+ + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A"
+ + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477"
+ + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3"
+ + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4"
+ + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6"
+ + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C"
+ + "D72B03746AE77F5E62292C311562A846505DC82DB854338A"
+ + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04"
+ + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1"
+ + "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe6144 = FromSafeP(draft_ffdhe6144_p);
+
+ private static readonly string draft_ffdhe8192_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D"
+ + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB"
+ + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832"
+ + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF"
+ + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902"
+ + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6"
+ + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A"
+ + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477"
+ + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3"
+ + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4"
+ + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6"
+ + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C"
+ + "D72B03746AE77F5E62292C311562A846505DC82DB854338A"
+ + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04"
+ + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1"
+ + "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838"
+ + "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E"
+ + "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665"
+ + "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282"
+ + "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022"
+ + "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C"
+ + "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9"
+ + "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457"
+ + "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30"
+ + "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D"
+ + "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C"
+ + "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe8192 = FromSafeP(draft_ffdhe8192_p);
+
+
+ public static void AddNegotiatedDheGroupsClientExtension(IDictionary extensions, byte[] dheGroups)
+ {
+ extensions[ExtensionType.negotiated_ff_dhe_groups] = CreateNegotiatedDheGroupsClientExtension(dheGroups);
+ }
+
+ public static void AddNegotiatedDheGroupsServerExtension(IDictionary extensions, byte dheGroup)
+ {
+ extensions[ExtensionType.negotiated_ff_dhe_groups] = CreateNegotiatedDheGroupsServerExtension(dheGroup);
+ }
+
+ public static byte[] GetNegotiatedDheGroupsClientExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups);
+ return extensionData == null ? null : ReadNegotiatedDheGroupsClientExtension(extensionData);
+ }
+
+ public static short GetNegotiatedDheGroupsServerExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups);
+ return extensionData == null ? (short)-1 : (short)ReadNegotiatedDheGroupsServerExtension(extensionData);
+ }
+
+ public static byte[] CreateNegotiatedDheGroupsClientExtension(byte[] dheGroups)
+ {
+ if (dheGroups == null || dheGroups.Length < 1 || dheGroups.Length > 255)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return TlsUtilities.EncodeUint8ArrayWithUint8Length(dheGroups);
+ }
+
+ public static byte[] CreateNegotiatedDheGroupsServerExtension(byte dheGroup)
+ {
+ return new byte[]{ dheGroup };
+ }
+
+ public static byte[] ReadNegotiatedDheGroupsClientExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ byte length = TlsUtilities.ReadUint8(buf);
+ if (length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] dheGroups = TlsUtilities.ReadUint8Array(length, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return dheGroups;
+ }
+
+ public static byte ReadNegotiatedDheGroupsServerExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ if (extensionData.Length != 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ return extensionData[0];
+ }
+
+ public static DHParameters GetParametersForDHEGroup(short dheGroup)
+ {
+ switch (dheGroup)
+ {
+ case FiniteFieldDheGroup.ffdhe2432:
+ return draft_ffdhe2432;
+ case FiniteFieldDheGroup.ffdhe3072:
+ return draft_ffdhe3072;
+ case FiniteFieldDheGroup.ffdhe4096:
+ return draft_ffdhe4096;
+ case FiniteFieldDheGroup.ffdhe6144:
+ return draft_ffdhe6144;
+ case FiniteFieldDheGroup.ffdhe8192:
+ return draft_ffdhe8192;
+ default:
+ return null;
+ }
+ }
+
+ public static bool ContainsDheCipherSuites(int[] cipherSuites)
+ {
+ for (int i = 0; i < cipherSuites.Length; ++i)
+ {
+ if (IsDheCipherSuite(cipherSuites[i]))
+ return true;
+ }
+ return false;
+ }
+
+ public static bool IsDheCipherSuite(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ /*
+ * RFC 2246
+ */
+ case CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+
+ /*
+ * RFC 3268
+ */
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+
+ /*
+ * RFC 5932
+ */
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+
+ /*
+ * RFC 4162
+ */
+ case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+
+ /*
+ * RFC 4279
+ */
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+
+ /*
+ * RFC 4785
+ */
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+
+ /*
+ * RFC 5246
+ */
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+
+ /*
+ * RFC 5288
+ */
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+
+ /*
+ * RFC 5487
+ */
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+
+ /*
+ * RFC 6367
+ */
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+
+ /*
+ * RFC 6655
+ */
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+
+ /*
+ * draft-agl-tls-chacha20poly1305-04
+ */
+ case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+
+ /*
+ * draft-josefsson-salsa20-tls-04
+ */
+ case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ public static bool AreCompatibleParameters(DHParameters a, DHParameters b)
+ {
+ return a.P.Equals(b.P) && a.G.Equals(b.G);
+ }
+
public static byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
DHPrivateKeyParameters privateKey)
{
@@ -36,40 +417,60 @@ namespace Org.BouncyCastle.Crypto.Tls
public static DHPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random,
DHParameters dhParams, Stream output)
{
- AsymmetricCipherKeyPair dhAgreeClientKeyPair = GenerateDHKeyPair(random, dhParams);
- DHPrivateKeyParameters dhAgreeClientPrivateKey =
- (DHPrivateKeyParameters)dhAgreeClientKeyPair.Private;
+ AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams);
- BigInteger Yc = ((DHPublicKeyParameters)dhAgreeClientKeyPair.Public).Y;
- byte[] keData = BigIntegers.AsUnsignedByteArray(Yc);
- TlsUtilities.WriteOpaque16(keData, output);
+ DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public;
+ WriteDHParameter(dhPublic.Y, output);
- return dhAgreeClientPrivateKey;
+ return (DHPrivateKeyParameters)kp.Private;
}
-
- public static DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
+
+ public static DHPrivateKeyParameters GenerateEphemeralServerKeyExchange(SecureRandom random,
+ DHParameters dhParams, Stream output)
+ {
+ AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams);
+
+ DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public;
+ new ServerDHParams(dhPublic).Encode(output);
+
+ return (DHPrivateKeyParameters)kp.Private;
+ }
+
+ public static DHParameters ValidateDHParameters(DHParameters parameters)
{
- BigInteger Y = key.Y;
- DHParameters parameters = key.Parameters;
BigInteger p = parameters.P;
BigInteger g = parameters.G;
if (!p.IsProbablePrime(2))
- {
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- if (g.CompareTo(BigInteger.Two) < 0 || g.CompareTo(p.Subtract(BigInteger.Two)) > 0)
- {
+ if (g.CompareTo(Two) < 0 || g.CompareTo(p.Subtract(Two)) > 0)
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- if (Y.CompareTo(BigInteger.Two) < 0 || Y.CompareTo(p.Subtract(BigInteger.One)) > 0)
- {
+
+
+ return parameters;
+ }
+
+ public static DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
+ {
+ DHParameters parameters = ValidateDHParameters(key.Parameters);
+
+ BigInteger Y = key.Y;
+ if (Y.CompareTo(Two) < 0 || Y.CompareTo(parameters.P.Subtract(Two)) > 0)
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
// TODO See RFC 2631 for more discussion of Diffie-Hellman validation
return key;
}
+
+ public static BigInteger ReadDHParameter(Stream input)
+ {
+ return new BigInteger(1, TlsUtilities.ReadOpaque16(input));
+ }
+
+ public static void WriteDHParameter(BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/crypto/src/crypto/tls/TlsDheKeyExchange.cs b/crypto/src/crypto/tls/TlsDheKeyExchange.cs
index ee6d6eb44..9831e8cd7 100644
--- a/crypto/src/crypto/tls/TlsDheKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDheKeyExchange.cs
@@ -1,53 +1,91 @@
using System;
+using System.Collections;
using System.IO;
-using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- internal class TlsDheKeyExchange
- : TlsDHKeyExchange
+ public class TlsDheKeyExchange
+ : TlsDHKeyExchange
{
- internal TlsDheKeyExchange(TlsClientContext context, int keyExchange)
- : base(context, keyExchange)
+ protected TlsSignerCredentials mServerCredentials = null;
+
+ public TlsDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
+ : base(keyExchange, supportedSignatureAlgorithms, dhParameters)
{
}
- public override void SkipServerKeyExchange()
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
{
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (!(serverCredentials is TlsSignerCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsSignerCredentials)serverCredentials;
+ }
+
+ public override byte[] GenerateServerKeyExchange()
+ {
+ if (this.mDHParameters == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ DigestInputBuffer buf = new DigestInputBuffer();
+
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+ this.mDHParameters, buf);
+
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ mContext, mServerCredentials);
+
+ IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm);
+
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+ d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ buf.UpdateDigest(d);
+
+ byte[] hash = DigestUtilities.DoFinal(d);
+
+ byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);
+
+ DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ signed_params.Encode(buf);
+
+ return buf.ToArray();
}
public override void ProcessServerKeyExchange(Stream input)
{
- SecurityParameters securityParameters = context.SecurityParameters;
+ SecurityParameters securityParameters = mContext.SecurityParameters;
- ISigner signer = InitSigner(tlsSigner, securityParameters);
- Stream sigIn = new SignerStream(input, signer, null);
+ SignerInputBuffer buf = new SignerInputBuffer();
+ Stream teeIn = new TeeInputStream(input, buf);
- byte[] pBytes = TlsUtilities.ReadOpaque16(sigIn);
- byte[] gBytes = TlsUtilities.ReadOpaque16(sigIn);
- byte[] YsBytes = TlsUtilities.ReadOpaque16(sigIn);
+ ServerDHParams dhParams = ServerDHParams.Parse(teeIn);
- byte[] sigByte = TlsUtilities.ReadOpaque16(input);
- if (!signer.VerifySignature(sigByte))
- {
- throw new TlsFatalAlert(AlertDescription.decrypt_error);
- }
+ DigitallySigned signed_params = DigitallySigned.Parse(mContext, input);
- BigInteger p = new BigInteger(1, pBytes);
- BigInteger g = new BigInteger(1, gBytes);
- BigInteger Ys = new BigInteger(1, YsBytes);
+ ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+ buf.UpdateSigner(signer);
+ if (!signer.VerifySignature(signed_params.Signature))
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
- this.dhAgreeServerPublicKey = ValidateDHPublicKey(
- new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey);
+ this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters);
}
- protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
+ protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+ SecurityParameters securityParameters)
{
- ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey);
+ ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
return signer;
diff --git a/crypto/src/crypto/tls/TlsDsaSigner.cs b/crypto/src/crypto/tls/TlsDsaSigner.cs
index bba114e90..f0c1e9451 100644
--- a/crypto/src/crypto/tls/TlsDsaSigner.cs
+++ b/crypto/src/crypto/tls/TlsDsaSigner.cs
@@ -7,45 +7,76 @@ using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Tls
{
- internal abstract class TlsDsaSigner
- : TlsSigner
+ public abstract class TlsDsaSigner
+ : AbstractTlsSigner
{
- public virtual byte[] GenerateRawSignature(SecureRandom random,
- AsymmetricKeyParameter privateKey, byte[] md5andsha1)
+ public override byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+ AsymmetricKeyParameter privateKey, byte[] hash)
{
- ISigner s = MakeSigner(new NullDigest(), true, new ParametersWithRandom(privateKey, random));
- // Note: Only use the SHA1 part of the hash
- s.BlockUpdate(md5andsha1, 16, 20);
- return s.GenerateSignature();
+ ISigner signer = MakeSigner(algorithm, true, true,
+ new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
+ if (algorithm == null)
+ {
+ // Note: Only use the SHA1 part of the (MD5/SHA1) hash
+ signer.BlockUpdate(hash, 16, 20);
+ }
+ else
+ {
+ signer.BlockUpdate(hash, 0, hash.Length);
+ }
+ return signer.GenerateSignature();
}
- public bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5andsha1)
+ public override bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+ AsymmetricKeyParameter publicKey, byte[] hash)
{
- ISigner s = MakeSigner(new NullDigest(), false, publicKey);
- // Note: Only use the SHA1 part of the hash
- s.BlockUpdate(md5andsha1, 16, 20);
- return s.VerifySignature(sigBytes);
+ ISigner signer = MakeSigner(algorithm, true, false, publicKey);
+ if (algorithm == null)
+ {
+ // Note: Only use the SHA1 part of the (MD5/SHA1) hash
+ signer.BlockUpdate(hash, 16, 20);
+ }
+ else
+ {
+ signer.BlockUpdate(hash, 0, hash.Length);
+ }
+ return signer.VerifySignature(sigBytes);
}
- public virtual ISigner CreateSigner(SecureRandom random, AsymmetricKeyParameter privateKey)
+ public override ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey)
{
- return MakeSigner(new Sha1Digest(), true, new ParametersWithRandom(privateKey, random));
+ return MakeSigner(algorithm, false, true, privateKey);
}
- public virtual ISigner CreateVerifyer(AsymmetricKeyParameter publicKey)
+ public override ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey)
{
- return MakeSigner(new Sha1Digest(), false, publicKey);
+ return MakeSigner(algorithm, false, false, publicKey);
}
- public abstract bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
+ protected virtual ICipherParameters MakeInitParameters(bool forSigning, ICipherParameters cp)
+ {
+ return cp;
+ }
- protected virtual ISigner MakeSigner(IDigest d, bool forSigning, ICipherParameters cp)
+ protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning,
+ ICipherParameters cp)
{
- ISigner s = new DsaDigestSigner(CreateDsaImpl(), d);
- s.Init(forSigning, cp);
+ if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
+ throw new InvalidOperationException();
+
+ if (algorithm != null && algorithm.Signature != SignatureAlgorithm)
+ throw new InvalidOperationException();
+
+ byte hashAlgorithm = algorithm == null ? HashAlgorithm.sha1 : algorithm.Hash;
+ IDigest d = raw ? new NullDigest() : TlsUtilities.CreateHash(hashAlgorithm);
+
+ ISigner s = new DsaDigestSigner(CreateDsaImpl(hashAlgorithm), d);
+ s.Init(forSigning, MakeInitParameters(forSigning, cp));
return s;
}
- protected abstract IDsa CreateDsaImpl();
+ protected abstract byte SignatureAlgorithm { get; }
+
+ protected abstract IDsa CreateDsaImpl(byte hashAlgorithm);
}
}
diff --git a/crypto/src/crypto/tls/TlsDssSigner.cs b/crypto/src/crypto/tls/TlsDssSigner.cs
index c6f1abcec..707ef3853 100644
--- a/crypto/src/crypto/tls/TlsDssSigner.cs
+++ b/crypto/src/crypto/tls/TlsDssSigner.cs
@@ -5,17 +5,22 @@ using Org.BouncyCastle.Crypto.Signers;
namespace Org.BouncyCastle.Crypto.Tls
{
- internal class TlsDssSigner
- : TlsDsaSigner
- {
- public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
- {
- return publicKey is DsaPublicKeyParameters;
- }
+ public class TlsDssSigner
+ : TlsDsaSigner
+ {
+ public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+ {
+ return publicKey is DsaPublicKeyParameters;
+ }
- protected override IDsa CreateDsaImpl()
- {
- return new DsaSigner();
- }
- }
+ protected override IDsa CreateDsaImpl(byte hashAlgorithm)
+ {
+ return new DsaSigner(new HMacDsaKCalculator(TlsUtilities.CreateHash(hashAlgorithm)));
+ }
+
+ protected override byte SignatureAlgorithm
+ {
+ get { return Tls.SignatureAlgorithm.dsa; }
+ }
+ }
}
diff --git a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
index 65d07a10c..992be4aca 100644
--- a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
@@ -3,149 +3,154 @@ using System.Collections;
using System.IO;
using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto.Agreement;
-using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
- /**
- * ECDH key exchange (see RFC 4492)
- */
- internal class TlsECDHKeyExchange
- : TlsKeyExchange
+ /// <summary>(D)TLS ECDH key exchange (see RFC 4492).</summary>
+ public class TlsECDHKeyExchange
+ : AbstractTlsKeyExchange
{
- protected TlsClientContext context;
- protected int keyExchange;
- protected TlsSigner tlsSigner;
+ protected TlsSigner mTlsSigner;
+ protected int[] mNamedCurves;
+ protected byte[] mClientECPointFormats, mServerECPointFormats;
- protected AsymmetricKeyParameter serverPublicKey;
- protected ECPublicKeyParameters ecAgreeServerPublicKey;
- protected TlsAgreementCredentials agreementCredentials;
- protected ECPrivateKeyParameters ecAgreeClientPrivateKey = null;
+ protected AsymmetricKeyParameter mServerPublicKey;
+ protected TlsAgreementCredentials mAgreementCredentials;
- internal TlsECDHKeyExchange(TlsClientContext context, int keyExchange)
+ protected ECPrivateKeyParameters mECAgreePrivateKey;
+ protected ECPublicKeyParameters mECAgreePublicKey;
+
+ public TlsECDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves,
+ byte[] clientECPointFormats, byte[] serverECPointFormats)
+ : base(keyExchange, supportedSignatureAlgorithms)
{
switch (keyExchange)
{
- case KeyExchangeAlgorithm.ECDHE_RSA:
- this.tlsSigner = new TlsRsaSigner();
- break;
- case KeyExchangeAlgorithm.ECDHE_ECDSA:
- this.tlsSigner = new TlsECDsaSigner();
- break;
- case KeyExchangeAlgorithm.ECDH_RSA:
- case KeyExchangeAlgorithm.ECDH_ECDSA:
- this.tlsSigner = null;
- break;
- default:
- throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ this.mTlsSigner = new TlsRsaSigner();
+ break;
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ this.mTlsSigner = new TlsECDsaSigner();
+ break;
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ this.mTlsSigner = null;
+ break;
+ default:
+ throw new InvalidOperationException("unsupported key exchange algorithm");
}
- this.context = context;
- this.keyExchange = keyExchange;
+ this.mNamedCurves = namedCurves;
+ this.mClientECPointFormats = clientECPointFormats;
+ this.mServerECPointFormats = serverECPointFormats;
}
- public virtual void SkipServerCertificate()
+ public override void Init(TlsContext context)
+ {
+ base.Init(context);
+
+ if (this.mTlsSigner != null)
+ {
+ this.mTlsSigner.Init(context);
+ }
+ }
+
+ public override void SkipServerCredentials()
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
- public virtual void ProcessServerCertificate(Certificate serverCertificate)
+ public override void ProcessServerCertificate(Certificate serverCertificate)
{
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
- SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
try
{
- this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
}
- catch (Exception)
+ catch (Exception e)
{
- throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
}
- if (tlsSigner == null)
+ if (mTlsSigner == null)
{
try
{
- this.ecAgreeServerPublicKey = ValidateECPublicKey((ECPublicKeyParameters)this.serverPublicKey);
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey((ECPublicKeyParameters) this.mServerPublicKey);
}
- catch (InvalidCastException)
+ catch (InvalidCastException e)
{
- throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
}
TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
}
else
{
- if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
- {
+ if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
throw new TlsFatalAlert(AlertDescription.certificate_unknown);
- }
TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
}
-
- // TODO
- /*
- * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
- * signing algorithm for the certificate must be the same as the algorithm for the
- * certificate key."
- */
- }
-
- public virtual void SkipServerKeyExchange()
- {
- // do nothing
+
+ base.ProcessServerCertificate(serverCertificate);
}
- public virtual void ProcessServerKeyExchange(Stream input)
+ public override bool RequiresServerKeyExchange
{
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ get
+ {
+ switch (mKeyExchange)
+ {
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ case KeyExchangeAlgorithm.ECDH_anon:
+ return true;
+ default:
+ return false;
+ }
+ }
}
- public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
{
/*
- * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable
- * with ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is
- * prohibited because the use of a long-term ECDH client key would jeopardize the
- * forward secrecy property of these algorithms.
+ * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
+ * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
+ * the use of a long-term ECDH client key would jeopardize the forward secrecy property of
+ * these algorithms.
*/
byte[] types = certificateRequest.CertificateTypes;
- foreach (byte type in types)
+ for (int i = 0; i < types.Length; ++i)
{
- switch (type)
+ switch (types[i])
{
- case ClientCertificateType.rsa_sign:
- case ClientCertificateType.dss_sign:
- case ClientCertificateType.ecdsa_sign:
- case ClientCertificateType.rsa_fixed_ecdh:
- case ClientCertificateType.ecdsa_fixed_ecdh:
- break;
- default:
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ case ClientCertificateType.rsa_fixed_ecdh:
+ case ClientCertificateType.ecdsa_fixed_ecdh:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
}
}
- public virtual void SkipClientCredentials()
- {
- this.agreementCredentials = null;
- }
-
- public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
{
if (clientCredentials is TlsAgreementCredentials)
{
- // TODO Validate client cert has matching parameters (see 'AreOnSameCurve')?
+ // TODO Validate client cert has matching parameters (see 'TlsEccUtilities.AreOnSameCurve')?
- this.agreementCredentials = (TlsAgreementCredentials)clientCredentials;
+ this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
}
else if (clientCredentials is TlsSignerCredentials)
{
@@ -157,80 +162,50 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
- public virtual void GenerateClientKeyExchange(Stream output)
+ public override void GenerateClientKeyExchange(Stream output)
{
- if (agreementCredentials == null)
+ if (mAgreementCredentials == null)
{
- GenerateEphemeralClientKeyExchange(ecAgreeServerPublicKey.Parameters, output);
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mServerECPointFormats, mECAgreePublicKey.Parameters, output);
}
}
- public virtual byte[] GeneratePremasterSecret()
+ public override void ProcessClientCertificate(Certificate clientCertificate)
{
- if (agreementCredentials != null)
- {
- return agreementCredentials.GenerateAgreement(ecAgreeServerPublicKey);
- }
-
- return CalculateECDHBasicAgreement(ecAgreeServerPublicKey, ecAgreeClientPrivateKey);
- }
-
- protected virtual bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
- {
- // TODO Move to ECDomainParameters.Equals() or other utility method?
- return a.Curve.Equals(b.Curve) && a.G.Equals(b.G) && a.N.Equals(b.N) && a.H.Equals(b.H);
+ // TODO Extract the public key
+ // TODO If the certificate is 'fixed', take the public key as mECAgreeClientPublicKey
}
- protected virtual byte[] ExternalizeKey(ECPublicKeyParameters keyParameters)
+ public override void ProcessClientKeyExchange(Stream input)
{
- // TODO Add support for compressed encoding and SPF extension
-
- /*
- * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format.
- * Here, the format MUST conform to what the server has requested through a
- * Supported Point Formats Extension if this extension was used, and MUST be
- * uncompressed if this extension was not used.
- */
- return keyParameters.Q.GetEncoded();
- }
+ if (mECAgreePublicKey != null)
+ {
+ // For ecdsa_fixed_ecdh and rsa_fixed_ecdh, the key arrived in the client certificate
+ return;
+ }
- protected virtual AsymmetricCipherKeyPair GenerateECKeyPair(ECDomainParameters ecParams)
- {
- ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
- ECKeyGenerationParameters keyGenerationParameters = new ECKeyGenerationParameters(ecParams,
- context.SecureRandom);
- keyPairGenerator.Init(keyGenerationParameters);
- return keyPairGenerator.GenerateKeyPair();
- }
+ byte[] point = TlsUtilities.ReadOpaque8(input);
- protected virtual void GenerateEphemeralClientKeyExchange(ECDomainParameters ecParams, Stream output)
- {
- AsymmetricCipherKeyPair ecAgreeClientKeyPair = GenerateECKeyPair(ecParams);
- this.ecAgreeClientPrivateKey = (ECPrivateKeyParameters)ecAgreeClientKeyPair.Private;
+ ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;
- byte[] keData = ExternalizeKey((ECPublicKeyParameters)ecAgreeClientKeyPair.Public);
- TlsUtilities.WriteOpaque8(keData, output);
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mServerECPointFormats, curve_params, point));
}
- protected virtual byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey,
- ECPrivateKeyParameters privateKey)
+ public override byte[] GeneratePremasterSecret()
{
- ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
- basicAgreement.Init(privateKey);
- BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
+ if (mAgreementCredentials != null)
+ {
+ return mAgreementCredentials.GenerateAgreement(mECAgreePublicKey);
+ }
- /*
- * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by
- * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for
- * any given field; leading zeros found in this octet string MUST NOT be truncated.
- */
- return BigIntegers.AsUnsignedByteArray(basicAgreement.GetFieldSize(), agreementValue);
- }
+ if (mECAgreePrivateKey != null)
+ {
+ return TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey);
+ }
- protected virtual ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
- {
- // TODO Check RFC 4492 for validation
- return key;
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
}
diff --git a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
index a671ebfbe..b681aada3 100644
--- a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
@@ -2,91 +2,111 @@ using System;
using System.Collections;
using System.IO;
-using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- /**
- * ECDHE key exchange (see RFC 4492)
- */
- internal class TlsECDheKeyExchange : TlsECDHKeyExchange
+ /// <summary>(D)TLS ECDHE key exchange (see RFC 4492).</summary>
+ public class TlsECDheKeyExchange
+ : TlsECDHKeyExchange
{
- internal TlsECDheKeyExchange(TlsClientContext context, int keyExchange)
- : base(context, keyExchange)
+ protected TlsSignerCredentials mServerCredentials = null;
+
+ public TlsECDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves,
+ byte[] clientECPointFormats, byte[] serverECPointFormats)
+ : base(keyExchange, supportedSignatureAlgorithms, namedCurves, clientECPointFormats, serverECPointFormats)
{
}
- public override void SkipServerKeyExchange()
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
{
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (!(serverCredentials is TlsSignerCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsSignerCredentials)serverCredentials;
}
- public override void ProcessServerKeyExchange(Stream input)
+ public override byte[] GenerateServerKeyExchange()
{
- SecurityParameters securityParameters = context.SecurityParameters;
+ DigestInputBuffer buf = new DigestInputBuffer();
- ISigner signer = InitSigner(tlsSigner, securityParameters);
- Stream sigIn = new SignerStream(input, signer, null);
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves,
+ mClientECPointFormats, buf);
- byte curveType = TlsUtilities.ReadUint8(sigIn);
- ECDomainParameters curve_params;
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ mContext, mServerCredentials);
- // Currently, we only support named curves
- if (curveType == ECCurveType.named_curve)
- {
- int namedCurve = TlsUtilities.ReadUint16(sigIn);
+ IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm);
- // TODO Check namedCurve is one we offered?
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+ d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ buf.UpdateDigest(d);
- curve_params = NamedCurveHelper.GetECParameters(namedCurve);
- }
- else
- {
- // TODO Add support for explicit curve parameters (read from sigIn)
+ byte[] hash = DigestUtilities.DoFinal(d);
- throw new TlsFatalAlert(AlertDescription.handshake_failure);
- }
+ byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);
- byte[] publicBytes = TlsUtilities.ReadOpaque8(sigIn);
+ DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ signed_params.Encode(buf);
- byte[] sigByte = TlsUtilities.ReadOpaque16(input);
- if (!signer.VerifySignature(sigByte))
- {
- throw new TlsFatalAlert(AlertDescription.decrypt_error);
- }
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerKeyExchange(Stream input)
+ {
+ SecurityParameters securityParameters = mContext.SecurityParameters;
- // TODO Check curve_params not null
+ SignerInputBuffer buf = new SignerInputBuffer();
+ Stream teeIn = new TeeInputStream(input, buf);
- ECPoint Q = curve_params.Curve.DecodePoint(publicBytes);
+ ECDomainParameters curve_params = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, teeIn);
- this.ecAgreeServerPublicKey = ValidateECPublicKey(new ECPublicKeyParameters(Q, curve_params));
+ byte[] point = TlsUtilities.ReadOpaque8(teeIn);
+
+ DigitallySigned signed_params = DigitallySigned.Parse(mContext, input);
+
+ ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+ buf.UpdateSigner(signer);
+ if (!signer.VerifySignature(signed_params.Signature))
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mClientECPointFormats, curve_params, point));
}
-
+
public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
{
/*
- * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable
- * with ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is
- * prohibited because the use of a long-term ECDH client key would jeopardize the
- * forward secrecy property of these algorithms.
+ * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
+ * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
+ * the use of a long-term ECDH client key would jeopardize the forward secrecy property of
+ * these algorithms.
*/
byte[] types = certificateRequest.CertificateTypes;
- foreach (byte type in types)
+ for (int i = 0; i < types.Length; ++i)
{
- switch (type)
+ switch (types[i])
{
- case ClientCertificateType.rsa_sign:
- case ClientCertificateType.dss_sign:
- case ClientCertificateType.ecdsa_sign:
- break;
- default:
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
}
}
-
+
public override void ProcessClientCredentials(TlsCredentials clientCredentials)
{
if (clientCredentials is TlsSignerCredentials)
@@ -99,9 +119,10 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
- protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
+ protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+ SecurityParameters securityParameters)
{
- ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey);
+ ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
return signer;
diff --git a/crypto/src/crypto/tls/TlsECDsaSigner.cs b/crypto/src/crypto/tls/TlsECDsaSigner.cs
index 3c30fdc0c..fa9d0b714 100644
--- a/crypto/src/crypto/tls/TlsECDsaSigner.cs
+++ b/crypto/src/crypto/tls/TlsECDsaSigner.cs
@@ -5,17 +5,22 @@ using Org.BouncyCastle.Crypto.Signers;
namespace Org.BouncyCastle.Crypto.Tls
{
- internal class TlsECDsaSigner
- : TlsDsaSigner
- {
- public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
- {
- return publicKey is ECPublicKeyParameters;
- }
+ public class TlsECDsaSigner
+ : TlsDsaSigner
+ {
+ public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+ {
+ return publicKey is ECPublicKeyParameters;
+ }
- protected override IDsa CreateDsaImpl()
- {
- return new ECDsaSigner();
- }
- }
+ protected override IDsa CreateDsaImpl(byte hashAlgorithm)
+ {
+ return new ECDsaSigner(new HMacDsaKCalculator(TlsUtilities.CreateHash(hashAlgorithm)));
+ }
+
+ protected override byte SignatureAlgorithm
+ {
+ get { return Tls.SignatureAlgorithm.ecdsa; }
+ }
+ }
}
diff --git a/crypto/src/crypto/tls/TlsEccUtilities.cs b/crypto/src/crypto/tls/TlsEccUtilities.cs
new file mode 100644
index 000000000..d0d794d0e
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsEccUtilities.cs
@@ -0,0 +1,718 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.Field;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsEccUtilities
+ {
+ private static readonly string[] CurveNames = new string[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
+ "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1",
+ "sect571k1", "sect571r1", "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "secp224k1",
+ "secp224r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1",
+ "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"};
+
+ public static void AddSupportedEllipticCurvesExtension(IDictionary extensions, int[] namedCurves)
+ {
+ extensions[ExtensionType.elliptic_curves] = CreateSupportedEllipticCurvesExtension(namedCurves);
+ }
+
+ public static void AddSupportedPointFormatsExtension(IDictionary extensions, byte[] ecPointFormats)
+ {
+ extensions[ExtensionType.ec_point_formats] = CreateSupportedPointFormatsExtension(ecPointFormats);
+ }
+
+ public static int[] GetSupportedEllipticCurvesExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.elliptic_curves);
+ return extensionData == null ? null : ReadSupportedEllipticCurvesExtension(extensionData);
+ }
+
+ public static byte[] GetSupportedPointFormatsExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats);
+ return extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData);
+ }
+
+ public static byte[] CreateSupportedEllipticCurvesExtension(int[] namedCurves)
+ {
+ if (namedCurves == null || namedCurves.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return TlsUtilities.EncodeUint16ArrayWithUint16Length(namedCurves);
+ }
+
+ public static byte[] CreateSupportedPointFormatsExtension(byte[] ecPointFormats)
+ {
+ if (ecPointFormats == null || !Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
+ {
+ /*
+ * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
+ * contain the value 0 (uncompressed) as one of the items in the list of point formats.
+ */
+
+ // NOTE: We add it at the end (lowest preference)
+ ecPointFormats = Arrays.Append(ecPointFormats, ECPointFormat.uncompressed);
+ }
+
+ return TlsUtilities.EncodeUint8ArrayWithUint8Length(ecPointFormats);
+ }
+
+ public static int[] ReadSupportedEllipticCurvesExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ int length = TlsUtilities.ReadUint16(buf);
+ if (length < 2 || (length & 1) != 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int[] namedCurves = TlsUtilities.ReadUint16Array(length / 2, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return namedCurves;
+ }
+
+ public static byte[] ReadSupportedPointFormatsExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ byte length = TlsUtilities.ReadUint8(buf);
+ if (length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] ecPointFormats = TlsUtilities.ReadUint8Array(length, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ if (!Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
+ {
+ /*
+ * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
+ * contain the value 0 (uncompressed) as one of the items in the list of point formats.
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ return ecPointFormats;
+ }
+
+ public static string GetNameOfNamedCurve(int namedCurve)
+ {
+ return IsSupportedNamedCurve(namedCurve) ? CurveNames[namedCurve - 1] : null;
+ }
+
+ public static ECDomainParameters GetParametersForNamedCurve(int namedCurve)
+ {
+ string curveName = GetNameOfNamedCurve(namedCurve);
+ if (curveName == null)
+ return null;
+
+ // Parameters are lazily created the first time a particular curve is accessed
+
+ X9ECParameters ecP = CustomNamedCurves.GetByName(curveName);
+ if (ecP == null)
+ {
+ ecP = ECNamedCurveTable.GetByName(curveName);
+ if (ecP == null)
+ return null;
+ }
+
+ // It's a bit inefficient to do this conversion every time
+ return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
+ }
+
+ public static bool HasAnySupportedNamedCurves()
+ {
+ return CurveNames.Length > 0;
+ }
+
+ public static bool ContainsEccCipherSuites(int[] cipherSuites)
+ {
+ for (int i = 0; i < cipherSuites.Length; ++i)
+ {
+ if (IsEccCipherSuite(cipherSuites[i]))
+ return true;
+ }
+ return false;
+ }
+
+ public static bool IsEccCipherSuite(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ /*
+ * RFC 4492
+ */
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+
+ /*
+ * RFC 5289
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+
+ /*
+ * RFC 5489
+ */
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+
+ /*
+ * RFC 6367
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+
+ /*
+ * RFC 7251
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+
+ /*
+ * draft-agl-tls-chacha20poly1305-04
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+
+ /*
+ * draft-josefsson-salsa20-tls-04
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ public static bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
+ {
+ // TODO Move to ECDomainParameters.Equals() or other utility method?
+ return a.Curve.Equals(b.Curve) && a.G.Equals(b.G) && a.N.Equals(b.N) && a.H.Equals(b.H);
+ }
+
+ public static bool IsSupportedNamedCurve(int namedCurve)
+ {
+ return (namedCurve > 0 && namedCurve <= CurveNames.Length);
+ }
+
+ public static bool IsCompressionPreferred(byte[] ecPointFormats, byte compressionFormat)
+ {
+ if (ecPointFormats == null)
+ return false;
+
+ for (int i = 0; i < ecPointFormats.Length; ++i)
+ {
+ byte ecPointFormat = ecPointFormats[i];
+ if (ecPointFormat == ECPointFormat.uncompressed)
+ return false;
+ if (ecPointFormat == compressionFormat)
+ return true;
+ }
+ return false;
+ }
+
+ public static byte[] SerializeECFieldElement(int fieldSize, BigInteger x)
+ {
+ return BigIntegers.AsUnsignedByteArray((fieldSize + 7) / 8, x);
+ }
+
+ public static byte[] SerializeECPoint(byte[] ecPointFormats, ECPoint point)
+ {
+ ECCurve curve = point.Curve;
+
+ /*
+ * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format. Here, the
+ * format MUST conform to what the server has requested through a Supported Point Formats
+ * Extension if this extension was used, and MUST be uncompressed if this extension was not
+ * used.
+ */
+ bool compressed = false;
+ if (ECAlgorithms.IsFpCurve(curve))
+ {
+ compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_prime);
+ }
+ else if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_char2);
+ }
+ return point.GetEncoded(compressed);
+ }
+
+ public static byte[] SerializeECPublicKey(byte[] ecPointFormats, ECPublicKeyParameters keyParameters)
+ {
+ return SerializeECPoint(ecPointFormats, keyParameters.Q);
+ }
+
+ public static BigInteger DeserializeECFieldElement(int fieldSize, byte[] encoding)
+ {
+ int requiredLength = (fieldSize + 7) / 8;
+ if (encoding.Length != requiredLength)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ return new BigInteger(1, encoding);
+ }
+
+ public static ECPoint DeserializeECPoint(byte[] ecPointFormats, ECCurve curve, byte[] encoding)
+ {
+ if (encoding == null || encoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ byte actualFormat;
+ switch (encoding[0])
+ {
+ case 0x02: // compressed
+ case 0x03: // compressed
+ {
+ if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ actualFormat = ECPointFormat.ansiX962_compressed_char2;
+ }
+ else if (ECAlgorithms.IsFpCurve(curve))
+ {
+ actualFormat = ECPointFormat.ansiX962_compressed_prime;
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ break;
+ }
+ case 0x04: // uncompressed
+ {
+ actualFormat = ECPointFormat.uncompressed;
+ break;
+ }
+ case 0x00: // infinity
+ case 0x06: // hybrid
+ case 0x07: // hybrid
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ if (actualFormat != ECPointFormat.uncompressed
+ && (ecPointFormats == null || !Arrays.Contains(ecPointFormats, actualFormat)))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ return curve.DecodePoint(encoding);
+ }
+
+ public static ECPublicKeyParameters DeserializeECPublicKey(byte[] ecPointFormats, ECDomainParameters curve_params,
+ byte[] encoding)
+ {
+ try
+ {
+ ECPoint Y = DeserializeECPoint(ecPointFormats, curve_params.Curve, encoding);
+ return new ECPublicKeyParameters(Y, curve_params);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+ }
+ }
+
+ public static byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey, ECPrivateKeyParameters privateKey)
+ {
+ ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
+ basicAgreement.Init(privateKey);
+ BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
+
+ /*
+ * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by
+ * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for
+ * any given field; leading zeros found in this octet string MUST NOT be truncated.
+ */
+ return BigIntegers.AsUnsignedByteArray(basicAgreement.GetFieldSize(), agreementValue);
+ }
+
+ public static AsymmetricCipherKeyPair GenerateECKeyPair(SecureRandom random, ECDomainParameters ecParams)
+ {
+ ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
+ keyPairGenerator.Init(new ECKeyGenerationParameters(ecParams, random));
+ return keyPairGenerator.GenerateKeyPair();
+ }
+
+ public static ECPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random, byte[] ecPointFormats,
+ ECDomainParameters ecParams, Stream output)
+ {
+ AsymmetricCipherKeyPair kp = GenerateECKeyPair(random, ecParams);
+
+ ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
+ WriteECPoint(ecPointFormats, ecPublicKey.Q, output);
+
+ return (ECPrivateKeyParameters)kp.Private;
+ }
+
+ // TODO Refactor around ServerECDHParams before making this public
+ internal static ECPrivateKeyParameters GenerateEphemeralServerKeyExchange(SecureRandom random, int[] namedCurves,
+ byte[] ecPointFormats, Stream output)
+ {
+ /* First we try to find a supported named curve from the client's list. */
+ int namedCurve = -1;
+ if (namedCurves == null)
+ {
+ // TODO Let the peer choose the default named curve
+ namedCurve = NamedCurve.secp256r1;
+ }
+ else
+ {
+ for (int i = 0; i < namedCurves.Length; ++i)
+ {
+ int entry = namedCurves[i];
+ if (NamedCurve.IsValid(entry) && IsSupportedNamedCurve(entry))
+ {
+ namedCurve = entry;
+ break;
+ }
+ }
+ }
+
+ ECDomainParameters ecParams = null;
+ if (namedCurve >= 0)
+ {
+ ecParams = GetParametersForNamedCurve(namedCurve);
+ }
+ else
+ {
+ /* If no named curves are suitable, check if the client supports explicit curves. */
+ if (Arrays.Contains(namedCurves, NamedCurve.arbitrary_explicit_prime_curves))
+ {
+ ecParams = GetParametersForNamedCurve(NamedCurve.secp256r1);
+ }
+ else if (Arrays.Contains(namedCurves, NamedCurve.arbitrary_explicit_char2_curves))
+ {
+ ecParams = GetParametersForNamedCurve(NamedCurve.sect283r1);
+ }
+ }
+
+ if (ecParams == null)
+ {
+ /*
+ * NOTE: We shouldn't have negotiated ECDHE key exchange since we apparently can't find
+ * a suitable curve.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ if (namedCurve < 0)
+ {
+ WriteExplicitECParameters(ecPointFormats, ecParams, output);
+ }
+ else
+ {
+ WriteNamedECParameters(namedCurve, output);
+ }
+
+ return GenerateEphemeralClientKeyExchange(random, ecPointFormats, ecParams, output);
+ }
+
+ public static ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
+ {
+ // TODO Check RFC 4492 for validation
+ return key;
+ }
+
+ public static int ReadECExponent(int fieldSize, Stream input)
+ {
+ BigInteger K = ReadECParameter(input);
+ if (K.BitLength < 32)
+ {
+ int k = K.IntValue;
+ if (k > 0 && k < fieldSize)
+ {
+ return k;
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ public static BigInteger ReadECFieldElement(int fieldSize, Stream input)
+ {
+ return DeserializeECFieldElement(fieldSize, TlsUtilities.ReadOpaque8(input));
+ }
+
+ public static BigInteger ReadECParameter(Stream input)
+ {
+ // TODO Are leading zeroes okay here?
+ return new BigInteger(1, TlsUtilities.ReadOpaque8(input));
+ }
+
+ public static ECDomainParameters ReadECParameters(int[] namedCurves, byte[] ecPointFormats, Stream input)
+ {
+ try
+ {
+ byte curveType = TlsUtilities.ReadUint8(input);
+
+ switch (curveType)
+ {
+ case ECCurveType.explicit_prime:
+ {
+ CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_prime_curves);
+
+ BigInteger prime_p = ReadECParameter(input);
+ BigInteger a = ReadECFieldElement(prime_p.BitLength, input);
+ BigInteger b = ReadECFieldElement(prime_p.BitLength, input);
+ byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
+ BigInteger order = ReadECParameter(input);
+ BigInteger cofactor = ReadECParameter(input);
+ ECCurve curve = new FpCurve(prime_p, a, b, order, cofactor);
+ ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
+ return new ECDomainParameters(curve, basePoint, order, cofactor);
+ }
+ case ECCurveType.explicit_char2:
+ {
+ CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_char2_curves);
+
+ int m = TlsUtilities.ReadUint16(input);
+ byte basis = TlsUtilities.ReadUint8(input);
+ if (!ECBasisType.IsValid(basis))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ int k1 = ReadECExponent(m, input), k2 = -1, k3 = -1;
+ if (basis == ECBasisType.ec_basis_pentanomial)
+ {
+ k2 = ReadECExponent(m, input);
+ k3 = ReadECExponent(m, input);
+ }
+
+ BigInteger a = ReadECFieldElement(m, input);
+ BigInteger b = ReadECFieldElement(m, input);
+ byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
+ BigInteger order = ReadECParameter(input);
+ BigInteger cofactor = ReadECParameter(input);
+
+ ECCurve curve = (basis == ECBasisType.ec_basis_pentanomial)
+ ? new F2mCurve(m, k1, k2, k3, a, b, order, cofactor)
+ : new F2mCurve(m, k1, a, b, order, cofactor);
+
+ ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
+
+ return new ECDomainParameters(curve, basePoint, order, cofactor);
+ }
+ case ECCurveType.named_curve:
+ {
+ int namedCurve = TlsUtilities.ReadUint16(input);
+ if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
+ {
+ /*
+ * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a
+ * specific curve. Values of NamedCurve that indicate support for a class of
+ * explicitly defined curves are not allowed here [...].
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ CheckNamedCurve(namedCurves, namedCurve);
+
+ return GetParametersForNamedCurve(namedCurve);
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+ }
+ }
+
+ private static void CheckNamedCurve(int[] namedCurves, int namedCurve)
+ {
+ if (namedCurves != null && !Arrays.Contains(namedCurves, namedCurve))
+ {
+ /*
+ * RFC 4492 4. [...] servers MUST NOT negotiate the use of an ECC cipher suite
+ * unless they can complete the handshake while respecting the choice of curves
+ * and compression techniques specified by the client.
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public static void WriteECExponent(int k, Stream output)
+ {
+ BigInteger K = BigInteger.ValueOf(k);
+ WriteECParameter(K, output);
+ }
+
+ public static void WriteECFieldElement(ECFieldElement x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(x.GetEncoded(), output);
+ }
+
+ public static void WriteECFieldElement(int fieldSize, BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(SerializeECFieldElement(fieldSize, x), output);
+ }
+
+ public static void WriteECParameter(BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(BigIntegers.AsUnsignedByteArray(x), output);
+ }
+
+ public static void WriteExplicitECParameters(byte[] ecPointFormats, ECDomainParameters ecParameters,
+ Stream output)
+ {
+ ECCurve curve = ecParameters.Curve;
+
+ if (ECAlgorithms.IsFpCurve(curve))
+ {
+ TlsUtilities.WriteUint8(ECCurveType.explicit_prime, output);
+
+ WriteECParameter(curve.Field.Characteristic, output);
+ }
+ else if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
+ int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
+
+ TlsUtilities.WriteUint8(ECCurveType.explicit_char2, output);
+
+ int m = exponents[exponents.Length - 1];
+ TlsUtilities.CheckUint16(m);
+ TlsUtilities.WriteUint16(m, output);
+
+ if (exponents.Length == 3)
+ {
+ TlsUtilities.WriteUint8(ECBasisType.ec_basis_trinomial, output);
+ WriteECExponent(exponents[1], output);
+ }
+ else if (exponents.Length == 5)
+ {
+ TlsUtilities.WriteUint8(ECBasisType.ec_basis_pentanomial, output);
+ WriteECExponent(exponents[1], output);
+ WriteECExponent(exponents[2], output);
+ WriteECExponent(exponents[3], output);
+ }
+ else
+ {
+ throw new ArgumentException("Only trinomial and pentomial curves are supported");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("'ecParameters' not a known curve type");
+ }
+
+ WriteECFieldElement(curve.A, output);
+ WriteECFieldElement(curve.B, output);
+ TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, ecParameters.G), output);
+ WriteECParameter(ecParameters.N, output);
+ WriteECParameter(ecParameters.H, output);
+ }
+
+ public static void WriteECPoint(byte[] ecPointFormats, ECPoint point, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, point), output);
+ }
+
+ public static void WriteNamedECParameters(int namedCurve, Stream output)
+ {
+ if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
+ {
+ /*
+ * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a specific
+ * curve. Values of NamedCurve that indicate support for a class of explicitly defined
+ * curves are not allowed here [...].
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ TlsUtilities.WriteUint8(ECCurveType.named_curve, output);
+ TlsUtilities.CheckUint16(namedCurve);
+ TlsUtilities.WriteUint16(namedCurve, output);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsEncryptionCredentials.cs b/crypto/src/crypto/tls/TlsEncryptionCredentials.cs
new file mode 100644
index 000000000..52f007006
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsEncryptionCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsEncryptionCredentials
+ : TlsCredentials
+ {
+ /// <exception cref="IOException"></exception>
+ byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret);
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsExtensionsUtilities.cs b/crypto/src/crypto/tls/TlsExtensionsUtilities.cs
new file mode 100644
index 000000000..46851b66c
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsExtensionsUtilities.cs
@@ -0,0 +1,258 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsExtensionsUtilities
+ {
+ public static IDictionary EnsureExtensionsInitialised(IDictionary extensions)
+ {
+ return extensions == null ? Platform.CreateHashtable() : extensions;
+ }
+
+ public static void AddEncryptThenMacExtension(IDictionary extensions)
+ {
+ extensions[ExtensionType.encrypt_then_mac] = CreateEncryptThenMacExtension();
+ }
+
+ public static void AddExtendedMasterSecretExtension(IDictionary extensions)
+ {
+ extensions[ExtensionType.extended_master_secret] = CreateExtendedMasterSecretExtension();
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static void AddHeartbeatExtension(IDictionary extensions, HeartbeatExtension heartbeatExtension)
+ {
+ extensions[ExtensionType.heartbeat] = CreateHeartbeatExtension(heartbeatExtension);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static void AddMaxFragmentLengthExtension(IDictionary extensions, byte maxFragmentLength)
+ {
+ extensions[ExtensionType.max_fragment_length] = CreateMaxFragmentLengthExtension(maxFragmentLength);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static void AddServerNameExtension(IDictionary extensions, ServerNameList serverNameList)
+ {
+ extensions[ExtensionType.server_name] = CreateServerNameExtension(serverNameList);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static void AddStatusRequestExtension(IDictionary extensions, CertificateStatusRequest statusRequest)
+ {
+ extensions[ExtensionType.status_request] = CreateStatusRequestExtension(statusRequest);
+ }
+
+ public static void AddTruncatedHMacExtension(IDictionary extensions)
+ {
+ extensions[ExtensionType.truncated_hmac] = CreateTruncatedHMacExtension();
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static HeartbeatExtension GetHeartbeatExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.heartbeat);
+ return extensionData == null ? null : ReadHeartbeatExtension(extensionData);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static short GetMaxFragmentLengthExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.max_fragment_length);
+ return extensionData == null ? (short)-1 : (short)ReadMaxFragmentLengthExtension(extensionData);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static ServerNameList GetServerNameExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name);
+ return extensionData == null ? null : ReadServerNameExtension(extensionData);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static CertificateStatusRequest GetStatusRequestExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request);
+ return extensionData == null ? null : ReadStatusRequestExtension(extensionData);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static bool HasEncryptThenMacExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.encrypt_then_mac);
+ return extensionData == null ? false : ReadEncryptThenMacExtension(extensionData);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static bool HasExtendedMasterSecretExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.extended_master_secret);
+ return extensionData == null ? false : ReadExtendedMasterSecretExtension(extensionData);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static bool HasTruncatedHMacExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.truncated_hmac);
+ return extensionData == null ? false : ReadTruncatedHMacExtension(extensionData);
+ }
+
+ public static byte[] CreateEmptyExtensionData()
+ {
+ return TlsUtilities.EmptyBytes;
+ }
+
+ public static byte[] CreateEncryptThenMacExtension()
+ {
+ return CreateEmptyExtensionData();
+ }
+
+ public static byte[] CreateExtendedMasterSecretExtension()
+ {
+ return CreateEmptyExtensionData();
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static byte[] CreateHeartbeatExtension(HeartbeatExtension heartbeatExtension)
+ {
+ if (heartbeatExtension == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ MemoryStream buf = new MemoryStream();
+
+ heartbeatExtension.Encode(buf);
+
+ return buf.ToArray();
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static byte[] CreateMaxFragmentLengthExtension(byte maxFragmentLength)
+ {
+ return new byte[]{ maxFragmentLength };
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static byte[] CreateServerNameExtension(ServerNameList serverNameList)
+ {
+ if (serverNameList == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ MemoryStream buf = new MemoryStream();
+
+ serverNameList.Encode(buf);
+
+ return buf.ToArray();
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static byte[] CreateStatusRequestExtension(CertificateStatusRequest statusRequest)
+ {
+ if (statusRequest == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ MemoryStream buf = new MemoryStream();
+
+ statusRequest.Encode(buf);
+
+ return buf.ToArray();
+ }
+
+ public static byte[] CreateTruncatedHMacExtension()
+ {
+ return CreateEmptyExtensionData();
+ }
+
+ /// <exception cref="IOException"></exception>
+ private static bool ReadEmptyExtensionData(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ if (extensionData.Length != 0)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return true;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static bool ReadEncryptThenMacExtension(byte[] extensionData)
+ {
+ return ReadEmptyExtensionData(extensionData);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static bool ReadExtendedMasterSecretExtension(byte[] extensionData)
+ {
+ return ReadEmptyExtensionData(extensionData);
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static HeartbeatExtension ReadHeartbeatExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ HeartbeatExtension heartbeatExtension = HeartbeatExtension.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return heartbeatExtension;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static short ReadMaxFragmentLengthExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ if (extensionData.Length != 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ return extensionData[0];
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static ServerNameList ReadServerNameExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ ServerNameList serverNameList = ServerNameList.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return serverNameList;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static CertificateStatusRequest ReadStatusRequestExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ CertificateStatusRequest statusRequest = CertificateStatusRequest.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return statusRequest;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public static bool ReadTruncatedHMacExtension(byte[] extensionData)
+ {
+ return ReadEmptyExtensionData(extensionData);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsFatalAlert.cs b/crypto/src/crypto/tls/TlsFatalAlert.cs
index 4fb2a41bd..55d784dd9 100644
--- a/crypto/src/crypto/tls/TlsFatalAlert.cs
+++ b/crypto/src/crypto/tls/TlsFatalAlert.cs
@@ -9,6 +9,12 @@ namespace Org.BouncyCastle.Crypto.Tls
private readonly byte alertDescription;
public TlsFatalAlert(byte alertDescription)
+ : this(alertDescription, null)
+ {
+ }
+
+ public TlsFatalAlert(byte alertDescription, Exception alertCause)
+ : base(Tls.AlertDescription.GetText(alertDescription), alertCause)
{
this.alertDescription = alertDescription;
}
diff --git a/crypto/src/crypto/tls/TlsHandshakeHash.cs b/crypto/src/crypto/tls/TlsHandshakeHash.cs
new file mode 100644
index 000000000..7118d9769
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsHandshakeHash.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsHandshakeHash
+ : IDigest
+ {
+ void Init(TlsContext context);
+
+ TlsHandshakeHash NotifyPrfDetermined();
+
+ void TrackHashAlgorithm(byte hashAlgorithm);
+
+ void SealHashAlgorithms();
+
+ TlsHandshakeHash StopTracking();
+
+ IDigest ForkPrfHash();
+
+ byte[] GetFinalHash(byte hashAlgorithm);
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsKeyExchange.cs b/crypto/src/crypto/tls/TlsKeyExchange.cs
index 5102edbec..6731f6f63 100644
--- a/crypto/src/crypto/tls/TlsKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsKeyExchange.cs
@@ -3,36 +3,52 @@ using System.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- /// <summary>
- /// A generic interface for key exchange implementations in TLS 1.0.
- /// </summary>
- public interface TlsKeyExchange
- {
- /// <exception cref="IOException"/>
- void SkipServerCertificate();
-
- /// <exception cref="IOException"/>
- void ProcessServerCertificate(Certificate serverCertificate);
-
- /// <exception cref="IOException"/>
- void SkipServerKeyExchange();
-
- /// <exception cref="IOException"/>
- void ProcessServerKeyExchange(Stream input);
-
- /// <exception cref="IOException"/>
- void ValidateCertificateRequest(CertificateRequest certificateRequest);
-
- /// <exception cref="IOException"/>
- void SkipClientCredentials();
-
- /// <exception cref="IOException"/>
- void ProcessClientCredentials(TlsCredentials clientCredentials);
-
- /// <exception cref="IOException"/>
- void GenerateClientKeyExchange(Stream output);
-
- /// <exception cref="IOException"/>
- byte[] GeneratePremasterSecret();
- }
+ /// <summary>
+ /// A generic interface for key exchange implementations in (D)TLS.
+ /// </summary>
+ public interface TlsKeyExchange
+ {
+ void Init(TlsContext context);
+
+ /// <exception cref="IOException"/>
+ void SkipServerCredentials();
+
+ /// <exception cref="IOException"/>
+ void ProcessServerCredentials(TlsCredentials serverCredentials);
+
+ /// <exception cref="IOException"/>
+ void ProcessServerCertificate(Certificate serverCertificate);
+
+ bool RequiresServerKeyExchange { get; }
+
+ /// <exception cref="IOException"/>
+ byte[] GenerateServerKeyExchange();
+
+ /// <exception cref="IOException"/>
+ void SkipServerKeyExchange();
+
+ /// <exception cref="IOException"/>
+ void ProcessServerKeyExchange(Stream input);
+
+ /// <exception cref="IOException"/>
+ void ValidateCertificateRequest(CertificateRequest certificateRequest);
+
+ /// <exception cref="IOException"/>
+ void SkipClientCredentials();
+
+ /// <exception cref="IOException"/>
+ void ProcessClientCredentials(TlsCredentials clientCredentials);
+
+ /// <exception cref="IOException"/>
+ void ProcessClientCertificate(Certificate clientCertificate);
+
+ /// <exception cref="IOException"/>
+ void GenerateClientKeyExchange(Stream output);
+
+ /// <exception cref="IOException"/>
+ void ProcessClientKeyExchange(Stream input);
+
+ /// <exception cref="IOException"/>
+ byte[] GeneratePremasterSecret();
+ }
}
diff --git a/crypto/src/crypto/tls/TlsMac.cs b/crypto/src/crypto/tls/TlsMac.cs
index e4313617e..a80319a17 100644
--- a/crypto/src/crypto/tls/TlsMac.cs
+++ b/crypto/src/crypto/tls/TlsMac.cs
@@ -9,134 +9,165 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
- /// <remarks>
- /// A generic TLS MAC implementation, which can be used with any kind of
- /// IDigest to act as an HMAC.
- /// </remarks>
+ /// <summary>
+ /// A generic TLS MAC implementation, acting as an HMAC based on some underlying Digest.
+ /// </summary>
public class TlsMac
{
- protected long seqNo;
- protected byte[] secret;
- protected HMac mac;
+ protected readonly TlsContext context;
+ protected readonly byte[] secret;
+ protected readonly IMac mac;
+ protected readonly int digestBlockSize;
+ protected readonly int digestOverhead;
+ protected readonly int macLength;
/**
- * Generate a new instance of an TlsMac.
- *
- * @param digest The digest to use.
- * @param key_block A byte-array where the key for this mac is located.
- * @param offset The number of bytes to skip, before the key starts in the buffer.
- * @param len The length of the key.
- */
- public TlsMac(
- IDigest digest,
- byte[] key_block,
- int offset,
- int len)
+ * Generate a new instance of an TlsMac.
+ *
+ * @param context the TLS client context
+ * @param digest The digest to use.
+ * @param key A byte-array where the key for this MAC is located.
+ * @param keyOff The number of bytes to skip, before the key starts in the buffer.
+ * @param keyLen The length of the key.
+ */
+ public TlsMac(TlsContext context, IDigest digest, byte[] key, int keyOff, int keyLen)
{
- this.seqNo = 0;
+ this.context = context;
- KeyParameter param = new KeyParameter(key_block, offset, len);
+ KeyParameter keyParameter = new KeyParameter(key, keyOff, keyLen);
- this.secret = Arrays.Clone(param.GetKey());
+ this.secret = Arrays.Clone(keyParameter.GetKey());
- this.mac = new HMac(digest);
- this.mac.Init(param);
- }
+ // TODO This should check the actual algorithm, not rely on the engine type
+ if (digest is LongDigest)
+ {
+ this.digestBlockSize = 128;
+ this.digestOverhead = 16;
+ }
+ else
+ {
+ this.digestBlockSize = 64;
+ this.digestOverhead = 8;
+ }
- /**
- * @return the MAC write secret
- */
- public virtual byte[] GetMacSecret()
- {
- return this.secret;
- }
+ if (TlsUtilities.IsSsl(context))
+ {
+ this.mac = new Ssl3Mac(digest);
- /**
- * @return the current write sequence number
- */
- public virtual long SequenceNumber
- {
- get { return this.seqNo; }
+ // TODO This should check the actual algorithm, not assume based on the digest size
+ if (digest.GetDigestSize() == 20)
+ {
+ /*
+ * NOTE: When SHA-1 is used with the SSL 3.0 MAC, the secret + input pad is not
+ * digest block-aligned.
+ */
+ this.digestOverhead = 4;
+ }
+ }
+ else
+ {
+ this.mac = new HMac(digest);
+
+ // NOTE: The input pad for HMAC is always a full digest block
+ }
+
+ this.mac.Init(keyParameter);
+
+ this.macLength = mac.GetMacSize();
+ if (context.SecurityParameters.truncatedHMac)
+ {
+ this.macLength = System.Math.Min(this.macLength, 10);
+ }
}
/**
- * Increment the current write sequence number
+ * @return the MAC write secret
*/
- public virtual void IncSequenceNumber()
+ public virtual byte[] MacSecret
{
- this.seqNo++;
+ get { return this.secret; }
}
/**
- * @return The Keysize of the mac.
- */
+ * @return The output length of this MAC.
+ */
public virtual int Size
{
- get { return mac.GetMacSize(); }
+ get { return macLength; }
}
/**
- * Calculate the mac for some given data.
- * <p/>
- * TlsMac will keep track of the sequence number internally.
- *
- * @param type The message type of the message.
- * @param message A byte-buffer containing the message.
- * @param offset The number of bytes to skip, before the message starts.
- * @param len The length of the message.
- * @return A new byte-buffer containing the mac value.
- */
- public virtual byte[] CalculateMac(byte type, byte[] message, int offset, int len)
+ * Calculate the MAC for some given data.
+ *
+ * @param type The message type of the message.
+ * @param message A byte-buffer containing the message.
+ * @param offset The number of bytes to skip, before the message starts.
+ * @param length The length of the message.
+ * @return A new byte-buffer containing the MAC value.
+ */
+ public virtual byte[] CalculateMac(long seqNo, byte type, byte[] message, int offset, int length)
{
- //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion;
- bool isTls = true;
+ ProtocolVersion serverVersion = context.ServerVersion;
+ bool isSsl = serverVersion.IsSsl;
- byte[] macHeader = new byte[isTls ? 13 : 11];
- TlsUtilities.WriteUint64(seqNo++, macHeader, 0);
+ byte[] macHeader = new byte[isSsl ? 11 : 13];
+ TlsUtilities.WriteUint64(seqNo, macHeader, 0);
TlsUtilities.WriteUint8(type, macHeader, 8);
- if (isTls)
+ if (!isSsl)
{
- TlsUtilities.WriteVersion(macHeader, 9);
+ TlsUtilities.WriteVersion(serverVersion, macHeader, 9);
}
- TlsUtilities.WriteUint16(len, macHeader, 11);
+ TlsUtilities.WriteUint16(length, macHeader, macHeader.Length - 2);
mac.BlockUpdate(macHeader, 0, macHeader.Length);
- mac.BlockUpdate(message, offset, len);
- return MacUtilities.DoFinal(mac);
+ mac.BlockUpdate(message, offset, length);
+
+ return Truncate(MacUtilities.DoFinal(mac));
}
- public virtual byte[] CalculateMacConstantTime(byte type, byte[] message, int offset, int len,
+ public virtual byte[] CalculateMacConstantTime(long seqNo, byte type, byte[] message, int offset, int length,
int fullLength, byte[] dummyData)
{
- // Actual MAC only calculated on 'len' bytes
- byte[] result = CalculateMac(type, message, offset, len);
+ /*
+ * Actual MAC only calculated on 'length' bytes...
+ */
+ byte[] result = CalculateMac(seqNo, type, message, offset, length);
+
+ /*
+ * ...but ensure a constant number of complete digest blocks are processed (as many as would
+ * be needed for 'fullLength' bytes of input).
+ */
+ int headerLength = TlsUtilities.IsSsl(context) ? 11 : 13;
- //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion;
- bool isTls = true;
+ // How many extra full blocks do we need to calculate?
+ int extra = GetDigestBlockCount(headerLength + fullLength) - GetDigestBlockCount(headerLength + length);
- // ...but ensure a constant number of complete digest blocks are processed (per 'fullLength')
- if (isTls)
+ while (--extra >= 0)
{
- // TODO Currently all TLS digests use a block size of 64, a suffix (length field) of 8, and padding (1+)
- int db = 64, ds = 8;
+ mac.BlockUpdate(dummyData, 0, digestBlockSize);
+ }
- int L1 = 13 + fullLength;
- int L2 = 13 + len;
+ // One more byte in case the implementation is "lazy" about processing blocks
+ mac.Update(dummyData[0]);
+ mac.Reset();
- // How many extra full blocks do we need to calculate?
- int extra = ((L1 + ds) / db) - ((L2 + ds) / db);
+ return result;
+ }
- while (--extra >= 0)
- {
- mac.BlockUpdate(dummyData, 0, db);
- }
+ protected virtual int GetDigestBlockCount(int inputLength)
+ {
+ // NOTE: This calculation assumes a minimum of 1 pad byte
+ return (inputLength + digestOverhead) / digestBlockSize;
+ }
- // One more byte in case the implementation is "lazy" about processing blocks
- mac.Update(dummyData[0]);
- mac.Reset();
+ protected virtual byte[] Truncate(byte[] bs)
+ {
+ if (bs.Length <= macLength)
+ {
+ return bs;
}
- return result;
+ return Arrays.CopyOf(bs, macLength);
}
}
}
diff --git a/crypto/src/crypto/tls/TlsNullCipher.cs b/crypto/src/crypto/tls/TlsNullCipher.cs
index 3e2bfa847..f30ace24f 100644
--- a/crypto/src/crypto/tls/TlsNullCipher.cs
+++ b/crypto/src/crypto/tls/TlsNullCipher.cs
@@ -1,28 +1,118 @@
using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
/// <summary>
- /// A NULL cipher suite, for use during handshake.
+ /// A NULL CipherSuite, with optional MAC.
/// </summary>
public class TlsNullCipher
- : TlsCipher
+ : TlsCipher
{
- public virtual byte[] EncodePlaintext(byte type, byte[] plaintext, int offset, int len)
+ protected readonly TlsContext context;
+
+ protected readonly TlsMac writeMac;
+ protected readonly TlsMac readMac;
+
+ public TlsNullCipher(TlsContext context)
{
- return CopyData(plaintext, offset, len);
+ this.context = context;
+ this.writeMac = null;
+ this.readMac = null;
}
- public virtual byte[] DecodeCiphertext(byte type, byte[] ciphertext, int offset, int len)
+ /// <exception cref="IOException"></exception>
+ public TlsNullCipher(TlsContext context, IDigest clientWriteDigest, IDigest serverWriteDigest)
{
- return CopyData(ciphertext, offset, len);
+ if ((clientWriteDigest == null) != (serverWriteDigest == null))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.context = context;
+
+ TlsMac clientWriteMac = null, serverWriteMac = null;
+
+ if (clientWriteDigest != null)
+ {
+ int key_block_size = clientWriteDigest.GetDigestSize()
+ + serverWriteDigest.GetDigestSize();
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+ int offset = 0;
+
+ clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+ clientWriteDigest.GetDigestSize());
+ offset += clientWriteDigest.GetDigestSize();
+
+ serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+ serverWriteDigest.GetDigestSize());
+ offset += serverWriteDigest.GetDigestSize();
+
+ if (offset != key_block_size)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ if (context.IsServer)
+ {
+ writeMac = serverWriteMac;
+ readMac = clientWriteMac;
+ }
+ else
+ {
+ writeMac = clientWriteMac;
+ readMac = serverWriteMac;
+ }
}
- protected virtual byte[] CopyData(byte[] text, int offset, int len)
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
{
- byte[] result = new byte[len];
- Array.Copy(text, offset, result, 0, len);
+ int result = ciphertextLimit;
+ if (writeMac != null)
+ {
+ result -= writeMac.Size;
+ }
return result;
}
+
+ /// <exception cref="IOException"></exception>
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+ {
+ if (writeMac == null)
+ {
+ return Arrays.CopyOfRange(plaintext, offset, offset + len);
+ }
+
+ byte[] mac = writeMac.CalculateMac(seqNo, type, plaintext, offset, len);
+ byte[] ciphertext = new byte[len + mac.Length];
+ Array.Copy(plaintext, offset, ciphertext, 0, len);
+ Array.Copy(mac, 0, ciphertext, len, mac.Length);
+ return ciphertext;
+ }
+
+ /// <exception cref="IOException"></exception>
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+ {
+ if (readMac == null)
+ {
+ return Arrays.CopyOfRange(ciphertext, offset, offset + len);
+ }
+
+ int macSize = readMac.Size;
+ if (len < macSize)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int macInputLen = len - macSize;
+
+ byte[] receivedMac = Arrays.CopyOfRange(ciphertext, offset + macInputLen, offset + len);
+ byte[] computedMac = readMac.CalculateMac(seqNo, type, ciphertext, offset, macInputLen);
+
+ if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac))
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+
+ return Arrays.CopyOfRange(ciphertext, offset, offset + macInputLen);
+ }
}
}
diff --git a/crypto/src/crypto/tls/TlsPeer.cs b/crypto/src/crypto/tls/TlsPeer.cs
index 5b5c94a44..1ae41a41a 100644
--- a/crypto/src/crypto/tls/TlsPeer.cs
+++ b/crypto/src/crypto/tls/TlsPeer.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
@@ -15,5 +16,47 @@ namespace Org.BouncyCastle.Crypto.Tls
/// random value.
/// </returns>
bool ShouldUseGmtUnixTime();
+
+ /// <summary>
+ /// Report whether the server supports secure renegotiation
+ /// </summary>
+ /// <remarks>
+ /// The protocol handler automatically processes the relevant extensions
+ /// </remarks>
+ /// <param name="secureRenegotiation">
+ /// A <see cref="System.Boolean"/>, true if the server supports secure renegotiation
+ /// </param>
+ /// <exception cref="IOException"></exception>
+ void NotifySecureRenegotiation(bool secureRenegotiation);
+
+ /// <summary>
+ /// Return an implementation of <see cref="TlsCompression"/> to handle record compression.
+ /// </summary>
+ /// <returns>A <see cref="TlsCompression"/></returns>
+ /// <exception cref="IOException"/>
+ TlsCompression GetCompression();
+
+ /// <summary>
+ /// Return an implementation of <see cref="TlsCipher"/> to use for encryption/decryption.
+ /// </summary>
+ /// <returns>A <see cref="TlsCipher"/></returns>
+ /// <exception cref="IOException"/>
+ TlsCipher GetCipher();
+
+ /// <summary>This method will be called when an alert is raised by the protocol.</summary>
+ /// <param name="alertLevel"><see cref="AlertLevel"/></param>
+ /// <param name="alertDescription"><see cref="AlertDescription"/></param>
+ /// <param name="message">A human-readable message explaining what caused this alert. May be null.</param>
+ /// <param name="cause">The <c>Exception</c> that caused this alert to be raised. May be null.</param>
+ void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause);
+
+ /// <summary>This method will be called when an alert is received from the remote peer.</summary>
+ /// <param name="alertLevel"><see cref="AlertLevel"/></param>
+ /// <param name="alertDescription"><see cref="AlertDescription"/></param>
+ void NotifyAlertReceived(byte alertLevel, byte alertDescription);
+
+ /// <summary>Notifies the peer that the handshake has been successfully completed.</summary>
+ /// <exception cref="IOException"></exception>
+ void NotifyHandshakeComplete();
}
}
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
new file mode 100644
index 000000000..7acc34d3c
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -0,0 +1,1318 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsProtocol
+ {
+ private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
+
+ /*
+ * Our Connection states
+ */
+ protected const short CS_START = 0;
+ protected const short CS_CLIENT_HELLO = 1;
+ protected const short CS_SERVER_HELLO = 2;
+ protected const short CS_SERVER_SUPPLEMENTAL_DATA = 3;
+ protected const short CS_SERVER_CERTIFICATE = 4;
+ protected const short CS_CERTIFICATE_STATUS = 5;
+ protected const short CS_SERVER_KEY_EXCHANGE = 6;
+ protected const short CS_CERTIFICATE_REQUEST = 7;
+ protected const short CS_SERVER_HELLO_DONE = 8;
+ protected const short CS_CLIENT_SUPPLEMENTAL_DATA = 9;
+ protected const short CS_CLIENT_CERTIFICATE = 10;
+ protected const short CS_CLIENT_KEY_EXCHANGE = 11;
+ protected const short CS_CERTIFICATE_VERIFY = 12;
+ protected const short CS_CLIENT_FINISHED = 13;
+ protected const short CS_SERVER_SESSION_TICKET = 14;
+ protected const short CS_SERVER_FINISHED = 15;
+ protected const short CS_END = 16;
+
+ /*
+ * Queues for data from some protocols.
+ */
+ private ByteQueue mApplicationDataQueue = new ByteQueue();
+ private ByteQueue mAlertQueue = new ByteQueue(2);
+ private ByteQueue mHandshakeQueue = new ByteQueue();
+ // private ByteQueue mHeartbeatQueue = new ByteQueue();
+
+ /*
+ * The Record Stream we use
+ */
+ internal RecordStream mRecordStream;
+ protected SecureRandom mSecureRandom;
+
+ private TlsStream mTlsStream = null;
+
+ private volatile bool mClosed = false;
+ private volatile bool mFailedWithError = false;
+ private volatile bool mAppDataReady = false;
+ private volatile bool mSplitApplicationDataRecords = true;
+ private byte[] mExpectedVerifyData = null;
+
+ protected TlsSession mTlsSession = null;
+ protected SessionParameters mSessionParameters = null;
+ protected SecurityParameters mSecurityParameters = null;
+ protected Certificate mPeerCertificate = null;
+
+ protected int[] mOfferedCipherSuites = null;
+ protected byte[] mOfferedCompressionMethods = null;
+ protected IDictionary mClientExtensions = null;
+ protected IDictionary mServerExtensions = null;
+
+ protected short mConnectionState = CS_START;
+ protected bool mResumedSession = false;
+ protected bool mReceivedChangeCipherSpec = false;
+ protected bool mSecureRenegotiation = false;
+ protected bool mAllowCertificateStatus = false;
+ protected bool mExpectSessionTicket = false;
+
+ protected bool mBlocking = true;
+ protected ByteQueueStream mInputBuffers = null;
+ protected ByteQueueStream mOutputBuffer = null;
+
+ public TlsProtocol(Stream stream, SecureRandom secureRandom)
+ : this(stream, stream, secureRandom)
+ {
+ }
+
+ public TlsProtocol(Stream input, Stream output, SecureRandom secureRandom)
+ {
+ this.mRecordStream = new RecordStream(this, input, output);
+ this.mSecureRandom = secureRandom;
+ }
+
+ public TlsProtocol(SecureRandom secureRandom)
+ {
+ this.mBlocking = false;
+ this.mInputBuffers = new ByteQueueStream();
+ this.mOutputBuffer = new ByteQueueStream();
+ this.mRecordStream = new RecordStream(this, mInputBuffers, mOutputBuffer);
+ this.mSecureRandom = secureRandom;
+ }
+
+ protected abstract TlsContext Context { get; }
+
+ internal abstract AbstractTlsContext ContextAdmin { get; }
+
+ protected abstract TlsPeer Peer { get; }
+
+ protected virtual void HandleChangeCipherSpecMessage()
+ {
+ }
+
+ protected abstract void HandleHandshakeMessage(byte type, byte[] buf);
+
+ protected virtual void HandleWarningMessage(byte description)
+ {
+ }
+
+ protected virtual void ApplyMaxFragmentLengthExtension()
+ {
+ if (mSecurityParameters.maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)mSecurityParameters.maxFragmentLength))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ int plainTextLimit = 1 << (8 + mSecurityParameters.maxFragmentLength);
+ mRecordStream.SetPlaintextLimit(plainTextLimit);
+ }
+ }
+
+ protected virtual void CheckReceivedChangeCipherSpec(bool expected)
+ {
+ if (expected != mReceivedChangeCipherSpec)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ protected virtual void CleanupHandshake()
+ {
+ if (this.mExpectedVerifyData != null)
+ {
+ Arrays.Fill(this.mExpectedVerifyData, (byte)0);
+ this.mExpectedVerifyData = null;
+ }
+
+ this.mSecurityParameters.Clear();
+ this.mPeerCertificate = null;
+
+ this.mOfferedCipherSuites = null;
+ this.mOfferedCompressionMethods = null;
+ this.mClientExtensions = null;
+ this.mServerExtensions = null;
+
+ this.mResumedSession = false;
+ this.mReceivedChangeCipherSpec = false;
+ this.mSecureRenegotiation = false;
+ this.mAllowCertificateStatus = false;
+ this.mExpectSessionTicket = false;
+ }
+
+ protected virtual void BlockForHandshake()
+ {
+ if (mBlocking)
+ {
+ while (this.mConnectionState != CS_END)
+ {
+ if (this.mClosed)
+ {
+ // TODO What kind of exception/alert?
+ }
+
+ SafeReadRecord();
+ }
+ }
+ }
+
+ protected virtual void CompleteHandshake()
+ {
+ try
+ {
+ this.mRecordStream.FinaliseHandshake();
+
+ this.mSplitApplicationDataRecords = !TlsUtilities.IsTlsV11(Context);
+
+ /*
+ * If this was an initial handshake, we are now ready to send and receive application data.
+ */
+ if (!mAppDataReady)
+ {
+ this.mAppDataReady = true;
+
+ if (mBlocking)
+ {
+ this.mTlsStream = new TlsStream(this);
+ }
+ }
+
+ if (this.mTlsSession != null)
+ {
+ if (this.mSessionParameters == null)
+ {
+ this.mSessionParameters = new SessionParameters.Builder()
+ .SetCipherSuite(this.mSecurityParameters.CipherSuite)
+ .SetCompressionAlgorithm(this.mSecurityParameters.CompressionAlgorithm)
+ .SetMasterSecret(this.mSecurityParameters.MasterSecret)
+ .SetPeerCertificate(this.mPeerCertificate)
+ .SetPskIdentity(this.mSecurityParameters.PskIdentity)
+ .SetSrpIdentity(this.mSecurityParameters.SrpIdentity)
+ // TODO Consider filtering extensions that aren't relevant to resumed sessions
+ .SetServerExtensions(this.mServerExtensions)
+ .Build();
+
+ this.mTlsSession = new TlsSessionImpl(this.mTlsSession.SessionID, this.mSessionParameters);
+ }
+
+ ContextAdmin.SetResumableSession(this.mTlsSession);
+ }
+
+ Peer.NotifyHandshakeComplete();
+ }
+ finally
+ {
+ CleanupHandshake();
+ }
+ }
+
+ protected internal void ProcessRecord(byte protocol, byte[] buf, int offset, int len)
+ {
+ /*
+ * Have a look at the protocol type, and add it to the correct queue.
+ */
+ switch (protocol)
+ {
+ case ContentType.alert:
+ {
+ mAlertQueue.AddData(buf, offset, len);
+ ProcessAlert();
+ break;
+ }
+ case ContentType.application_data:
+ {
+ if (!mAppDataReady)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ mApplicationDataQueue.AddData(buf, offset, len);
+ ProcessApplicationData();
+ break;
+ }
+ case ContentType.change_cipher_spec:
+ {
+ ProcessChangeCipherSpec(buf, offset, len);
+ break;
+ }
+ case ContentType.handshake:
+ {
+ mHandshakeQueue.AddData(buf, offset, len);
+ ProcessHandshake();
+ break;
+ }
+ case ContentType.heartbeat:
+ {
+ if (!mAppDataReady)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ // TODO[RFC 6520]
+ // mHeartbeatQueue.AddData(buf, offset, len);
+ // ProcessHeartbeat();
+ break;
+ }
+ default:
+ /*
+ * Uh, we don't know this protocol.
+ *
+ * RFC2246 defines on page 13, that we should ignore this.
+ */
+ break;
+ }
+ }
+
+ private void ProcessHandshake()
+ {
+ bool read;
+ do
+ {
+ read = false;
+ /*
+ * We need the first 4 bytes, they contain type and length of the message.
+ */
+ if (mHandshakeQueue.Available >= 4)
+ {
+ byte[] beginning = new byte[4];
+ mHandshakeQueue.Read(beginning, 0, 4, 0);
+ byte type = TlsUtilities.ReadUint8(beginning, 0);
+ int len = TlsUtilities.ReadUint24(beginning, 1);
+
+ /*
+ * Check if we have enough bytes in the buffer to read the full message.
+ */
+ if (mHandshakeQueue.Available >= (len + 4))
+ {
+ /*
+ * Read the message.
+ */
+ byte[] buf = mHandshakeQueue.RemoveData(len, 4);
+
+ CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);
+
+ /*
+ * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
+ * starting at client hello up to, but not including, this finished message.
+ * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
+ */
+ switch (type)
+ {
+ case HandshakeType.hello_request:
+ break;
+ case HandshakeType.finished:
+ default:
+ {
+ TlsContext ctx = Context;
+ if (type == HandshakeType.finished
+ && this.mExpectedVerifyData == null
+ && ctx.SecurityParameters.MasterSecret != null)
+ {
+ this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
+ }
+
+ mRecordStream.UpdateHandshakeData(beginning, 0, 4);
+ mRecordStream.UpdateHandshakeData(buf, 0, len);
+ break;
+ }
+ }
+
+ /*
+ * Now, parse the message.
+ */
+ HandleHandshakeMessage(type, buf);
+ read = true;
+ }
+ }
+ }
+ while (read);
+ }
+
+ private void ProcessApplicationData()
+ {
+ /*
+ * There is nothing we need to do here.
+ *
+ * This function could be used for callbacks when application data arrives in the future.
+ */
+ }
+
+ private void ProcessAlert()
+ {
+ while (mAlertQueue.Available >= 2)
+ {
+ /*
+ * An alert is always 2 bytes. Read the alert.
+ */
+ byte[] tmp = mAlertQueue.RemoveData(2, 0);
+ byte level = tmp[0];
+ byte description = tmp[1];
+
+ Peer.NotifyAlertReceived(level, description);
+
+ if (level == AlertLevel.fatal)
+ {
+ /*
+ * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
+ * without proper close_notify messages with level equal to warning.
+ */
+ InvalidateSession();
+
+ this.mFailedWithError = true;
+ this.mClosed = true;
+
+ mRecordStream.SafeClose();
+
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+ else
+ {
+
+ /*
+ * RFC 5246 7.2.1. The other party MUST respond with a close_notify alert of its own
+ * and close down the connection immediately, discarding any pending writes.
+ */
+ // TODO Can close_notify be a fatal alert?
+ if (description == AlertDescription.close_notify)
+ {
+ HandleClose(false);
+ }
+
+ /*
+ * If it is just a warning, we continue.
+ */
+ HandleWarningMessage(description);
+ }
+ }
+ }
+
+ /**
+ * This method is called, when a change cipher spec message is received.
+ *
+ * @throws IOException If the message has an invalid content or the handshake is not in the correct
+ * state.
+ */
+ private void ProcessChangeCipherSpec(byte[] buf, int off, int len)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ byte message = TlsUtilities.ReadUint8(buf, off + i);
+
+ if (message != ChangeCipherSpec.change_cipher_spec)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ if (this.mReceivedChangeCipherSpec
+ || mAlertQueue.Available > 0
+ || mHandshakeQueue.Available > 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ mRecordStream.ReceivedReadCipherSpec();
+
+ this.mReceivedChangeCipherSpec = true;
+
+ HandleChangeCipherSpecMessage();
+ }
+ }
+
+ protected internal virtual int ApplicationDataAvailable()
+ {
+ return mApplicationDataQueue.Available;
+ }
+
+ /**
+ * Read data from the network. The method will return immediately, if there is still some data
+ * left in the buffer, or block until some application data has been read from the network.
+ *
+ * @param buf The buffer where the data will be copied to.
+ * @param offset The position where the data will be placed in the buffer.
+ * @param len The maximum number of bytes to read.
+ * @return The number of bytes read.
+ * @throws IOException If something goes wrong during reading data.
+ */
+ protected internal virtual int ReadApplicationData(byte[] buf, int offset, int len)
+ {
+ if (len < 1)
+ return 0;
+
+ while (mApplicationDataQueue.Available == 0)
+ {
+ /*
+ * We need to read some data.
+ */
+ if (this.mClosed)
+ {
+ if (this.mFailedWithError)
+ {
+ /*
+ * Something went terribly wrong, we should throw an IOException
+ */
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+
+ /*
+ * Connection has been closed, there is no more data to read.
+ */
+ return 0;
+ }
+
+ SafeReadRecord();
+ }
+
+ len = System.Math.Min(len, mApplicationDataQueue.Available);
+ mApplicationDataQueue.RemoveData(buf, offset, len, 0);
+ return len;
+ }
+
+ protected virtual void SafeReadRecord()
+ {
+ try
+ {
+ if (!mRecordStream.ReadRecord())
+ {
+ // TODO It would be nicer to allow graceful connection close if between records
+ // this.FailWithError(AlertLevel.warning, AlertDescription.close_notify);
+ throw new EndOfStreamException();
+ }
+ }
+ catch (TlsFatalAlert e)
+ {
+ if (!mClosed)
+ {
+ this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to read record", e);
+ }
+ throw e;
+ }
+ catch (Exception e)
+ {
+ if (!mClosed)
+ {
+ this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e);
+ }
+ throw e;
+ }
+ }
+
+ protected virtual void SafeWriteRecord(byte type, byte[] buf, int offset, int len)
+ {
+ try
+ {
+ mRecordStream.WriteRecord(type, buf, offset, len);
+ }
+ catch (TlsFatalAlert e)
+ {
+ if (!mClosed)
+ {
+ this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to write record", e);
+ }
+ throw e;
+ }
+ catch (Exception e)
+ {
+ if (!mClosed)
+ {
+ this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to write record", e);
+ }
+ throw e;
+ }
+ }
+
+ /**
+ * Send some application data to the remote system.
+ * <p/>
+ * The method will handle fragmentation internally.
+ *
+ * @param buf The buffer with the data.
+ * @param offset The position in the buffer where the data is placed.
+ * @param len The length of the data.
+ * @throws IOException If something goes wrong during sending.
+ */
+ protected internal virtual void WriteData(byte[] buf, int offset, int len)
+ {
+ if (this.mClosed)
+ {
+ if (this.mFailedWithError)
+ throw new IOException(TLS_ERROR_MESSAGE);
+
+ throw new IOException("Sorry, connection has been closed, you cannot write more data");
+ }
+
+ while (len > 0)
+ {
+ /*
+ * RFC 5246 6.2.1. Zero-length fragments of Application data MAY be sent as they are
+ * potentially useful as a traffic analysis countermeasure.
+ *
+ * NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting.
+ */
+
+ if (this.mSplitApplicationDataRecords)
+ {
+ /*
+ * Protect against known IV attack!
+ *
+ * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE.
+ */
+ SafeWriteRecord(ContentType.application_data, buf, offset, 1);
+ ++offset;
+ --len;
+ }
+
+ if (len > 0)
+ {
+ // Fragment data according to the current fragment limit.
+ int toWrite = System.Math.Min(len, mRecordStream.GetPlaintextLimit());
+ SafeWriteRecord(ContentType.application_data, buf, offset, toWrite);
+ offset += toWrite;
+ len -= toWrite;
+ }
+ }
+ }
+
+ protected virtual void WriteHandshakeMessage(byte[] buf, int off, int len)
+ {
+ while (len > 0)
+ {
+ // Fragment data according to the current fragment limit.
+ int toWrite = System.Math.Min(len, mRecordStream.GetPlaintextLimit());
+ SafeWriteRecord(ContentType.handshake, buf, off, toWrite);
+ off += toWrite;
+ len -= toWrite;
+ }
+ }
+
+ /// <summary>The secure bidirectional stream for this connection</summary>
+ /// <remarks>Only allowed in blocking mode.</remarks>
+ public virtual Stream Stream
+ {
+ get
+ {
+ if (!mBlocking)
+ throw new InvalidOperationException("Cannot use Stream in non-blocking mode! Use OfferInput()/OfferOutput() instead.");
+ return this.mTlsStream;
+ }
+ }
+
+ /**
+ * Offer input from an arbitrary source. Only allowed in non-blocking mode.<br>
+ * <br>
+ * After this method returns, the input buffer is "owned" by this object. Other code
+ * must not attempt to do anything with it.<br>
+ * <br>
+ * This method will decrypt and process all records that are fully available.
+ * If only part of a record is available, the buffer will be retained until the
+ * remainder of the record is offered.<br>
+ * <br>
+ * If any records containing application data were processed, the decrypted data
+ * can be obtained using {@link #readInput(byte[], int, int)}. If any records
+ * containing protocol data were processed, a response may have been generated.
+ * You should always check to see if there is any available output after calling
+ * this method by calling {@link #getAvailableOutputBytes()}.
+ * @param input The input buffer to offer
+ * @throws IOException If an error occurs while decrypting or processing a record
+ */
+ public virtual void OfferInput(byte[] input)
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use OfferInput() in blocking mode! Use Stream instead.");
+ if (mClosed)
+ throw new IOException("Connection is closed, cannot accept any more input");
+
+ mInputBuffers.Write(input);
+
+ // loop while there are enough bytes to read the length of the next record
+ while (mInputBuffers.Available >= RecordStream.TLS_HEADER_SIZE)
+ {
+ byte[] header = new byte[RecordStream.TLS_HEADER_SIZE];
+ mInputBuffers.Peek(header);
+
+ int totalLength = TlsUtilities.ReadUint16(header, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE;
+ if (mInputBuffers.Available < totalLength)
+ {
+ // not enough bytes to read a whole record
+ break;
+ }
+
+ SafeReadRecord();
+ }
+ }
+
+ /**
+ * Gets the amount of received application data. A call to {@link #readInput(byte[], int, int)}
+ * is guaranteed to be able to return at least this much data.<br>
+ * <br>
+ * Only allowed in non-blocking mode.
+ * @return The number of bytes of available application data
+ */
+ public virtual int GetAvailableInputBytes()
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use GetAvailableInputBytes() in blocking mode! Use ApplicationDataAvailable() instead.");
+
+ return ApplicationDataAvailable();
+ }
+
+ /**
+ * Retrieves received application data. Use {@link #getAvailableInputBytes()} to check
+ * how much application data is currently available. This method functions similarly to
+ * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data
+ * is available, nothing will be copied and zero will be returned.<br>
+ * <br>
+ * Only allowed in non-blocking mode.
+ * @param buffer The buffer to hold the application data
+ * @param offset The start offset in the buffer at which the data is written
+ * @param length The maximum number of bytes to read
+ * @return The total number of bytes copied to the buffer. May be less than the
+ * length specified if the length was greater than the amount of available data.
+ */
+ public virtual int ReadInput(byte[] buffer, int offset, int length)
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use ReadInput() in blocking mode! Use Stream instead.");
+
+ return ReadApplicationData(buffer, offset, System.Math.Min(length, ApplicationDataAvailable()));
+ }
+
+ /**
+ * Offer output from an arbitrary source. Only allowed in non-blocking mode.<br>
+ * <br>
+ * After this method returns, the specified section of the buffer will have been
+ * processed. Use {@link #readOutput(byte[], int, int)} to get the bytes to
+ * transmit to the other peer.<br>
+ * <br>
+ * This method must not be called until after the handshake is complete! Attempting
+ * to call it before the handshake is complete will result in an exception.
+ * @param buffer The buffer containing application data to encrypt
+ * @param offset The offset at which to begin reading data
+ * @param length The number of bytes of data to read
+ * @throws IOException If an error occurs encrypting the data, or the handshake is not complete
+ */
+ public virtual void OfferOutput(byte[] buffer, int offset, int length)
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use OfferOutput() in blocking mode! Use Stream instead.");
+ if (!mAppDataReady)
+ throw new IOException("Application data cannot be sent until the handshake is complete!");
+
+ WriteData(buffer, offset, length);
+ }
+
+ /**
+ * Gets the amount of encrypted data available to be sent. A call to
+ * {@link #readOutput(byte[], int, int)} is guaranteed to be able to return at
+ * least this much data.<br>
+ * <br>
+ * Only allowed in non-blocking mode.
+ * @return The number of bytes of available encrypted data
+ */
+ public virtual int GetAvailableOutputBytes()
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use GetAvailableOutputBytes() in blocking mode! Use Stream instead.");
+
+ return mOutputBuffer.Available;
+ }
+
+ /**
+ * Retrieves encrypted data to be sent. Use {@link #getAvailableOutputBytes()} to check
+ * how much encrypted data is currently available. This method functions similarly to
+ * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data
+ * is available, nothing will be copied and zero will be returned.<br>
+ * <br>
+ * Only allowed in non-blocking mode.
+ * @param buffer The buffer to hold the encrypted data
+ * @param offset The start offset in the buffer at which the data is written
+ * @param length The maximum number of bytes to read
+ * @return The total number of bytes copied to the buffer. May be less than the
+ * length specified if the length was greater than the amount of available data.
+ */
+ public virtual int ReadOutput(byte[] buffer, int offset, int length)
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use ReadOutput() in blocking mode! Use Stream instead.");
+
+ return mOutputBuffer.Read(buffer, offset, length);
+ }
+
+ /**
+ * Terminate this connection with an alert. Can be used for normal closure too.
+ *
+ * @param alertLevel
+ * See {@link AlertLevel} for values.
+ * @param alertDescription
+ * See {@link AlertDescription} for values.
+ * @throws IOException
+ * If alert was fatal.
+ */
+ protected virtual void FailWithError(byte alertLevel, byte alertDescription, string message, Exception cause)
+ {
+ /*
+ * Check if the connection is still open.
+ */
+ if (!mClosed)
+ {
+ /*
+ * Prepare the message
+ */
+ this.mClosed = true;
+
+ if (alertLevel == AlertLevel.fatal)
+ {
+ /*
+ * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
+ * without proper close_notify messages with level equal to warning.
+ */
+ // TODO This isn't quite in the right place. Also, as of TLS 1.1 the above is obsolete.
+ InvalidateSession();
+
+ this.mFailedWithError = true;
+ }
+ RaiseAlert(alertLevel, alertDescription, message, cause);
+ mRecordStream.SafeClose();
+ if (alertLevel != AlertLevel.fatal)
+ {
+ return;
+ }
+ }
+
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+
+ protected virtual void InvalidateSession()
+ {
+ if (this.mSessionParameters != null)
+ {
+ this.mSessionParameters.Clear();
+ this.mSessionParameters = null;
+ }
+
+ if (this.mTlsSession != null)
+ {
+ this.mTlsSession.Invalidate();
+ this.mTlsSession = null;
+ }
+ }
+
+ protected virtual void ProcessFinishedMessage(MemoryStream buf)
+ {
+ if (mExpectedVerifyData == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ byte[] verify_data = TlsUtilities.ReadFully(mExpectedVerifyData.Length, buf);
+
+ AssertEmpty(buf);
+
+ /*
+ * Compare both checksums.
+ */
+ if (!Arrays.ConstantTimeAreEqual(mExpectedVerifyData, verify_data))
+ {
+ /*
+ * Wrong checksum in the finished message.
+ */
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+ }
+ }
+
+ protected virtual void RaiseAlert(byte alertLevel, byte alertDescription, string message, Exception cause)
+ {
+ Peer.NotifyAlertRaised(alertLevel, alertDescription, message, cause);
+
+ byte[] error = new byte[]{ alertLevel, alertDescription };
+
+ SafeWriteRecord(ContentType.alert, error, 0, 2);
+ }
+
+ protected virtual void RaiseWarning(byte alertDescription, string message)
+ {
+ RaiseAlert(AlertLevel.warning, alertDescription, message, null);
+ }
+
+ protected virtual void SendCertificateMessage(Certificate certificate)
+ {
+ if (certificate == null)
+ {
+ certificate = Certificate.EmptyChain;
+ }
+
+ if (certificate.IsEmpty)
+ {
+ TlsContext context = Context;
+ if (!context.IsServer)
+ {
+ ProtocolVersion serverVersion = Context.ServerVersion;
+ if (serverVersion.IsSsl)
+ {
+ string errorMessage = serverVersion.ToString() + " client didn't provide credentials";
+ RaiseWarning(AlertDescription.no_certificate, errorMessage);
+ return;
+ }
+ }
+ }
+
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate);
+
+ certificate.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendChangeCipherSpecMessage()
+ {
+ byte[] message = new byte[]{ 1 };
+ SafeWriteRecord(ContentType.change_cipher_spec, message, 0, message.Length);
+ mRecordStream.SentWriteCipherSpec();
+ }
+
+ protected virtual void SendFinishedMessage()
+ {
+ byte[] verify_data = CreateVerifyData(Context.IsServer);
+
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.finished, verify_data.Length);
+
+ message.Write(verify_data, 0, verify_data.Length);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendSupplementalDataMessage(IList supplementalData)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.supplemental_data);
+
+ WriteSupplementalData(message, supplementalData);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual byte[] CreateVerifyData(bool isServer)
+ {
+ TlsContext context = Context;
+ string asciiLabel = isServer ? ExporterLabel.server_finished : ExporterLabel.client_finished;
+ byte[] sslSender = isServer ? TlsUtilities.SSL_SERVER : TlsUtilities.SSL_CLIENT;
+ byte[] hash = GetCurrentPrfHash(context, mRecordStream.HandshakeHash, sslSender);
+ return TlsUtilities.CalculateVerifyData(context, asciiLabel, hash);
+ }
+
+ /**
+ * Closes this connection.
+ *
+ * @throws IOException If something goes wrong during closing.
+ */
+ public virtual void Close()
+ {
+ HandleClose(true);
+ }
+
+ protected virtual void HandleClose(bool user_canceled)
+ {
+ if (!mClosed)
+ {
+ if (user_canceled && !mAppDataReady)
+ {
+ RaiseWarning(AlertDescription.user_canceled, "User canceled handshake");
+ }
+ this.FailWithError(AlertLevel.warning, AlertDescription.close_notify, "Connection closed", null);
+ }
+ }
+
+ protected internal virtual void Flush()
+ {
+ mRecordStream.Flush();
+ }
+
+ public virtual bool IsClosed
+ {
+ get { return mClosed; }
+ }
+
+ protected virtual short ProcessMaxFragmentLengthExtension(IDictionary clientExtensions, IDictionary serverExtensions,
+ byte alertDescription)
+ {
+ short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
+ if (maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)maxFragmentLength)
+ || (!this.mResumedSession && maxFragmentLength != TlsExtensionsUtilities
+ .GetMaxFragmentLengthExtension(clientExtensions)))
+ {
+ throw new TlsFatalAlert(alertDescription);
+ }
+ }
+ return maxFragmentLength;
+ }
+
+ protected virtual void RefuseRenegotiation()
+ {
+ /*
+ * RFC 5746 4.5 SSLv3 clients that refuse renegotiation SHOULD use a fatal
+ * handshake_failure alert.
+ */
+ if (TlsUtilities.IsSsl(Context))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ RaiseWarning(AlertDescription.no_renegotiation, "Renegotiation not supported");
+ }
+
+ /**
+ * Make sure the InputStream 'buf' now empty. Fail otherwise.
+ *
+ * @param buf The InputStream to check.
+ * @throws IOException If 'buf' is not empty.
+ */
+ protected internal static void AssertEmpty(MemoryStream buf)
+ {
+ if (buf.Position < buf.Length)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ protected internal static byte[] CreateRandomBlock(bool useGmtUnixTime, IRandomGenerator randomGenerator)
+ {
+ byte[] result = new byte[32];
+ randomGenerator.NextBytes(result);
+
+ if (useGmtUnixTime)
+ {
+ TlsUtilities.WriteGmtUnixTime(result, 0);
+ }
+
+ return result;
+ }
+
+ protected internal static byte[] CreateRenegotiationInfo(byte[] renegotiated_connection)
+ {
+ return TlsUtilities.EncodeOpaque8(renegotiated_connection);
+ }
+
+ protected internal static void EstablishMasterSecret(TlsContext context, TlsKeyExchange keyExchange)
+ {
+ byte[] pre_master_secret = keyExchange.GeneratePremasterSecret();
+
+ try
+ {
+ context.SecurityParameters.masterSecret = TlsUtilities.CalculateMasterSecret(context, pre_master_secret);
+ }
+ finally
+ {
+ // TODO Is there a way to ensure the data is really overwritten?
+ /*
+ * RFC 2246 8.1. The pre_master_secret should be deleted from memory once the
+ * master_secret has been computed.
+ */
+ if (pre_master_secret != null)
+ {
+ Arrays.Fill(pre_master_secret, (byte)0);
+ }
+ }
+ }
+
+ /**
+ * 'sender' only relevant to SSLv3
+ */
+ protected internal static byte[] GetCurrentPrfHash(TlsContext context, TlsHandshakeHash handshakeHash, byte[] sslSender)
+ {
+ IDigest d = handshakeHash.ForkPrfHash();
+
+ if (sslSender != null && TlsUtilities.IsSsl(context))
+ {
+ d.BlockUpdate(sslSender, 0, sslSender.Length);
+ }
+
+ return DigestUtilities.DoFinal(d);
+ }
+
+ protected internal static IDictionary ReadExtensions(MemoryStream input)
+ {
+ if (input.Position >= input.Length)
+ return null;
+
+ byte[] extBytes = TlsUtilities.ReadOpaque16(input);
+
+ AssertEmpty(input);
+
+ MemoryStream buf = new MemoryStream(extBytes, false);
+
+ // Integer -> byte[]
+ IDictionary extensions = Platform.CreateHashtable();
+
+ while (buf.Position < buf.Length)
+ {
+ int extension_type = TlsUtilities.ReadUint16(buf);
+ byte[] extension_data = TlsUtilities.ReadOpaque16(buf);
+
+ /*
+ * RFC 3546 2.3 There MUST NOT be more than one extension of the same type.
+ */
+ if (extensions.Contains(extension_type))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ extensions.Add(extension_type, extension_data);
+ }
+
+ return extensions;
+ }
+
+ protected internal static IList ReadSupplementalDataMessage(MemoryStream input)
+ {
+ byte[] supp_data = TlsUtilities.ReadOpaque24(input);
+
+ AssertEmpty(input);
+
+ MemoryStream buf = new MemoryStream(supp_data, false);
+
+ IList supplementalData = Platform.CreateArrayList();
+
+ while (buf.Position < buf.Length)
+ {
+ int supp_data_type = TlsUtilities.ReadUint16(buf);
+ byte[] data = TlsUtilities.ReadOpaque16(buf);
+
+ supplementalData.Add(new SupplementalDataEntry(supp_data_type, data));
+ }
+
+ return supplementalData;
+ }
+
+ protected internal static void WriteExtensions(Stream output, IDictionary extensions)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ foreach (int extension_type in extensions.Keys)
+ {
+ byte[] extension_data = (byte[])extensions[extension_type];
+
+ TlsUtilities.CheckUint16(extension_type);
+ TlsUtilities.WriteUint16(extension_type, buf);
+ TlsUtilities.WriteOpaque16(extension_data, buf);
+ }
+
+ byte[] extBytes = buf.ToArray();
+
+ TlsUtilities.WriteOpaque16(extBytes, output);
+ }
+
+ protected internal static void WriteSupplementalData(Stream output, IList supplementalData)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ foreach (SupplementalDataEntry entry in supplementalData)
+ {
+ int supp_data_type = entry.DataType;
+ TlsUtilities.CheckUint16(supp_data_type);
+ TlsUtilities.WriteUint16(supp_data_type, buf);
+ TlsUtilities.WriteOpaque16(entry.Data, buf);
+ }
+
+ byte[] supp_data = buf.ToArray();
+
+ TlsUtilities.WriteOpaque24(supp_data, output);
+ }
+
+ protected internal static int GetPrfAlgorithm(TlsContext context, int ciphersuite)
+ {
+ bool isTLSv12 = TlsUtilities.IsTlsV12(context);
+
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ {
+ if (isTLSv12)
+ {
+ return PrfAlgorithm.tls_prf_sha256;
+ }
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ {
+ if (isTLSv12)
+ {
+ return PrfAlgorithm.tls_prf_sha384;
+ }
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+ {
+ if (isTLSv12)
+ {
+ return PrfAlgorithm.tls_prf_sha384;
+ }
+ return PrfAlgorithm.tls_prf_legacy;
+ }
+
+ default:
+ {
+ if (isTLSv12)
+ {
+ return PrfAlgorithm.tls_prf_sha256;
+ }
+ return PrfAlgorithm.tls_prf_legacy;
+ }
+ }
+ }
+
+ internal class HandshakeMessage
+ : MemoryStream
+ {
+ internal HandshakeMessage(byte handshakeType)
+ : this(handshakeType, 60)
+ {
+ }
+
+ internal HandshakeMessage(byte handshakeType, int length)
+ : base(length + 4)
+ {
+ TlsUtilities.WriteUint8(handshakeType, this);
+ // Reserve space for length
+ TlsUtilities.WriteUint24(0, this);
+ }
+
+ internal void Write(byte[] data)
+ {
+ Write(data, 0, data.Length);
+ }
+
+ internal void WriteToRecordStream(TlsProtocol protocol)
+ {
+ // Patch actual length back in
+ long length = Length - 4;
+ TlsUtilities.CheckUint24(length);
+ this.Position = 1;
+ TlsUtilities.WriteUint24((int)length, this);
+ protocol.WriteHandshakeMessage(GetBuffer(), 0, (int)Length);
+ this.Close();
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsProtocolHandler.cs b/crypto/src/crypto/tls/TlsProtocolHandler.cs
index 4707df3b5..6f223467f 100644
--- a/crypto/src/crypto/tls/TlsProtocolHandler.cs
+++ b/crypto/src/crypto/tls/TlsProtocolHandler.cs
@@ -21,1224 +21,19 @@ using Org.BouncyCastle.Utilities.Date;
namespace Org.BouncyCastle.Crypto.Tls
{
- /// <remarks>An implementation of all high level protocols in TLS 1.0.</remarks>
+ [Obsolete("Use 'TlsClientProtocol' instead")]
public class TlsProtocolHandler
+ : TlsClientProtocol
{
- /*
- * Our Connection states
- */
- private const short CS_CLIENT_HELLO_SEND = 1;
- private const short CS_SERVER_HELLO_RECEIVED = 2;
- private const short CS_SERVER_CERTIFICATE_RECEIVED = 3;
- private const short CS_SERVER_KEY_EXCHANGE_RECEIVED = 4;
- private const short CS_CERTIFICATE_REQUEST_RECEIVED = 5;
- private const short CS_SERVER_HELLO_DONE_RECEIVED = 6;
- private const short CS_CLIENT_KEY_EXCHANGE_SEND = 7;
- private const short CS_CERTIFICATE_VERIFY_SEND = 8;
- private const short CS_CLIENT_CHANGE_CIPHER_SPEC_SEND = 9;
- private const short CS_CLIENT_FINISHED_SEND = 10;
- private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 11;
- private const short CS_DONE = 12;
-
- private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
-
- /*
- * Queues for data from some protocols.
- */
-
- private ByteQueue applicationDataQueue = new ByteQueue();
- private ByteQueue alertQueue = new ByteQueue(2);
- private ByteQueue handshakeQueue = new ByteQueue();
-
- /*
- * The Record Stream we use
- */
- private RecordStream rs;
- private SecureRandom random;
-
- private TlsStream tlsStream = null;
-
- private bool closed = false;
- private bool failedWithError = false;
- private bool appDataReady = false;
- private IDictionary clientExtensions;
-
- private SecurityParameters securityParameters = null;
-
- private TlsClientContextImpl tlsClientContext = null;
- private TlsClient tlsClient = null;
- private int[] offeredCipherSuites = null;
- private byte[] offeredCompressionMethods = null;
- private TlsKeyExchange keyExchange = null;
- private TlsAuthentication authentication = null;
- private CertificateRequest certificateRequest = null;
-
- private short connection_state = 0;
-
- private static SecureRandom CreateSecureRandom()
- {
- /*
- * We use our threaded seed generator to generate a good random seed. If the user
- * has a better random seed, he should use the constructor with a SecureRandom.
- *
- * Hopefully, 20 bytes in fast mode are good enough.
- */
- byte[] seed = new ThreadedSeedGenerator().GenerateSeed(20, true);
-
- return new SecureRandom(seed);
- }
-
- public TlsProtocolHandler(
- Stream s)
- : this(s, s)
- {
- }
-
- public TlsProtocolHandler(
- Stream s,
- SecureRandom sr)
- : this(s, s, sr)
- {
- }
-
- /// <remarks>Both streams can be the same object</remarks>
- public TlsProtocolHandler(
- Stream inStr,
- Stream outStr)
- : this(inStr, outStr, CreateSecureRandom())
+ public TlsProtocolHandler(Stream stream, SecureRandom secureRandom)
+ : base(stream, stream, secureRandom)
{
}
/// <remarks>Both streams can be the same object</remarks>
- public TlsProtocolHandler(
- Stream inStr,
- Stream outStr,
- SecureRandom sr)
- {
- this.rs = new RecordStream(this, inStr, outStr);
- this.random = sr;
- }
-
- internal void ProcessData(
- byte contentType,
- byte[] buf,
- int offset,
- int len)
- {
- /*
- * Have a look at the protocol type, and add it to the correct queue.
- */
- switch (contentType)
- {
- case ContentType.change_cipher_spec:
- ProcessChangeCipherSpec(buf, offset, len);
- break;
- case ContentType.alert:
- alertQueue.AddData(buf, offset, len);
- ProcessAlert();
- break;
- case ContentType.handshake:
- handshakeQueue.AddData(buf, offset, len);
- ProcessHandshake();
- break;
- case ContentType.application_data:
- if (!appDataReady)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
- }
- applicationDataQueue.AddData(buf, offset, len);
- ProcessApplicationData();
- break;
- default:
- /*
- * Uh, we don't know this protocol.
- *
- * RFC2246 defines on page 13, that we should ignore this.
- */
- break;
- }
- }
-
- private void ProcessHandshake()
- {
- bool read;
- do
- {
- read = false;
-
- /*
- * We need the first 4 bytes, they contain type and length of
- * the message.
- */
- if (handshakeQueue.Available >= 4)
- {
- byte[] beginning = new byte[4];
- handshakeQueue.Read(beginning, 0, 4, 0);
- MemoryStream bis = new MemoryStream(beginning, false);
- byte handshakeType = TlsUtilities.ReadUint8(bis);
- int len = TlsUtilities.ReadUint24(bis);
-
- /*
- * Check if we have enough bytes in the buffer to read
- * the full message.
- */
- if (handshakeQueue.Available >= (len + 4))
- {
- /*
- * Read the message.
- */
- byte[] buf = handshakeQueue.RemoveData(len, 4);
-
- /*
- * RFC 2246 7.4.9. The value handshake_messages includes all
- * handshake messages starting at client hello up to, but not
- * including, this finished message. [..] Note: [Also,] Hello Request
- * messages are omitted from handshake hashes.
- */
- switch (handshakeType)
- {
- case HandshakeType.hello_request:
- case HandshakeType.finished:
- break;
- default:
- rs.UpdateHandshakeData(beginning, 0, 4);
- rs.UpdateHandshakeData(buf, 0, len);
- break;
- }
-
- /*
- * Now, parse the message.
- */
- ProcessHandshakeMessage(handshakeType, buf);
- read = true;
- }
- }
- }
- while (read);
- }
-
- private void ProcessHandshakeMessage(byte handshakeType, byte[] buf)
- {
- MemoryStream inStr = new MemoryStream(buf, false);
-
- /*
- * Check the type.
- */
- switch (handshakeType)
- {
- case HandshakeType.certificate:
- {
- switch (connection_state)
- {
- case CS_SERVER_HELLO_RECEIVED:
- {
- // Parse the Certificate message and send to cipher suite
-
- Certificate serverCertificate = Certificate.Parse(inStr);
-
- AssertEmpty(inStr);
-
- this.keyExchange.ProcessServerCertificate(serverCertificate);
-
- this.authentication = tlsClient.GetAuthentication();
- this.authentication.NotifyServerCertificate(serverCertificate);
-
- break;
- }
- default:
- this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
- break;
- }
-
- connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
- break;
- }
- case HandshakeType.finished:
- switch (connection_state)
- {
- case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
- /*
- * Read the checksum from the finished message, it has always 12 bytes.
- */
- byte[] serverVerifyData = new byte[12];
- TlsUtilities.ReadFully(serverVerifyData, inStr);
-
- AssertEmpty(inStr);
-
- /*
- * Calculate our own checksum.
- */
- byte[] expectedServerVerifyData = TlsUtilities.PRF(
- securityParameters.masterSecret, "server finished",
- rs.GetCurrentHash(), 12);
-
- /*
- * Compare both checksums.
- */
- if (!Arrays.ConstantTimeAreEqual(expectedServerVerifyData, serverVerifyData))
- {
- /*
- * Wrong checksum in the finished message.
- */
- this.FailWithError(AlertLevel.fatal, AlertDescription.decrypt_error);
- }
-
- connection_state = CS_DONE;
-
- /*
- * We are now ready to receive application data.
- */
- this.appDataReady = true;
- break;
- default:
- this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
- break;
- }
- break;
- case HandshakeType.server_hello:
- switch (connection_state)
- {
- case CS_CLIENT_HELLO_SEND:
- /*
- * Read the server hello message
- */
- TlsUtilities.CheckVersion(inStr);
-
- /*
- * Read the server random
- */
- securityParameters.serverRandom = new byte[32];
- TlsUtilities.ReadFully(securityParameters.serverRandom, inStr);
-
- byte[] sessionID = TlsUtilities.ReadOpaque8(inStr);
- if (sessionID.Length > 32)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
- }
-
- this.tlsClient.NotifySessionID(sessionID);
-
- /*
- * Find out which CipherSuite the server has chosen and check that
- * it was one of the offered ones.
- */
- int selectedCipherSuite = TlsUtilities.ReadUint16(inStr);
- if (!ArrayContains(offeredCipherSuites, selectedCipherSuite)
- || selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
- }
-
- this.tlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
-
- /*
- * Find out which CompressionMethod the server has chosen and check that
- * it was one of the offered ones.
- */
- byte selectedCompressionMethod = TlsUtilities.ReadUint8(inStr);
- if (!ArrayContains(offeredCompressionMethods, selectedCompressionMethod))
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
- }
-
- this.tlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
-
- /*
- * RFC3546 2.2 The extended server hello message format MAY be
- * sent in place of the server hello message when the client has
- * requested extended functionality via the extended client hello
- * message specified in Section 2.1.
- * ...
- * Note that the extended server hello message is only sent in response
- * to an extended client hello message. This prevents the possibility
- * that the extended server hello message could "break" existing TLS 1.0
- * clients.
- */
-
- /*
- * TODO RFC 3546 2.3
- * If [...] the older session is resumed, then the server MUST ignore
- * extensions appearing in the client hello, and send a server hello
- * containing no extensions.
- */
-
- // Int32 -> byte[]
- IDictionary serverExtensions = Platform.CreateHashtable();
-
- if (inStr.Position < inStr.Length)
- {
- // Process extensions from extended server hello
- byte[] extBytes = TlsUtilities.ReadOpaque16(inStr);
-
- MemoryStream ext = new MemoryStream(extBytes, false);
- while (ext.Position < ext.Length)
- {
- int extType = TlsUtilities.ReadUint16(ext);
- byte[] extValue = TlsUtilities.ReadOpaque16(ext);
-
- // Note: RFC 5746 makes a special case for EXT_RenegotiationInfo
- if (extType != ExtensionType.renegotiation_info
- && !clientExtensions.Contains(extType))
- {
- /*
- * RFC 3546 2.3
- * Note that for all extension types (including those defined in
- * future), the extension type MUST NOT appear in the extended server
- * hello unless the same extension type appeared in the corresponding
- * client hello. Thus clients MUST abort the handshake if they receive
- * an extension type in the extended server hello that they did not
- * request in the associated (extended) client hello.
- */
- this.FailWithError(AlertLevel.fatal, AlertDescription.unsupported_extension);
- }
-
- if (serverExtensions.Contains(extType))
- {
- /*
- * RFC 3546 2.3
- * Also note that when multiple extensions of different types are
- * present in the extended client hello or the extended server hello,
- * the extensions may appear in any order. There MUST NOT be more than
- * one extension of the same type.
- */
- this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
- }
-
- serverExtensions.Add(extType, extValue);
- }
- }
-
- AssertEmpty(inStr);
-
- /*
- * RFC 5746 3.4. When a ServerHello is received, the client MUST check if it
- * includes the "renegotiation_info" extension:
- */
- {
- bool secure_negotiation = serverExtensions.Contains(ExtensionType.renegotiation_info);
-
- /*
- * If the extension is present, set the secure_renegotiation flag
- * to TRUE. The client MUST then verify that the length of the
- * "renegotiated_connection" field is zero, and if it is not, MUST
- * abort the handshake (by sending a fatal handshake_failure
- * alert).
- */
- if (secure_negotiation)
- {
- byte[] renegExtValue = (byte[])serverExtensions[ExtensionType.renegotiation_info];
-
- if (!Arrays.ConstantTimeAreEqual(renegExtValue,
- CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
- }
- }
-
- tlsClient.NotifySecureRenegotiation(secure_negotiation);
- }
-
- if (clientExtensions != null)
- {
- tlsClient.ProcessServerExtensions(serverExtensions);
- }
-
- this.keyExchange = tlsClient.GetKeyExchange();
-
- connection_state = CS_SERVER_HELLO_RECEIVED;
- break;
- default:
- this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
- break;
- }
- break;
- case HandshakeType.server_hello_done:
- switch (connection_state)
- {
- case CS_SERVER_HELLO_RECEIVED:
- case CS_SERVER_CERTIFICATE_RECEIVED:
- case CS_SERVER_KEY_EXCHANGE_RECEIVED:
- case CS_CERTIFICATE_REQUEST_RECEIVED:
-
- // NB: Original code used case label fall-through
-
- if (connection_state == CS_SERVER_HELLO_RECEIVED)
- {
- // There was no server certificate message; check it's OK
- this.keyExchange.SkipServerCertificate();
- this.authentication = null;
-
- // There was no server key exchange message; check it's OK
- this.keyExchange.SkipServerKeyExchange();
- }
- else if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
- {
- // There was no server key exchange message; check it's OK
- this.keyExchange.SkipServerKeyExchange();
- }
-
- AssertEmpty(inStr);
-
- connection_state = CS_SERVER_HELLO_DONE_RECEIVED;
-
- TlsCredentials clientCreds = null;
- if (certificateRequest == null)
- {
- this.keyExchange.SkipClientCredentials();
- }
- else
- {
- clientCreds = this.authentication.GetClientCredentials(certificateRequest);
-
- Certificate clientCert;
- if (clientCreds == null)
- {
- this.keyExchange.SkipClientCredentials();
- clientCert = Certificate.EmptyChain;
- }
- else
- {
- this.keyExchange.ProcessClientCredentials(clientCreds);
- clientCert = clientCreds.Certificate;
- }
-
- SendClientCertificate(clientCert);
- }
-
- /*
- * Send the client key exchange message, depending on the key
- * exchange we are using in our CipherSuite.
- */
- SendClientKeyExchange();
-
- connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;
-
- if (clientCreds != null && clientCreds is TlsSignerCredentials)
- {
- TlsSignerCredentials signerCreds = (TlsSignerCredentials)clientCreds;
- byte[] md5andsha1 = rs.GetCurrentHash();
- byte[] clientCertificateSignature = signerCreds.GenerateCertificateSignature(
- md5andsha1);
- SendCertificateVerify(clientCertificateSignature);
-
- connection_state = CS_CERTIFICATE_VERIFY_SEND;
- }
-
- /*
- * Now, we send change cipher state
- */
- byte[] cmessage = new byte[1];
- cmessage[0] = 1;
- rs.WriteMessage(ContentType.change_cipher_spec, cmessage, 0, cmessage.Length);
-
- connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;
-
- /*
- * Calculate the master_secret
- */
- byte[] pms = this.keyExchange.GeneratePremasterSecret();
-
- securityParameters.masterSecret = TlsUtilities.PRF(pms, "master secret",
- TlsUtilities.Concat(securityParameters.clientRandom, securityParameters.serverRandom),
- 48);
-
- // TODO Is there a way to ensure the data is really overwritten?
- /*
- * RFC 2246 8.1. The pre_master_secret should be deleted from
- * memory once the master_secret has been computed.
- */
- Array.Clear(pms, 0, pms.Length);
-
- /*
- * Initialize our cipher suite
- */
- rs.ClientCipherSpecDecided(tlsClient.GetCompression(), tlsClient.GetCipher());
-
- /*
- * Send our finished message.
- */
- byte[] clientVerifyData = TlsUtilities.PRF(securityParameters.masterSecret,
- "client finished", rs.GetCurrentHash(), 12);
-
- MemoryStream bos = new MemoryStream();
- TlsUtilities.WriteUint8((byte)HandshakeType.finished, bos);
- TlsUtilities.WriteOpaque24(clientVerifyData, bos);
- byte[] message = bos.ToArray();
-
- rs.WriteMessage(ContentType.handshake, message, 0, message.Length);
-
- this.connection_state = CS_CLIENT_FINISHED_SEND;
- break;
- default:
- this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
- break;
- }
- break;
- case HandshakeType.server_key_exchange:
- {
- switch (connection_state)
- {
- case CS_SERVER_HELLO_RECEIVED:
- case CS_SERVER_CERTIFICATE_RECEIVED:
- {
- // NB: Original code used case label fall-through
- if (connection_state == CS_SERVER_HELLO_RECEIVED)
- {
- // There was no server certificate message; check it's OK
- this.keyExchange.SkipServerCertificate();
- this.authentication = null;
- }
-
- this.keyExchange.ProcessServerKeyExchange(inStr);
-
- AssertEmpty(inStr);
- break;
- }
- default:
- this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
- break;
- }
-
- this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
- break;
- }
- case HandshakeType.certificate_request:
- switch (connection_state)
- {
- case CS_SERVER_CERTIFICATE_RECEIVED:
- case CS_SERVER_KEY_EXCHANGE_RECEIVED:
- {
- // NB: Original code used case label fall-through
- if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
- {
- // There was no server key exchange message; check it's OK
- this.keyExchange.SkipServerKeyExchange();
- }
-
- if (this.authentication == null)
- {
- /*
- * RFC 2246 7.4.4. It is a fatal handshake_failure alert
- * for an anonymous server to request client identification.
- */
- this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
- }
-
- this.certificateRequest = CertificateRequest.Parse(//getContext(),
- inStr);
-
- AssertEmpty(inStr);
-
- this.keyExchange.ValidateCertificateRequest(this.certificateRequest);
-
- break;
- }
- default:
- this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
- break;
- }
-
- this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
- break;
- case HandshakeType.hello_request:
- /*
- * RFC 2246 7.4.1.1 Hello request
- * This message will be ignored by the client if the client is currently
- * negotiating a session. This message may be ignored by the client if it
- * does not wish to renegotiate a session, or the client may, if it wishes,
- * respond with a no_renegotiation alert.
- */
- if (connection_state == CS_DONE)
- {
- // Renegotiation not supported yet
- SendAlert(AlertLevel.warning, AlertDescription.no_renegotiation);
- }
- break;
- case HandshakeType.client_key_exchange:
- case HandshakeType.certificate_verify:
- case HandshakeType.client_hello:
- default:
- // We do not support this!
- this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
- break;
- }
- }
-
- private void ProcessApplicationData()
- {
- /*
- * There is nothing we need to do here.
- *
- * This function could be used for callbacks when application
- * data arrives in the future.
- */
- }
-
- private void ProcessAlert()
- {
- while (alertQueue.Available >= 2)
- {
- /*
- * An alert is always 2 bytes. Read the alert.
- */
- byte[] tmp = alertQueue.RemoveData(2, 0);
- byte level = tmp[0];
- byte description = tmp[1];
- if (level == (byte)AlertLevel.fatal)
- {
- this.failedWithError = true;
- this.closed = true;
- /*
- * Now try to Close the stream, ignore errors.
- */
- try
- {
- rs.Close();
- }
- catch (Exception)
- {
- }
- throw new IOException(TLS_ERROR_MESSAGE);
- }
- else
- {
- if (description == (byte)AlertDescription.close_notify)
- {
- HandleClose(false);
- }
-
- /*
- * If it is just a warning, we continue.
- */
- }
- }
- }
-
- /**
- * This method is called, when a change cipher spec message is received.
- *
- * @throws IOException If the message has an invalid content or the
- * handshake is not in the correct state.
- */
- private void ProcessChangeCipherSpec(byte[] buf, int off, int len)
- {
- for (int i = 0; i < len; ++i)
- {
- if (buf[off + i] != 1)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.decode_error);
- }
-
- /*
- * Check if we are in the correct connection state.
- */
- if (this.connection_state != CS_CLIENT_FINISHED_SEND)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
- }
-
- rs.ServerClientSpecReceived();
-
- this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED;
- }
- }
-
- private void SendClientCertificate(Certificate clientCert)
- {
- MemoryStream bos = new MemoryStream();
- TlsUtilities.WriteUint8((byte)HandshakeType.certificate, bos);
-
- // Reserve space for length
- TlsUtilities.WriteUint24(0, bos);
-
- clientCert.Encode(bos);
- byte[] message = bos.ToArray();
-
- // Patch actual length back in
- TlsUtilities.WriteUint24(message.Length - 4, message, 1);
-
- rs.WriteMessage(ContentType.handshake, message, 0, message.Length);
- }
-
- private void SendClientKeyExchange()
- {
- MemoryStream bos = new MemoryStream();
- TlsUtilities.WriteUint8((byte)HandshakeType.client_key_exchange, bos);
-
- // Reserve space for length
- TlsUtilities.WriteUint24(0, bos);
-
- this.keyExchange.GenerateClientKeyExchange(bos);
- byte[] message = bos.ToArray();
-
- // Patch actual length back in
- TlsUtilities.WriteUint24(message.Length - 4, message, 1);
-
- rs.WriteMessage(ContentType.handshake, message, 0, message.Length);
- }
-
- private void SendCertificateVerify(byte[] data)
- {
- /*
- * Send signature of handshake messages so far to prove we are the owner of
- * the cert See RFC 2246 sections 4.7, 7.4.3 and 7.4.8
- */
- MemoryStream bos = new MemoryStream();
- TlsUtilities.WriteUint8((byte)HandshakeType.certificate_verify, bos);
- TlsUtilities.WriteUint24(data.Length + 2, bos);
- TlsUtilities.WriteOpaque16(data, bos);
- byte[] message = bos.ToArray();
-
- rs.WriteMessage(ContentType.handshake, message, 0, message.Length);
- }
-
- /// <summary>Connects to the remote system.</summary>
- /// <param name="verifyer">Will be used when a certificate is received to verify
- /// that this certificate is accepted by the client.</param>
- /// <exception cref="IOException">If handshake was not successful</exception>
- [Obsolete("Use version taking TlsClient")]
- public virtual void Connect(
- ICertificateVerifyer verifyer)
- {
- this.Connect(new LegacyTlsClient(verifyer));
- }
-
- public virtual void Connect(TlsClient tlsClient)
- {
- if (tlsClient == null)
- throw new ArgumentNullException("tlsClient");
- if (this.tlsClient != null)
- throw new InvalidOperationException("Connect can only be called once");
-
- /*
- * Send Client hello
- *
- * First, generate some random data.
- */
- this.securityParameters = new SecurityParameters();
- this.securityParameters.clientRandom = CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(), random,
- ExporterLabel.client_random);
-
- this.tlsClientContext = new TlsClientContextImpl(random, securityParameters);
- this.tlsClient = tlsClient;
- this.tlsClient.Init(tlsClientContext);
-
- MemoryStream outStr = new MemoryStream();
- TlsUtilities.WriteVersion(outStr);
- outStr.Write(securityParameters.clientRandom, 0, 32);
-
- /*
- * Length of Session id
- */
- TlsUtilities.WriteUint8(0, outStr);
-
- this.offeredCipherSuites = this.tlsClient.GetCipherSuites();
-
- // Int32 -> byte[]
- this.clientExtensions = this.tlsClient.GetClientExtensions();
-
- // Cipher Suites (and SCSV)
- {
- /*
- * RFC 5746 3.4.
- * The client MUST include either an empty "renegotiation_info"
- * extension, or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling
- * cipher suite value in the ClientHello. Including both is NOT
- * RECOMMENDED.
- */
- bool noRenegExt = clientExtensions == null
- || !clientExtensions.Contains(ExtensionType.renegotiation_info);
-
- int count = offeredCipherSuites.Length;
- if (noRenegExt)
- {
- // Note: 1 extra slot for TLS_EMPTY_RENEGOTIATION_INFO_SCSV
- ++count;
- }
-
- TlsUtilities.WriteUint16(2 * count, outStr);
-
- for (int i = 0; i < offeredCipherSuites.Length; ++i)
- {
- TlsUtilities.WriteUint16((int)offeredCipherSuites[i], outStr);
- }
-
- if (noRenegExt)
- {
- TlsUtilities.WriteUint16((int)CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV, outStr);
- }
- }
-
- /*
- * Compression methods, just the null method.
- */
- this.offeredCompressionMethods = tlsClient.GetCompressionMethods();
-
- {
- TlsUtilities.WriteUint8((byte)offeredCompressionMethods.Length, outStr);
- for (int i = 0; i < offeredCompressionMethods.Length; ++i)
- {
- TlsUtilities.WriteUint8(offeredCompressionMethods[i], outStr);
- }
- }
-
- // Extensions
- if (clientExtensions != null)
- {
- MemoryStream ext = new MemoryStream();
-
- foreach (int extType in clientExtensions.Keys)
- {
- WriteExtension(ext, extType, (byte[])clientExtensions[extType]);
- }
-
- TlsUtilities.WriteOpaque16(ext.ToArray(), outStr);
- }
-
- MemoryStream bos = new MemoryStream();
- TlsUtilities.WriteUint8((byte)HandshakeType.client_hello, bos);
- TlsUtilities.WriteUint24((int)outStr.Length, bos);
- byte[] outBytes = outStr.ToArray();
- bos.Write(outBytes, 0, outBytes.Length);
- byte[] message = bos.ToArray();
- SafeWriteMessage(ContentType.handshake, message, 0, message.Length);
- connection_state = CS_CLIENT_HELLO_SEND;
-
- /*
- * We will now read data, until we have completed the handshake.
- */
- while (connection_state != CS_DONE)
- {
- SafeReadData();
- }
-
- this.tlsStream = new TlsStream(this);
- }
-
- /**
- * Read data from the network. The method will return immediately, if there is
- * still some data left in the buffer, or block until some application
- * data has been read from the network.
- *
- * @param buf The buffer where the data will be copied to.
- * @param offset The position where the data will be placed in the buffer.
- * @param len The maximum number of bytes to read.
- * @return The number of bytes read.
- * @throws IOException If something goes wrong during reading data.
- */
- internal int ReadApplicationData(byte[] buf, int offset, int len)
- {
- while (applicationDataQueue.Available == 0)
- {
- if (this.closed)
- {
- /*
- * We need to read some data.
- */
- if (this.failedWithError)
- {
- /*
- * Something went terribly wrong, we should throw an IOException
- */
- throw new IOException(TLS_ERROR_MESSAGE);
- }
-
- /*
- * Connection has been closed, there is no more data to read.
- */
- return 0;
- }
-
- SafeReadData();
- }
- len = System.Math.Min(len, applicationDataQueue.Available);
- applicationDataQueue.RemoveData(buf, offset, len, 0);
- return len;
- }
-
- private void SafeReadData()
- {
- try
- {
- rs.ReadData();
- }
- catch (TlsFatalAlert e)
- {
- if (!this.closed)
- {
- this.FailWithError(AlertLevel.fatal, e.AlertDescription);
- }
- throw e;
- }
- catch (IOException e)
- {
- if (!this.closed)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error);
- }
- throw e;
- }
- catch (Exception e)
- {
- if (!this.closed)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error);
- }
- throw e;
- }
- }
-
- private void SafeWriteMessage(byte type, byte[] buf, int offset, int len)
- {
- try
- {
- rs.WriteMessage(type, buf, offset, len);
- }
- catch (TlsFatalAlert e)
- {
- if (!this.closed)
- {
- this.FailWithError(AlertLevel.fatal, e.AlertDescription);
- }
- throw e;
- }
- catch (IOException e)
- {
- if (!closed)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error);
- }
- throw e;
- }
- catch (Exception e)
- {
- if (!closed)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error);
- }
- throw e;
- }
- }
-
- /**
- * Send some application data to the remote system.
- * <p/>
- * The method will handle fragmentation internally.
- *
- * @param buf The buffer with the data.
- * @param offset The position in the buffer where the data is placed.
- * @param len The length of the data.
- * @throws IOException If something goes wrong during sending.
- */
- internal void WriteData(byte[] buf, int offset, int len)
- {
- if (this.closed)
- {
- if (this.failedWithError)
- throw new IOException(TLS_ERROR_MESSAGE);
-
- throw new IOException("Sorry, connection has been closed, you cannot write more data");
- }
-
- while (len > 0)
- {
- /*
- * RFC 5246 6.2.1. Zero-length fragments of Application data MAY be sent as they are
- * potentially useful as a traffic analysis countermeasure.
- *
- * NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting.
- */
-
- //if (this.splitApplicationDataRecords)
- {
- /*
- * Protect against known IV attack!
- *
- * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE.
- */
- SafeWriteMessage(ContentType.application_data, buf, offset, 1);
- ++offset;
- --len;
- }
-
- if (len > 0)
- {
- // Fragment data according to the current fragment limit.
- //int toWrite = System.Math.Min(len, recordStream.GetPlaintextLimit());
- int toWrite = System.Math.Min(len, 1 << 14);
- SafeWriteMessage(ContentType.application_data, buf, offset, toWrite);
- offset += toWrite;
- len -= toWrite;
- }
- }
- }
-
- /// <summary>A Stream which can be used to send data.</summary>
- [Obsolete("Use 'Stream' property instead")]
- public virtual Stream OutputStream
- {
- get { return this.tlsStream; }
- }
-
- /// <summary>A Stream which can be used to read data.</summary>
- [Obsolete("Use 'Stream' property instead")]
- public virtual Stream InputStream
- {
- get { return this.tlsStream; }
- }
-
- /// <summary>The secure bidirectional stream for this connection</summary>
- public virtual Stream Stream
- {
- get { return this.tlsStream; }
- }
-
- /**
- * Terminate this connection with an alert.
- * <p/>
- * Can be used for normal closure too.
- *
- * @param alertLevel The level of the alert, an be AlertLevel.fatal or AL_warning.
- * @param alertDescription The exact alert message.
- * @throws IOException If alert was fatal.
- */
- private void FailWithError(byte alertLevel, byte alertDescription)
- {
- /*
- * Check if the connection is still open.
- */
- if (!closed)
- {
- /*
- * Prepare the message
- */
- this.closed = true;
-
- if (alertLevel == AlertLevel.fatal)
- {
- /*
- * This is a fatal message.
- */
- this.failedWithError = true;
- }
- SendAlert(alertLevel, alertDescription);
- rs.Close();
- if (alertLevel == AlertLevel.fatal)
- {
- throw new IOException(TLS_ERROR_MESSAGE);
- }
- }
- else
- {
- throw new IOException(TLS_ERROR_MESSAGE);
- }
- }
-
- internal void SendAlert(byte alertLevel, byte alertDescription)
- {
- byte[] error = new byte[] { alertLevel, alertDescription };
-
- rs.WriteMessage(ContentType.alert, error, 0, 2);
- }
-
- /// <summary>Closes this connection</summary>
- /// <exception cref="IOException">If something goes wrong during closing.</exception>
- public virtual void Close()
- {
- HandleClose(true);
- }
-
- protected virtual void HandleClose(bool user_canceled)
- {
- if (!closed)
- {
- if (user_canceled && !appDataReady)
- {
- SendAlert(AlertLevel.warning, AlertDescription.user_canceled);
- }
- this.FailWithError(AlertLevel.warning, AlertDescription.close_notify);
- }
- }
-
- /**
- * Make sure the Stream is now empty. Fail otherwise.
- *
- * @param is The Stream to check.
- * @throws IOException If is is not empty.
- */
- internal void AssertEmpty(
- MemoryStream inStr)
- {
- if (inStr.Position < inStr.Length)
- {
- throw new TlsFatalAlert(AlertDescription.decode_error);
- }
- }
-
- protected static byte[] CreateRandomBlock(bool useGMTUnixTime, SecureRandom random, string asciiLabel)
- {
- /*
- * We use the TLS 1.0 PRF on the SecureRandom output, to guard against RNGs where the raw
- * output could be used to recover the internal state.
- */
- byte[] secret = new byte[32];
- random.NextBytes(secret);
-
- byte[] seed = new byte[8];
- // TODO Use high-resolution timer
- TlsUtilities.WriteUint64(DateTimeUtilities.CurrentUnixMs(), seed, 0);
-
- byte[] result = TlsUtilities.PRF(secret, asciiLabel, seed, 32);
-
- if (useGMTUnixTime)
- {
- TlsUtilities.WriteGmtUnixTime(result, 0);
- }
-
- return result;
- }
-
- internal void Flush()
- {
- rs.Flush();
- }
-
- internal bool IsClosed
- {
- get { return closed; }
- }
-
- private static bool ArrayContains(byte[] a, byte n)
- {
- for (int i = 0; i < a.Length; ++i)
- {
- if (a[i] == n)
- return true;
- }
- return false;
- }
-
- private static bool ArrayContains(int[] a, int n)
- {
- for (int i = 0; i < a.Length; ++i)
- {
- if (a[i] == n)
- return true;
- }
- return false;
- }
-
- private static byte[] CreateRenegotiationInfo(byte[] renegotiated_connection)
- {
- MemoryStream buf = new MemoryStream();
- TlsUtilities.WriteOpaque8(renegotiated_connection, buf);
- return buf.ToArray();
- }
-
- private static void WriteExtension(Stream output, int extType, byte[] extValue)
+ public TlsProtocolHandler(Stream input, Stream output, SecureRandom secureRandom)
+ : base(input, output, secureRandom)
{
- TlsUtilities.WriteUint16(extType, output);
- TlsUtilities.WriteOpaque16(extValue, output);
}
}
}
diff --git a/crypto/src/crypto/tls/TlsPskIdentityManager.cs b/crypto/src/crypto/tls/TlsPskIdentityManager.cs
new file mode 100644
index 000000000..a72c2299c
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsPskIdentityManager.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsPskIdentityManager
+ {
+ byte[] GetHint();
+
+ byte[] GetPsk(byte[] identity);
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsPskKeyExchange.cs b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
index 9961fc9d1..0af7f7a69 100644
--- a/crypto/src/crypto/tls/TlsPskKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
@@ -1,190 +1,314 @@
using System;
+using System.Collections;
using System.IO;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- internal class TlsPskKeyExchange
- : TlsKeyExchange
+ /// <summary>(D)TLS PSK key exchange (RFC 4279).</summary>
+ public class TlsPskKeyExchange
+ : AbstractTlsKeyExchange
{
- protected TlsClientContext context;
- protected int keyExchange;
- protected TlsPskIdentity pskIdentity;
+ protected TlsPskIdentity mPskIdentity;
+ protected TlsPskIdentityManager mPskIdentityManager;
- protected byte[] psk_identity_hint = null;
+ protected DHParameters mDHParameters;
+ protected int[] mNamedCurves;
+ protected byte[] mClientECPointFormats, mServerECPointFormats;
- protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
- protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
+ protected byte[] mPskIdentityHint = null;
+ protected byte[] mPsk = null;
- protected AsymmetricKeyParameter serverPublicKey = null;
- protected RsaKeyParameters rsaServerPublicKey = null;
- protected byte[] premasterSecret;
+ protected DHPrivateKeyParameters mDHAgreePrivateKey = null;
+ protected DHPublicKeyParameters mDHAgreePublicKey = null;
- internal TlsPskKeyExchange(TlsClientContext context, int keyExchange,
- TlsPskIdentity pskIdentity)
+ protected ECPrivateKeyParameters mECAgreePrivateKey = null;
+ protected ECPublicKeyParameters mECAgreePublicKey = null;
+
+ protected AsymmetricKeyParameter mServerPublicKey = null;
+ protected RsaKeyParameters mRsaServerPublicKey = null;
+ protected TlsEncryptionCredentials mServerCredentials = null;
+ protected byte[] mPremasterSecret;
+
+ public TlsPskKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsPskIdentity pskIdentity,
+ TlsPskIdentityManager pskIdentityManager, DHParameters dhParameters, int[] namedCurves,
+ byte[] clientECPointFormats, byte[] serverECPointFormats)
+ : base(keyExchange, supportedSignatureAlgorithms)
{
switch (keyExchange)
{
- case KeyExchangeAlgorithm.PSK:
- case KeyExchangeAlgorithm.RSA_PSK:
- case KeyExchangeAlgorithm.DHE_PSK:
- break;
- default:
- throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ break;
+ default:
+ throw new InvalidOperationException("unsupported key exchange algorithm");
}
- this.context = context;
- this.keyExchange = keyExchange;
- this.pskIdentity = pskIdentity;
+ this.mPskIdentity = pskIdentity;
+ this.mPskIdentityManager = pskIdentityManager;
+ this.mDHParameters = dhParameters;
+ this.mNamedCurves = namedCurves;
+ this.mClientECPointFormats = clientECPointFormats;
+ this.mServerECPointFormats = serverECPointFormats;
}
- public virtual void SkipServerCertificate()
+ public override void SkipServerCredentials()
{
- if (keyExchange == KeyExchangeAlgorithm.RSA_PSK)
- {
+ if (mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
}
- public virtual void ProcessServerCertificate(Certificate serverCertificate)
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
{
- if (keyExchange != KeyExchangeAlgorithm.RSA_PSK)
+ if (!(serverCredentials is TlsEncryptionCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsEncryptionCredentials)serverCredentials;
+ }
+
+ public override byte[] GenerateServerKeyExchange()
+ {
+ this.mPskIdentityHint = mPskIdentityManager.GetHint();
+
+ if (this.mPskIdentityHint == null && !RequiresServerKeyExchange)
+ return null;
+
+ MemoryStream buf = new MemoryStream();
+
+ if (this.mPskIdentityHint == null)
{
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ TlsUtilities.WriteOpaque16(TlsUtilities.EmptyBytes, buf);
+ }
+ else
+ {
+ TlsUtilities.WriteOpaque16(this.mPskIdentityHint, buf);
}
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ if (this.mDHParameters == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+ this.mDHParameters, buf);
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+ {
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+ mNamedCurves, mClientECPointFormats, buf);
+ }
+
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (mKeyExchange != KeyExchangeAlgorithm.RSA_PSK)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
- SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
try
{
- this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
}
- // catch (RuntimeException)
- catch (Exception)
+ catch (Exception e)
{
- throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
}
// Sanity check the PublicKeyFactory
- if (this.serverPublicKey.IsPrivate)
- {
+ if (this.mServerPublicKey.IsPrivate)
throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey);
+ this.mRsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.mServerPublicKey);
TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
- // TODO
- /*
- * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
- * signing algorithm for the certificate must be the same as the algorithm for the
- * certificate key."
- */
+ base.ProcessServerCertificate(serverCertificate);
}
- public virtual void SkipServerKeyExchange()
+ public override bool RequiresServerKeyExchange
{
- if (keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ get
{
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ switch (mKeyExchange)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ return true;
+ default:
+ return false;
+ }
}
-
- this.psk_identity_hint = TlsUtilities.EmptyBytes;
}
- public virtual void ProcessServerKeyExchange(Stream input)
+ public override void ProcessServerKeyExchange(Stream input)
{
- this.psk_identity_hint = TlsUtilities.ReadOpaque16(input);
+ this.mPskIdentityHint = TlsUtilities.ReadOpaque16(input);
- if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
{
- byte[] pBytes = TlsUtilities.ReadOpaque16(input);
- byte[] gBytes = TlsUtilities.ReadOpaque16(input);
- byte[] YsBytes = TlsUtilities.ReadOpaque16(input);
+ ServerDHParams serverDHParams = ServerDHParams.Parse(input);
- BigInteger p = new BigInteger(1, pBytes);
- BigInteger g = new BigInteger(1, gBytes);
- BigInteger Ys = new BigInteger(1, YsBytes);
-
- this.dhAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey(
- new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(serverDHParams.PublicKey);
+ this.mDHParameters = mDHAgreePublicKey.Parameters;
}
- else if (this.psk_identity_hint.Length == 0)
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
{
- // TODO Should we enforce that this message should have been skipped if hint is empty?
- //throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ ECDomainParameters ecParams = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, input);
+
+ byte[] point = TlsUtilities.ReadOpaque8(input);
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mClientECPointFormats, ecParams, point));
}
}
- public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
- public virtual void SkipClientCredentials()
- {
- // OK
- }
-
- public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
- public virtual void GenerateClientKeyExchange(Stream output)
+ public override void GenerateClientKeyExchange(Stream output)
{
- if (psk_identity_hint == null || psk_identity_hint.Length == 0)
+ if (mPskIdentityHint == null)
{
- pskIdentity.SkipIdentityHint();
+ mPskIdentity.SkipIdentityHint();
}
else
{
- pskIdentity.NotifyIdentityHint(psk_identity_hint);
+ mPskIdentity.NotifyIdentityHint(mPskIdentityHint);
}
- byte[] psk_identity = pskIdentity.GetPskIdentity();
+ byte[] psk_identity = mPskIdentity.GetPskIdentity();
+ if (psk_identity == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.mPsk = mPskIdentity.GetPsk();
+ if (mPsk == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
TlsUtilities.WriteOpaque16(psk_identity, output);
- if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ mContext.SecurityParameters.pskIdentity = psk_identity;
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mDHParameters, output);
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+ {
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mServerECPointFormats, mECAgreePublicKey.Parameters, output);
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(mContext,
+ this.mRsaServerPublicKey, output);
+ }
+ }
+
+ public override void ProcessClientKeyExchange(Stream input)
+ {
+ byte[] psk_identity = TlsUtilities.ReadOpaque16(input);
+
+ this.mPsk = mPskIdentityManager.GetPsk(psk_identity);
+ if (mPsk == null)
+ throw new TlsFatalAlert(AlertDescription.unknown_psk_identity);
+
+ mContext.SecurityParameters.pskIdentity = psk_identity;
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ BigInteger Yc = TlsDHUtilities.ReadDHParameter(input);
+
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters));
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
{
- this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(
- context.SecureRandom, this.rsaServerPublicKey, output);
+ byte[] point = TlsUtilities.ReadOpaque8(input);
+
+ ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mServerECPointFormats, curve_params, point));
}
- else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
{
- this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(
- context.SecureRandom, this.dhAgreeServerPublicKey.Parameters, output);
+ byte[] encryptedPreMasterSecret;
+ if (TlsUtilities.IsSsl(mContext))
+ {
+ // TODO Do any SSLv3 clients actually include the length?
+ encryptedPreMasterSecret = Streams.ReadAll(input);
+ }
+ else
+ {
+ encryptedPreMasterSecret = TlsUtilities.ReadOpaque16(input);
+ }
+
+ this.mPremasterSecret = mServerCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret);
}
}
- public virtual byte[] GeneratePremasterSecret()
+ public override byte[] GeneratePremasterSecret()
{
- byte[] psk = pskIdentity.GetPsk();
- byte[] other_secret = GenerateOtherSecret(psk.Length);
+ byte[] other_secret = GenerateOtherSecret(mPsk.Length);
- MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length);
+ MemoryStream buf = new MemoryStream(4 + other_secret.Length + mPsk.Length);
TlsUtilities.WriteOpaque16(other_secret, buf);
- TlsUtilities.WriteOpaque16(psk, buf);
+ TlsUtilities.WriteOpaque16(mPsk, buf);
+
+ Arrays.Fill(mPsk, (byte)0);
+ this.mPsk = null;
+
return buf.ToArray();
}
protected virtual byte[] GenerateOtherSecret(int pskLength)
{
- if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
{
- return TlsDHUtilities.CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
+ if (mDHAgreePrivateKey != null)
+ {
+ return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey);
+ }
+
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
- if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
{
- return this.premasterSecret;
+ if (mECAgreePrivateKey != null)
+ {
+ return TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey);
+ }
+
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ return this.mPremasterSecret;
}
return new byte[pskLength];
@@ -193,12 +317,10 @@ namespace Org.BouncyCastle.Crypto.Tls
protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key)
{
// TODO What is the minimum bit length required?
- // key.Modulus.BitLength;
+ // key.Modulus.BitLength;
if (!key.Exponent.IsProbablePrime(2))
- {
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
return key;
}
diff --git a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
index aad482316..b02d56486 100644
--- a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
@@ -1,163 +1,138 @@
using System;
+using System.Collections;
using System.IO;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- /// <summary>
- /// TLS 1.0 RSA key exchange.
- /// </summary>
- internal class TlsRsaKeyExchange
- : TlsKeyExchange
+ /// <summary>(D)TLS and SSLv3 RSA key exchange.</summary>
+ public class TlsRsaKeyExchange
+ : AbstractTlsKeyExchange
{
- protected TlsClientContext context;
+ protected AsymmetricKeyParameter mServerPublicKey = null;
- protected AsymmetricKeyParameter serverPublicKey = null;
+ protected RsaKeyParameters mRsaServerPublicKey = null;
- protected RsaKeyParameters rsaServerPublicKey = null;
+ protected TlsEncryptionCredentials mServerCredentials = null;
- protected byte[] premasterSecret;
+ protected byte[] mPremasterSecret;
- internal TlsRsaKeyExchange(TlsClientContext context)
+ public TlsRsaKeyExchange(IList supportedSignatureAlgorithms)
+ : base(KeyExchangeAlgorithm.RSA, supportedSignatureAlgorithms)
{
- this.context = context;
}
- public virtual void SkipServerCertificate()
+ public override void SkipServerCredentials()
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
- public virtual void ProcessServerCertificate(Certificate serverCertificate)
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
{
+ if (!(serverCredentials is TlsEncryptionCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsEncryptionCredentials)serverCredentials;
+ }
+
+ public override void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
- SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
try
{
- this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
}
-// catch (RuntimeException)
- catch (Exception)
+ catch (Exception e)
{
- throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
}
// Sanity check the PublicKeyFactory
- if (this.serverPublicKey.IsPrivate)
- {
+ if (this.mServerPublicKey.IsPrivate)
throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey);
+ this.mRsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.mServerPublicKey);
TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
- // TODO
- /*
- * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
- * signing algorithm for the certificate must be the same as the algorithm for the
- * certificate key."
- */
- }
-
- public virtual void SkipServerKeyExchange()
- {
- // OK
- }
-
- public virtual void ProcessServerKeyExchange(Stream input)
- {
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ base.ProcessServerCertificate(serverCertificate);
}
- public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
{
byte[] types = certificateRequest.CertificateTypes;
- foreach (byte type in types)
+ for (int i = 0; i < types.Length; ++i)
{
- switch (type)
+ switch (types[i])
{
- case ClientCertificateType.rsa_sign:
- case ClientCertificateType.dss_sign:
- case ClientCertificateType.ecdsa_sign:
- break;
- default:
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
}
}
- public virtual void SkipClientCredentials()
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
{
- // OK
+ if (!(clientCredentials is TlsSignerCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
- public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
+ public override void GenerateClientKeyExchange(Stream output)
{
- if (!(clientCredentials is TlsSignerCredentials))
- {
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
+ this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(mContext, mRsaServerPublicKey, output);
}
-
- public virtual void GenerateClientKeyExchange(Stream output)
+
+ public override void ProcessClientKeyExchange(Stream input)
{
- this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(
- context.SecureRandom, this.rsaServerPublicKey, output);
+ byte[] encryptedPreMasterSecret;
+ if (TlsUtilities.IsSsl(mContext))
+ {
+ // TODO Do any SSLv3 clients actually include the length?
+ encryptedPreMasterSecret = Streams.ReadAll(input);
+ }
+ else
+ {
+ encryptedPreMasterSecret = TlsUtilities.ReadOpaque16(input);
+ }
+
+ this.mPremasterSecret = mServerCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret);
}
- public virtual byte[] GeneratePremasterSecret()
+ public override byte[] GeneratePremasterSecret()
{
- byte[] tmp = this.premasterSecret;
- this.premasterSecret = null;
+ if (this.mPremasterSecret == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ byte[] tmp = this.mPremasterSecret;
+ this.mPremasterSecret = null;
return tmp;
}
- // Would be needed to process RSA_EXPORT server key exchange
-// protected virtual void ProcessRsaServerKeyExchange(Stream input, ISigner signer)
-// {
-// Stream sigIn = input;
-// if (signer != null)
-// {
-// sigIn = new SignerStream(input, signer, null);
-// }
-//
-// byte[] modulusBytes = TlsUtilities.ReadOpaque16(sigIn);
-// byte[] exponentBytes = TlsUtilities.ReadOpaque16(sigIn);
-//
-// if (signer != null)
-// {
-// byte[] sigByte = TlsUtilities.ReadOpaque16(input);
-//
-// if (!signer.VerifySignature(sigByte))
-// {
-// handler.FailWithError(AlertLevel.fatal, AlertDescription.decrypt_error);
-// }
-// }
-//
-// BigInteger modulus = new BigInteger(1, modulusBytes);
-// BigInteger exponent = new BigInteger(1, exponentBytes);
-//
-// this.rsaServerPublicKey = ValidateRSAPublicKey(new RsaKeyParameters(false, modulus, exponent));
-// }
-
protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key)
{
// TODO What is the minimum bit length required?
-// key.Modulus.BitLength;
+ // key.Modulus.BitLength;
if (!key.Exponent.IsProbablePrime(2))
- {
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
return key;
}
diff --git a/crypto/src/crypto/tls/TlsRsaSigner.cs b/crypto/src/crypto/tls/TlsRsaSigner.cs
index ce18ef5e1..6da1c5e9b 100644
--- a/crypto/src/crypto/tls/TlsRsaSigner.cs
+++ b/crypto/src/crypto/tls/TlsRsaSigner.cs
@@ -10,50 +10,92 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
- internal class TlsRsaSigner
- : TlsSigner
+ public class TlsRsaSigner
+ : AbstractTlsSigner
{
- public virtual byte[] GenerateRawSignature(SecureRandom random,
- AsymmetricKeyParameter privateKey, byte[] md5AndSha1)
+ public override byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+ AsymmetricKeyParameter privateKey, byte[] hash)
{
- IAsymmetricBlockCipher engine = CreateRsaImpl();
- engine.Init(true, new ParametersWithRandom(privateKey, random));
- return engine.ProcessBlock(md5AndSha1, 0, md5AndSha1.Length);
+ ISigner signer = MakeSigner(algorithm, true, true,
+ new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
+ signer.BlockUpdate(hash, 0, hash.Length);
+ return signer.GenerateSignature();
}
- public virtual bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey,
- byte[] md5AndSha1)
+ public override bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+ AsymmetricKeyParameter publicKey, byte[] hash)
{
- IAsymmetricBlockCipher engine = CreateRsaImpl();
- engine.Init(false, publicKey);
- byte[] signed = engine.ProcessBlock(sigBytes, 0, sigBytes.Length);
- return Arrays.ConstantTimeAreEqual(signed, md5AndSha1);
+ ISigner signer = MakeSigner(algorithm, true, false, publicKey);
+ signer.BlockUpdate(hash, 0, hash.Length);
+ return signer.VerifySignature(sigBytes);
}
- public virtual ISigner CreateSigner(SecureRandom random, AsymmetricKeyParameter privateKey)
+ public override ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey)
{
- return MakeSigner(new CombinedHash(), true, new ParametersWithRandom(privateKey, random));
+ return MakeSigner(algorithm, false, true, new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
}
- public virtual ISigner CreateVerifyer(AsymmetricKeyParameter publicKey)
+ public override ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey)
{
- return MakeSigner(new CombinedHash(), false, publicKey);
+ return MakeSigner(algorithm, false, false, publicKey);
}
- public virtual bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+ public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
{
return publicKey is RsaKeyParameters && !publicKey.IsPrivate;
}
- protected virtual ISigner MakeSigner(IDigest d, bool forSigning, ICipherParameters cp)
+ protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning,
+ ICipherParameters cp)
{
- ISigner s = new GenericSigner(CreateRsaImpl(), d);
+ if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
+ throw new InvalidOperationException();
+ if (algorithm != null && algorithm.Signature != SignatureAlgorithm.rsa)
+ throw new InvalidOperationException();
+
+ IDigest d;
+ if (raw)
+ {
+ d = new NullDigest();
+ }
+ else if (algorithm == null)
+ {
+ d = new CombinedHash();
+ }
+ else
+ {
+ d = TlsUtilities.CreateHash(algorithm.Hash);
+ }
+
+ ISigner s;
+ if (algorithm != null)
+ {
+ /*
+ * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated
+ * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1].
+ */
+ s = new RsaDigestSigner(d, TlsUtilities.GetOidForHashAlgorithm(algorithm.Hash));
+ }
+ else
+ {
+ /*
+ * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme
+ * that did not include a DigestInfo encoding.
+ */
+ s = new GenericSigner(CreateRsaImpl(), d);
+ }
s.Init(forSigning, cp);
return s;
}
protected virtual IAsymmetricBlockCipher CreateRsaImpl()
{
+ /*
+ * RFC 5264 7.4.7.1. Implementation note: It is now known that remote timing-based attacks
+ * on TLS are possible, at least when the client and server are on the same LAN.
+ * Accordingly, implementations that use static RSA keys MUST use RSA blinding or some other
+ * anti-timing technique, as described in [TIMING].
+ */
return new Pkcs1Encoding(new RsaBlindedEngine());
}
}
diff --git a/crypto/src/crypto/tls/TlsRsaUtilities.cs b/crypto/src/crypto/tls/TlsRsaUtilities.cs
index 4450ba452..0e42c1733 100644
--- a/crypto/src/crypto/tls/TlsRsaUtilities.cs
+++ b/crypto/src/crypto/tls/TlsRsaUtilities.cs
@@ -5,38 +5,128 @@ using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
- public abstract class TlsRsaUtilities
- {
- public static byte[] GenerateEncryptedPreMasterSecret(SecureRandom random,
- RsaKeyParameters rsaServerPublicKey, Stream output)
- {
- /*
- * Choose a PremasterSecret and send it encrypted to the server
- */
- byte[] premasterSecret = new byte[48];
- random.NextBytes(premasterSecret);
- TlsUtilities.WriteVersion(premasterSecret, 0);
-
- Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine());
- encoding.Init(true, new ParametersWithRandom(rsaServerPublicKey, random));
-
- try
- {
- byte[] keData = encoding.ProcessBlock(premasterSecret, 0, premasterSecret.Length);
- TlsUtilities.WriteOpaque16(keData, output);
- }
- catch (InvalidCipherTextException)
- {
- /*
- * This should never happen, only during decryption.
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
-
- return premasterSecret;
- }
- }
+ public abstract class TlsRsaUtilities
+ {
+ /// <exception cref="IOException"></exception>
+ public static byte[] GenerateEncryptedPreMasterSecret(TlsContext context, RsaKeyParameters rsaServerPublicKey,
+ Stream output)
+ {
+ /*
+ * Choose a PremasterSecret and send it encrypted to the server
+ */
+ byte[] premasterSecret = new byte[48];
+ context.SecureRandom.NextBytes(premasterSecret);
+ TlsUtilities.WriteVersion(context.ClientVersion, premasterSecret, 0);
+
+ Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine());
+ encoding.Init(true, new ParametersWithRandom(rsaServerPublicKey, context.SecureRandom));
+
+ try
+ {
+ byte[] encryptedPreMasterSecret = encoding.ProcessBlock(premasterSecret, 0, premasterSecret.Length);
+
+ if (TlsUtilities.IsSsl(context))
+ {
+ // TODO Do any SSLv3 servers actually expect the length?
+ output.Write(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.Length);
+ }
+ else
+ {
+ TlsUtilities.WriteOpaque16(encryptedPreMasterSecret, output);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ /*
+ * This should never happen, only during decryption.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+
+ return premasterSecret;
+ }
+
+ public static byte[] SafeDecryptPreMasterSecret(TlsContext context, RsaKeyParameters rsaServerPrivateKey,
+ byte[] encryptedPreMasterSecret)
+ {
+ /*
+ * RFC 5246 7.4.7.1.
+ */
+ ProtocolVersion clientVersion = context.ClientVersion;
+
+ // TODO Provide as configuration option?
+ bool versionNumberCheckDisabled = false;
+
+ /*
+ * Generate 48 random bytes we can use as a Pre-Master-Secret, if the
+ * PKCS1 padding check should fail.
+ */
+ byte[] fallback = new byte[48];
+ context.SecureRandom.NextBytes(fallback);
+
+ byte[] M = Arrays.Clone(fallback);
+ try
+ {
+ Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine(), fallback);
+ encoding.Init(false,
+ new ParametersWithRandom(rsaServerPrivateKey, context.SecureRandom));
+
+ M = encoding.ProcessBlock(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.Length);
+ }
+ catch (Exception)
+ {
+ /*
+ * This should never happen since the decryption should never throw an exception
+ * and return a random value instead.
+ *
+ * In any case, a TLS server MUST NOT generate an alert if processing an
+ * RSA-encrypted premaster secret message fails, or the version number is not as
+ * expected. Instead, it MUST continue the handshake with a randomly generated
+ * premaster secret.
+ */
+ }
+
+ /*
+ * If ClientHello.client_version is TLS 1.1 or higher, server implementations MUST
+ * check the version number [..].
+ */
+ if (versionNumberCheckDisabled && clientVersion.IsEqualOrEarlierVersionOf(ProtocolVersion.TLSv10))
+ {
+ /*
+ * If the version number is TLS 1.0 or earlier, server
+ * implementations SHOULD check the version number, but MAY have a
+ * configuration option to disable the check.
+ *
+ * So there is nothing to do here.
+ */
+ }
+ else
+ {
+ /*
+ * OK, we need to compare the version number in the decrypted Pre-Master-Secret with the
+ * clientVersion received during the handshake. If they don't match, we replace the
+ * decrypted Pre-Master-Secret with a random one.
+ */
+ int correct = (clientVersion.MajorVersion ^ (M[0] & 0xff))
+ | (clientVersion.MinorVersion ^ (M[1] & 0xff));
+ correct |= correct >> 1;
+ correct |= correct >> 2;
+ correct |= correct >> 4;
+ int mask = ~((correct & 1) - 1);
+
+ /*
+ * mask will be all bits set to 0xff if the version number differed.
+ */
+ for (int i = 0; i < 48; i++)
+ {
+ M[i] = (byte)((M[i] & (~mask)) | (fallback[i] & mask));
+ }
+ }
+ return M;
+ }
+ }
}
diff --git a/crypto/src/crypto/tls/TlsServer.cs b/crypto/src/crypto/tls/TlsServer.cs
new file mode 100644
index 000000000..e791f93a9
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsServer.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsServer
+ : TlsPeer
+ {
+ void Init(TlsServerContext context);
+
+ /// <exception cref="IOException"></exception>
+ void NotifyClientVersion(ProtocolVersion clientVersion);
+
+ /// <exception cref="IOException"></exception>
+ void NotifyFallback(bool isFallback);
+
+ /// <exception cref="IOException"></exception>
+ void NotifyOfferedCipherSuites(int[] offeredCipherSuites);
+
+ /// <exception cref="IOException"></exception>
+ void NotifyOfferedCompressionMethods(byte[] offeredCompressionMethods);
+
+ /// <param name="clientExtensions">A <see cref="IDictionary"/> (Int32 -> byte[]). Will never be null.</param>
+ /// <exception cref="IOException"></exception>
+ void ProcessClientExtensions(IDictionary clientExtensions);
+
+ /// <exception cref="IOException"></exception>
+ ProtocolVersion GetServerVersion();
+
+ /// <exception cref="IOException"></exception>
+ int GetSelectedCipherSuite();
+
+ /// <exception cref="IOException"></exception>
+ byte GetSelectedCompressionMethod();
+
+ /// <summary>
+ /// Get the (optional) table of server extensions to be included in (extended) server hello.
+ /// </summary>
+ /// <returns>
+ /// A <see cref="IDictionary"/> (Int32 -> byte[]). May be null.
+ /// </returns>
+ /// <exception cref="IOException"></exception>
+ IDictionary GetServerExtensions();
+
+ /// <returns>
+ /// A <see cref="IList"/> (<see cref="SupplementalDataEntry"/>). May be null.
+ /// </returns>
+ /// <exception cref="IOException"></exception>
+ IList GetServerSupplementalData();
+
+ /// <exception cref="IOException"></exception>
+ TlsCredentials GetCredentials();
+
+ /// <remarks>
+ /// This method will be called (only) if the server included an extension of type
+ /// "status_request" with empty "extension_data" in the extended server hello. See <i>RFC 3546
+ /// 3.6. Certificate Status Request</i>. If a non-null <see cref="CertificateStatus"/> is returned, it
+ /// is sent to the client as a handshake message of type "certificate_status".
+ /// </remarks>
+ /// <returns>A <see cref="CertificateStatus"/> to be sent to the client (or null for none).</returns>
+ /// <exception cref="IOException"></exception>
+ CertificateStatus GetCertificateStatus();
+
+ /// <exception cref="IOException"></exception>
+ TlsKeyExchange GetKeyExchange();
+
+ /// <exception cref="IOException"></exception>
+ CertificateRequest GetCertificateRequest();
+
+ /// <param name="clientSupplementalData"><see cref="IList"/> (<see cref="SupplementalDataEntry"/>)</param>
+ /// <exception cref="IOException"></exception>
+ void ProcessClientSupplementalData(IList clientSupplementalData);
+
+ /// <summary>
+ /// Called by the protocol handler to report the client certificate, only if <c>GetCertificateRequest</c>
+ /// returned non-null.
+ /// </summary>
+ /// <remarks>Note: this method is responsible for certificate verification and validation.</remarks>
+ /// <param name="clientCertificate">the effective client certificate (may be an empty chain).</param>
+ /// <exception cref="IOException"></exception>
+ void NotifyClientCertificate(Certificate clientCertificate);
+
+ /// <summary>RFC 5077 3.3. NewSessionTicket Handshake Message.</summary>
+ /// <remarks>
+ /// This method will be called (only) if a NewSessionTicket extension was sent by the server. See
+ /// <i>RFC 5077 4. Recommended Ticket Construction</i> for recommended format and protection.
+ /// </remarks>
+ /// <returns>The <see cref="NewSessionTicket">ticket</see>)</returns>
+ /// <exception cref="IOException"></exception>
+ NewSessionTicket GetNewSessionTicket();
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsServerContext.cs b/crypto/src/crypto/tls/TlsServerContext.cs
new file mode 100644
index 000000000..4021571aa
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsServerContext.cs
@@ -0,0 +1,11 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsServerContext
+ : TlsContext
+ {
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsServerContextImpl.cs b/crypto/src/crypto/tls/TlsServerContextImpl.cs
new file mode 100644
index 000000000..d56566ffc
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsServerContextImpl.cs
@@ -0,0 +1,20 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class TlsServerContextImpl
+ : AbstractTlsContext, TlsServerContext
+ {
+ internal TlsServerContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
+ : base(secureRandom, securityParameters)
+ {
+ }
+
+ public override bool IsServer
+ {
+ get { return true; }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
new file mode 100644
index 000000000..27f7a1dfd
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -0,0 +1,803 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsServerProtocol
+ : TlsProtocol
+ {
+ protected TlsServer mTlsServer = null;
+ internal TlsServerContextImpl mTlsServerContext = null;
+
+ protected TlsKeyExchange mKeyExchange = null;
+ protected TlsCredentials mServerCredentials = null;
+ protected CertificateRequest mCertificateRequest = null;
+
+ protected short mClientCertificateType = -1;
+ protected TlsHandshakeHash mPrepareFinishHash = null;
+
+ /**
+ * Constructor for blocking mode.
+ * @param stream The bi-directional stream of data to/from the client
+ * @param output The stream of data to the client
+ * @param secureRandom Random number generator for various cryptographic functions
+ */
+ public TlsServerProtocol(Stream stream, SecureRandom secureRandom)
+ : base(stream, secureRandom)
+ {
+ }
+
+ /**
+ * Constructor for blocking mode.
+ * @param input The stream of data from the client
+ * @param output The stream of data to the client
+ * @param secureRandom Random number generator for various cryptographic functions
+ */
+ public TlsServerProtocol(Stream input, Stream output, SecureRandom secureRandom)
+ : base(input, output, secureRandom)
+ {
+ }
+
+ /**
+ * Constructor for non-blocking mode.<br>
+ * <br>
+ * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
+ * provide the received ciphertext, then use
+ * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br>
+ * <br>
+ * Similarly, when data needs to be sent, use
+ * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
+ * {@link #readOutput(byte[], int, int)} to get the corresponding
+ * ciphertext.
+ *
+ * @param secureRandom
+ * Random number generator for various cryptographic functions
+ */
+ public TlsServerProtocol(SecureRandom secureRandom)
+ : base(secureRandom)
+ {
+ }
+
+ /**
+ * Receives a TLS handshake in the role of server.<br>
+ * <br>
+ * In blocking mode, this will not return until the handshake is complete.
+ * In non-blocking mode, use {@link TlsPeer#notifyHandshakeComplete()} to
+ * receive a callback when the handshake is complete.
+ *
+ * @param tlsServer
+ * @throws IOException If in blocking mode and handshake was not successful.
+ */
+ public virtual void Accept(TlsServer tlsServer)
+ {
+ if (tlsServer == null)
+ throw new ArgumentNullException("tlsServer");
+ if (this.mTlsServer != null)
+ throw new InvalidOperationException("'Accept' can only be called once");
+
+ this.mTlsServer = tlsServer;
+
+ this.mSecurityParameters = new SecurityParameters();
+ this.mSecurityParameters.entity = ConnectionEnd.server;
+
+ this.mTlsServerContext = new TlsServerContextImpl(mSecureRandom, mSecurityParameters);
+
+ this.mSecurityParameters.serverRandom = CreateRandomBlock(tlsServer.ShouldUseGmtUnixTime(),
+ mTlsServerContext.NonceRandomGenerator);
+
+ this.mTlsServer.Init(mTlsServerContext);
+ this.mRecordStream.Init(mTlsServerContext);
+
+ this.mRecordStream.SetRestrictReadVersion(false);
+
+ BlockForHandshake();
+ }
+
+ protected override void CleanupHandshake()
+ {
+ base.CleanupHandshake();
+
+ this.mKeyExchange = null;
+ this.mServerCredentials = null;
+ this.mCertificateRequest = null;
+ this.mPrepareFinishHash = null;
+ }
+
+ protected override TlsContext Context
+ {
+ get { return mTlsServerContext; }
+ }
+
+ internal override AbstractTlsContext ContextAdmin
+ {
+ get { return mTlsServerContext; }
+ }
+
+ protected override TlsPeer Peer
+ {
+ get { return mTlsServer; }
+ }
+
+ protected override void HandleHandshakeMessage(byte type, byte[] data)
+ {
+ MemoryStream buf = new MemoryStream(data);
+
+ switch (type)
+ {
+ case HandshakeType.client_hello:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_START:
+ {
+ ReceiveClientHelloMessage(buf);
+ this.mConnectionState = CS_CLIENT_HELLO;
+
+ SendServerHelloMessage();
+ this.mConnectionState = CS_SERVER_HELLO;
+
+ mRecordStream.NotifyHelloComplete();
+
+ IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
+ if (serverSupplementalData != null)
+ {
+ SendSupplementalDataMessage(serverSupplementalData);
+ }
+ this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
+
+ this.mKeyExchange = mTlsServer.GetKeyExchange();
+ this.mKeyExchange.Init(Context);
+
+ this.mServerCredentials = mTlsServer.GetCredentials();
+
+ Certificate serverCertificate = null;
+
+ if (this.mServerCredentials == null)
+ {
+ this.mKeyExchange.SkipServerCredentials();
+ }
+ else
+ {
+ this.mKeyExchange.ProcessServerCredentials(this.mServerCredentials);
+
+ serverCertificate = this.mServerCredentials.Certificate;
+ SendCertificateMessage(serverCertificate);
+ }
+ this.mConnectionState = CS_SERVER_CERTIFICATE;
+
+ // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+ if (serverCertificate == null || serverCertificate.IsEmpty)
+ {
+ this.mAllowCertificateStatus = false;
+ }
+
+ if (this.mAllowCertificateStatus)
+ {
+ CertificateStatus certificateStatus = mTlsServer.GetCertificateStatus();
+ if (certificateStatus != null)
+ {
+ SendCertificateStatusMessage(certificateStatus);
+ }
+ }
+
+ this.mConnectionState = CS_CERTIFICATE_STATUS;
+
+ byte[] serverKeyExchange = this.mKeyExchange.GenerateServerKeyExchange();
+ if (serverKeyExchange != null)
+ {
+ SendServerKeyExchangeMessage(serverKeyExchange);
+ }
+ this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
+
+ if (this.mServerCredentials != null)
+ {
+ this.mCertificateRequest = mTlsServer.GetCertificateRequest();
+ if (this.mCertificateRequest != null)
+ {
+ this.mKeyExchange.ValidateCertificateRequest(mCertificateRequest);
+
+ SendCertificateRequestMessage(mCertificateRequest);
+
+ TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
+ this.mCertificateRequest.SupportedSignatureAlgorithms);
+ }
+ }
+ this.mConnectionState = CS_CERTIFICATE_REQUEST;
+
+ SendServerHelloDoneMessage();
+ this.mConnectionState = CS_SERVER_HELLO_DONE;
+
+ this.mRecordStream.HandshakeHash.SealHashAlgorithms();
+
+ break;
+ }
+ case CS_END:
+ {
+ RefuseRenegotiation();
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.supplemental_data:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO_DONE:
+ {
+ mTlsServer.ProcessClientSupplementalData(ReadSupplementalDataMessage(buf));
+ this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.certificate:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO_DONE:
+ case CS_CLIENT_SUPPLEMENTAL_DATA:
+ {
+ if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
+ {
+ mTlsServer.ProcessClientSupplementalData(null);
+ }
+
+ if (this.mCertificateRequest == null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ ReceiveCertificateMessage(buf);
+ this.mConnectionState = CS_CLIENT_CERTIFICATE;
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.client_key_exchange:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO_DONE:
+ case CS_CLIENT_SUPPLEMENTAL_DATA:
+ case CS_CLIENT_CERTIFICATE:
+ {
+ if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
+ {
+ mTlsServer.ProcessClientSupplementalData(null);
+ }
+
+ if (mConnectionState < CS_CLIENT_CERTIFICATE)
+ {
+ if (this.mCertificateRequest == null)
+ {
+ this.mKeyExchange.SkipClientCredentials();
+ }
+ else
+ {
+ if (TlsUtilities.IsTlsV12(Context))
+ {
+ /*
+ * RFC 5246 If no suitable certificate is available, the client MUST Send a
+ * certificate message containing no certificates.
+ *
+ * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ else if (TlsUtilities.IsSsl(Context))
+ {
+ if (this.mPeerCertificate == null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ else
+ {
+ NotifyClientCertificate(Certificate.EmptyChain);
+ }
+ }
+ }
+
+ ReceiveClientKeyExchangeMessage(buf);
+ this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.certificate_verify:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_KEY_EXCHANGE:
+ {
+ /*
+ * RFC 5246 7.4.8 This message is only sent following a client certificate that has
+ * signing capability (i.e., all certificates except those containing fixed
+ * Diffie-Hellman parameters).
+ */
+ if (!ExpectCertificateVerifyMessage())
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ ReceiveCertificateVerifyMessage(buf);
+ this.mConnectionState = CS_CERTIFICATE_VERIFY;
+
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.finished:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_KEY_EXCHANGE:
+ case CS_CERTIFICATE_VERIFY:
+ {
+ if (mConnectionState < CS_CERTIFICATE_VERIFY && ExpectCertificateVerifyMessage())
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ ProcessFinishedMessage(buf);
+ this.mConnectionState = CS_CLIENT_FINISHED;
+
+ if (this.mExpectSessionTicket)
+ {
+ SendNewSessionTicketMessage(mTlsServer.GetNewSessionTicket());
+ SendChangeCipherSpecMessage();
+ }
+ this.mConnectionState = CS_SERVER_SESSION_TICKET;
+
+ SendFinishedMessage();
+ this.mConnectionState = CS_SERVER_FINISHED;
+ this.mConnectionState = CS_END;
+
+ CompleteHandshake();
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.hello_request:
+ case HandshakeType.hello_verify_request:
+ case HandshakeType.server_hello:
+ case HandshakeType.server_key_exchange:
+ case HandshakeType.certificate_request:
+ case HandshakeType.server_hello_done:
+ case HandshakeType.session_ticket:
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ protected override void HandleWarningMessage(byte description)
+ {
+ switch (description)
+ {
+ case AlertDescription.no_certificate:
+ {
+ /*
+ * SSL 3.0 If the server has sent a certificate request Message, the client must Send
+ * either the certificate message or a no_certificate alert.
+ */
+ if (TlsUtilities.IsSsl(Context) && mCertificateRequest != null)
+ {
+ NotifyClientCertificate(Certificate.EmptyChain);
+ }
+ break;
+ }
+ default:
+ {
+ base.HandleWarningMessage(description);
+ break;
+ }
+ }
+ }
+
+ protected virtual void NotifyClientCertificate(Certificate clientCertificate)
+ {
+ if (mCertificateRequest == null)
+ throw new InvalidOperationException();
+ if (mPeerCertificate != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ this.mPeerCertificate = clientCertificate;
+
+ if (clientCertificate.IsEmpty)
+ {
+ this.mKeyExchange.SkipClientCredentials();
+ }
+ else
+ {
+
+ /*
+ * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request
+ * message was non-empty, one of the certificates in the certificate chain SHOULD be
+ * issued by one of the listed CAs.
+ */
+
+ this.mClientCertificateType = TlsUtilities.GetClientCertificateType(clientCertificate,
+ this.mServerCredentials.Certificate);
+
+ this.mKeyExchange.ProcessClientCertificate(clientCertificate);
+ }
+
+ /*
+ * RFC 5246 7.4.6. If the client does not Send any certificates, the server MAY at its
+ * discretion either continue the handshake without client authentication, or respond with a
+ * fatal handshake_failure alert. Also, if some aspect of the certificate chain was
+ * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its
+ * discretion either continue the handshake (considering the client unauthenticated) or Send
+ * a fatal alert.
+ */
+ this.mTlsServer.NotifyClientCertificate(clientCertificate);
+ }
+
+ protected virtual void ReceiveCertificateMessage(MemoryStream buf)
+ {
+ Certificate clientCertificate = Certificate.Parse(buf);
+
+ AssertEmpty(buf);
+
+ NotifyClientCertificate(clientCertificate);
+ }
+
+ protected virtual void ReceiveCertificateVerifyMessage(MemoryStream buf)
+ {
+ DigitallySigned clientCertificateVerify = DigitallySigned.Parse(Context, buf);
+
+ AssertEmpty(buf);
+
+ // Verify the CertificateVerify message contains a correct signature.
+ try
+ {
+ byte[] hash;
+ if (TlsUtilities.IsTlsV12(Context))
+ {
+ hash = mPrepareFinishHash.GetFinalHash(clientCertificateVerify.Algorithm.Hash);
+ }
+ else
+ {
+ hash = mSecurityParameters.SessionHash;
+ }
+
+ X509CertificateStructure x509Cert = mPeerCertificate.GetCertificateAt(0);
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
+
+ TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)mClientCertificateType);
+ tlsSigner.Init(Context);
+ if (!tlsSigner.VerifyRawSignature(clientCertificateVerify.Algorithm,
+ clientCertificateVerify.Signature, publicKey, hash))
+ {
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.decrypt_error, e);
+ }
+ }
+
+ protected virtual void ReceiveClientHelloMessage(MemoryStream buf)
+ {
+ ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);
+ mRecordStream.SetWriteVersion(client_version);
+
+ if (client_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ byte[] client_random = TlsUtilities.ReadFully(32, buf);
+
+ /*
+ * TODO RFC 5077 3.4. If a ticket is presented by the client, the server MUST NOT attempt to
+ * use the Session ID in the ClientHello for stateful session resumption.
+ */
+ byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
+ if (sessionID.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ /*
+ * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
+ * resumption request), this vector MUST include at least the cipher_suite from that
+ * session.
+ */
+ int cipher_suites_length = TlsUtilities.ReadUint16(buf);
+ if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ this.mOfferedCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);
+
+ /*
+ * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
+ * resumption request), it MUST include the compression_method from that session.
+ */
+ int compression_methods_length = TlsUtilities.ReadUint8(buf);
+ if (compression_methods_length < 1)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ this.mOfferedCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and Send a server hello containing no
+ * extensions.
+ */
+ this.mClientExtensions = ReadExtensions(buf);
+
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
+ * that do not use the extended master secret [..]. (and see 5.2, 5.3)
+ */
+ this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mClientExtensions);
+
+ ContextAdmin.SetClientVersion(client_version);
+
+ mTlsServer.NotifyClientVersion(client_version);
+ mTlsServer.NotifyFallback(Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));
+
+ mSecurityParameters.clientRandom = client_random;
+
+ mTlsServer.NotifyOfferedCipherSuites(mOfferedCipherSuites);
+ mTlsServer.NotifyOfferedCompressionMethods(mOfferedCompressionMethods);
+
+ /*
+ * RFC 5746 3.6. Server Behavior: Initial Handshake
+ */
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+ * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+ * ClientHello. Including both is NOT RECOMMENDED.
+ */
+
+ /*
+ * When a ClientHello is received, the server MUST check if it includes the
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
+ * to TRUE.
+ */
+ if (Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
+ {
+ this.mSecureRenegotiation = true;
+ }
+
+ /*
+ * The server MUST check if the "renegotiation_info" extension is included in the
+ * ClientHello.
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
+ if (renegExtData != null)
+ {
+ /*
+ * If the extension is present, set secure_renegotiation flag to TRUE. The
+ * server MUST then verify that the length of the "renegotiated_connection"
+ * field is zero, and if it is not, MUST abort the handshake.
+ */
+ this.mSecureRenegotiation = true;
+
+ if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ mTlsServer.NotifySecureRenegotiation(this.mSecureRenegotiation);
+
+ if (mClientExtensions != null)
+ {
+ mTlsServer.ProcessClientExtensions(mClientExtensions);
+ }
+ }
+
+ protected virtual void ReceiveClientKeyExchangeMessage(MemoryStream buf)
+ {
+ mKeyExchange.ProcessClientKeyExchange(buf);
+
+ AssertEmpty(buf);
+
+ this.mPrepareFinishHash = mRecordStream.PrepareToFinish();
+ this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, mPrepareFinishHash, null);
+
+ EstablishMasterSecret(Context, mKeyExchange);
+ mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+ if (!mExpectSessionTicket)
+ {
+ SendChangeCipherSpecMessage();
+ }
+ }
+
+ protected virtual void SendCertificateRequestMessage(CertificateRequest certificateRequest)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_request);
+
+ certificateRequest.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendCertificateStatusMessage(CertificateStatus certificateStatus)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_status);
+
+ certificateStatus.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendNewSessionTicketMessage(NewSessionTicket newSessionTicket)
+ {
+ if (newSessionTicket == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.session_ticket);
+
+ newSessionTicket.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendServerHelloMessage()
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);
+
+ {
+ ProtocolVersion server_version = mTlsServer.GetServerVersion();
+ if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ mRecordStream.ReadVersion = server_version;
+ mRecordStream.SetWriteVersion(server_version);
+ mRecordStream.SetRestrictReadVersion(true);
+ ContextAdmin.SetServerVersion(server_version);
+
+ TlsUtilities.WriteVersion(server_version, message);
+ }
+
+ message.Write(this.mSecurityParameters.serverRandom);
+
+ /*
+ * The server may return an empty session_id to indicate that the session will not be cached
+ * and therefore cannot be resumed.
+ */
+ TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message);
+
+ int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();
+ if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+ || CipherSuite.IsScsv(selectedCipherSuite)
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ mSecurityParameters.cipherSuite = selectedCipherSuite;
+
+ byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod();
+ if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod))
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+ TlsUtilities.WriteUint16(selectedCipherSuite, message);
+ TlsUtilities.WriteUint8(selectedCompressionMethod, message);
+
+ this.mServerExtensions = mTlsServer.GetServerExtensions();
+
+ /*
+ * RFC 5746 3.6. Server Behavior: Initial Handshake
+ */
+ if (this.mSecureRenegotiation)
+ {
+ byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
+ bool noRenegExt = (null == renegExtData);
+
+ if (noRenegExt)
+ {
+ /*
+ * Note that Sending a "renegotiation_info" extension in response to a ClientHello
+ * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
+ * Section 7.4.1.4, on the server Sending unsolicited extensions and is only allowed
+ * because the client is signaling its willingness to receive the extension via the
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+ */
+
+ /*
+ * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
+ * "renegotiation_info" extension in the ServerHello message.
+ */
+ this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
+ this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
+ }
+ }
+
+ if (mSecurityParameters.extendedMasterSecret)
+ {
+ this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
+ TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions);
+ }
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and Send a server hello containing no
+ * extensions.
+ */
+
+ if (this.mServerExtensions != null)
+ {
+ this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);
+
+ this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions,
+ mServerExtensions, AlertDescription.internal_error);
+
+ this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);
+
+ /*
+ * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+ * a session resumption handshake.
+ */
+ this.mAllowCertificateStatus = !mResumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request,
+ AlertDescription.internal_error);
+
+ this.mExpectSessionTicket = !mResumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket,
+ AlertDescription.internal_error);
+
+ WriteExtensions(message, this.mServerExtensions);
+ }
+
+ mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
+
+ /*
+ * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
+ * a verify_data_length equal to 12. This includes all existing cipher suites.
+ */
+ mSecurityParameters.verifyDataLength = 12;
+
+ ApplyMaxFragmentLengthExtension();
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendServerHelloDoneMessage()
+ {
+ byte[] message = new byte[4];
+ TlsUtilities.WriteUint8(HandshakeType.server_hello_done, message, 0);
+ TlsUtilities.WriteUint24(0, message, 1);
+
+ WriteHandshakeMessage(message, 0, message.Length);
+ }
+
+ protected virtual void SendServerKeyExchangeMessage(byte[] serverKeyExchange)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.server_key_exchange, serverKeyExchange.Length);
+
+ message.Write(serverKeyExchange);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual bool ExpectCertificateVerifyMessage()
+ {
+ return mClientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)mClientCertificateType);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsSession.cs b/crypto/src/crypto/tls/TlsSession.cs
new file mode 100644
index 000000000..6c229913b
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSession.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsSession
+ {
+ SessionParameters ExportSessionParameters();
+
+ byte[] SessionID { get; }
+
+ void Invalidate();
+
+ bool IsResumable { get; }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsSessionImpl.cs b/crypto/src/crypto/tls/TlsSessionImpl.cs
new file mode 100644
index 000000000..866392623
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSessionImpl.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class TlsSessionImpl
+ : TlsSession
+ {
+ internal readonly byte[] mSessionID;
+ internal SessionParameters mSessionParameters;
+
+ internal TlsSessionImpl(byte[] sessionID, SessionParameters sessionParameters)
+ {
+ if (sessionID == null)
+ throw new ArgumentNullException("sessionID");
+ if (sessionID.Length < 1 || sessionID.Length > 32)
+ throw new ArgumentException("must have length between 1 and 32 bytes, inclusive", "sessionID");
+
+ this.mSessionID = Arrays.Clone(sessionID);
+ this.mSessionParameters = sessionParameters;
+ }
+
+ public virtual SessionParameters ExportSessionParameters()
+ {
+ lock (this)
+ {
+ return this.mSessionParameters == null ? null : this.mSessionParameters.Copy();
+ }
+ }
+
+ public virtual byte[] SessionID
+ {
+ get { lock (this) return mSessionID; }
+ }
+
+ public virtual void Invalidate()
+ {
+ lock (this)
+ {
+ if (this.mSessionParameters != null)
+ {
+ this.mSessionParameters.Clear();
+ this.mSessionParameters = null;
+ }
+ }
+ }
+
+ public virtual bool IsResumable
+ {
+ get { lock (this) return this.mSessionParameters != null; }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsSigner.cs b/crypto/src/crypto/tls/TlsSigner.cs
index 79d468fee..ffdd4c9a1 100644
--- a/crypto/src/crypto/tls/TlsSigner.cs
+++ b/crypto/src/crypto/tls/TlsSigner.cs
@@ -1,18 +1,29 @@
using System;
-using Org.BouncyCastle.Security;
-
namespace Org.BouncyCastle.Crypto.Tls
{
public interface TlsSigner
{
- byte[] GenerateRawSignature(SecureRandom random, AsymmetricKeyParameter privateKey,
- byte[] md5andsha1);
- bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5andsha1);
+ void Init(TlsContext context);
+
+ byte[] GenerateRawSignature(AsymmetricKeyParameter privateKey, byte[] md5AndSha1);
+
+ byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+ AsymmetricKeyParameter privateKey, byte[] hash);
+
+ bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5AndSha1);
+
+ bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+ AsymmetricKeyParameter publicKey, byte[] hash);
+
+ ISigner CreateSigner(AsymmetricKeyParameter privateKey);
+
+ ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey);
- ISigner CreateSigner(SecureRandom random, AsymmetricKeyParameter privateKey);
ISigner CreateVerifyer(AsymmetricKeyParameter publicKey);
+ ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey);
+
bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
}
}
diff --git a/crypto/src/crypto/tls/TlsSignerCredentials.cs b/crypto/src/crypto/tls/TlsSignerCredentials.cs
index 2adb06c26..92ed7cc19 100644
--- a/crypto/src/crypto/tls/TlsSignerCredentials.cs
+++ b/crypto/src/crypto/tls/TlsSignerCredentials.cs
@@ -3,9 +3,12 @@ using System.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- public interface TlsSignerCredentials : TlsCredentials
- {
- /// <exception cref="IOException"></exception>
- byte[] GenerateCertificateSignature(byte[] md5andsha1);
- }
+ public interface TlsSignerCredentials
+ : TlsCredentials
+ {
+ /// <exception cref="IOException"></exception>
+ byte[] GenerateCertificateSignature(byte[] hash);
+
+ SignatureAndHashAlgorithm SignatureAndHashAlgorithm { get; }
+ }
}
diff --git a/crypto/src/crypto/tls/TlsSrpGroupVerifier.cs b/crypto/src/crypto/tls/TlsSrpGroupVerifier.cs
new file mode 100644
index 000000000..185f2f50a
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSrpGroupVerifier.cs
@@ -0,0 +1,17 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsSrpGroupVerifier
+ {
+ /**
+ * Check whether the given SRP group parameters are acceptable for use.
+ *
+ * @param group the {@link SRP6GroupParameters} to check
+ * @return true if (and only if) the specified group parameters are acceptable
+ */
+ bool Accept(Srp6GroupParameters group);
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsSrpIdentityManager.cs b/crypto/src/crypto/tls/TlsSrpIdentityManager.cs
new file mode 100644
index 000000000..080a0dc16
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSrpIdentityManager.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsSrpIdentityManager
+ {
+ /**
+ * Lookup the {@link TlsSRPLoginParameters} corresponding to the specified identity.
+ *
+ * NOTE: To avoid "identity probing", unknown identities SHOULD be handled as recommended in RFC
+ * 5054 2.5.1.3. {@link SimulatedTlsSRPIdentityManager} is provided for this purpose.
+ *
+ * @param identity
+ * the SRP identity sent by the connecting client
+ * @return the {@link TlsSRPLoginParameters} for the specified identity, or else 'simulated'
+ * parameters if the identity is not recognized. A null value is also allowed, but not
+ * recommended.
+ */
+ TlsSrpLoginParameters GetLoginParameters(byte[] identity);
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
index 950be87ba..ce8e4834a 100644
--- a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
@@ -1,200 +1,282 @@
using System;
+using System.Collections;
using System.IO;
-using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Agreement.Srp;
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- /// <summary>
- /// TLS 1.1 SRP key exchange.
- /// </summary>
- internal class TlsSrpKeyExchange
- : TlsKeyExchange
+ /// <summary>(D)TLS SRP key exchange (RFC 5054).</summary>
+ public class TlsSrpKeyExchange
+ : AbstractTlsKeyExchange
{
- protected TlsClientContext context;
- protected int keyExchange;
- protected TlsSigner tlsSigner;
- protected byte[] identity;
- protected byte[] password;
-
- protected AsymmetricKeyParameter serverPublicKey = null;
-
- protected byte[] s = null;
- protected BigInteger B = null;
- protected Srp6Client srpClient = new Srp6Client();
-
- internal TlsSrpKeyExchange(TlsClientContext context, int keyExchange,
- byte[] identity, byte[] password)
+ protected static TlsSigner CreateSigner(int keyExchange)
{
switch (keyExchange)
{
case KeyExchangeAlgorithm.SRP:
- this.tlsSigner = null;
- break;
+ return null;
case KeyExchangeAlgorithm.SRP_RSA:
- this.tlsSigner = new TlsRsaSigner();
- break;
+ return new TlsRsaSigner();
case KeyExchangeAlgorithm.SRP_DSS:
- this.tlsSigner = new TlsDssSigner();
- break;
+ return new TlsDssSigner();
default:
- throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
+ throw new ArgumentException("unsupported key exchange algorithm");
}
+ }
+
+ protected TlsSigner mTlsSigner;
+ protected TlsSrpGroupVerifier mGroupVerifier;
+ protected byte[] mIdentity;
+ protected byte[] mPassword;
+
+ protected AsymmetricKeyParameter mServerPublicKey = null;
+
+ protected Srp6GroupParameters mSrpGroup = null;
+ protected Srp6Client mSrpClient = null;
+ protected Srp6Server mSrpServer = null;
+ protected BigInteger mSrpPeerCredentials = null;
+ protected BigInteger mSrpVerifier = null;
+ protected byte[] mSrpSalt = null;
+
+ protected TlsSignerCredentials mServerCredentials = null;
+
+ [Obsolete("Use constructor taking an explicit 'groupVerifier' argument")]
+ public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity, byte[] password)
+ : this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsSrpGroupVerifier(), identity, password)
+ {
+ }
+
+ public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsSrpGroupVerifier groupVerifier,
+ byte[] identity, byte[] password)
+ : base(keyExchange, supportedSignatureAlgorithms)
+ {
+ this.mTlsSigner = CreateSigner(keyExchange);
+ this.mGroupVerifier = groupVerifier;
+ this.mIdentity = identity;
+ this.mPassword = password;
+ this.mSrpClient = new Srp6Client();
+ }
- this.context = context;
- this.keyExchange = keyExchange;
- this.identity = identity;
- this.password = password;
+ public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity,
+ TlsSrpLoginParameters loginParameters)
+ : base(keyExchange, supportedSignatureAlgorithms)
+ {
+ this.mTlsSigner = CreateSigner(keyExchange);
+ this.mIdentity = identity;
+ this.mSrpServer = new Srp6Server();
+ this.mSrpGroup = loginParameters.Group;
+ this.mSrpVerifier = loginParameters.Verifier;
+ this.mSrpSalt = loginParameters.Salt;
}
- public virtual void SkipServerCertificate()
+ public override void Init(TlsContext context)
{
- if (tlsSigner != null)
+ base.Init(context);
+
+ if (this.mTlsSigner != null)
{
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ this.mTlsSigner.Init(context);
}
}
- public virtual void ProcessServerCertificate(Certificate serverCertificate)
+ public override void SkipServerCredentials()
{
- if (tlsSigner == null)
- {
+ if (mTlsSigner != null)
throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
+ }
+
+ public override void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (mTlsSigner == null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
- SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
try
{
- this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
}
-// catch (RuntimeException)
- catch (Exception)
+ catch (Exception e)
{
- throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
}
- if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
- {
+ if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
throw new TlsFatalAlert(AlertDescription.certificate_unknown);
- }
TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
- // TODO
- /*
- * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
- * signing algorithm for the certificate must be the same as the algorithm for the
- * certificate key."
- */
+ base.ProcessServerCertificate(serverCertificate);
}
- public virtual void SkipServerKeyExchange()
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
{
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if ((mKeyExchange == KeyExchangeAlgorithm.SRP) || !(serverCredentials is TlsSignerCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsSignerCredentials)serverCredentials;
+ }
+
+ public override bool RequiresServerKeyExchange
+ {
+ get { return true; }
}
- public virtual void ProcessServerKeyExchange(Stream input)
+ public override byte[] GenerateServerKeyExchange()
{
- SecurityParameters securityParameters = context.SecurityParameters;
+ mSrpServer.Init(mSrpGroup, mSrpVerifier, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom);
+ BigInteger B = mSrpServer.GenerateServerCredentials();
- Stream sigIn = input;
- ISigner signer = null;
+ ServerSrpParams srpParams = new ServerSrpParams(mSrpGroup.N, mSrpGroup.G, mSrpSalt, B);
- if (tlsSigner != null)
+ DigestInputBuffer buf = new DigestInputBuffer();
+
+ srpParams.Encode(buf);
+
+ if (mServerCredentials != null)
{
- signer = InitSigner(tlsSigner, securityParameters);
- sigIn = new SignerStream(input, signer, null);
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ mContext, mServerCredentials);
+
+ IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm);
+
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+ d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ buf.UpdateDigest(d);
+
+ byte[] hash = new byte[d.GetDigestSize()];
+ d.DoFinal(hash, 0);
+
+ byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);
+
+ DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ signed_params.Encode(buf);
}
- byte[] NBytes = TlsUtilities.ReadOpaque16(sigIn);
- byte[] gBytes = TlsUtilities.ReadOpaque16(sigIn);
- byte[] sBytes = TlsUtilities.ReadOpaque8(sigIn);
- byte[] BBytes = TlsUtilities.ReadOpaque16(sigIn);
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerKeyExchange(Stream input)
+ {
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+
+ SignerInputBuffer buf = null;
+ Stream teeIn = input;
- if (signer != null)
+ if (mTlsSigner != null)
{
- byte[] sigByte = TlsUtilities.ReadOpaque16(input);
+ buf = new SignerInputBuffer();
+ teeIn = new TeeInputStream(input, buf);
+ }
- if (!signer.VerifySignature(sigByte))
- {
+ ServerSrpParams srpParams = ServerSrpParams.Parse(teeIn);
+
+ if (buf != null)
+ {
+ DigitallySigned signed_params = DigitallySigned.Parse(mContext, input);
+
+ ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+ buf.UpdateSigner(signer);
+ if (!signer.VerifySignature(signed_params.Signature))
throw new TlsFatalAlert(AlertDescription.decrypt_error);
- }
}
- BigInteger N = new BigInteger(1, NBytes);
- BigInteger g = new BigInteger(1, gBytes);
+ this.mSrpGroup = new Srp6GroupParameters(srpParams.N, srpParams.G);
- // TODO Validate group parameters (see RFC 5054)
- //throw new TlsFatalAlert(AlertDescription.insufficient_security);
+ if (!mGroupVerifier.Accept(mSrpGroup))
+ throw new TlsFatalAlert(AlertDescription.insufficient_security);
- this.s = sBytes;
+ this.mSrpSalt = srpParams.S;
/*
- * RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter"
- * alert if B % N = 0.
- */
+ * RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter" alert if
+ * B % N = 0.
+ */
try
{
- this.B = Srp6Utilities.ValidatePublicValue(N, new BigInteger(1, BBytes));
+ this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, srpParams.B);
}
- catch (CryptoException)
+ catch (CryptoException e)
{
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
}
- this.srpClient.Init(N, g, new Sha1Digest(), context.SecureRandom);
+ this.mSrpClient.Init(mSrpGroup, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom);
}
- public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
- public virtual void SkipClientCredentials()
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
{
- // OK
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
-
- public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
+
+ public override void GenerateClientKeyExchange(Stream output)
{
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ BigInteger A = mSrpClient.GenerateClientCredentials(mSrpSalt, mIdentity, mPassword);
+ TlsSrpUtilities.WriteSrpParameter(A, output);
+
+ mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity);
}
- public virtual void GenerateClientKeyExchange(Stream output)
+ public override void ProcessClientKeyExchange(Stream input)
{
- byte[] keData = BigIntegers.AsUnsignedByteArray(srpClient.GenerateClientCredentials(s,
- this.identity, this.password));
- TlsUtilities.WriteOpaque16(keData, output);
+ /*
+ * RFC 5054 2.5.4: The server MUST abort the handshake with an "illegal_parameter" alert if
+ * A % N = 0.
+ */
+ try
+ {
+ this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, TlsSrpUtilities.ReadSrpParameter(input));
+ }
+ catch (CryptoException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+ }
+
+ mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity);
}
- public virtual byte[] GeneratePremasterSecret()
+ public override byte[] GeneratePremasterSecret()
{
try
{
+ BigInteger S = mSrpServer != null
+ ? mSrpServer.CalculateSecret(mSrpPeerCredentials)
+ : mSrpClient.CalculateSecret(mSrpPeerCredentials);
+
// TODO Check if this needs to be a fixed size
- return BigIntegers.AsUnsignedByteArray(srpClient.CalculateSecret(B));
+ return BigIntegers.AsUnsignedByteArray(S);
}
- catch (CryptoException)
+ catch (CryptoException e)
{
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
}
}
- protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
+ protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+ SecurityParameters securityParameters)
{
- ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey);
+ ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
return signer;
diff --git a/crypto/src/crypto/tls/TlsSrpLoginParameters.cs b/crypto/src/crypto/tls/TlsSrpLoginParameters.cs
new file mode 100644
index 000000000..5ae4641f6
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSrpLoginParameters.cs
@@ -0,0 +1,36 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsSrpLoginParameters
+ {
+ protected readonly Srp6GroupParameters mGroup;
+ protected readonly BigInteger mVerifier;
+ protected readonly byte[] mSalt;
+
+ public TlsSrpLoginParameters(Srp6GroupParameters group, BigInteger verifier, byte[] salt)
+ {
+ this.mGroup = group;
+ this.mVerifier = verifier;
+ this.mSalt = salt;
+ }
+
+ public virtual Srp6GroupParameters Group
+ {
+ get { return mGroup; }
+ }
+
+ public virtual byte[] Salt
+ {
+ get { return mSalt; }
+ }
+
+ public virtual BigInteger Verifier
+ {
+ get { return mVerifier; }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsSrpUtilities.cs b/crypto/src/crypto/tls/TlsSrpUtilities.cs
new file mode 100644
index 000000000..873189dc6
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSrpUtilities.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsSrpUtilities
+ {
+ public static void AddSrpExtension(IDictionary extensions, byte[] identity)
+ {
+ extensions[ExtensionType.srp] = CreateSrpExtension(identity);
+ }
+
+ public static byte[] GetSrpExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.srp);
+ return extensionData == null ? null : ReadSrpExtension(extensionData);
+ }
+
+ public static byte[] CreateSrpExtension(byte[] identity)
+ {
+ if (identity == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return TlsUtilities.EncodeOpaque8(identity);
+ }
+
+ public static byte[] ReadSrpExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+ byte[] identity = TlsUtilities.ReadOpaque8(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return identity;
+ }
+
+ public static BigInteger ReadSrpParameter(Stream input)
+ {
+ return new BigInteger(1, TlsUtilities.ReadOpaque16(input));
+ }
+
+ public static void WriteSrpParameter(BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output);
+ }
+
+ public static bool IsSrpCipherSuite(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsSrtpUtilities.cs b/crypto/src/crypto/tls/TlsSrtpUtilities.cs
new file mode 100644
index 000000000..626c0e3a4
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSrtpUtilities.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 5764 DTLS Extension to Establish Keys for SRTP.
+ */
+ public abstract class TlsSRTPUtils
+ {
+ public static void AddUseSrtpExtension(IDictionary extensions, UseSrtpData useSRTPData)
+ {
+ extensions[ExtensionType.use_srtp] = CreateUseSrtpExtension(useSRTPData);
+ }
+
+ public static UseSrtpData GetUseSrtpExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.use_srtp);
+ return extensionData == null ? null : ReadUseSrtpExtension(extensionData);
+ }
+
+ public static byte[] CreateUseSrtpExtension(UseSrtpData useSrtpData)
+ {
+ if (useSrtpData == null)
+ throw new ArgumentNullException("useSrtpData");
+
+ MemoryStream buf = new MemoryStream();
+
+ // SRTPProtectionProfiles
+ TlsUtilities.WriteUint16ArrayWithUint16Length(useSrtpData.ProtectionProfiles, buf);
+
+ // srtp_mki
+ TlsUtilities.WriteOpaque8(useSrtpData.Mki, buf);
+
+ return buf.ToArray();
+ }
+
+ public static UseSrtpData ReadUseSrtpExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, true);
+
+ // SRTPProtectionProfiles
+ int length = TlsUtilities.ReadUint16(buf);
+ if (length < 2 || (length & 1) != 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+ int[] protectionProfiles = TlsUtilities.ReadUint16Array(length / 2, buf);
+
+ // srtp_mki
+ byte[] mki = TlsUtilities.ReadOpaque8(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return new UseSrtpData(protectionProfiles, mki);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsStream.cs b/crypto/src/crypto/tls/TlsStream.cs
index fe24ad3ed..7ff7184e3 100644
--- a/crypto/src/crypto/tls/TlsStream.cs
+++ b/crypto/src/crypto/tls/TlsStream.cs
@@ -3,84 +3,83 @@ using System.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
- internal class TlsStream
- : Stream
- {
- private readonly TlsProtocolHandler handler;
+ internal class TlsStream
+ : Stream
+ {
+ private readonly TlsProtocol handler;
- internal TlsStream(
- TlsProtocolHandler handler)
- {
- this.handler = handler;
- }
+ internal TlsStream(TlsProtocol handler)
+ {
+ this.handler = handler;
+ }
- public override bool CanRead
- {
- get { return !handler.IsClosed; }
- }
+ public override bool CanRead
+ {
+ get { return !handler.IsClosed; }
+ }
- public override bool CanSeek
- {
- get { return false; }
- }
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
- public override bool CanWrite
- {
- get { return !handler.IsClosed; }
- }
+ public override bool CanWrite
+ {
+ get { return !handler.IsClosed; }
+ }
- public override void Close()
- {
- handler.Close();
- }
+ public override void Close()
+ {
+ handler.Close();
+ }
- public override void Flush()
- {
- handler.Flush();
- }
+ public override void Flush()
+ {
+ handler.Flush();
+ }
public override long Length
- {
- get { throw new NotSupportedException(); }
- }
+ {
+ get { throw new NotSupportedException(); }
+ }
- public override long Position
+ public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
- public override int Read(byte[] buf, int off, int len)
- {
- return this.handler.ReadApplicationData(buf, off, len);
- }
+ public override int Read(byte[] buf, int off, int len)
+ {
+ return this.handler.ReadApplicationData(buf, off, len);
+ }
- public override int ReadByte()
- {
- byte[] buf = new byte[1];
- if (this.Read(buf, 0, 1) <= 0)
- return -1;
- return buf[0];
- }
+ public override int ReadByte()
+ {
+ byte[] buf = new byte[1];
+ if (this.Read(buf, 0, 1) <= 0)
+ return -1;
+ return buf[0];
+ }
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
+ {
+ throw new NotSupportedException();
+ }
- public override void Write(byte[] buf, int off, int len)
- {
- this.handler.WriteData(buf, off, len);
- }
+ public override void Write(byte[] buf, int off, int len)
+ {
+ this.handler.WriteData(buf, off, len);
+ }
- public override void WriteByte(byte b)
- {
- this.handler.WriteData(new byte[] { b }, 0, 1);
- }
- }
+ public override void WriteByte(byte b)
+ {
+ this.handler.WriteData(new byte[] { b }, 0, 1);
+ }
+ }
}
diff --git a/crypto/src/crypto/tls/TlsStreamCipher.cs b/crypto/src/crypto/tls/TlsStreamCipher.cs
index 35f794d96..45f2a9a70 100644
--- a/crypto/src/crypto/tls/TlsStreamCipher.cs
+++ b/crypto/src/crypto/tls/TlsStreamCipher.cs
@@ -1,108 +1,164 @@
using System;
+using System.IO;
-using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
- public class TlsStreamCipher : TlsCipher
+ public class TlsStreamCipher
+ : TlsCipher
{
- protected TlsClientContext context;
+ protected readonly TlsContext context;
- protected IStreamCipher encryptCipher;
- protected IStreamCipher decryptCipher;
+ protected readonly IStreamCipher encryptCipher;
+ protected readonly IStreamCipher decryptCipher;
- protected TlsMac writeMac;
- protected TlsMac readMac;
+ protected readonly TlsMac writeMac;
+ protected readonly TlsMac readMac;
- public TlsStreamCipher(TlsClientContext context, IStreamCipher encryptCipher,
- IStreamCipher decryptCipher, IDigest writeDigest, IDigest readDigest, int cipherKeySize)
+ protected readonly bool usesNonce;
+
+ /// <exception cref="IOException"></exception>
+ public TlsStreamCipher(TlsContext context, IStreamCipher clientWriteCipher,
+ IStreamCipher serverWriteCipher, IDigest clientWriteDigest, IDigest serverWriteDigest,
+ int cipherKeySize, bool usesNonce)
{
+ bool isServer = context.IsServer;
+
this.context = context;
- this.encryptCipher = encryptCipher;
- this.decryptCipher = decryptCipher;
+ this.usesNonce = usesNonce;
- int prfSize = (2 * cipherKeySize) + writeDigest.GetDigestSize()
- + readDigest.GetDigestSize();
+ this.encryptCipher = clientWriteCipher;
+ this.decryptCipher = serverWriteCipher;
- SecurityParameters securityParameters = context.SecurityParameters;
+ int key_block_size = (2 * cipherKeySize) + clientWriteDigest.GetDigestSize()
+ + serverWriteDigest.GetDigestSize();
- byte[] keyBlock = TlsUtilities.PRF(securityParameters.masterSecret, "key expansion",
- TlsUtilities.Concat(securityParameters.serverRandom, securityParameters.clientRandom),
- prfSize);
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
int offset = 0;
// Init MACs
- writeMac = CreateTlsMac(writeDigest, keyBlock, ref offset);
- readMac = CreateTlsMac(readDigest, keyBlock, ref offset);
+ TlsMac clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+ clientWriteDigest.GetDigestSize());
+ offset += clientWriteDigest.GetDigestSize();
+ TlsMac serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+ serverWriteDigest.GetDigestSize());
+ offset += serverWriteDigest.GetDigestSize();
// Build keys
- KeyParameter encryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize);
- KeyParameter decryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize);
+ KeyParameter clientWriteKey = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter serverWriteKey = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
- if (offset != prfSize)
+ if (offset != key_block_size)
+ {
throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
- // Init Ciphers
- encryptCipher.Init(true, encryptKey);
- decryptCipher.Init(false, decryptKey);
- }
-
- public byte[] EncodePlaintext(byte type, byte[] plaintext, int offset, int len)
- {
- byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len);
- int size = len + mac.Length;
+ ICipherParameters encryptParams, decryptParams;
+ if (isServer)
+ {
+ this.writeMac = serverWriteMac;
+ this.readMac = clientWriteMac;
+ this.encryptCipher = serverWriteCipher;
+ this.decryptCipher = clientWriteCipher;
+ encryptParams = serverWriteKey;
+ decryptParams = clientWriteKey;
+ }
+ else
+ {
+ this.writeMac = clientWriteMac;
+ this.readMac = serverWriteMac;
+ this.encryptCipher = clientWriteCipher;
+ this.decryptCipher = serverWriteCipher;
+ encryptParams = clientWriteKey;
+ decryptParams = serverWriteKey;
+ }
- byte[] outbuf = new byte[size];
+ if (usesNonce)
+ {
+ byte[] dummyNonce = new byte[8];
+ encryptParams = new ParametersWithIV(encryptParams, dummyNonce);
+ decryptParams = new ParametersWithIV(decryptParams, dummyNonce);
+ }
- encryptCipher.ProcessBytes(plaintext, offset, len, outbuf, 0);
- encryptCipher.ProcessBytes(mac, 0, mac.Length, outbuf, len);
+ this.encryptCipher.Init(true, encryptParams);
+ this.decryptCipher.Init(false, decryptParams);
+ }
- return outbuf;
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
+ {
+ return ciphertextLimit - writeMac.Size;
}
- public byte[] DecodeCiphertext(byte type, byte[] ciphertext, int offset, int len)
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
{
- byte[] deciphered = new byte[len];
- decryptCipher.ProcessBytes(ciphertext, offset, len, deciphered, 0);
+ /*
+ * draft-josefsson-salsa20-tls-04 2.1 Note that Salsa20 requires a 64-bit nonce. That
+ * nonce is updated on the encryption of every TLS record, and is set to be the 64-bit TLS
+ * record sequence number. In case of DTLS the 64-bit nonce is formed as the concatenation
+ * of the 16-bit epoch with the 48-bit sequence number.
+ */
+ if (usesNonce)
+ {
+ UpdateIV(encryptCipher, true, seqNo);
+ }
- int plaintextSize = deciphered.Length - readMac.Size;
- byte[] plainText = CopyData(deciphered, 0, plaintextSize);
+ byte[] outBuf = new byte[len + writeMac.Size];
- byte[] receivedMac = CopyData(deciphered, plaintextSize, readMac.Size);
- byte[] computedMac = readMac.CalculateMac(type, plainText, 0, plainText.Length);
+ encryptCipher.ProcessBytes(plaintext, offset, len, outBuf, 0);
- if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac))
- {
- throw new TlsFatalAlert(AlertDescription.bad_record_mac);
- }
+ byte[] mac = writeMac.CalculateMac(seqNo, type, plaintext, offset, len);
+ encryptCipher.ProcessBytes(mac, 0, mac.Length, outBuf, len);
- return plainText;
+ return outBuf;
}
- protected virtual TlsMac CreateTlsMac(IDigest digest, byte[] buf, ref int off)
+ /// <exception cref="IOException"></exception>
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
{
- int len = digest.GetDigestSize();
- TlsMac mac = new TlsMac(digest, buf, off, len);
- off += len;
- return mac;
+ /*
+ * draft-josefsson-salsa20-tls-04 2.1 Note that Salsa20 requires a 64-bit nonce. That
+ * nonce is updated on the encryption of every TLS record, and is set to be the 64-bit TLS
+ * record sequence number. In case of DTLS the 64-bit nonce is formed as the concatenation
+ * of the 16-bit epoch with the 48-bit sequence number.
+ */
+ if (usesNonce)
+ {
+ UpdateIV(decryptCipher, false, seqNo);
+ }
+
+ int macSize = readMac.Size;
+ if (len < macSize)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int plaintextLength = len - macSize;
+
+ byte[] deciphered = new byte[len];
+ decryptCipher.ProcessBytes(ciphertext, offset, len, deciphered, 0);
+ CheckMac(seqNo, type, deciphered, plaintextLength, len, deciphered, 0, plaintextLength);
+ return Arrays.CopyOfRange(deciphered, 0, plaintextLength);
}
- protected virtual KeyParameter CreateKeyParameter(byte[] buf, ref int off, int len)
+ /// <exception cref="IOException"></exception>
+ protected virtual void CheckMac(long seqNo, byte type, byte[] recBuf, int recStart, int recEnd, byte[] calcBuf, int calcOff, int calcLen)
{
- KeyParameter key = new KeyParameter(buf, off, len);
- off += len;
- return key;
+ byte[] receivedMac = Arrays.CopyOfRange(recBuf, recStart, recEnd);
+ byte[] computedMac = readMac.CalculateMac(seqNo, type, calcBuf, calcOff, calcLen);
+
+ if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac))
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
}
- protected virtual byte[] CopyData(byte[] text, int offset, int len)
+ protected virtual void UpdateIV(IStreamCipher cipher, bool forEncryption, long seqNo)
{
- byte[] result = new byte[len];
- Array.Copy(text, offset, result, 0, len);
- return result;
+ byte[] nonce = new byte[8];
+ TlsUtilities.WriteUint64(seqNo, nonce, 0);
+ cipher.Init(forEncryption, new ParametersWithIV(null, nonce));
}
}
}
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 2309fc3da..a8c8a2b28 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -4,10 +4,13 @@ using System.IO;
using System.Text;
using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Date;
using Org.BouncyCastle.Utilities.IO;
@@ -15,9 +18,12 @@ using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
/// <remarks>Some helper functions for MicroTLS.</remarks>
- public class TlsUtilities
+ public abstract class TlsUtilities
{
public static readonly byte[] EmptyBytes = new byte[0];
+ public static readonly short[] EmptyShorts = new short[0];
+ public static readonly int[] EmptyInts = new int[0];
+ public static readonly long[] EmptyLongs = new long[0];
public static void CheckUint8(int i)
{
@@ -25,82 +31,199 @@ namespace Org.BouncyCastle.Crypto.Tls
throw new TlsFatalAlert(AlertDescription.internal_error);
}
+ public static void CheckUint8(long i)
+ {
+ if (!IsValidUint8(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
public static void CheckUint16(int i)
{
if (!IsValidUint16(i))
throw new TlsFatalAlert(AlertDescription.internal_error);
}
+ public static void CheckUint16(long i)
+ {
+ if (!IsValidUint16(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
public static void CheckUint24(int i)
{
if (!IsValidUint24(i))
throw new TlsFatalAlert(AlertDescription.internal_error);
}
+ public static void CheckUint24(long i)
+ {
+ if (!IsValidUint24(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint32(long i)
+ {
+ if (!IsValidUint32(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint48(long i)
+ {
+ if (!IsValidUint48(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint64(long i)
+ {
+ if (!IsValidUint64(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
public static bool IsValidUint8(int i)
{
return (i & 0xFF) == i;
}
+ public static bool IsValidUint8(long i)
+ {
+ return (i & 0xFFL) == i;
+ }
+
public static bool IsValidUint16(int i)
{
return (i & 0xFFFF) == i;
}
+ public static bool IsValidUint16(long i)
+ {
+ return (i & 0xFFFFL) == i;
+ }
+
public static bool IsValidUint24(int i)
{
return (i & 0xFFFFFF) == i;
}
- internal static void WriteUint8(byte i, Stream os)
+ public static bool IsValidUint24(long i)
+ {
+ return (i & 0xFFFFFFL) == i;
+ }
+
+ public static bool IsValidUint32(long i)
+ {
+ return (i & 0xFFFFFFFFL) == i;
+ }
+
+ public static bool IsValidUint48(long i)
+ {
+ return (i & 0xFFFFFFFFFFFFL) == i;
+ }
+
+ public static bool IsValidUint64(long i)
+ {
+ return true;
+ }
+
+ public static bool IsSsl(TlsContext context)
+ {
+ return context.ServerVersion.IsSsl;
+ }
+
+ public static bool IsTlsV11(TlsContext context)
+ {
+ return ProtocolVersion.TLSv11.IsEqualOrEarlierVersionOf(context.ServerVersion.GetEquivalentTLSVersion());
+ }
+
+ public static bool IsTlsV12(TlsContext context)
+ {
+ return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(context.ServerVersion.GetEquivalentTLSVersion());
+ }
+
+ public static void WriteUint8(byte i, Stream output)
{
- os.WriteByte(i);
+ output.WriteByte(i);
}
- internal static void WriteUint8(byte i, byte[] buf, int offset)
+ public static void WriteUint8(byte i, byte[] buf, int offset)
{
buf[offset] = i;
}
- internal static void WriteUint16(int i, Stream os)
+ public static void WriteUint16(int i, Stream output)
{
- os.WriteByte((byte)(i >> 8));
- os.WriteByte((byte)i);
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
}
- internal static void WriteUint16(int i, byte[] buf, int offset)
+ public static void WriteUint16(int i, byte[] buf, int offset)
{
buf[offset] = (byte)(i >> 8);
buf[offset + 1] = (byte)i;
}
- internal static void WriteUint24(int i, Stream os)
+ public static void WriteUint24(int i, Stream output)
{
- os.WriteByte((byte)(i >> 16));
- os.WriteByte((byte)(i >> 8));
- os.WriteByte((byte)i);
+ output.WriteByte((byte)(i >> 16));
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
}
- internal static void WriteUint24(int i, byte[] buf, int offset)
+ public static void WriteUint24(int i, byte[] buf, int offset)
{
buf[offset] = (byte)(i >> 16);
buf[offset + 1] = (byte)(i >> 8);
- buf[offset + 2] = (byte)(i);
+ buf[offset + 2] = (byte)i;
+ }
+
+ public static void WriteUint32(long i, Stream output)
+ {
+ output.WriteByte((byte)(i >> 24));
+ output.WriteByte((byte)(i >> 16));
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
+ }
+
+ public static void WriteUint32(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 24);
+ buf[offset + 1] = (byte)(i >> 16);
+ buf[offset + 2] = (byte)(i >> 8);
+ buf[offset + 3] = (byte)i;
+ }
+
+ public static void WriteUint48(long i, Stream output)
+ {
+ output.WriteByte((byte)(i >> 40));
+ output.WriteByte((byte)(i >> 32));
+ output.WriteByte((byte)(i >> 24));
+ output.WriteByte((byte)(i >> 16));
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
+ }
+
+ public static void WriteUint48(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 40);
+ buf[offset + 1] = (byte)(i >> 32);
+ buf[offset + 2] = (byte)(i >> 24);
+ buf[offset + 3] = (byte)(i >> 16);
+ buf[offset + 4] = (byte)(i >> 8);
+ buf[offset + 5] = (byte)i;
}
- internal static void WriteUint64(long i, Stream os)
+ public static void WriteUint64(long i, Stream output)
{
- os.WriteByte((byte)(i >> 56));
- os.WriteByte((byte)(i >> 48));
- os.WriteByte((byte)(i >> 40));
- os.WriteByte((byte)(i >> 32));
- os.WriteByte((byte)(i >> 24));
- os.WriteByte((byte)(i >> 16));
- os.WriteByte((byte)(i >> 8));
- os.WriteByte((byte)i);
+ output.WriteByte((byte)(i >> 56));
+ output.WriteByte((byte)(i >> 48));
+ output.WriteByte((byte)(i >> 40));
+ output.WriteByte((byte)(i >> 32));
+ output.WriteByte((byte)(i >> 24));
+ output.WriteByte((byte)(i >> 16));
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
}
- internal static void WriteUint64(long i, byte[] buf, int offset)
+ public static void WriteUint64(long i, byte[] buf, int offset)
{
buf[offset] = (byte)(i >> 56);
buf[offset + 1] = (byte)(i >> 48);
@@ -109,30 +232,39 @@ namespace Org.BouncyCastle.Crypto.Tls
buf[offset + 4] = (byte)(i >> 24);
buf[offset + 5] = (byte)(i >> 16);
buf[offset + 6] = (byte)(i >> 8);
- buf[offset + 7] = (byte)(i);
+ buf[offset + 7] = (byte)i;
+ }
+
+ public static void WriteOpaque8(byte[] buf, Stream output)
+ {
+ WriteUint8((byte)buf.Length, output);
+ output.Write(buf, 0, buf.Length);
}
- internal static void WriteOpaque8(byte[] buf, Stream os)
+ public static void WriteOpaque16(byte[] buf, Stream output)
{
- WriteUint8((byte)buf.Length, os);
- os.Write(buf, 0, buf.Length);
+ WriteUint16(buf.Length, output);
+ output.Write(buf, 0, buf.Length);
}
- internal static void WriteOpaque16(byte[] buf, Stream os)
+ public static void WriteOpaque24(byte[] buf, Stream output)
{
- WriteUint16(buf.Length, os);
- os.Write(buf, 0, buf.Length);
+ WriteUint24(buf.Length, output);
+ output.Write(buf, 0, buf.Length);
}
- internal static void WriteOpaque24(byte[] buf, Stream os)
+ public static void WriteUint8Array(byte[] uints, Stream output)
{
- WriteUint24(buf.Length, os);
- os.Write(buf, 0, buf.Length);
+ output.Write(uints, 0, uints.Length);
}
- internal static void WriteUint8Array(byte[] uints, Stream os)
+ public static void WriteUint8Array(byte[] uints, byte[] buf, int offset)
{
- os.Write(uints, 0, uints.Length);
+ for (int i = 0; i < uints.Length; ++i)
+ {
+ WriteUint8(uints[i], buf, offset);
+ ++offset;
+ }
}
public static void WriteUint8ArrayWithUint8Length(byte[] uints, Stream output)
@@ -142,17 +274,70 @@ namespace Org.BouncyCastle.Crypto.Tls
WriteUint8Array(uints, output);
}
- internal static void WriteUint16Array(int[] uints, Stream os)
+ public static void WriteUint8ArrayWithUint8Length(byte[] uints, byte[] buf, int offset)
+ {
+ CheckUint8(uints.Length);
+ WriteUint8((byte)uints.Length, buf, offset);
+ WriteUint8Array(uints, buf, offset + 1);
+ }
+
+ public static void WriteUint16Array(int[] uints, Stream output)
{
for (int i = 0; i < uints.Length; ++i)
{
- WriteUint16(uints[i], os);
+ WriteUint16(uints[i], output);
}
}
- internal static byte ReadUint8(Stream inStr)
+ public static void WriteUint16Array(int[] uints, byte[] buf, int offset)
{
- int i = inStr.ReadByte();
+ for (int i = 0; i < uints.Length; ++i)
+ {
+ WriteUint16(uints[i], buf, offset);
+ offset += 2;
+ }
+ }
+
+ public static void WriteUint16ArrayWithUint16Length(int[] uints, Stream output)
+ {
+ int length = 2 * uints.Length;
+ CheckUint16(length);
+ WriteUint16(length, output);
+ WriteUint16Array(uints, output);
+ }
+
+ public static void WriteUint16ArrayWithUint16Length(int[] uints, byte[] buf, int offset)
+ {
+ int length = 2 * uints.Length;
+ CheckUint16(length);
+ WriteUint16(length, buf, offset);
+ WriteUint16Array(uints, buf, offset + 2);
+ }
+
+ public static byte[] EncodeOpaque8(byte[] buf)
+ {
+ CheckUint8(buf.Length);
+ return Arrays.Prepend(buf, (byte)buf.Length);
+ }
+
+ public static byte[] EncodeUint8ArrayWithUint8Length(byte[] uints)
+ {
+ byte[] result = new byte[1 + uints.Length];
+ WriteUint8ArrayWithUint8Length(uints, result, 0);
+ return result;
+ }
+
+ public static byte[] EncodeUint16ArrayWithUint16Length(int[] uints)
+ {
+ int length = 2 * uints.Length;
+ byte[] result = new byte[2 + length];
+ WriteUint16ArrayWithUint16Length(uints, result, 0);
+ return result;
+ }
+
+ public static byte ReadUint8(Stream input)
+ {
+ int i = input.ReadByte();
if (i < 0)
{
throw new EndOfStreamException();
@@ -160,10 +345,15 @@ namespace Org.BouncyCastle.Crypto.Tls
return (byte)i;
}
- internal static int ReadUint16(Stream inStr)
+ public static byte ReadUint8(byte[] buf, int offset)
{
- int i1 = inStr.ReadByte();
- int i2 = inStr.ReadByte();
+ return buf[offset];
+ }
+
+ public static int ReadUint16(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
if ((i1 | i2) < 0)
{
throw new EndOfStreamException();
@@ -171,11 +361,18 @@ namespace Org.BouncyCastle.Crypto.Tls
return i1 << 8 | i2;
}
- internal static int ReadUint24(Stream inStr)
+ public static int ReadUint16(byte[] buf, int offset)
{
- int i1 = inStr.ReadByte();
- int i2 = inStr.ReadByte();
- int i3 = inStr.ReadByte();
+ uint n = (uint)buf[offset] << 8;
+ n |= (uint)buf[++offset];
+ return (int)n;
+ }
+
+ public static int ReadUint24(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ int i3 = input.ReadByte();
if ((i1 | i2 | i3) < 0)
{
throw new EndOfStreamException();
@@ -183,6 +380,63 @@ namespace Org.BouncyCastle.Crypto.Tls
return (i1 << 16) | (i2 << 8) | i3;
}
+ public static int ReadUint24(byte[] buf, int offset)
+ {
+ uint n = (uint)buf[offset] << 16;
+ n |= (uint)buf[++offset] << 8;
+ n |= (uint)buf[++offset];
+ return (int)n;
+ }
+
+ public static long ReadUint32(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ int i3 = input.ReadByte();
+ int i4 = input.ReadByte();
+ if (i4 < 0)
+ {
+ throw new EndOfStreamException();
+ }
+ return (long)(uint)((i1 << 24) | (i2 << 16) | (i3 << 8) | i4);
+ }
+
+ public static long ReadUint32(byte[] buf, int offset)
+ {
+ uint n = (uint)buf[offset] << 24;
+ n |= (uint)buf[++offset] << 16;
+ n |= (uint)buf[++offset] << 8;
+ n |= (uint)buf[++offset];
+ return (long)n;
+ }
+
+ public static long ReadUint48(Stream input)
+ {
+ int hi = ReadUint24(input);
+ int lo = ReadUint24(input);
+ return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL);
+ }
+
+ public static long ReadUint48(byte[] buf, int offset)
+ {
+ int hi = ReadUint24(buf, offset);
+ int lo = ReadUint24(buf, offset + 3);
+ return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL);
+ }
+
+ public static byte[] ReadAllOrNothing(int length, Stream input)
+ {
+ if (length < 1)
+ return EmptyBytes;
+ byte[] buf = new byte[length];
+ int read = Streams.ReadFully(input, buf);
+ if (read == 0)
+ return null;
+ if (read != length)
+ throw new EndOfStreamException();
+ return buf;
+ }
+
public static byte[] ReadFully(int length, Stream input)
{
if (length < 1)
@@ -193,25 +447,25 @@ namespace Org.BouncyCastle.Crypto.Tls
return buf;
}
- internal static void ReadFully(byte[] buf, Stream inStr)
+ public static void ReadFully(byte[] buf, Stream input)
{
- if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length)
+ if (Streams.ReadFully(input, buf, 0, buf.Length) < buf.Length)
throw new EndOfStreamException();
}
- internal static byte[] ReadOpaque8(Stream inStr)
+ public static byte[] ReadOpaque8(Stream input)
{
- byte length = ReadUint8(inStr);
+ byte length = ReadUint8(input);
byte[] bytes = new byte[length];
- ReadFully(bytes, inStr);
+ ReadFully(bytes, input);
return bytes;
}
- internal static byte[] ReadOpaque16(Stream inStr)
+ public static byte[] ReadOpaque16(Stream input)
{
- int length = ReadUint16(inStr);
+ int length = ReadUint16(input);
byte[] bytes = new byte[length];
- ReadFully(bytes, inStr);
+ ReadFully(bytes, input);
return bytes;
}
@@ -221,22 +475,56 @@ namespace Org.BouncyCastle.Crypto.Tls
return ReadFully(length, input);
}
- internal static void CheckVersion(byte[] readVersion)
+ public static byte[] ReadUint8Array(int count, Stream input)
{
- if ((readVersion[0] != 3) || (readVersion[1] != 1))
+ byte[] uints = new byte[count];
+ for (int i = 0; i < count; ++i)
{
- throw new TlsFatalAlert(AlertDescription.protocol_version);
+ uints[i] = ReadUint8(input);
}
+ return uints;
}
- internal static void CheckVersion(Stream inStr)
+ public static int[] ReadUint16Array(int count, Stream input)
{
- int i1 = inStr.ReadByte();
- int i2 = inStr.ReadByte();
- if ((i1 != 3) || (i2 != 1))
+ int[] uints = new int[count];
+ for (int i = 0; i < count; ++i)
{
- throw new TlsFatalAlert(AlertDescription.protocol_version);
+ uints[i] = ReadUint16(input);
}
+ return uints;
+ }
+
+ public static ProtocolVersion ReadVersion(byte[] buf, int offset)
+ {
+ return ProtocolVersion.Get(buf[offset], buf[offset + 1]);
+ }
+
+ public static ProtocolVersion ReadVersion(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ if (i2 < 0)
+ {
+ throw new EndOfStreamException();
+ }
+ return ProtocolVersion.Get(i1, i2);
+ }
+
+ public static int ReadVersionRaw(byte[] buf, int offset)
+ {
+ return (buf[offset] << 8) | buf[offset + 1];
+ }
+
+ public static int ReadVersionRaw(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ if (i2 < 0)
+ {
+ throw new EndOfStreamException();
+ }
+ return (i1 << 8) | i2;
}
public static Asn1Object ReadAsn1Object(byte[] encoding)
@@ -263,7 +551,7 @@ namespace Org.BouncyCastle.Crypto.Tls
return result;
}
- internal static void WriteGmtUnixTime(byte[] buf, int offset)
+ public static void WriteGmtUnixTime(byte[] buf, int offset)
{
int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L);
buf[offset] = (byte)(t >> 24);
@@ -272,16 +560,152 @@ namespace Org.BouncyCastle.Crypto.Tls
buf[offset + 3] = (byte)t;
}
- internal static void WriteVersion(Stream os)
+ public static void WriteVersion(ProtocolVersion version, Stream output)
+ {
+ output.WriteByte((byte)version.MajorVersion);
+ output.WriteByte((byte)version.MinorVersion);
+ }
+
+ public static void WriteVersion(ProtocolVersion version, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)version.MajorVersion;
+ buf[offset + 1] = (byte)version.MinorVersion;
+ }
+
+ public static IList GetDefaultDssSignatureAlgorithms()
+ {
+ return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.dsa));
+ }
+
+ public static IList GetDefaultECDsaSignatureAlgorithms()
+ {
+ return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa));
+ }
+
+ public static IList GetDefaultRsaSignatureAlgorithms()
+ {
+ return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa));
+ }
+
+ public static byte[] GetExtensionData(IDictionary extensions, int extensionType)
+ {
+ return extensions == null ? null : (byte[])extensions[extensionType];
+ }
+
+ public static IList GetDefaultSupportedSignatureAlgorithms()
+ {
+ byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha1, HashAlgorithm.sha224, HashAlgorithm.sha256,
+ HashAlgorithm.sha384, HashAlgorithm.sha512 };
+ byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa, SignatureAlgorithm.dsa,
+ SignatureAlgorithm.ecdsa };
+
+ IList result = Platform.CreateArrayList();
+ for (int i = 0; i < signatureAlgorithms.Length; ++i)
+ {
+ for (int j = 0; j < hashAlgorithms.Length; ++j)
+ {
+ result.Add(new SignatureAndHashAlgorithm(hashAlgorithms[j], signatureAlgorithms[i]));
+ }
+ }
+ return result;
+ }
+
+ public static SignatureAndHashAlgorithm GetSignatureAndHashAlgorithm(TlsContext context,
+ TlsSignerCredentials signerCredentials)
+ {
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
+ if (IsTlsV12(context))
+ {
+ signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm;
+ if (signatureAndHashAlgorithm == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ return signatureAndHashAlgorithm;
+ }
+
+ public static bool HasExpectedEmptyExtensionData(IDictionary extensions, int extensionType,
+ byte alertDescription)
+ {
+ byte[] extension_data = GetExtensionData(extensions, extensionType);
+ if (extension_data == null)
+ return false;
+ if (extension_data.Length != 0)
+ throw new TlsFatalAlert(alertDescription);
+ return true;
+ }
+
+ public static TlsSession ImportSession(byte[] sessionID, SessionParameters sessionParameters)
+ {
+ return new TlsSessionImpl(sessionID, sessionParameters);
+ }
+
+ public static bool IsSignatureAlgorithmsExtensionAllowed(ProtocolVersion clientVersion)
+ {
+ return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(clientVersion.GetEquivalentTLSVersion());
+ }
+
+ /**
+ * Add a 'signature_algorithms' extension to existing extensions.
+ *
+ * @param extensions A {@link Hashtable} to add the extension to.
+ * @param supportedSignatureAlgorithms {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+ * @throws IOException
+ */
+ public static void AddSignatureAlgorithmsExtension(IDictionary extensions, IList supportedSignatureAlgorithms)
+ {
+ extensions[ExtensionType.signature_algorithms] = CreateSignatureAlgorithmsExtension(supportedSignatureAlgorithms);
+ }
+
+ /**
+ * Get a 'signature_algorithms' extension from extensions.
+ *
+ * @param extensions A {@link Hashtable} to get the extension from, if it is present.
+ * @return A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}, or null.
+ * @throws IOException
+ */
+ public static IList GetSignatureAlgorithmsExtension(IDictionary extensions)
{
- os.WriteByte(3);
- os.WriteByte(1);
+ byte[] extensionData = GetExtensionData(extensions, ExtensionType.signature_algorithms);
+ return extensionData == null ? null : ReadSignatureAlgorithmsExtension(extensionData);
}
- internal static void WriteVersion(byte[] buf, int offset)
+ /**
+ * Create a 'signature_algorithms' extension value.
+ *
+ * @param supportedSignatureAlgorithms A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+ * @return A byte array suitable for use as an extension value.
+ * @throws IOException
+ */
+ public static byte[] CreateSignatureAlgorithmsExtension(IList supportedSignatureAlgorithms)
{
- buf[offset] = 3;
- buf[offset + 1] = 1;
+ MemoryStream buf = new MemoryStream();
+
+ // supported_signature_algorithms
+ EncodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, false, buf);
+
+ return buf.ToArray();
+ }
+
+ /**
+ * Read 'signature_algorithms' extension data.
+ *
+ * @param extensionData The extension data.
+ * @return A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+ * @throws IOException
+ */
+ public static IList ReadSignatureAlgorithmsExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ // supported_signature_algorithms
+ IList supported_signature_algorithms = ParseSupportedSignatureAlgorithms(false, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return supported_signature_algorithms;
}
public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous,
@@ -295,8 +719,8 @@ namespace Org.BouncyCastle.Crypto.Tls
// supported_signature_algorithms
int length = 2 * supportedSignatureAlgorithms.Count;
- TlsUtilities.CheckUint16(length);
- TlsUtilities.WriteUint16(length, output);
+ CheckUint16(length);
+ WriteUint16(length, output);
foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms)
{
@@ -313,58 +737,76 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
- private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
+ public static IList ParseSupportedSignatureAlgorithms(bool allowAnonymous, Stream input)
{
- HMac mac = new HMac(digest);
- mac.Init(new KeyParameter(secret));
- byte[] a = seed;
- int size = digest.GetDigestSize();
- int iterations = (output.Length + size - 1) / size;
- byte[] buf = new byte[mac.GetMacSize()];
- byte[] buf2 = new byte[mac.GetMacSize()];
- for (int i = 0; i < iterations; i++)
+ // supported_signature_algorithms
+ int length = ReadUint16(input);
+ if (length < 2 || (length & 1) != 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ int count = length / 2;
+ IList supportedSignatureAlgorithms = Platform.CreateArrayList(count);
+ for (int i = 0; i < count; ++i)
{
- mac.BlockUpdate(a, 0, a.Length);
- mac.DoFinal(buf, 0);
- a = buf;
- mac.BlockUpdate(a, 0, a.Length);
- mac.BlockUpdate(seed, 0, seed.Length);
- mac.DoFinal(buf2, 0);
- Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
+ SignatureAndHashAlgorithm entry = SignatureAndHashAlgorithm.Parse(input);
+ if (!allowAnonymous && entry.Signature == SignatureAlgorithm.anonymous)
+ {
+ /*
+ * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used
+ * in Section 7.4.3. It MUST NOT appear in this extension.
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ supportedSignatureAlgorithms.Add(entry);
}
+ return supportedSignatureAlgorithms;
}
- internal static byte[] PRF(byte[] secret, string asciiLabel, byte[] seed, int size)
+ public static byte[] PRF(TlsContext context, byte[] secret, string asciiLabel, byte[] seed, int size)
{
- byte[] label = Strings.ToAsciiByteArray(asciiLabel);
+ ProtocolVersion version = context.ServerVersion;
- int s_half = (secret.Length + 1) / 2;
- byte[] s1 = new byte[s_half];
- byte[] s2 = new byte[s_half];
- Array.Copy(secret, 0, s1, 0, s_half);
- Array.Copy(secret, secret.Length - s_half, s2, 0, s_half);
+ if (version.IsSsl)
+ throw new InvalidOperationException("No PRF available for SSLv3 session");
- byte[] ls = Concat(label, seed);
+ byte[] label = Strings.ToByteArray(asciiLabel);
+ byte[] labelSeed = Concat(label, seed);
+
+ int prfAlgorithm = context.SecurityParameters.PrfAlgorithm;
+ if (prfAlgorithm == PrfAlgorithm.tls_prf_legacy)
+ return PRF_legacy(secret, label, labelSeed, size);
+
+ IDigest prfDigest = CreatePrfHash(prfAlgorithm);
byte[] buf = new byte[size];
- byte[] prf = new byte[size];
- hmac_hash(new MD5Digest(), s1, ls, prf);
- hmac_hash(new Sha1Digest(), s2, ls, buf);
- for (int i = 0; i < size; i++)
- {
- buf[i] ^= prf[i];
- }
+ HMacHash(prfDigest, secret, labelSeed, buf);
return buf;
}
- internal static byte[] PRF_1_2(IDigest digest, byte[] secret, string asciiLabel, byte[] seed, int size)
+ public static byte[] PRF_legacy(byte[] secret, string asciiLabel, byte[] seed, int size)
{
- byte[] label = Strings.ToAsciiByteArray(asciiLabel);
+ byte[] label = Strings.ToByteArray(asciiLabel);
byte[] labelSeed = Concat(label, seed);
- byte[] buf = new byte[size];
- hmac_hash(digest, secret, labelSeed, buf);
- return buf;
+ return PRF_legacy(secret, label, labelSeed, size);
+ }
+
+ internal static byte[] PRF_legacy(byte[] secret, byte[] label, byte[] labelSeed, int size)
+ {
+ int s_half = (secret.Length + 1) / 2;
+ byte[] s1 = new byte[s_half];
+ byte[] s2 = new byte[s_half];
+ Array.Copy(secret, 0, s1, 0, s_half);
+ Array.Copy(secret, secret.Length - s_half, s2, 0, s_half);
+
+ byte[] b1 = new byte[size];
+ byte[] b2 = new byte[size];
+ HMacHash(CreateHash(HashAlgorithm.md5), s1, labelSeed, b1);
+ HMacHash(CreateHash(HashAlgorithm.sha1), s2, labelSeed, b2);
+ for (int i = 0; i < size; i++)
+ {
+ b1[i] ^= b2[i];
+ }
+ return b1;
}
internal static byte[] Concat(byte[] a, byte[] b)
@@ -375,6 +817,27 @@ namespace Org.BouncyCastle.Crypto.Tls
return c;
}
+ internal static void HMacHash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
+ {
+ HMac mac = new HMac(digest);
+ mac.Init(new KeyParameter(secret));
+ byte[] a = seed;
+ int size = digest.GetDigestSize();
+ int iterations = (output.Length + size - 1) / size;
+ byte[] buf = new byte[mac.GetMacSize()];
+ byte[] buf2 = new byte[mac.GetMacSize()];
+ for (int i = 0; i < iterations; i++)
+ {
+ mac.BlockUpdate(a, 0, a.Length);
+ mac.DoFinal(buf, 0);
+ a = buf;
+ mac.BlockUpdate(a, 0, a.Length);
+ mac.BlockUpdate(seed, 0, seed.Length);
+ mac.DoFinal(buf2, 0);
+ Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
+ }
+ }
+
internal static void ValidateKeyUsage(X509CertificateStructure c, int keyUsageBits)
{
X509Extensions exts = c.TbsCertificate.Extensions;
@@ -386,11 +849,1351 @@ namespace Org.BouncyCastle.Crypto.Tls
DerBitString ku = KeyUsage.GetInstance(ext);
int bits = ku.GetBytes()[0];
if ((bits & keyUsageBits) != keyUsageBits)
- {
throw new TlsFatalAlert(AlertDescription.certificate_unknown);
- }
}
}
}
+
+ internal static byte[] CalculateKeyBlock(TlsContext context, int size)
+ {
+ SecurityParameters securityParameters = context.SecurityParameters;
+ byte[] master_secret = securityParameters.MasterSecret;
+ byte[] seed = Concat(securityParameters.ServerRandom, securityParameters.ClientRandom);
+
+ if (IsSsl(context))
+ return CalculateKeyBlock_Ssl(master_secret, seed, size);
+
+ return PRF(context, master_secret, ExporterLabel.key_expansion, seed, size);
+ }
+
+ internal static byte[] CalculateKeyBlock_Ssl(byte[] master_secret, byte[] random, int size)
+ {
+ IDigest md5 = CreateHash(HashAlgorithm.md5);
+ IDigest sha1 = CreateHash(HashAlgorithm.sha1);
+ int md5Size = md5.GetDigestSize();
+ byte[] shatmp = new byte[sha1.GetDigestSize()];
+ byte[] tmp = new byte[size + md5Size];
+
+ int i = 0, pos = 0;
+ while (pos < size)
+ {
+ byte[] ssl3Const = SSL3_CONST[i];
+
+ sha1.BlockUpdate(ssl3Const, 0, ssl3Const.Length);
+ sha1.BlockUpdate(master_secret, 0, master_secret.Length);
+ sha1.BlockUpdate(random, 0, random.Length);
+ sha1.DoFinal(shatmp, 0);
+
+ md5.BlockUpdate(master_secret, 0, master_secret.Length);
+ md5.BlockUpdate(shatmp, 0, shatmp.Length);
+ md5.DoFinal(tmp, pos);
+
+ pos += md5Size;
+ ++i;
+ }
+
+ return Arrays.CopyOfRange(tmp, 0, size);
+ }
+
+ internal static byte[] CalculateMasterSecret(TlsContext context, byte[] pre_master_secret)
+ {
+ SecurityParameters securityParameters = context.SecurityParameters;
+
+ byte[] seed = securityParameters.extendedMasterSecret
+ ? securityParameters.SessionHash
+ : Concat(securityParameters.ClientRandom, securityParameters.ServerRandom);
+
+ if (IsSsl(context))
+ return CalculateMasterSecret_Ssl(pre_master_secret, seed);
+
+ string asciiLabel = securityParameters.extendedMasterSecret
+ ? ExporterLabel.extended_master_secret
+ : ExporterLabel.master_secret;
+
+ return PRF(context, pre_master_secret, asciiLabel, seed, 48);
+ }
+
+ internal static byte[] CalculateMasterSecret_Ssl(byte[] pre_master_secret, byte[] random)
+ {
+ IDigest md5 = CreateHash(HashAlgorithm.md5);
+ IDigest sha1 = CreateHash(HashAlgorithm.sha1);
+ int md5Size = md5.GetDigestSize();
+ byte[] shatmp = new byte[sha1.GetDigestSize()];
+
+ byte[] rval = new byte[md5Size * 3];
+ int pos = 0;
+
+ for (int i = 0; i < 3; ++i)
+ {
+ byte[] ssl3Const = SSL3_CONST[i];
+
+ sha1.BlockUpdate(ssl3Const, 0, ssl3Const.Length);
+ sha1.BlockUpdate(pre_master_secret, 0, pre_master_secret.Length);
+ sha1.BlockUpdate(random, 0, random.Length);
+ sha1.DoFinal(shatmp, 0);
+
+ md5.BlockUpdate(pre_master_secret, 0, pre_master_secret.Length);
+ md5.BlockUpdate(shatmp, 0, shatmp.Length);
+ md5.DoFinal(rval, pos);
+
+ pos += md5Size;
+ }
+
+ return rval;
+ }
+
+ internal static byte[] CalculateVerifyData(TlsContext context, string asciiLabel, byte[] handshakeHash)
+ {
+ if (IsSsl(context))
+ return handshakeHash;
+
+ SecurityParameters securityParameters = context.SecurityParameters;
+ byte[] master_secret = securityParameters.MasterSecret;
+ int verify_data_length = securityParameters.VerifyDataLength;
+
+ return PRF(context, master_secret, asciiLabel, handshakeHash, verify_data_length);
+ }
+
+ public static IDigest CreateHash(byte hashAlgorithm)
+ {
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithm.md5:
+ return new MD5Digest();
+ case HashAlgorithm.sha1:
+ return new Sha1Digest();
+ case HashAlgorithm.sha224:
+ return new Sha224Digest();
+ case HashAlgorithm.sha256:
+ return new Sha256Digest();
+ case HashAlgorithm.sha384:
+ return new Sha384Digest();
+ case HashAlgorithm.sha512:
+ return new Sha512Digest();
+ default:
+ throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+ }
+ }
+
+ public static IDigest CreateHash(SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+ {
+ return signatureAndHashAlgorithm == null
+ ? new CombinedHash()
+ : CreateHash(signatureAndHashAlgorithm.Hash);
+ }
+
+ public static IDigest CloneHash(byte hashAlgorithm, IDigest hash)
+ {
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithm.md5:
+ return new MD5Digest((MD5Digest)hash);
+ case HashAlgorithm.sha1:
+ return new Sha1Digest((Sha1Digest)hash);
+ case HashAlgorithm.sha224:
+ return new Sha224Digest((Sha224Digest)hash);
+ case HashAlgorithm.sha256:
+ return new Sha256Digest((Sha256Digest)hash);
+ case HashAlgorithm.sha384:
+ return new Sha384Digest((Sha384Digest)hash);
+ case HashAlgorithm.sha512:
+ return new Sha512Digest((Sha512Digest)hash);
+ default:
+ throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+ }
+ }
+
+ public static IDigest CreatePrfHash(int prfAlgorithm)
+ {
+ switch (prfAlgorithm)
+ {
+ case PrfAlgorithm.tls_prf_legacy:
+ return new CombinedHash();
+ default:
+ return CreateHash(GetHashAlgorithmForPrfAlgorithm(prfAlgorithm));
+ }
+ }
+
+ public static IDigest ClonePrfHash(int prfAlgorithm, IDigest hash)
+ {
+ switch (prfAlgorithm)
+ {
+ case PrfAlgorithm.tls_prf_legacy:
+ return new CombinedHash((CombinedHash)hash);
+ default:
+ return CloneHash(GetHashAlgorithmForPrfAlgorithm(prfAlgorithm), hash);
+ }
+ }
+
+ public static byte GetHashAlgorithmForPrfAlgorithm(int prfAlgorithm)
+ {
+ switch (prfAlgorithm)
+ {
+ case PrfAlgorithm.tls_prf_legacy:
+ throw new ArgumentException("legacy PRF not a valid algorithm", "prfAlgorithm");
+ case PrfAlgorithm.tls_prf_sha256:
+ return HashAlgorithm.sha256;
+ case PrfAlgorithm.tls_prf_sha384:
+ return HashAlgorithm.sha384;
+ default:
+ throw new ArgumentException("unknown PrfAlgorithm", "prfAlgorithm");
+ }
+ }
+
+ public static DerObjectIdentifier GetOidForHashAlgorithm(byte hashAlgorithm)
+ {
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithm.md5:
+ return PkcsObjectIdentifiers.MD5;
+ case HashAlgorithm.sha1:
+ return X509ObjectIdentifiers.IdSha1;
+ case HashAlgorithm.sha224:
+ return NistObjectIdentifiers.IdSha224;
+ case HashAlgorithm.sha256:
+ return NistObjectIdentifiers.IdSha256;
+ case HashAlgorithm.sha384:
+ return NistObjectIdentifiers.IdSha384;
+ case HashAlgorithm.sha512:
+ return NistObjectIdentifiers.IdSha512;
+ default:
+ throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+ }
+ }
+
+ internal static short GetClientCertificateType(Certificate clientCertificate, Certificate serverCertificate)
+ {
+ if (clientCertificate.IsEmpty)
+ return -1;
+
+ X509CertificateStructure x509Cert = clientCertificate.GetCertificateAt(0);
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ try
+ {
+ AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
+ if (publicKey.IsPrivate)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ /*
+ * TODO RFC 5246 7.4.6. The certificates MUST be signed using an acceptable hash/
+ * signature algorithm pair, as described in Section 7.4.4. Note that this relaxes the
+ * constraints on certificate-signing algorithms found in prior versions of TLS.
+ */
+
+ /*
+ * RFC 5246 7.4.6. Client Certificate
+ */
+
+ /*
+ * RSA public key; the certificate MUST allow the key to be used for signing with the
+ * signature scheme and hash algorithm that will be employed in the certificate verify
+ * message.
+ */
+ if (publicKey is RsaKeyParameters)
+ {
+ ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+ return ClientCertificateType.rsa_sign;
+ }
+
+ /*
+ * DSA public key; the certificate MUST allow the key to be used for signing with the
+ * hash algorithm that will be employed in the certificate verify message.
+ */
+ if (publicKey is DsaPublicKeyParameters)
+ {
+ ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+ return ClientCertificateType.dss_sign;
+ }
+
+ /*
+ * ECDSA-capable public key; the certificate MUST allow the key to be used for signing
+ * with the hash algorithm that will be employed in the certificate verify message; the
+ * public key MUST use a curve and point format supported by the server.
+ */
+ if (publicKey is ECPublicKeyParameters)
+ {
+ ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+ // TODO Check the curve and point format
+ return ClientCertificateType.ecdsa_sign;
+ }
+
+ // TODO Add support for ClientCertificateType.*_fixed_*
+
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+ }
+ }
+
+ internal static void TrackHashAlgorithms(TlsHandshakeHash handshakeHash, IList supportedSignatureAlgorithms)
+ {
+ if (supportedSignatureAlgorithms != null)
+ {
+ foreach (SignatureAndHashAlgorithm signatureAndHashAlgorithm in supportedSignatureAlgorithms)
+ {
+ byte hashAlgorithm = signatureAndHashAlgorithm.Hash;
+ handshakeHash.TrackHashAlgorithm(hashAlgorithm);
+ }
+ }
+ }
+
+ public static bool HasSigningCapability(byte clientCertificateType)
+ {
+ switch (clientCertificateType)
+ {
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ case ClientCertificateType.rsa_sign:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static TlsSigner CreateTlsSigner(byte clientCertificateType)
+ {
+ switch (clientCertificateType)
+ {
+ case ClientCertificateType.dss_sign:
+ return new TlsDssSigner();
+ case ClientCertificateType.ecdsa_sign:
+ return new TlsECDsaSigner();
+ case ClientCertificateType.rsa_sign:
+ return new TlsRsaSigner();
+ default:
+ throw new ArgumentException("not a type with signing capability", "clientCertificateType");
+ }
+ }
+
+ internal static readonly byte[] SSL_CLIENT = {0x43, 0x4C, 0x4E, 0x54};
+ internal static readonly byte[] SSL_SERVER = {0x53, 0x52, 0x56, 0x52};
+
+ // SSL3 magic mix constants ("A", "BB", "CCC", ...)
+ internal static readonly byte[][] SSL3_CONST = GenSsl3Const();
+
+ private static byte[][] GenSsl3Const()
+ {
+ int n = 10;
+ byte[][] arr = new byte[n][];
+ for (int i = 0; i < n; i++)
+ {
+ byte[] b = new byte[i + 1];
+ Arrays.Fill(b, (byte)('A' + i));
+ arr[i] = b;
+ }
+ return arr;
+ }
+
+ private static IList VectorOfOne(object obj)
+ {
+ IList v = Platform.CreateArrayList(1);
+ v.Add(obj);
+ return v;
+ }
+
+ public static int GetCipherType(int ciphersuite)
+ {
+ switch (GetEncryptionAlgorithm(ciphersuite))
+ {
+ case EncryptionAlgorithm.AES_128_GCM:
+ case EncryptionAlgorithm.AES_256_GCM:
+ case EncryptionAlgorithm.AES_128_CCM:
+ case EncryptionAlgorithm.AES_128_CCM_8:
+ case EncryptionAlgorithm.AES_256_CCM:
+ case EncryptionAlgorithm.AES_256_CCM_8:
+ case EncryptionAlgorithm.CAMELLIA_128_GCM:
+ case EncryptionAlgorithm.CAMELLIA_256_GCM:
+ case EncryptionAlgorithm.AEAD_CHACHA20_POLY1305:
+ return CipherType.aead;
+
+ case EncryptionAlgorithm.RC2_CBC_40:
+ case EncryptionAlgorithm.IDEA_CBC:
+ case EncryptionAlgorithm.DES40_CBC:
+ case EncryptionAlgorithm.DES_CBC:
+ case EncryptionAlgorithm.cls_3DES_EDE_CBC:
+ case EncryptionAlgorithm.AES_128_CBC:
+ case EncryptionAlgorithm.AES_256_CBC:
+ case EncryptionAlgorithm.CAMELLIA_128_CBC:
+ case EncryptionAlgorithm.CAMELLIA_256_CBC:
+ case EncryptionAlgorithm.SEED_CBC:
+ return CipherType.block;
+
+ case EncryptionAlgorithm.RC4_40:
+ case EncryptionAlgorithm.RC4_128:
+ case EncryptionAlgorithm.ESTREAM_SALSA20:
+ case EncryptionAlgorithm.SALSA20:
+ return CipherType.stream;
+
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public static int GetEncryptionAlgorithm(int ciphersuite)
+ {
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ return EncryptionAlgorithm.cls_3DES_EDE_CBC;
+
+ case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ return EncryptionAlgorithm.AEAD_CHACHA20_POLY1305;
+
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ return EncryptionAlgorithm.AES_128_CBC;
+
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ return EncryptionAlgorithm.AES_128_CBC;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ return EncryptionAlgorithm.AES_128_CCM;
+
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ return EncryptionAlgorithm.AES_128_CCM_8;
+
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ return EncryptionAlgorithm.AES_128_GCM;
+
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return EncryptionAlgorithm.AES_256_CBC;
+
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ return EncryptionAlgorithm.AES_256_CBC;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ return EncryptionAlgorithm.AES_256_CBC;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ return EncryptionAlgorithm.AES_256_CCM;
+
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ return EncryptionAlgorithm.AES_256_CCM_8;
+
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ return EncryptionAlgorithm.AES_256_GCM;
+
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ return EncryptionAlgorithm.CAMELLIA_128_CBC;
+
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ return EncryptionAlgorithm.CAMELLIA_128_CBC;
+
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ return EncryptionAlgorithm.CAMELLIA_128_GCM;
+
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ return EncryptionAlgorithm.CAMELLIA_256_GCM;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ return EncryptionAlgorithm.ESTREAM_SALSA20;
+
+ case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+ return EncryptionAlgorithm.NULL;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+ return EncryptionAlgorithm.NULL;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ return EncryptionAlgorithm.NULL;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+ return EncryptionAlgorithm.NULL;
+
+ case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+ return EncryptionAlgorithm.RC4_128;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+ return EncryptionAlgorithm.RC4_128;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+ return EncryptionAlgorithm.SALSA20;
+
+ case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+ return EncryptionAlgorithm.SEED_CBC;
+
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public static int GetKeyExchangeAlgorithm(int ciphersuite)
+ {
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DH_DSS;
+
+ case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DH_RSA;
+
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DHE_DSS;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ return KeyExchangeAlgorithm.DHE_PSK;
+
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DHE_RSA;
+
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDH_ECDSA;
+
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDH_RSA;
+
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+ return KeyExchangeAlgorithm.ECDHE_ECDSA;
+
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+ return KeyExchangeAlgorithm.ECDHE_PSK;
+
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+ return KeyExchangeAlgorithm.ECDHE_RSA;
+
+ case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
+ return KeyExchangeAlgorithm.PSK;
+
+ case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.RSA;
+
+ case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
+ return KeyExchangeAlgorithm.RSA_PSK;
+
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return KeyExchangeAlgorithm.SRP;
+
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ return KeyExchangeAlgorithm.SRP_DSS;
+
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ return KeyExchangeAlgorithm.SRP_RSA;
+
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public static int GetMacAlgorithm(int ciphersuite)
+ {
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ return MacAlgorithm.cls_null;
+
+ case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+ return MacAlgorithm.hmac_md5;
+
+ case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return MacAlgorithm.hmac_sha1;
+
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ return MacAlgorithm.hmac_sha256;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+ return MacAlgorithm.hmac_sha384;
+
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public static ProtocolVersion GetMinimumVersion(int ciphersuite)
+ {
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ return ProtocolVersion.TLSv12;
+
+ default:
+ return ProtocolVersion.SSLv3;
+ }
+ }
+
+ public static bool IsAeadCipherSuite(int ciphersuite)
+ {
+ return CipherType.aead == GetCipherType(ciphersuite);
+ }
+
+ public static bool IsBlockCipherSuite(int ciphersuite)
+ {
+ return CipherType.block == GetCipherType(ciphersuite);
+ }
+
+ public static bool IsStreamCipherSuite(int ciphersuite)
+ {
+ return CipherType.stream == GetCipherType(ciphersuite);
+ }
+
+ public static bool IsValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion)
+ {
+ return GetMinimumVersion(cipherSuite).IsEqualOrEarlierVersionOf(serverVersion.GetEquivalentTLSVersion());
+ }
}
}
diff --git a/crypto/src/crypto/tls/UrlAndHash.cs b/crypto/src/crypto/tls/UrlAndHash.cs
new file mode 100644
index 000000000..9ffd2cbf8
--- /dev/null
+++ b/crypto/src/crypto/tls/UrlAndHash.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 6066 5.
+ */
+ public class UrlAndHash
+ {
+ protected readonly string mUrl;
+ protected readonly byte[] mSha1Hash;
+
+ public UrlAndHash(string url, byte[] sha1Hash)
+ {
+ if (url == null || url.Length < 1 || url.Length >= (1 << 16))
+ throw new ArgumentException("must have length from 1 to (2^16 - 1)", "url");
+ if (sha1Hash != null && sha1Hash.Length != 20)
+ throw new ArgumentException("must have length == 20, if present", "sha1Hash");
+
+ this.mUrl = url;
+ this.mSha1Hash = sha1Hash;
+ }
+
+ public virtual string Url
+ {
+ get { return mUrl; }
+ }
+
+ public virtual byte[] Sha1Hash
+ {
+ get { return mSha1Hash; }
+ }
+
+ /**
+ * Encode this {@link UrlAndHash} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ byte[] urlEncoding = Strings.ToByteArray(this.mUrl);
+ TlsUtilities.WriteOpaque16(urlEncoding, output);
+
+ if (this.mSha1Hash == null)
+ {
+ TlsUtilities.WriteUint8(0, output);
+ }
+ else
+ {
+ TlsUtilities.WriteUint8(1, output);
+ output.Write(this.mSha1Hash, 0, this.mSha1Hash.Length);
+ }
+ }
+
+ /**
+ * Parse a {@link UrlAndHash} from a {@link Stream}.
+ *
+ * @param context
+ * the {@link TlsContext} of the current connection.
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link UrlAndHash} object.
+ * @throws IOException
+ */
+ public static UrlAndHash Parse(TlsContext context, Stream input)
+ {
+ byte[] urlEncoding = TlsUtilities.ReadOpaque16(input);
+ if (urlEncoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ string url = Strings.FromByteArray(urlEncoding);
+
+ byte[] sha1Hash = null;
+ byte padding = TlsUtilities.ReadUint8(input);
+ switch (padding)
+ {
+ case 0:
+ if (TlsUtilities.IsTlsV12(context))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ break;
+ case 1:
+ sha1Hash = TlsUtilities.ReadFully(20, input);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ return new UrlAndHash(url, sha1Hash);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/UseSrtpData.cs b/crypto/src/crypto/tls/UseSrtpData.cs
new file mode 100644
index 000000000..fe8f8accb
--- /dev/null
+++ b/crypto/src/crypto/tls/UseSrtpData.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 5764 4.1.1
+ */
+ public class UseSrtpData
+ {
+ protected readonly int[] mProtectionProfiles;
+ protected readonly byte[] mMki;
+
+ /**
+ * @param protectionProfiles see {@link SrtpProtectionProfile} for valid constants.
+ * @param mki valid lengths from 0 to 255.
+ */
+ public UseSrtpData(int[] protectionProfiles, byte[] mki)
+ {
+ if (protectionProfiles == null || protectionProfiles.Length < 1
+ || protectionProfiles.Length >= (1 << 15))
+ {
+ throw new ArgumentException("must have length from 1 to (2^15 - 1)", "protectionProfiles");
+ }
+
+ if (mki == null)
+ {
+ mki = TlsUtilities.EmptyBytes;
+ }
+ else if (mki.Length > 255)
+ {
+ throw new ArgumentException("cannot be longer than 255 bytes", "mki");
+ }
+
+ this.mProtectionProfiles = protectionProfiles;
+ this.mMki = mki;
+ }
+
+ /**
+ * @return see {@link SrtpProtectionProfile} for valid constants.
+ */
+ public virtual int[] ProtectionProfiles
+ {
+ get { return mProtectionProfiles; }
+ }
+
+ /**
+ * @return valid lengths from 0 to 255.
+ */
+ public virtual byte[] Mki
+ {
+ get { return mMki; }
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/UserMappingType.cs b/crypto/src/crypto/tls/UserMappingType.cs
index 6e6d40a58..6cff51736 100644
--- a/crypto/src/crypto/tls/UserMappingType.cs
+++ b/crypto/src/crypto/tls/UserMappingType.cs
@@ -8,6 +8,6 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 4681
*/
- public const short upn_domain_hint = 64;
+ public const byte upn_domain_hint = 64;
}
}
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index 087cb7cea..dc00ab450 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -117,6 +117,22 @@ namespace Org.BouncyCastle.Crypto.Utilities
UInt32_To_BE((uint)(n), bs, off + 4);
}
+ internal static byte[] UInt64_To_BE(ulong[] ns)
+ {
+ byte[] bs = new byte[8 * ns.Length];
+ UInt64_To_BE(ns, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt64_To_BE(ulong[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ UInt64_To_BE(ns[i], bs, off);
+ off += 8;
+ }
+ }
+
internal static ulong BE_To_UInt64(byte[] bs)
{
uint hi = BE_To_UInt32(bs);
@@ -131,6 +147,15 @@ namespace Org.BouncyCastle.Crypto.Utilities
return ((ulong)hi << 32) | (ulong)lo;
}
+ internal static void BE_To_UInt64(byte[] bs, int off, ulong[] ns)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ ns[i] = BE_To_UInt64(bs, off);
+ off += 8;
+ }
+ }
+
internal static void UInt16_To_LE(ushort n, byte[] bs)
{
bs[0] = (byte)(n);
diff --git a/crypto/src/math/Primes.cs b/crypto/src/math/Primes.cs
new file mode 100644
index 000000000..420c3cc5a
--- /dev/null
+++ b/crypto/src/math/Primes.cs
@@ -0,0 +1,584 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math
+{
+ /**
+ * Utility methods for generating primes and testing for primality.
+ */
+ public abstract class Primes
+ {
+ private static readonly BigInteger One = BigInteger.One;
+ private static readonly BigInteger Two = BigInteger.Two;
+ private static readonly BigInteger Three = BigInteger.Three;
+
+ /**
+ * Used to return the output from the
+ * {@linkplain Primes#enhancedMRProbablePrimeTest(BigInteger, SecureRandom, int) Enhanced
+ * Miller-Rabin Probabilistic Primality Test}
+ */
+ public class MROutput
+ {
+ internal static MROutput ProbablyPrime()
+ {
+ return new MROutput(false, null);
+ }
+
+ internal static MROutput ProvablyCompositeWithFactor(BigInteger factor)
+ {
+ return new MROutput(true, factor);
+ }
+
+ internal static MROutput ProvablyCompositeNotPrimePower()
+ {
+ return new MROutput(true, null);
+ }
+
+ private readonly bool mProvablyComposite;
+ private readonly BigInteger mFactor;
+
+ private MROutput(bool provablyComposite, BigInteger factor)
+ {
+ this.mProvablyComposite = provablyComposite;
+ this.mFactor = factor;
+ }
+
+ public BigInteger Factor
+ {
+ get { return mFactor; }
+ }
+
+ public bool IsProvablyComposite
+ {
+ get { return mProvablyComposite; }
+ }
+
+ public bool IsNotPrimePower
+ {
+ get { return mProvablyComposite && mFactor == null; }
+ }
+ }
+
+ /**
+ * Used to return the output from the {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime Routine}
+ */
+ public class STOutput
+ {
+ private readonly BigInteger mPrime;
+ private readonly byte[] mPrimeSeed;
+ private readonly int mPrimeGenCounter;
+
+ internal STOutput(BigInteger prime, byte[] primeSeed, int primeGenCounter)
+ {
+ this.mPrime = prime;
+ this.mPrimeSeed = primeSeed;
+ this.mPrimeGenCounter = primeGenCounter;
+ }
+
+ public BigInteger Prime
+ {
+ get { return mPrime; }
+ }
+
+ public byte[] PrimeSeed
+ {
+ get { return mPrimeSeed; }
+ }
+
+ public int PrimeGenCounter
+ {
+ get { return mPrimeGenCounter; }
+ }
+ }
+
+ /**
+ * FIPS 186-4 C.6 Shawe-Taylor Random_Prime Routine
+ *
+ * Construct a provable prime number using a hash function.
+ *
+ * @param hash
+ * the {@link Digest} instance to use (as "Hash()"). Cannot be null.
+ * @param length
+ * the length (in bits) of the prime to be generated. Must be at least 2.
+ * @param inputSeed
+ * the seed to be used for the generation of the requested prime. Cannot be null or
+ * empty.
+ * @return an {@link STOutput} instance containing the requested prime.
+ */
+ public static STOutput GenerateSTRandomPrime(IDigest hash, int length, byte[] inputSeed)
+ {
+ if (hash == null)
+ throw new ArgumentNullException("hash");
+ if (length < 2)
+ throw new ArgumentException("must be >= 2", "length");
+ if (inputSeed == null)
+ throw new ArgumentNullException("inputSeed");
+ if (inputSeed.Length == 0)
+ throw new ArgumentException("cannot be empty", "inputSeed");
+
+ return ImplSTRandomPrime(hash, length, Arrays.Clone(inputSeed));
+ }
+
+ /**
+ * FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test
+ *
+ * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an
+ * alternative to {@link #isMRProbablePrime(BigInteger, SecureRandom, int)} that provides more
+ * information about a composite candidate, which may be useful when generating or validating
+ * RSA moduli.
+ *
+ * @param candidate
+ * the {@link BigInteger} instance to test for primality.
+ * @param random
+ * the source of randomness to use to choose bases.
+ * @param iterations
+ * the number of randomly-chosen bases to perform the test for.
+ * @return an {@link MROutput} instance that can be further queried for details.
+ */
+ public static MROutput EnhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations)
+ {
+ CheckCandidate(candidate, "candidate");
+
+ if (random == null)
+ throw new ArgumentNullException("random");
+ if (iterations < 1)
+ throw new ArgumentException("must be > 0", "iterations");
+
+ if (candidate.BitLength == 2)
+ return MROutput.ProbablyPrime();
+
+ if (!candidate.TestBit(0))
+ return MROutput.ProvablyCompositeWithFactor(Two);
+
+ BigInteger w = candidate;
+ BigInteger wSubOne = candidate.Subtract(One);
+ BigInteger wSubTwo = candidate.Subtract(Two);
+
+ int a = wSubOne.GetLowestSetBit();
+ BigInteger m = wSubOne.ShiftRight(a);
+
+ for (int i = 0; i < iterations; ++i)
+ {
+ BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
+ BigInteger g = b.Gcd(w);
+
+ if (g.CompareTo(One) > 0)
+ return MROutput.ProvablyCompositeWithFactor(g);
+
+ BigInteger z = b.ModPow(m, w);
+
+ if (z.Equals(One) || z.Equals(wSubOne))
+ continue;
+
+ bool primeToBase = false;
+
+ BigInteger x = z;
+ for (int j = 1; j < a; ++j)
+ {
+ z = z.ModPow(Two, w);
+
+ if (z.Equals(wSubOne))
+ {
+ primeToBase = true;
+ break;
+ }
+
+ if (z.Equals(One))
+ break;
+
+ x = z;
+ }
+
+ if (!primeToBase)
+ {
+ if (!z.Equals(One))
+ {
+ x = z;
+ z = z.ModPow(Two, w);
+
+ if (!z.Equals(One))
+ {
+ x = z;
+ }
+ }
+
+ g = x.Subtract(One).Gcd(w);
+
+ if (g.CompareTo(One) > 0)
+ return MROutput.ProvablyCompositeWithFactor(g);
+
+ return MROutput.ProvablyCompositeNotPrimePower();
+ }
+ }
+
+ return MROutput.ProbablyPrime();
+ }
+
+ /**
+ * A fast check for small divisors, up to some implementation-specific limit.
+ *
+ * @param candidate
+ * the {@link BigInteger} instance to test for division by small factors.
+ *
+ * @return <code>true</code> if the candidate is found to have any small factors,
+ * <code>false</code> otherwise.
+ */
+ public static bool HasAnySmallFactors(BigInteger candidate)
+ {
+ CheckCandidate(candidate, "candidate");
+
+ return ImplHasAnySmallFactors(candidate);
+ }
+
+ /**
+ * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test
+ *
+ * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases.
+ *
+ * @param candidate
+ * the {@link BigInteger} instance to test for primality.
+ * @param random
+ * the source of randomness to use to choose bases.
+ * @param iterations
+ * the number of randomly-chosen bases to perform the test for.
+ * @return <code>false</code> if any witness to compositeness is found amongst the chosen bases
+ * (so <code>candidate</code> is definitely NOT prime), or else <code>true</code>
+ * (indicating primality with some probability dependent on the number of iterations
+ * that were performed).
+ */
+ public static bool IsMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations)
+ {
+ CheckCandidate(candidate, "candidate");
+
+ if (random == null)
+ throw new ArgumentException("cannot be null", "random");
+ if (iterations < 1)
+ throw new ArgumentException("must be > 0", "iterations");
+
+ if (candidate.BitLength == 2)
+ return true;
+ if (!candidate.TestBit(0))
+ return false;
+
+ BigInteger w = candidate;
+ BigInteger wSubOne = candidate.Subtract(One);
+ BigInteger wSubTwo = candidate.Subtract(Two);
+
+ int a = wSubOne.GetLowestSetBit();
+ BigInteger m = wSubOne.ShiftRight(a);
+
+ for (int i = 0; i < iterations; ++i)
+ {
+ BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
+
+ if (!ImplMRProbablePrimeToBase(w, wSubOne, m, a, b))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base).
+ *
+ * Run a single iteration of the Miller-Rabin algorithm against the specified base.
+ *
+ * @param candidate
+ * the {@link BigInteger} instance to test for primality.
+ * @param baseValue
+ * the base value to use for this iteration.
+ * @return <code>false</code> if the specified base is a witness to compositeness (so
+ * <code>candidate</code> is definitely NOT prime), or else <code>true</code>.
+ */
+ public static bool IsMRProbablePrimeToBase(BigInteger candidate, BigInteger baseValue)
+ {
+ CheckCandidate(candidate, "candidate");
+ CheckCandidate(baseValue, "baseValue");
+
+ if (baseValue.CompareTo(candidate.Subtract(One)) >= 0)
+ throw new ArgumentException("must be < ('candidate' - 1)", "baseValue");
+
+ if (candidate.BitLength == 2)
+ return true;
+
+ BigInteger w = candidate;
+ BigInteger wSubOne = candidate.Subtract(One);
+
+ int a = wSubOne.GetLowestSetBit();
+ BigInteger m = wSubOne.ShiftRight(a);
+
+ return ImplMRProbablePrimeToBase(w, wSubOne, m, a, baseValue);
+ }
+
+ private static void CheckCandidate(BigInteger n, string name)
+ {
+ if (n == null || n.SignValue < 1 || n.BitLength < 2)
+ throw new ArgumentException("must be non-null and >= 2", name);
+ }
+
+ private static bool ImplHasAnySmallFactors(BigInteger x)
+ {
+ /*
+ * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders.
+ */
+ int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
+ int r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r & 1) != 0 && (r % 3) != 0 && (r % 5) != 0 && (r % 7) != 0 && (r % 11) != 0
+ && (r % 13) != 0 && (r % 17) != 0 && (r % 19) != 0 && (r % 23) != 0)
+ {
+ m = 29 * 31 * 37 * 41 * 43;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 29) != 0 && (r % 31) != 0 && (r % 37) != 0 && (r % 41) != 0 && (r % 43) != 0)
+ {
+ m = 47 * 53 * 59 * 61 * 67;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 47) != 0 && (r % 53) != 0 && (r % 59) != 0 && (r % 61) != 0 && (r % 67) != 0)
+ {
+ m = 71 * 73 * 79 * 83;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 71) != 0 && (r % 73) != 0 && (r % 79) != 0 && (r % 83) != 0)
+ {
+ m = 89 * 97 * 101 * 103;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 89) != 0 && (r % 97) != 0 && (r % 101) != 0 && (r % 103) != 0)
+ {
+ m = 107 * 109 * 113 * 127;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 107) != 0 && (r % 109) != 0 && (r % 113) != 0 && (r % 127) != 0)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ private static bool ImplMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b)
+ {
+ BigInteger z = b.ModPow(m, w);
+
+ if (z.Equals(One) || z.Equals(wSubOne))
+ return true;
+
+ bool result = false;
+
+ for (int j = 1; j < a; ++j)
+ {
+ z = z.ModPow(Two, w);
+
+ if (z.Equals(wSubOne))
+ {
+ result = true;
+ break;
+ }
+
+ if (z.Equals(One))
+ return false;
+ }
+
+ return result;
+ }
+
+ private static STOutput ImplSTRandomPrime(IDigest d, int length, byte[] primeSeed)
+ {
+ int dLen = d.GetDigestSize();
+
+ if (length < 33)
+ {
+ int primeGenCounter = 0;
+
+ byte[] c0 = new byte[dLen];
+ byte[] c1 = new byte[dLen];
+
+ for (;;)
+ {
+ Hash(d, primeSeed, c0, 0);
+ Inc(primeSeed, 1);
+
+ Hash(d, primeSeed, c1, 0);
+ Inc(primeSeed, 1);
+
+ uint c = Extract32(c0) ^ Extract32(c1);
+ c &= (uint.MaxValue >> (32 - length));
+ c |= (1U << (length - 1)) | 1U;
+
+ ++primeGenCounter;
+
+ if (IsPrime32(c))
+ {
+ return new STOutput(BigInteger.ValueOf((long)c), primeSeed, primeGenCounter);
+ }
+
+ if (primeGenCounter > (4 * length))
+ {
+ throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine");
+ }
+ }
+ }
+
+ STOutput rec = ImplSTRandomPrime(d, (length + 3)/2, primeSeed);
+
+ {
+ BigInteger c0 = rec.Prime;
+ primeSeed = rec.PrimeSeed;
+ int primeGenCounter = rec.PrimeGenCounter;
+
+ int outlen = 8 * dLen;
+ int iterations = (length - 1)/outlen;
+
+ int oldCounter = primeGenCounter;
+
+ BigInteger x = HashGen(d, primeSeed, iterations + 1);
+ x = x.Mod(One.ShiftLeft(length - 1)).SetBit(length - 1);
+
+ BigInteger c0x2 = c0.ShiftLeft(1);
+ BigInteger tx2 = x.Subtract(One).Divide(c0x2).Add(One).ShiftLeft(1);
+ int dt = 0;
+
+ BigInteger c = tx2.Multiply(c0).Add(One);
+
+ /*
+ * TODO Since the candidate primes are generated by constant steps ('c0x2'),
+ * sieving could be used here in place of the 'HasAnySmallFactors' approach.
+ */
+ for (;;)
+ {
+ if (c.BitLength > length)
+ {
+ tx2 = One.ShiftLeft(length - 1).Subtract(One).Divide(c0x2).Add(One).ShiftLeft(1);
+ c = tx2.Multiply(c0).Add(One);
+ }
+
+ ++primeGenCounter;
+
+ /*
+ * This is an optimization of the original algorithm, using trial division to screen out
+ * many non-primes quickly.
+ *
+ * NOTE: 'primeSeed' is still incremented as if we performed the full check!
+ */
+ if (!ImplHasAnySmallFactors(c))
+ {
+ BigInteger a = HashGen(d, primeSeed, iterations + 1);
+ a = a.Mod(c.Subtract(Three)).Add(Two);
+
+ tx2 = tx2.Add(BigInteger.ValueOf(dt));
+ dt = 0;
+
+ BigInteger z = a.ModPow(tx2, c);
+
+ if (c.Gcd(z.Subtract(One)).Equals(One) && z.ModPow(c0, c).Equals(One))
+ {
+ return new STOutput(c, primeSeed, primeGenCounter);
+ }
+ }
+ else
+ {
+ Inc(primeSeed, iterations + 1);
+ }
+
+ if (primeGenCounter >= ((4 * length) + oldCounter))
+ {
+ throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine");
+ }
+
+ dt += 2;
+ c = c.Add(c0x2);
+ }
+ }
+ }
+
+ private static uint Extract32(byte[] bs)
+ {
+ uint result = 0;
+
+ int count = System.Math.Min(4, bs.Length);
+ for (int i = 0; i < count; ++i)
+ {
+ uint b = bs[bs.Length - (i + 1)];
+ result |= (b << (8 * i));
+ }
+
+ return result;
+ }
+
+ private static void Hash(IDigest d, byte[] input, byte[] output, int outPos)
+ {
+ d.BlockUpdate(input, 0, input.Length);
+ d.DoFinal(output, outPos);
+ }
+
+ private static BigInteger HashGen(IDigest d, byte[] seed, int count)
+ {
+ int dLen = d.GetDigestSize();
+ int pos = count * dLen;
+ byte[] buf = new byte[pos];
+ for (int i = 0; i < count; ++i)
+ {
+ pos -= dLen;
+ Hash(d, seed, buf, pos);
+ Inc(seed, 1);
+ }
+ return new BigInteger(1, buf);
+ }
+
+ private static void Inc(byte[] seed, int c)
+ {
+ int pos = seed.Length;
+ while (c > 0 && --pos >= 0)
+ {
+ c += seed[pos];
+ seed[pos] = (byte)c;
+ c >>= 8;
+ }
+ }
+
+ private static bool IsPrime32(uint x)
+ {
+ /*
+ * Use wheel factorization with 2, 3, 5 to select trial divisors.
+ */
+
+ if (x <= 5)
+ {
+ return x == 2 || x == 3 || x == 5;
+ }
+
+ if ((x & 1) == 0 || (x % 3) == 0 || (x % 5) == 0)
+ {
+ return false;
+ }
+
+ uint[] ds = new uint[]{ 1, 7, 11, 13, 17, 19, 23, 29 };
+ uint b = 0;
+ for (int pos = 1; ; pos = 0)
+ {
+ /*
+ * Trial division by wheel-selected divisors
+ */
+ while (pos < ds.Length)
+ {
+ uint d = b + ds[pos];
+ if (x % d == 0)
+ {
+ return x < 30;
+ }
+ ++pos;
+ }
+
+ b += 30;
+
+ if ((b >> 16 != 0) || (b * b >= x))
+ {
+ return true;
+ }
+ }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs
index 6519e81c6..5d60de40f 100644
--- a/crypto/src/math/ec/ECAlgorithms.cs
+++ b/crypto/src/math/ec/ECAlgorithms.cs
@@ -10,14 +10,23 @@ namespace Org.BouncyCastle.Math.EC
{
public static bool IsF2mCurve(ECCurve c)
{
- IFiniteField field = c.Field;
+ return IsF2mField(c.Field);
+ }
+
+ public static bool IsF2mField(IFiniteField field)
+ {
return field.Dimension > 1 && field.Characteristic.Equals(BigInteger.Two)
&& field is IPolynomialExtensionField;
}
public static bool IsFpCurve(ECCurve c)
{
- return c.Field.Dimension == 1;
+ return IsFpField(c.Field);
+ }
+
+ public static bool IsFpField(IFiniteField field)
+ {
+ return field.Dimension == 1;
}
public static ECPoint SumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
@@ -49,10 +58,10 @@ namespace Org.BouncyCastle.Math.EC
GlvEndomorphism glvEndomorphism = c.GetEndomorphism() as GlvEndomorphism;
if (glvEndomorphism != null)
{
- return ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism);
+ return ValidatePoint(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism));
}
- return ImplSumOfMultiplies(imported, ks);
+ return ValidatePoint(ImplSumOfMultiplies(imported, ks));
}
public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b)
@@ -61,22 +70,22 @@ namespace Org.BouncyCastle.Math.EC
Q = ImportPoint(cp, Q);
// Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
- if (cp is F2mCurve)
{
- F2mCurve f2mCurve = (F2mCurve) cp;
- if (f2mCurve.IsKoblitz)
+ AbstractF2mCurve f2mCurve = cp as AbstractF2mCurve;
+ if (f2mCurve != null && f2mCurve.IsKoblitz)
{
- return P.Multiply(a).Add(Q.Multiply(b));
+ return ValidatePoint(P.Multiply(a).Add(Q.Multiply(b)));
}
}
GlvEndomorphism glvEndomorphism = cp.GetEndomorphism() as GlvEndomorphism;
if (glvEndomorphism != null)
{
- return ImplSumOfMultipliesGlv(new ECPoint[] { P, Q }, new BigInteger[] { a, b }, glvEndomorphism);
+ return ValidatePoint(
+ ImplSumOfMultipliesGlv(new ECPoint[] { P, Q }, new BigInteger[] { a, b }, glvEndomorphism));
}
- return ImplShamirsTrickWNaf(P, a, Q, b);
+ return ValidatePoint(ImplShamirsTrickWNaf(P, a, Q, b));
}
/*
@@ -102,7 +111,7 @@ namespace Org.BouncyCastle.Math.EC
ECCurve cp = P.Curve;
Q = ImportPoint(cp, Q);
- return ImplShamirsTrickJsf(P, k, Q, l);
+ return ValidatePoint(ImplShamirsTrickJsf(P, k, Q, l));
}
public static ECPoint ImportPoint(ECCurve c, ECPoint p)
@@ -116,6 +125,11 @@ namespace Org.BouncyCastle.Math.EC
public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len)
{
+ MontgomeryTrick(zs, off, len, null);
+ }
+
+ public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len, ECFieldElement scale)
+ {
/*
* Uses the "Montgomery Trick" to invert many field elements, with only a single actual
* field inversion. See e.g. the paper:
@@ -132,7 +146,14 @@ namespace Org.BouncyCastle.Math.EC
c[i] = c[i - 1].Multiply(zs[off + i]);
}
- ECFieldElement u = c[--i].Invert();
+ --i;
+
+ if (scale != null)
+ {
+ c[i] = c[i].Multiply(scale);
+ }
+
+ ECFieldElement u = c[i].Invert();
while (i > 0)
{
@@ -145,6 +166,47 @@ namespace Org.BouncyCastle.Math.EC
zs[off] = u;
}
+ /**
+ * Simple shift-and-add multiplication. Serves as reference implementation
+ * to verify (possibly faster) implementations, and for very small scalars.
+ *
+ * @param p
+ * The point to multiply.
+ * @param k
+ * The multiplier.
+ * @return The result of the point multiplication <code>kP</code>.
+ */
+ public static ECPoint ReferenceMultiply(ECPoint p, BigInteger k)
+ {
+ BigInteger x = k.Abs();
+ ECPoint q = p.Curve.Infinity;
+ int t = x.BitLength;
+ if (t > 0)
+ {
+ if (x.TestBit(0))
+ {
+ q = p;
+ }
+ for (int i = 1; i < t; i++)
+ {
+ p = p.Twice();
+ if (x.TestBit(i))
+ {
+ q = q.Add(p);
+ }
+ }
+ }
+ return k.SignValue < 0 ? q.Negate() : q;
+ }
+
+ public static ECPoint ValidatePoint(ECPoint p)
+ {
+ if (!p.IsValid())
+ throw new ArgumentException("Invalid point", "p");
+
+ return p;
+ }
+
internal static ECPoint ImplShamirsTrickJsf(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
{
ECCurve curve = P.Curve;
@@ -386,7 +448,7 @@ namespace Org.BouncyCastle.Math.EC
{
int n = System.Math.Abs(wi);
WNafPreCompInfo info = infos[j];
- ECPoint[] table = (wi < 0 == negs[j]) ? info.PreCompNeg : info.PreComp;
+ ECPoint[] table = (wi < 0 == negs[j]) ? info.PreComp : info.PreCompNeg;
r = r.Add(table[n >> 1]);
}
}
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 9c16375e6..40b46ce72 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -102,6 +102,27 @@ namespace Org.BouncyCastle.Math.EC
return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
}
+ public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
+ {
+ ECPoint p = CreatePoint(x, y);
+ if (!p.IsValid())
+ {
+ throw new ArgumentException("Invalid point coordinates");
+ }
+ return p;
+ }
+
+ [Obsolete("Per-point compression property will be removed")]
+ public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
+ {
+ ECPoint p = CreatePoint(x, y, withCompression);
+ if (!p.IsValid())
+ {
+ throw new ArgumentException("Invalid point coordinates");
+ }
+ return p;
+ }
+
public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
{
return CreatePoint(x, y, false);
@@ -185,7 +206,7 @@ namespace Org.BouncyCastle.Math.EC
// TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
p = p.Normalize();
- return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
+ return ValidatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
}
/**
@@ -200,26 +221,56 @@ namespace Org.BouncyCastle.Math.EC
*/
public virtual void NormalizeAll(ECPoint[] points)
{
- CheckPoints(points);
+ NormalizeAll(points, 0, points.Length, null);
+ }
+
+ /**
+ * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+ * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
+ * than one point is to be normalized, this method will generally be more efficient than
+ * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively
+ * each z coordinate is scaled by this value prior to normalization (but only one
+ * actual multiplication is needed).
+ *
+ * @param points
+ * An array of points that will be updated in place with their normalized versions,
+ * where necessary
+ * @param off
+ * The start of the range of points to normalize
+ * @param len
+ * The length of the range of points to normalize
+ * @param iso
+ * The (optional) z-scaling factor - can be null
+ */
+ public virtual void NormalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)
+ {
+ CheckPoints(points, off, len);
- if (this.CoordinateSystem == ECCurve.COORD_AFFINE)
+ switch (this.CoordinateSystem)
{
- return;
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ if (iso != null)
+ throw new ArgumentException("not valid for affine coordinates", "iso");
+
+ return;
+ }
}
/*
* Figure out which of the points actually need to be normalized
*/
- ECFieldElement[] zs = new ECFieldElement[points.Length];
- int[] indices = new int[points.Length];
+ ECFieldElement[] zs = new ECFieldElement[len];
+ int[] indices = new int[len];
int count = 0;
- for (int i = 0; i < points.Length; ++i)
+ for (int i = 0; i < len; ++i)
{
- ECPoint p = points[i];
- if (null != p && !p.IsNormalized())
+ ECPoint p = points[off + i];
+ if (null != p && (iso != null || !p.IsNormalized()))
{
zs[count] = p.GetZCoord(0);
- indices[count++] = i;
+ indices[count++] = off + i;
}
}
@@ -228,7 +279,7 @@ namespace Org.BouncyCastle.Math.EC
return;
}
- ECAlgorithms.MontgomeryTrick(zs, 0, count);
+ ECAlgorithms.MontgomeryTrick(zs, 0, count, iso);
for (int j = 0; j < count; ++j)
{
@@ -277,12 +328,19 @@ namespace Org.BouncyCastle.Math.EC
protected virtual void CheckPoints(ECPoint[] points)
{
+ CheckPoints(points, 0, points.Length);
+ }
+
+ protected virtual void CheckPoints(ECPoint[] points, int off, int len)
+ {
if (points == null)
throw new ArgumentNullException("points");
+ if (off < 0 || len < 0 || (off > (points.Length - len)))
+ throw new ArgumentException("invalid range specified", "points");
- for (int i = 0; i < points.Length; ++i)
+ for (int i = 0; i < len; ++i)
{
- ECPoint point = points[i];
+ ECPoint point = points[off + i];
if (null != point && this != point.Curve)
throw new ArgumentException("entries must be null or on this curve", "points");
}
@@ -344,7 +402,8 @@ namespace Org.BouncyCastle.Math.EC
ECPoint p = null;
int expectedLength = (FieldSize + 7) / 8;
- switch (encoded[0])
+ byte type = encoded[0];
+ switch (type)
{
case 0x00: // infinity
{
@@ -361,10 +420,13 @@ namespace Org.BouncyCastle.Math.EC
if (encoded.Length != (expectedLength + 1))
throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
- int yTilde = encoded[0] & 1;
+ int yTilde = type & 1;
BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
p = DecompressPoint(yTilde, X);
+ if (!p.SatisfiesCofactor())
+ throw new ArgumentException("Invalid point");
+
break;
}
@@ -376,7 +438,7 @@ namespace Org.BouncyCastle.Math.EC
BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
- p = CreatePoint(X, Y);
+ p = ValidatePoint(X, Y);
break;
}
@@ -389,26 +451,59 @@ namespace Org.BouncyCastle.Math.EC
BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
- if (Y.TestBit(0) != (encoded[0] == 0x07))
+ if (Y.TestBit(0) != (type == 0x07))
throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
- p = CreatePoint(X, Y);
+ p = ValidatePoint(X, Y);
break;
}
default:
- throw new FormatException("Invalid point encoding " + encoded[0]);
+ throw new FormatException("Invalid point encoding " + type);
}
+ if (type != 0x00 && p.IsInfinity)
+ throw new ArgumentException("Invalid infinity encoding", "encoded");
+
return p;
}
}
+ public abstract class AbstractFpCurve
+ : ECCurve
+ {
+ protected AbstractFpCurve(BigInteger q)
+ : base(FiniteFields.GetPrimeField(q))
+ {
+ }
+
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1);
+ ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
+ ECFieldElement y = rhs.Sqrt();
+
+ /*
+ * If y is not a square, then we haven't got a point on the curve
+ */
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ if (y.TestBitZero() != (yTilde == 1))
+ {
+ // Use the other root
+ y = y.Negate();
+ }
+
+ return CreateRawPoint(x, y, true);
+ }
+ }
+
/**
* Elliptic curve over Fp
*/
public class FpCurve
- : ECCurve
+ : AbstractFpCurve
{
private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
@@ -421,7 +516,7 @@ namespace Org.BouncyCastle.Math.EC
}
public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_q = q;
this.m_r = FpFieldElement.CalculateResidue(q);
@@ -440,7 +535,7 @@ namespace Org.BouncyCastle.Math.EC
}
protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_q = q;
this.m_r = r;
@@ -523,37 +618,22 @@ namespace Org.BouncyCastle.Math.EC
return base.ImportPoint(p);
}
+ }
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ public abstract class AbstractF2mCurve
+ : ECCurve
+ {
+ public static BigInteger Inverse(int m, int[] ks, BigInteger x)
{
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Add(m_a).Multiply(x).Add(m_b);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new FpPoint(this, x, beta, true);
+ return new LongArray(x).ModInverse(m, ks).ToBigInteger();
}
- }
- /**
- * Elliptic curves over F2m. The Weierstrass equation is given by
- * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
- */
- public class F2mCurve : ECCurve
- {
- private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+ /**
+ * The auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code> used for partial modular reduction for
+ * Koblitz curves.
+ */
+ private BigInteger[] si = null;
private static IFiniteField BuildField(int m, int k1, int k2, int k3)
{
@@ -585,6 +665,166 @@ namespace Org.BouncyCastle.Math.EC
return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
}
+ protected AbstractF2mCurve(int m, int k1, int k2, int k3)
+ : base(BuildField(m, k1, k2, k3))
+ {
+ }
+
+ [Obsolete("Per-point compression property will be removed")]
+ public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
+ {
+ ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ if (X.IsZero)
+ {
+ if (!Y.Square().Equals(B))
+ throw new ArgumentException();
+ }
+ else
+ {
+ // Y becomes Lambda (X + Y/X) here
+ Y = Y.Divide(X).Add(X);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return CreateRawPoint(X, Y, withCompression);
+ }
+
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement xp = FromBigInteger(X1), yp = null;
+ if (xp.IsZero)
+ {
+ yp = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
+ ECFieldElement z = SolveQuadradicEquation(beta);
+
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ yp = z.Add(xp);
+ break;
+ }
+ default:
+ {
+ yp = z.Multiply(xp);
+ break;
+ }
+ }
+ }
+ }
+
+ if (yp == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return CreateRawPoint(xp, yp, true);
+ }
+
+ /**
+ * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+ * D.1.6) The other solution is <code>z + 1</code>.
+ *
+ * @param beta
+ * The value to solve the qradratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadradicEquation(ECFieldElement beta)
+ {
+ if (beta.IsZero)
+ return beta;
+
+ ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero);
+
+ int m = FieldSize;
+ Random rand = new Random();
+ do
+ {
+ ECFieldElement t = FromBigInteger(new BigInteger(m, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < m; i++)
+ {
+ ECFieldElement w2 = w.Square();
+ z = z.Square().Add(w2.Multiply(t));
+ w = w2.Add(beta);
+ }
+ if (!w.IsZero)
+ {
+ return null;
+ }
+ gamma = z.Square().Add(z);
+ }
+ while (gamma.IsZero);
+
+ return z;
+ }
+
+ /**
+ * @return the auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code> used for partial modular reduction for
+ * Koblitz curves.
+ */
+ internal virtual BigInteger[] GetSi()
+ {
+ if (si == null)
+ {
+ lock (this)
+ {
+ if (si == null)
+ {
+ si = Tnaf.GetSi(this);
+ }
+ }
+ }
+ return si;
+ }
+
+ /**
+ * Returns true if this is a Koblitz curve (ABC curve).
+ * @return true if this is a Koblitz curve (ABC curve), false otherwise
+ */
+ public virtual bool IsKoblitz
+ {
+ get
+ {
+ return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
+ }
+ }
+ }
+
+ /**
+ * Elliptic curves over F2m. The Weierstrass equation is given by
+ * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
+ */
+ public class F2mCurve
+ : AbstractF2mCurve
+ {
+ private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
/**
* The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
*/
@@ -622,19 +862,6 @@ namespace Org.BouncyCastle.Math.EC
protected readonly F2mPoint m_infinity;
/**
- * The parameter <code>μ</code> of the elliptic curve if this is
- * a Koblitz curve.
- */
- private sbyte mu = 0;
-
- /**
- * The auxiliary values <code>s<sub>0</sub></code> and
- * <code>s<sub>1</sub></code> used for partial modular reduction for
- * Koblitz curves.
- */
- private BigInteger[] si = null;
-
- /**
* Constructor for Trinomial Polynomial Basis (TPB).
* @param m The exponent <code>m</code> of
* <code>F<sub>2<sup>m</sup></sub></code>.
@@ -748,7 +975,7 @@ namespace Org.BouncyCastle.Math.EC
BigInteger b,
BigInteger order,
BigInteger cofactor)
- : base(BuildField(m, k1, k2, k3))
+ : base(m, k1, k2, k3)
{
this.m = m;
this.k1 = k1;
@@ -781,7 +1008,7 @@ namespace Org.BouncyCastle.Math.EC
}
protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
- : base(BuildField(m, k1, k2, k3))
+ : base(m, k1, k2, k3)
{
this.m = m;
this.k1 = k1;
@@ -834,37 +1061,6 @@ namespace Org.BouncyCastle.Math.EC
return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
}
- [Obsolete("Per-point compression property will be removed")]
- public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
- {
- ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
-
- switch (this.CoordinateSystem)
- {
- case COORD_LAMBDA_AFFINE:
- case COORD_LAMBDA_PROJECTIVE:
- {
- if (X.IsZero)
- {
- if (!Y.Square().Equals(B))
- throw new ArgumentException();
- }
- else
- {
- // Y becomes Lambda (X + Y/X) here
- Y = Y.Divide(X).Add(X);
- }
- break;
- }
- default:
- {
- break;
- }
- }
-
- return CreateRawPoint(X, Y, withCompression);
- }
-
protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
{
return new F2mPoint(this, x, y, withCompression);
@@ -880,143 +1076,6 @@ namespace Org.BouncyCastle.Math.EC
get { return m_infinity; }
}
- /**
- * Returns true if this is a Koblitz curve (ABC curve).
- * @return true if this is a Koblitz curve (ABC curve), false otherwise
- */
- public virtual bool IsKoblitz
- {
- get
- {
- return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
- }
- }
-
- /**
- * Returns the parameter <code>μ</code> of the elliptic curve.
- * @return <code>μ</code> of the elliptic curve.
- * @throws ArgumentException if the given ECCurve is not a
- * Koblitz curve.
- */
- internal virtual sbyte GetMu()
- {
- if (mu == 0)
- {
- lock (this)
- {
- if (mu == 0)
- {
- mu = Tnaf.GetMu(this);
- }
- }
- }
-
- return mu;
- }
-
- /**
- * @return the auxiliary values <code>s<sub>0</sub></code> and
- * <code>s<sub>1</sub></code> used for partial modular reduction for
- * Koblitz curves.
- */
- internal virtual BigInteger[] GetSi()
- {
- if (si == null)
- {
- lock (this)
- {
- if (si == null)
- {
- si = Tnaf.GetSi(this);
- }
- }
- }
- return si;
- }
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement xp = FromBigInteger(X1), yp;
- if (xp.IsZero)
- {
- yp = m_b.Sqrt();
- }
- else
- {
- ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
- ECFieldElement z = SolveQuadradicEquation(beta);
-
- if (z == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (z.TestBitZero() != (yTilde == 1))
- {
- z = z.AddOne();
- }
-
- switch (this.CoordinateSystem)
- {
- case COORD_LAMBDA_AFFINE:
- case COORD_LAMBDA_PROJECTIVE:
- {
- yp = z.Add(xp);
- break;
- }
- default:
- {
- yp = z.Multiply(xp);
- break;
- }
- }
- }
-
- return new F2mPoint(this, xp, yp, true);
- }
-
- /**
- * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
- * D.1.6) The other solution is <code>z + 1</code>.
- *
- * @param beta
- * The value to solve the qradratic equation for.
- * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
- * <code>null</code> if no solution exists.
- */
- private ECFieldElement SolveQuadradicEquation(ECFieldElement beta)
- {
- if (beta.IsZero)
- {
- return beta;
- }
-
- ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
- ECFieldElement z = null;
- ECFieldElement gamma = null;
-
- Random rand = new Random();
- do
- {
- ECFieldElement t = FromBigInteger(new BigInteger(m, rand));
- z = zeroElement;
- ECFieldElement w = beta;
- for (int i = 1; i <= m - 1; i++)
- {
- ECFieldElement w2 = w.Square();
- z = z.Square().Add(w2.Multiply(t));
- w = w2.Add(beta);
- }
- if (!w.IsZero)
- {
- return null;
- }
- gamma = z.Square().Add(z);
- }
- while (gamma.IsZero);
-
- return z;
- }
-
public int M
{
get { return m; }
diff --git a/crypto/src/math/ec/ECFieldElement.cs b/crypto/src/math/ec/ECFieldElement.cs
index e589fc737..4d4fb3e4d 100644
--- a/crypto/src/math/ec/ECFieldElement.cs
+++ b/crypto/src/math/ec/ECFieldElement.cs
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC
@@ -55,6 +56,16 @@ namespace Org.BouncyCastle.Math.EC
return Square().Add(x.Multiply(y));
}
+ public virtual ECFieldElement SquarePow(int pow)
+ {
+ ECFieldElement r = this;
+ for (int i = 0; i < pow; ++i)
+ {
+ r = r.Square();
+ }
+ return r;
+ }
+
public virtual bool TestBitZero()
{
return ToBigInteger().TestBit(0);
@@ -593,6 +604,9 @@ namespace Org.BouncyCastle.Math.EC
int k3,
BigInteger x)
{
+ if (x == null || x.SignValue < 0 || x.BitLength > m)
+ throw new ArgumentException("value invalid in F2m field element", "x");
+
if ((k2 == 0) && (k3 == 0))
{
this.representation = Tpb;
@@ -812,6 +826,11 @@ namespace Org.BouncyCastle.Math.EC
return new F2mFieldElement(m, ks, aa);
}
+ public override ECFieldElement SquarePow(int pow)
+ {
+ return pow < 1 ? this : new F2mFieldElement(m, ks, x.ModSquareN(pow, m, ks));
+ }
+
public override ECFieldElement Invert()
{
return new F2mFieldElement(this.m, this.ks, this.x.ModInverse(m, ks));
@@ -819,14 +838,7 @@ namespace Org.BouncyCastle.Math.EC
public override ECFieldElement Sqrt()
{
- LongArray x1 = this.x;
- if (x1.IsOne() || x1.IsZero())
- {
- return this;
- }
-
- LongArray x2 = x1.ModSquareN(m - 1, m, ks);
- return new F2mFieldElement(m, ks, x2);
+ return (x.IsZero() || x.IsOne()) ? this : SquarePow(m - 1);
}
/**
diff --git a/crypto/src/math/ec/ECPoint.cs b/crypto/src/math/ec/ECPoint.cs
index 0430a6110..a5ba515c5 100644
--- a/crypto/src/math/ec/ECPoint.cs
+++ b/crypto/src/math/ec/ECPoint.cs
@@ -67,6 +67,14 @@ namespace Org.BouncyCastle.Math.EC
this.m_withCompression = withCompression;
}
+ protected internal bool SatisfiesCofactor()
+ {
+ BigInteger h = Curve.Cofactor;
+ return h == null || h.Equals(BigInteger.One) || !ECAlgorithms.ReferenceMultiply(this, h).IsInfinity;
+ }
+
+ protected abstract bool SatisfiesCurveEquation();
+
public ECPoint GetDetachedPoint()
{
return Normalize().Detach();
@@ -289,6 +297,26 @@ namespace Org.BouncyCastle.Math.EC
get { return m_withCompression; }
}
+ public bool IsValid()
+ {
+ if (IsInfinity)
+ return true;
+
+ // TODO Sanity-check the field elements
+
+ ECCurve curve = Curve;
+ if (curve != null)
+ {
+ if (!SatisfiesCurveEquation())
+ return false;
+
+ if (!SatisfiesCofactor())
+ return false;
+ }
+
+ return true;
+ }
+
public virtual ECPoint ScaleX(ECFieldElement scale)
{
return IsInfinity
@@ -497,14 +525,84 @@ namespace Org.BouncyCastle.Math.EC
}
}
+ public abstract class AbstractFpPoint
+ : ECPointBase
+ {
+ protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ }
+
+ protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get { return this.AffineYCoord.TestBitZero(); }
+ }
+
+ protected override bool SatisfiesCurveEquation()
+ {
+ ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = Curve.A, B = Curve.B;
+ ECFieldElement lhs = Y.Square();
+
+ switch (CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_AFFINE:
+ break;
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Z = this.RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
+ lhs = lhs.Multiply(Z);
+ A = A.Multiply(Z2);
+ B = B.Multiply(Z3);
+ }
+ break;
+ }
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ ECFieldElement Z = this.RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square(), Z6 = Z2.Multiply(Z4);
+ A = A.Multiply(Z4);
+ B = B.Multiply(Z6);
+ }
+ break;
+ }
+ default:
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+
+ ECFieldElement rhs = X.Square().Add(A).Multiply(X).Add(B);
+ return lhs.Equals(rhs);
+ }
+
+ public override ECPoint Subtract(ECPoint b)
+ {
+ if (b.IsInfinity)
+ return this;
+
+ // Add -b
+ return Add(b.Negate());
+ }
+ }
+
/**
* Elliptic curve points over Fp
*/
public class FpPoint
- : ECPointBase
+ : AbstractFpPoint
{
/**
- * Create a point which encodes with point compression.
+ * Create a point which encodes without point compression.
*
* @param curve the curve to use
* @param x affine x co-ordinate
@@ -516,7 +614,7 @@ namespace Org.BouncyCastle.Math.EC
}
/**
- * Create a point that encodes with or without point compresion.
+ * Create a point that encodes with or without point compression.
*
* @param curve the curve to use
* @param x affine x co-ordinate
@@ -540,11 +638,6 @@ namespace Org.BouncyCastle.Math.EC
return new FpPoint(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECFieldElement GetZCoord(int index)
{
if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.CurveCoordinateSystem)
@@ -1135,16 +1228,6 @@ namespace Org.BouncyCastle.Math.EC
return a.Add(b).Square().Subtract(aSquared).Subtract(bSquared);
}
- public override ECPoint Subtract(
- ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- // Add -b
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
@@ -1217,11 +1300,229 @@ namespace Org.BouncyCastle.Math.EC
}
}
+ public abstract class AbstractF2mPoint
+ : ECPointBase
+ {
+ protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ }
+
+ protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override bool SatisfiesCurveEquation()
+ {
+ ECCurve curve = Curve;
+ ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = curve.A, B = curve.B;
+ ECFieldElement lhs, rhs;
+
+ int coord = curve.CoordinateSystem;
+ if (coord == ECCurve.COORD_LAMBDA_PROJECTIVE)
+ {
+ ECFieldElement Z = this.RawZCoords[0];
+ bool ZIsOne = Z.IsOne;
+
+ if (X.IsZero)
+ {
+ // NOTE: For x == 0, we expect the affine-y instead of the lambda-y
+ lhs = Y.Square();
+ rhs = B;
+ if (!ZIsOne)
+ {
+ ECFieldElement Z2 = Z.Square();
+ rhs = rhs.Multiply(Z2);
+ }
+ }
+ else
+ {
+ ECFieldElement L = Y, X2 = X.Square();
+ if (ZIsOne)
+ {
+ lhs = L.Square().Add(L).Add(A);
+ rhs = X2.Square().Add(B);
+ }
+ else
+ {
+ ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square();
+ lhs = L.Add(Z).MultiplyPlusProduct(L, A, Z2);
+ // TODO If sqrt(b) is precomputed this can be simplified to a single square
+ rhs = X2.SquarePlusProduct(B, Z4);
+ }
+ lhs = lhs.Multiply(X2);
+ }
+ }
+ else
+ {
+ lhs = Y.Add(X).Multiply(Y);
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ break;
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Z = this.RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
+ lhs = lhs.Multiply(Z);
+ A = A.Multiply(Z);
+ B = B.Multiply(Z3);
+ }
+ break;
+ }
+ default:
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+
+ rhs = X.Add(A).Multiply(X.Square()).Add(B);
+ }
+
+ return lhs.Equals(rhs);
+ }
+
+ public override ECPoint ScaleX(ECFieldElement scale)
+ {
+ if (this.IsInfinity)
+ return this;
+
+ switch (CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ ECFieldElement X2 = X.Multiply(scale);
+ ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2);
+
+ return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
+ }
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0];
+
+ // We scale the Z coordinate also, to avoid an inversion
+ ECFieldElement X2 = X.Multiply(scale.Square());
+ ECFieldElement L2 = L.Add(X).Add(X2);
+ ECFieldElement Z2 = Z.Multiply(scale);
+
+ return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed);
+ }
+ default:
+ {
+ return base.ScaleX(scale);
+ }
+ }
+ }
+
+ public override ECPoint ScaleY(ECFieldElement scale)
+ {
+ if (this.IsInfinity)
+ return this;
+
+ switch (CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X);
+
+ return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
+ }
+ default:
+ {
+ return base.ScaleY(scale);
+ }
+ }
+ }
+
+ public override ECPoint Subtract(ECPoint b)
+ {
+ if (b.IsInfinity)
+ return this;
+
+ // Add -b
+ return Add(b.Negate());
+ }
+
+ public virtual AbstractF2mPoint Tau()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.RawXCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ ECFieldElement Y1 = this.RawYCoord;
+ return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(), IsCompressed);
+ }
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(),
+ new ECFieldElement[] { Z1.Square() }, IsCompressed);
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+
+ public virtual AbstractF2mPoint TauPow(int pow)
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.RawXCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ ECFieldElement Y1 = this.RawYCoord;
+ return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow), IsCompressed);
+ }
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow),
+ new ECFieldElement[] { Z1.SquarePow(pow) }, IsCompressed);
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+ }
+
/**
* Elliptic curve points over F2m
*/
public class F2mPoint
- : ECPointBase
+ : AbstractF2mPoint
{
/**
* @param curve base curve
@@ -1323,66 +1624,6 @@ namespace Org.BouncyCastle.Math.EC
}
}
- public override ECPoint ScaleX(ECFieldElement scale)
- {
- if (this.IsInfinity)
- return this;
-
- switch (CurveCoordinateSystem)
- {
- case ECCurve.COORD_LAMBDA_AFFINE:
- {
- // Y is actually Lambda (X + Y/X) here
- ECFieldElement X = RawXCoord, L = RawYCoord;
-
- ECFieldElement X2 = X.Multiply(scale);
- ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2);
-
- return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
- }
- case ECCurve.COORD_LAMBDA_PROJECTIVE:
- {
- // Y is actually Lambda (X + Y/X) here
- ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0];
-
- // We scale the Z coordinate also, to avoid an inversion
- ECFieldElement X2 = X.Multiply(scale.Square());
- ECFieldElement L2 = L.Add(X).Add(X2);
- ECFieldElement Z2 = Z.Multiply(scale);
-
- return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed);
- }
- default:
- {
- return base.ScaleX(scale);
- }
- }
- }
-
- public override ECPoint ScaleY(ECFieldElement scale)
- {
- if (this.IsInfinity)
- return this;
-
- switch (CurveCoordinateSystem)
- {
- case ECCurve.COORD_LAMBDA_AFFINE:
- case ECCurve.COORD_LAMBDA_PROJECTIVE:
- {
- ECFieldElement X = RawXCoord, L = RawYCoord;
-
- // Y is actually Lambda (X + Y/X) here
- ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X);
-
- return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
- }
- default:
- {
- return base.ScaleY(scale);
- }
- }
- }
-
protected internal override bool CompressionYTilde
{
get
@@ -1411,44 +1652,8 @@ namespace Org.BouncyCastle.Math.EC
}
}
- /**
- * Check, if two <code>ECPoint</code>s can be added or subtracted.
- * @param a The first <code>ECPoint</code> to check.
- * @param b The second <code>ECPoint</code> to check.
- * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
- * cannot be added.
- */
- private static void CheckPoints(
- ECPoint a,
- ECPoint b)
- {
- // Check, if points are on the same curve
- if (!a.Curve.Equals(b.Curve))
- throw new ArgumentException("Only points on the same curve can be added or subtracted");
-
-// F2mFieldElement.CheckFieldElements(a.x, b.x);
- }
-
- /* (non-Javadoc)
- * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
- */
public override ECPoint Add(ECPoint b)
{
- CheckPoints(this, b);
- return AddSimple((F2mPoint) b);
- }
-
- /**
- * Adds another <code>ECPoints.F2m</code> to <code>this</code> without
- * checking if both points are on the same curve. Used by multiplication
- * algorithms, because there all points are a multiple of the same point
- * and hence the checks can be omitted.
- * @param b The other <code>ECPoints.F2m</code> to add to
- * <code>this</code>.
- * @return <code>this + b</code>
- */
- internal F2mPoint AddSimple(F2mPoint b)
- {
if (this.IsInfinity)
return b;
if (b.IsInfinity)
@@ -1472,10 +1677,10 @@ namespace Org.BouncyCastle.Math.EC
{
if (dy.IsZero)
{
- return (F2mPoint)Twice();
+ return Twice();
}
- return (F2mPoint)curve.Infinity;
+ return curve.Infinity;
}
ECFieldElement L = dy.Divide(dx);
@@ -1513,10 +1718,10 @@ namespace Org.BouncyCastle.Math.EC
{
if (U.IsZero)
{
- return (F2mPoint)Twice();
+ return Twice();
}
- return (F2mPoint)curve.Infinity;
+ return curve.Infinity;
}
ECFieldElement VSq = V.Square();
@@ -1537,9 +1742,9 @@ namespace Org.BouncyCastle.Math.EC
if (X1.IsZero)
{
if (X2.IsZero)
- return (F2mPoint)curve.Infinity;
+ return curve.Infinity;
- return b.AddSimple(this);
+ return b.Add(this);
}
ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
@@ -1568,10 +1773,10 @@ namespace Org.BouncyCastle.Math.EC
{
if (A.IsZero)
{
- return (F2mPoint)Twice();
+ return Twice();
}
- return (F2mPoint)curve.Infinity;
+ return curve.Infinity;
}
ECFieldElement X3, L3, Z3;
@@ -1633,68 +1838,6 @@ namespace Org.BouncyCastle.Math.EC
}
/* (non-Javadoc)
- * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
- */
- public override ECPoint Subtract(
- ECPoint b)
- {
- CheckPoints(this, b);
- return SubtractSimple((F2mPoint) b);
- }
-
- /**
- * Subtracts another <code>ECPoints.F2m</code> from <code>this</code>
- * without checking if both points are on the same curve. Used by
- * multiplication algorithms, because there all points are a multiple
- * of the same point and hence the checks can be omitted.
- * @param b The other <code>ECPoints.F2m</code> to subtract from
- * <code>this</code>.
- * @return <code>this - b</code>
- */
- internal F2mPoint SubtractSimple(
- F2mPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- // Add -b
- return AddSimple((F2mPoint) b.Negate());
- }
-
- public virtual F2mPoint Tau()
- {
- if (this.IsInfinity)
- {
- return this;
- }
-
- ECCurve curve = this.Curve;
- int coord = curve.CoordinateSystem;
-
- ECFieldElement X1 = this.RawXCoord;
-
- switch (coord)
- {
- case ECCurve.COORD_AFFINE:
- case ECCurve.COORD_LAMBDA_AFFINE:
- {
- ECFieldElement Y1 = this.RawYCoord;
- return new F2mPoint(curve, X1.Square(), Y1.Square(), IsCompressed);
- }
- case ECCurve.COORD_HOMOGENEOUS:
- case ECCurve.COORD_LAMBDA_PROJECTIVE:
- {
- ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
- return new F2mPoint(curve, X1.Square(), Y1.Square(), new ECFieldElement[] { Z1.Square() }, IsCompressed);
- }
- default:
- {
- throw new InvalidOperationException("unsupported coordinate system");
- }
- }
- }
-
- /* (non-Javadoc)
* @see Org.BouncyCastle.Math.EC.ECPoint#twice()
*/
public override ECPoint Twice()
diff --git a/crypto/src/math/ec/LongArray.cs b/crypto/src/math/ec/LongArray.cs
index c4e3dacbc..84462e0ea 100644
--- a/crypto/src/math/ec/LongArray.cs
+++ b/crypto/src/math/ec/LongArray.cs
@@ -13,7 +13,7 @@ namespace Org.BouncyCastle.Math.EC
* This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
* In a binary field, this operation is the same as squaring an 8 bit number.
*/
- private static readonly int[] INTERLEAVE2_TABLE = new int[]
+ private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
{
0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
diff --git a/crypto/src/math/ec/abc/Tnaf.cs b/crypto/src/math/ec/abc/Tnaf.cs
index 9f16886f5..b6e792aa4 100644
--- a/crypto/src/math/ec/abc/Tnaf.cs
+++ b/crypto/src/math/ec/abc/Tnaf.cs
@@ -384,11 +384,11 @@ namespace Org.BouncyCastle.Math.EC.Abc
/**
* Applies the operation <code>τ()</code> to an
- * <code>F2mPoint</code>.
- * @param p The F2mPoint to which <code>τ()</code> is applied.
+ * <code>AbstractF2mPoint</code>.
+ * @param p The AbstractF2mPoint to which <code>τ()</code> is applied.
* @return <code>τ(p)</code>
*/
- public static F2mPoint Tau(F2mPoint p)
+ public static AbstractF2mPoint Tau(AbstractF2mPoint p)
{
return p.Tau();
}
@@ -403,7 +403,7 @@ namespace Org.BouncyCastle.Math.EC.Abc
* @throws ArgumentException if the given ECCurve is not a Koblitz
* curve.
*/
- public static sbyte GetMu(F2mCurve curve)
+ public static sbyte GetMu(AbstractF2mCurve curve)
{
BigInteger a = curve.A.ToBigInteger();
@@ -423,6 +423,16 @@ namespace Org.BouncyCastle.Math.EC.Abc
return mu;
}
+ public static sbyte GetMu(ECFieldElement curveA)
+ {
+ return (sbyte)(curveA.IsZero ? -1 : 1);
+ }
+
+ public static sbyte GetMu(int curveA)
+ {
+ return (sbyte)(curveA == 0 ? -1 : 1);
+ }
+
/**
* Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
* <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
@@ -526,53 +536,60 @@ namespace Org.BouncyCastle.Math.EC.Abc
* @throws ArgumentException if <code>curve</code> is not a
* Koblitz curve (Anomalous Binary Curve, ABC).
*/
- public static BigInteger[] GetSi(F2mCurve curve)
+ public static BigInteger[] GetSi(AbstractF2mCurve curve)
{
if (!curve.IsKoblitz)
throw new ArgumentException("si is defined for Koblitz curves only");
- int m = curve.M;
+ int m = curve.FieldSize;
int a = curve.A.ToBigInteger().IntValue;
- sbyte mu = curve.GetMu();
- int h = curve.Cofactor.IntValue;
+ sbyte mu = GetMu(a);
+ int shifts = GetShiftsForCofactor(curve.Cofactor);
int index = m + 3 - a;
BigInteger[] ui = GetLucas(mu, index, false);
- BigInteger dividend0;
- BigInteger dividend1;
if (mu == 1)
{
- dividend0 = BigInteger.One.Subtract(ui[1]);
- dividend1 = BigInteger.One.Subtract(ui[0]);
- }
- else if (mu == -1)
- {
- dividend0 = BigInteger.One.Add(ui[1]);
- dividend1 = BigInteger.One.Add(ui[0]);
- }
- else
- {
- throw new ArgumentException("mu must be 1 or -1");
+ ui[0] = ui[0].Negate();
+ ui[1] = ui[1].Negate();
}
- BigInteger[] si = new BigInteger[2];
+ BigInteger dividend0 = BigInteger.One.Add(ui[1]).ShiftRight(shifts);
+ BigInteger dividend1 = BigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate();
- if (h == 2)
- {
- si[0] = dividend0.ShiftRight(1);
- si[1] = dividend1.ShiftRight(1).Negate();
- }
- else if (h == 4)
+ return new BigInteger[] { dividend0, dividend1 };
+ }
+
+ public static BigInteger[] GetSi(int fieldSize, int curveA, BigInteger cofactor)
+ {
+ sbyte mu = GetMu(curveA);
+ int shifts = GetShiftsForCofactor(cofactor);
+ int index = fieldSize + 3 - curveA;
+ BigInteger[] ui = GetLucas(mu, index, false);
+ if (mu == 1)
{
- si[0] = dividend0.ShiftRight(2);
- si[1] = dividend1.ShiftRight(2).Negate();
+ ui[0] = ui[0].Negate();
+ ui[1] = ui[1].Negate();
}
- else
+
+ BigInteger dividend0 = BigInteger.One.Add(ui[1]).ShiftRight(shifts);
+ BigInteger dividend1 = BigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate();
+
+ return new BigInteger[] { dividend0, dividend1 };
+ }
+
+ protected static int GetShiftsForCofactor(BigInteger h)
+ {
+ if (h != null && h.BitLength < 4)
{
- throw new ArgumentException("h (Cofactor) must be 2 or 4");
+ int hi = h.IntValue;
+ if (hi == 2)
+ return 1;
+ if (hi == 4)
+ return 2;
}
- return si;
+ throw new ArgumentException("h (Cofactor) must be 2 or 4");
}
/**
@@ -624,70 +641,77 @@ namespace Org.BouncyCastle.Math.EC.Abc
}
/**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
* by a <code>BigInteger</code> using the reduced <code>τ</code>-adic
* NAF (RTNAF) method.
- * @param p The F2mPoint to Multiply.
+ * @param p The AbstractF2mPoint to Multiply.
* @param k The <code>BigInteger</code> by which to Multiply <code>p</code>.
* @return <code>k * p</code>
*/
- public static F2mPoint MultiplyRTnaf(F2mPoint p, BigInteger k)
+ public static AbstractF2mPoint MultiplyRTnaf(AbstractF2mPoint p, BigInteger k)
{
- F2mCurve curve = (F2mCurve) p.Curve;
- int m = curve.M;
- sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
- sbyte mu = curve.GetMu();
+ AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+ int m = curve.FieldSize;
+ int a = curve.A.ToBigInteger().IntValue;
+ sbyte mu = GetMu(a);
BigInteger[] s = curve.GetSi();
- ZTauElement rho = PartModReduction(k, m, a, s, mu, (sbyte)10);
+ ZTauElement rho = PartModReduction(k, m, (sbyte)a, s, mu, (sbyte)10);
return MultiplyTnaf(p, rho);
}
/**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
* by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
* using the <code>τ</code>-adic NAF (TNAF) method.
- * @param p The F2mPoint to Multiply.
+ * @param p The AbstractF2mPoint to Multiply.
* @param lambda The element <code>λ</code> of
* <code><b>Z</b>[τ]</code>.
* @return <code>λ * p</code>
*/
- public static F2mPoint MultiplyTnaf(F2mPoint p, ZTauElement lambda)
+ public static AbstractF2mPoint MultiplyTnaf(AbstractF2mPoint p, ZTauElement lambda)
{
- F2mCurve curve = (F2mCurve)p.Curve;
- sbyte mu = curve.GetMu();
+ AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+ sbyte mu = GetMu(curve.A);
sbyte[] u = TauAdicNaf(mu, lambda);
- F2mPoint q = MultiplyFromTnaf(p, u);
+ AbstractF2mPoint q = MultiplyFromTnaf(p, u);
return q;
}
/**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
* by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
* using the <code>τ</code>-adic NAF (TNAF) method, given the TNAF
* of <code>λ</code>.
- * @param p The F2mPoint to Multiply.
+ * @param p The AbstractF2mPoint to Multiply.
* @param u The the TNAF of <code>λ</code>..
* @return <code>λ * p</code>
*/
- public static F2mPoint MultiplyFromTnaf(F2mPoint p, sbyte[] u)
+ public static AbstractF2mPoint MultiplyFromTnaf(AbstractF2mPoint p, sbyte[] u)
{
- F2mCurve curve = (F2mCurve)p.Curve;
- F2mPoint q = (F2mPoint) curve.Infinity;
+ ECCurve curve = p.Curve;
+ AbstractF2mPoint q = (AbstractF2mPoint)curve.Infinity;
+ AbstractF2mPoint pNeg = (AbstractF2mPoint)p.Negate();
+ int tauCount = 0;
for (int i = u.Length - 1; i >= 0; i--)
{
- q = Tau(q);
- if (u[i] == 1)
- {
- q = (F2mPoint)q.AddSimple(p);
- }
- else if (u[i] == -1)
+ ++tauCount;
+ sbyte ui = u[i];
+ if (ui != 0)
{
- q = (F2mPoint)q.SubtractSimple(p);
+ q = q.TauPow(tauCount);
+ tauCount = 0;
+
+ ECPoint x = ui > 0 ? p : pNeg;
+ q = (AbstractF2mPoint)q.Add(x);
}
}
+ if (tauCount > 0)
+ {
+ q = q.TauPow(tauCount);
+ }
return q;
}
@@ -800,28 +824,21 @@ namespace Org.BouncyCastle.Math.EC.Abc
* @param a The parameter <code>a</code> of the elliptic curve.
* @return The precomputation array for <code>p</code>.
*/
- public static F2mPoint[] GetPreComp(F2mPoint p, sbyte a)
+ public static AbstractF2mPoint[] GetPreComp(AbstractF2mPoint p, sbyte a)
{
- F2mPoint[] pu;
- pu = new F2mPoint[16];
- pu[1] = p;
- sbyte[][] alphaTnaf;
- if (a == 0)
- {
- alphaTnaf = Tnaf.Alpha0Tnaf;
- }
- else
- {
- // a == 1
- alphaTnaf = Tnaf.Alpha1Tnaf;
- }
+ sbyte[][] alphaTnaf = (a == 0) ? Tnaf.Alpha0Tnaf : Tnaf.Alpha1Tnaf;
+
+ AbstractF2mPoint[] pu = new AbstractF2mPoint[(uint)(alphaTnaf.Length + 1) >> 1];
+ pu[0] = p;
- int precompLen = alphaTnaf.Length;
- for (int i = 3; i < precompLen; i = i + 2)
+ uint precompLen = (uint)alphaTnaf.Length;
+ for (uint i = 3; i < precompLen; i += 2)
{
- pu[i] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
+ pu[i >> 1] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
}
-
+
+ p.Curve.NormalizeAll(pu);
+
return pu;
}
}
diff --git a/crypto/src/math/ec/custom/djb/Curve25519.cs b/crypto/src/math/ec/custom/djb/Curve25519.cs
index 3dbdac051..6ed7c0648 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519.cs
@@ -1,13 +1,12 @@
using System;
-using Org.BouncyCastle.Math.EC.Custom.Sec;
-using Org.BouncyCastle.Math.Field;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Djb
{
internal class Curve25519
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = Nat256.ToBigInteger(Curve25519Field.P);
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
protected readonly Curve25519Point m_infinity;
public Curve25519()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new Curve25519Point(this, null, null);
@@ -74,27 +73,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
{
return new Curve25519Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Add(A).Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new Curve25519Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/djb/Curve25519Field.cs b/crypto/src/math/ec/custom/djb/Curve25519Field.cs
index 809e51b80..837821e1a 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519Field.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519Field.cs
@@ -1,7 +1,7 @@
using System;
using System.Diagnostics;
-using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.Raw;
namespace Org.BouncyCastle.Math.EC.Custom.Djb
{
diff --git a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
index 8d5a80326..732e9e468 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
@@ -1,6 +1,6 @@
using System;
-using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Djb
diff --git a/crypto/src/math/ec/custom/djb/Curve25519Point.cs b/crypto/src/math/ec/custom/djb/Curve25519Point.cs
index f3da59d16..eb8fc12f2 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519Point.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519Point.cs
@@ -1,11 +1,11 @@
using System;
-using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.Raw;
namespace Org.BouncyCastle.Math.EC.Custom.Djb
{
internal class Curve25519Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -48,11 +48,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
return new Curve25519Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECFieldElement GetZCoord(int index)
{
if (index == 1)
@@ -224,14 +219,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
return TwiceJacobianModified(false).Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
new file mode 100644
index 000000000..9da27b470
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP128R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"));
+
+ private const int SecP128R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP128R1Point m_infinity;
+
+ public SecP128R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP128R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("E87579C11079F43DD824993C2CEE5ED3")));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFE0000000075A30D1B9038A115"));
+ this.m_cofactor = BigInteger.One;
+
+ this.m_coord = SecP128R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP128R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP128R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP128R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP128R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Field.cs b/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
new file mode 100644
index 000000000..ff6fb6b65
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
@@ -0,0 +1,218 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP128R1Field
+ {
+ // 2^128 - 2^97 - 1
+ internal static readonly uint[] P = new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD };
+ internal static readonly uint[] PExt = new uint[] { 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0xFFFFFFFE,
+ 0xFFFFFFFF, 0x00000003, 0xFFFFFFFC };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFB,
+ 0x00000001, 0x00000000, 0xFFFFFFFC, 0x00000003 };
+ private const uint P3 = 0xFFFFFFFD;
+ private const uint PExt7 = 0xFFFFFFFC;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat128.Add(x, y, z);
+ if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat256.Add(xx, yy, zz);
+ if (c != 0 || (zz[7] == PExt7 && Nat256.Gte(zz, PExt)))
+ {
+ Nat.AddTo(PExtInv.Length, PExtInv, zz);
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(4, x, z);
+ if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat128.FromBigInteger(x);
+ if (z[3] == P3 && Nat128.Gte(z, P))
+ {
+ Nat128.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(4, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat128.Add(x, P, z);
+ Nat.ShiftDownBit(4, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat128.CreateExt();
+ Nat128.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat128.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[7] == PExt7 && Nat256.Gte(zz, PExt)))
+ {
+ Nat.AddTo(PExtInv.Length, PExtInv, zz);
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat128.IsZero(x))
+ {
+ Nat128.Zero(z);
+ }
+ else
+ {
+ Nat128.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+ ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+ x3 += x7; x6 += (x7 << 1);
+ x2 += x6; x5 += (x6 << 1);
+ x1 += x5; x4 += (x5 << 1);
+ x0 += x4; x3 += (x4 << 1);
+
+ z[0] = (uint)x0; x1 += (x0 >> 32);
+ z[1] = (uint)x1; x2 += (x1 >> 32);
+ z[2] = (uint)x2; x3 += (x2 >> 32);
+ z[3] = (uint)x3;
+
+ Reduce32((uint)(x3 >> 32), z);
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ while (x != 0)
+ {
+ ulong c, x4 = x;
+
+ c = (ulong)z[0] + x4;
+ z[0] = (uint)c; c >>= 32;
+ if (c != 0)
+ {
+ c += (ulong)z[1];
+ z[1] = (uint)c; c >>= 32;
+ c += (ulong)z[2];
+ z[2] = (uint)c; c >>= 32;
+ }
+ c += (ulong)z[3] + (x4 << 1);
+ z[3] = (uint)c; c >>= 32;
+
+ Debug.Assert(c >= 0 && c <= 2);
+
+ x = (uint)c;
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat128.CreateExt();
+ Nat128.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat128.CreateExt();
+ Nat128.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat128.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat128.Sub(x, y, z);
+ if (c != 0)
+ {
+ SubPInvFrom(z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(10, xx, yy, zz);
+ if (c != 0)
+ {
+ Nat.SubFrom(PExtInv.Length, PExtInv, zz);
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(4, x, 0, z);
+ if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ private static void AddPInvTo(uint[] z)
+ {
+ long c = (long)z[0] + 1;
+ z[0] = (uint)c; c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c; c >>= 32;
+ c += (long)z[2];
+ z[2] = (uint)c; c >>= 32;
+ }
+ c += (long)z[3] + 2;
+ z[3] = (uint)c;
+ }
+
+ private static void SubPInvFrom(uint[] z)
+ {
+ long c = (long)z[0] - 1;
+ z[0] = (uint)c; c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c; c >>= 32;
+ c += (long)z[2];
+ z[2] = (uint)c; c >>= 32;
+ }
+ c += (long)z[3] - 2;
+ z[3] = (uint)c;
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
new file mode 100644
index 000000000..fa7951d5d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
@@ -0,0 +1,198 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP128R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP128R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP128R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP128R1FieldElement", "x");
+
+ this.x = SecP128R1Field.FromBigInteger(x);
+ }
+
+ public SecP128R1FieldElement()
+ {
+ this.x = Nat128.Create();
+ }
+
+ protected internal SecP128R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat128.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat128.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat128.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat128.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP128R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Add(x, ((SecP128R1FieldElement)b).x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.AddOne(x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Subtract(x, ((SecP128R1FieldElement)b).x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Multiply(x, ((SecP128R1FieldElement)b).x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ // return multiply(b.invert());
+ uint[] z = Nat128.Create();
+ Mod.Invert(SecP128R1Field.P, ((SecP128R1FieldElement)b).x, z);
+ SecP128R1Field.Multiply(z, x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Negate(x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Square(x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ // return new SecP128R1FieldElement(toBigInteger().modInverse(Q));
+ uint[] z = Nat128.Create();
+ Mod.Invert(SecP128R1Field.P, x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^126 - 2^95
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 31 1s } { 95 0s }
+ *
+ * Therefore we need an addition chain containing 31 (the length of the repunit) We use:
+ * 1, 2, 4, 8, 10, 20, 30, [31]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat128.IsZero(x1) || Nat128.IsOne(x1))
+ return this;
+
+ uint[] x2 = Nat128.Create();
+ SecP128R1Field.Square(x1, x2);
+ SecP128R1Field.Multiply(x2, x1, x2);
+ uint[] x4 = Nat128.Create();
+ SecP128R1Field.SquareN(x2, 2, x4);
+ SecP128R1Field.Multiply(x4, x2, x4);
+ uint[] x8 = Nat128.Create();
+ SecP128R1Field.SquareN(x4, 4, x8);
+ SecP128R1Field.Multiply(x8, x4, x8);
+ uint[] x10 = x4;
+ SecP128R1Field.SquareN(x8, 2, x10);
+ SecP128R1Field.Multiply(x10, x2, x10);
+ uint[] x20 = x2;
+ SecP128R1Field.SquareN(x10, 10, x20);
+ SecP128R1Field.Multiply(x20, x10, x20);
+ uint[] x30 = x8;
+ SecP128R1Field.SquareN(x20, 10, x30);
+ SecP128R1Field.Multiply(x30, x10, x30);
+ uint[] x31 = x10;
+ SecP128R1Field.Square(x30, x31);
+ SecP128R1Field.Multiply(x31, x1, x31);
+
+ uint[] t1 = x31;
+ SecP128R1Field.SquareN(t1, 95, t1);
+
+ uint[] t2 = x30;
+ SecP128R1Field.Square(t1, t2);
+
+ return Nat128.Eq(x1, t2) ? new SecP128R1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP128R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP128R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP128R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat128.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 4);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Point.cs b/crypto/src/math/ec/custom/sec/SecP128R1Point.cs
new file mode 100644
index 000000000..ae76d3cd1
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP128R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(boolean)}
+ */
+ public SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP128R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP128R1FieldElement X1 = (SecP128R1FieldElement)this.RawXCoord, Y1 = (SecP128R1FieldElement)this.RawYCoord;
+ SecP128R1FieldElement X2 = (SecP128R1FieldElement)b.RawXCoord, Y2 = (SecP128R1FieldElement)b.RawYCoord;
+
+ SecP128R1FieldElement Z1 = (SecP128R1FieldElement)this.RawZCoords[0];
+ SecP128R1FieldElement Z2 = (SecP128R1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat128.CreateExt();
+ uint[] t2 = Nat128.Create();
+ uint[] t3 = Nat128.Create();
+ uint[] t4 = Nat128.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP128R1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP128R1Field.Multiply(S2, X2.x, U2);
+
+ SecP128R1Field.Multiply(S2, Z1.x, S2);
+ SecP128R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP128R1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP128R1Field.Multiply(S1, X1.x, U1);
+
+ SecP128R1Field.Multiply(S1, Z2.x, S1);
+ SecP128R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat128.Create();
+ SecP128R1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP128R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat128.IsZero(H))
+ {
+ if (Nat128.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP128R1Field.Square(H, HSquared);
+
+ uint[] G = Nat128.Create();
+ SecP128R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP128R1Field.Multiply(HSquared, U1, V);
+
+ SecP128R1Field.Negate(G, G);
+ Nat128.Mul(S1, G, tt1);
+
+ c = Nat128.AddBothTo(V, V, G);
+ SecP128R1Field.Reduce32(c, G);
+
+ SecP128R1FieldElement X3 = new SecP128R1FieldElement(t4);
+ SecP128R1Field.Square(R, X3.x);
+ SecP128R1Field.Subtract(X3.x, G, X3.x);
+
+ SecP128R1FieldElement Y3 = new SecP128R1FieldElement(G);
+ SecP128R1Field.Subtract(V, X3.x, Y3.x);
+ SecP128R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP128R1Field.Reduce(tt1, Y3.x);
+
+ SecP128R1FieldElement Z3 = new SecP128R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP128R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP128R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP128R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP128R1FieldElement Y1 = (SecP128R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP128R1FieldElement X1 = (SecP128R1FieldElement)this.RawXCoord, Z1 = (SecP128R1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat128.Create();
+ uint[] t2 = Nat128.Create();
+
+ uint[] Y1Squared = Nat128.Create();
+ SecP128R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat128.Create();
+ SecP128R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP128R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP128R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP128R1Field.Add(X1.x, Z1Squared, M);
+ SecP128R1Field.Multiply(M, t1, M);
+ c = Nat128.AddBothTo(M, M, M);
+ SecP128R1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP128R1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(4, S, 2, 0);
+ SecP128R1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(4, T, 3, 0, t1);
+ SecP128R1Field.Reduce32(c, t1);
+
+ SecP128R1FieldElement X3 = new SecP128R1FieldElement(T);
+ SecP128R1Field.Square(M, X3.x);
+ SecP128R1Field.Subtract(X3.x, S, X3.x);
+ SecP128R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP128R1FieldElement Y3 = new SecP128R1FieldElement(S);
+ SecP128R1Field.Subtract(S, X3.x, Y3.x);
+ SecP128R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP128R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP128R1FieldElement Z3 = new SecP128R1FieldElement(M);
+ SecP128R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP128R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP128R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between twicePlus and threeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP128R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
new file mode 100644
index 000000000..7d45c6227
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160K1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = SecP160R2Curve.q;
+
+ private const int SECP160K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP160K1Point m_infinity;
+
+ public SecP160K1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP160K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.ValueOf(7));
+ this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000001B8FA16DFAB9ACA16B6B3"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SECP160K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP160K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP160R2FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP160K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP160K1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160K1Point.cs b/crypto/src/math/ec/custom/sec/SecP160K1Point.cs
new file mode 100644
index 000000000..1bcbadb33
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160K1Point.cs
@@ -0,0 +1,269 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160K1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.CreatePoint to construct points
+ */
+ public SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+ bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP160K1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ // B.3 pg 62
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Y1 = (SecP160R2FieldElement)this.RawYCoord;
+ SecP160R2FieldElement X2 = (SecP160R2FieldElement)b.RawXCoord, Y2 = (SecP160R2FieldElement)b.RawYCoord;
+
+ SecP160R2FieldElement Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+ SecP160R2FieldElement Z2 = (SecP160R2FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat160.CreateExt();
+ uint[] t2 = Nat160.Create();
+ uint[] t3 = Nat160.Create();
+ uint[] t4 = Nat160.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP160R2Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP160R2Field.Multiply(S2, X2.x, U2);
+
+ SecP160R2Field.Multiply(S2, Z1.x, S2);
+ SecP160R2Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP160R2Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP160R2Field.Multiply(S1, X1.x, U1);
+
+ SecP160R2Field.Multiply(S1, Z2.x, S1);
+ SecP160R2Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat160.Create();
+ SecP160R2Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP160R2Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat160.IsZero(H))
+ {
+ if (Nat160.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP160R2Field.Square(H, HSquared);
+
+ uint[] G = Nat160.Create();
+ SecP160R2Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP160R2Field.Multiply(HSquared, U1, V);
+
+ SecP160R2Field.Negate(G, G);
+ Nat160.Mul(S1, G, tt1);
+
+ c = Nat160.AddBothTo(V, V, G);
+ SecP160R2Field.Reduce32(c, G);
+
+ SecP160R2FieldElement X3 = new SecP160R2FieldElement(t4);
+ SecP160R2Field.Square(R, X3.x);
+ SecP160R2Field.Subtract(X3.x, G, X3.x);
+
+ SecP160R2FieldElement Y3 = new SecP160R2FieldElement(G);
+ SecP160R2Field.Subtract(V, X3.x, Y3.x);
+ SecP160R2Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP160R2Field.Reduce(tt1, Y3.x);
+
+ SecP160R2FieldElement Z3 = new SecP160R2FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP160K1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ // B.3 pg 62
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP160R2FieldElement Y1 = (SecP160R2FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+
+ uint c;
+
+ uint[] Y1Squared = Nat160.Create();
+ SecP160R2Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat160.Create();
+ SecP160R2Field.Square(Y1Squared, T);
+
+ uint[] M = Nat160.Create();
+ SecP160R2Field.Square(X1.x, M);
+ c = Nat160.AddBothTo(M, M, M);
+ SecP160R2Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP160R2Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(5, S, 2, 0);
+ SecP160R2Field.Reduce32(c, S);
+
+ uint[] t1 = Nat160.Create();
+ c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+ SecP160R2Field.Reduce32(c, t1);
+
+ SecP160R2FieldElement X3 = new SecP160R2FieldElement(T);
+ SecP160R2Field.Square(M, X3.x);
+ SecP160R2Field.Subtract(X3.x, S, X3.x);
+ SecP160R2Field.Subtract(X3.x, S, X3.x);
+
+ SecP160R2FieldElement Y3 = new SecP160R2FieldElement(S);
+ SecP160R2Field.Subtract(S, X3.x, Y3.x);
+ SecP160R2Field.Multiply(Y3.x, M, Y3.x);
+ SecP160R2Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP160R2FieldElement Z3 = new SecP160R2FieldElement(M);
+ SecP160R2Field.Twice(Y1.x, Z3.x);
+ if (!Z1.IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP160K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and threeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP160K1Point(Curve, this.RawXCoord, this.RawYCoord.Negate(), this.RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
new file mode 100644
index 000000000..87389af36
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF"));
+
+ private const int SecP160R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP160R1Point m_infinity;
+
+ public SecP160R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP160R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45")));
+ this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000001F4C8F927AED3CA752257"));
+ this.m_cofactor = BigInteger.One;
+
+ this.m_coord = SecP160R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP160R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP160R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP160R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP160R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Field.cs b/crypto/src/math/ec/custom/sec/SecP160R1Field.cs
new file mode 100644
index 000000000..6a5a2ef64
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R1Field.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R1Field
+ {
+ // 2^160 - 2^31 - 1
+ internal static readonly uint[] P = new uint[] { 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
+ internal static readonly uint[] PExt = new uint[] { 0x00000001, 0x40000001, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xBFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x00000001, 0x00000001 };
+ private const uint P4 = 0xFFFFFFFF;
+ private const uint PExt9 = 0xFFFFFFFF;
+ private const uint PInv = 0x80000001;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat160.Add(x, y, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.AddWordTo(5, PInv, z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(10, xx, yy, zz);
+ if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(5, x, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.AddWordTo(5, PInv, z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat160.FromBigInteger(x);
+ if (z[4] == P4 && Nat160.Gte(z, P))
+ {
+ Nat160.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(5, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat160.Add(x, P, z);
+ Nat.ShiftDownBit(5, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat160.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat160.IsZero(x))
+ {
+ Nat160.Zero(z);
+ }
+ else
+ {
+ Nat160.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong x5 = xx[5], x6 = xx[6], x7 = xx[7], x8 = xx[8], x9 = xx[9];
+
+ ulong c = 0;
+ c += (ulong)xx[0] + x5 + (x5 << 31);
+ z[0] = (uint)c; c >>= 32;
+ c += (ulong)xx[1] + x6 + (x6 << 31);
+ z[1] = (uint)c; c >>= 32;
+ c += (ulong)xx[2] + x7 + (x7 << 31);
+ z[2] = (uint)c; c >>= 32;
+ c += (ulong)xx[3] + x8 + (x8 << 31);
+ z[3] = (uint)c; c >>= 32;
+ c += (ulong)xx[4] + x9 + (x9 << 31);
+ z[4] = (uint)c; c >>= 32;
+
+ Debug.Assert(c >> 32 == 0);
+
+ Reduce32((uint)c, z);
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ if ((x != 0 && Nat160.MulWordsAdd(PInv, x, z, 0) != 0)
+ || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.AddWordTo(5, PInv, z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat160.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat160.Sub(x, y, z);
+ if (c != 0)
+ {
+ Nat.SubWordFrom(5, PInv, z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(10, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(5, x, 0, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.AddWordTo(5, PInv, z);
+ }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
new file mode 100644
index 000000000..d1fc75644
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
@@ -0,0 +1,203 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP160R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP160R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP160R1FieldElement", "x");
+
+ this.x = SecP160R1Field.FromBigInteger(x);
+ }
+
+ public SecP160R1FieldElement()
+ {
+ this.x = Nat160.Create();
+ }
+
+ protected internal SecP160R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat160.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat160.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat160.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat160.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP160R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Add(x, ((SecP160R1FieldElement)b).x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.AddOne(x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Subtract(x, ((SecP160R1FieldElement)b).x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Multiply(x, ((SecP160R1FieldElement)b).x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ // return multiply(b.invert());
+ uint[] z = Nat160.Create();
+ Mod.Invert(SecP160R1Field.P, ((SecP160R1FieldElement)b).x, z);
+ SecP160R1Field.Multiply(z, x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Negate(x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Square(x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ // return new SecP160R1FieldElement(ToBigInteger().modInverse(Q));
+ uint[] z = Nat160.Create();
+ Mod.Invert(SecP160R1Field.P, x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^158 - 2^29
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 129 1s } { 29 0s }
+ *
+ * Therefore we need an addition chain containing 129 (the length of the repunit) We use:
+ * 1, 2, 4, 8, 16, 32, 64, 128, [129]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat160.IsZero(x1) || Nat160.IsOne(x1))
+ {
+ return this;
+ }
+
+ uint[] x2 = Nat160.Create();
+ SecP160R1Field.Square(x1, x2);
+ SecP160R1Field.Multiply(x2, x1, x2);
+ uint[] x4 = Nat160.Create();
+ SecP160R1Field.SquareN(x2, 2, x4);
+ SecP160R1Field.Multiply(x4, x2, x4);
+ uint[] x8 = x2;
+ SecP160R1Field.SquareN(x4, 4, x8);
+ SecP160R1Field.Multiply(x8, x4, x8);
+ uint[] x16 = x4;
+ SecP160R1Field.SquareN(x8, 8, x16);
+ SecP160R1Field.Multiply(x16, x8, x16);
+ uint[] x32 = x8;
+ SecP160R1Field.SquareN(x16, 16, x32);
+ SecP160R1Field.Multiply(x32, x16, x32);
+ uint[] x64 = x16;
+ SecP160R1Field.SquareN(x32, 32, x64);
+ SecP160R1Field.Multiply(x64, x32, x64);
+ uint[] x128 = x32;
+ SecP160R1Field.SquareN(x64, 64, x128);
+ SecP160R1Field.Multiply(x128, x64, x128);
+ uint[] x129 = x64;
+ SecP160R1Field.Square(x128, x129);
+ SecP160R1Field.Multiply(x129, x1, x129);
+
+ uint[] t1 = x129;
+ SecP160R1Field.SquareN(t1, 29, t1);
+
+ uint[] t2 = x128;
+ SecP160R1Field.Square(t1, t2);
+
+ return Nat160.Eq(x1, t2) ? new SecP160R1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP160R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP160R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP160R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat160.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 5);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Point.cs b/crypto/src/math/ec/custom/sec/SecP160R1Point.cs
new file mode 100644
index 000000000..f9f065de6
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.CreatePoint to construct points
+ */
+ public SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP160R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP160R1FieldElement X1 = (SecP160R1FieldElement)this.RawXCoord, Y1 = (SecP160R1FieldElement)this.RawYCoord;
+ SecP160R1FieldElement X2 = (SecP160R1FieldElement)b.RawXCoord, Y2 = (SecP160R1FieldElement)b.RawYCoord;
+
+ SecP160R1FieldElement Z1 = (SecP160R1FieldElement)this.RawZCoords[0];
+ SecP160R1FieldElement Z2 = (SecP160R1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat160.CreateExt();
+ uint[] t2 = Nat160.Create();
+ uint[] t3 = Nat160.Create();
+ uint[] t4 = Nat160.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP160R1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP160R1Field.Multiply(S2, X2.x, U2);
+
+ SecP160R1Field.Multiply(S2, Z1.x, S2);
+ SecP160R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP160R1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP160R1Field.Multiply(S1, X1.x, U1);
+
+ SecP160R1Field.Multiply(S1, Z2.x, S1);
+ SecP160R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat160.Create();
+ SecP160R1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP160R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat160.IsZero(H))
+ {
+ if (Nat160.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP160R1Field.Square(H, HSquared);
+
+ uint[] G = Nat160.Create();
+ SecP160R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP160R1Field.Multiply(HSquared, U1, V);
+
+ SecP160R1Field.Negate(G, G);
+ Nat160.Mul(S1, G, tt1);
+
+ c = Nat160.AddBothTo(V, V, G);
+ SecP160R1Field.Reduce32(c, G);
+
+ SecP160R1FieldElement X3 = new SecP160R1FieldElement(t4);
+ SecP160R1Field.Square(R, X3.x);
+ SecP160R1Field.Subtract(X3.x, G, X3.x);
+
+ SecP160R1FieldElement Y3 = new SecP160R1FieldElement(G);
+ SecP160R1Field.Subtract(V, X3.x, Y3.x);
+ SecP160R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP160R1Field.Reduce(tt1, Y3.x);
+
+ SecP160R1FieldElement Z3 = new SecP160R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP160R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP160R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP160R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP160R1FieldElement Y1 = (SecP160R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP160R1FieldElement X1 = (SecP160R1FieldElement)this.RawXCoord, Z1 = (SecP160R1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat160.Create();
+ uint[] t2 = Nat160.Create();
+
+ uint[] Y1Squared = Nat160.Create();
+ SecP160R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat160.Create();
+ SecP160R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP160R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP160R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP160R1Field.Add(X1.x, Z1Squared, M);
+ SecP160R1Field.Multiply(M, t1, M);
+ c = Nat160.AddBothTo(M, M, M);
+ SecP160R1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP160R1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(5, S, 2, 0);
+ SecP160R1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+ SecP160R1Field.Reduce32(c, t1);
+
+ SecP160R1FieldElement X3 = new SecP160R1FieldElement(T);
+ SecP160R1Field.Square(M, X3.x);
+ SecP160R1Field.Subtract(X3.x, S, X3.x);
+ SecP160R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP160R1FieldElement Y3 = new SecP160R1FieldElement(S);
+ SecP160R1Field.Subtract(S, X3.x, Y3.x);
+ SecP160R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP160R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP160R1FieldElement Z3 = new SecP160R1FieldElement(M);
+ SecP160R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP160R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP160R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP160R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
new file mode 100644
index 000000000..100561453
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R2Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"));
+
+ private const int SecP160R2_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP160R2Point m_infinity;
+
+ public SecP160R2Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP160R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("B4E134D3FB59EB8BAB57274904664D5AF50388BA")));
+ this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000000351EE786A818F3A1A16B"));
+ this.m_cofactor = BigInteger.One;
+
+ this.m_coord = SecP160R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP160R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP160R2FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP160R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP160R2Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Field.cs b/crypto/src/math/ec/custom/sec/SecP160R2Field.cs
new file mode 100644
index 000000000..1bef32eea
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R2Field.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R2Field
+ {
+ // 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFAC73, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x1B44BBA9, 0x0000A71A, 0x00000001, 0x00000000, 0x00000000,
+ 0xFFFF58E6, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xE4BB4457, 0xFFFF58E5, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x0000A719, 0x00000002 };
+ private const uint P4 = 0xFFFFFFFF;
+ private const uint PExt9 = 0xFFFFFFFF;
+ private const uint PInv33 = 0x538D;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat160.Add(x, y, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(10, xx, yy, zz);
+ if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(5, x, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat160.FromBigInteger(x);
+ if (z[4] == P4 && Nat160.Gte(z, P))
+ {
+ Nat160.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(5, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat160.Add(x, P, z);
+ Nat.ShiftDownBit(5, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat160.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat160.IsZero(x))
+ {
+ Nat160.Zero(z);
+ }
+ else
+ {
+ Nat160.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong cc = Nat160.Mul33Add(PInv33, xx, 5, xx, 0, z, 0);
+ uint c = Nat160.Mul33DWordAdd(PInv33, cc, z, 0);
+
+ Debug.Assert(c == 0 || c == 1);
+
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ if ((x != 0 && Nat160.Mul33WordAdd(PInv33, x, z, 0) != 0)
+ || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat160.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat160.Sub(x, y, z);
+ if (c != 0)
+ {
+ Nat.Sub33From(5, PInv33, z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(10, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(5, x, 0, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
new file mode 100644
index 000000000..bdb5245b2
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
@@ -0,0 +1,218 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R2FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP160R2Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP160R2FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP160R2FieldElement", "x");
+
+ this.x = SecP160R2Field.FromBigInteger(x);
+ }
+
+ public SecP160R2FieldElement()
+ {
+ this.x = Nat160.Create();
+ }
+
+ protected internal SecP160R2FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat160.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat160.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat160.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat160.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP160R2Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Add(x, ((SecP160R2FieldElement)b).x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.AddOne(x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Subtract(x, ((SecP160R2FieldElement)b).x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Multiply(x, ((SecP160R2FieldElement)b).x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ // return Multiply(b.invert());
+ uint[] z = Nat160.Create();
+ Mod.Invert(SecP160R2Field.P, ((SecP160R2FieldElement)b).x, z);
+ SecP160R2Field.Multiply(z, x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Negate(x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Square(x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ // return new SecP160R2FieldElement(ToBigInteger().modInverse(Q));
+ uint[] z = Nat160.Create();
+ Mod.Invert(SecP160R2Field.P, x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^158 - 2^30 - 2^12 - 2^10 - 2^7 - 2^6 - 2^5 - 2^1 - 2^0
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get: { 127 1s } { 1
+ * 0s } { 17 1s } { 1 0s } { 1 1s } { 1 0s } { 2 1s } { 3 0s } { 3 1s } { 1 0s } { 1 1s }
+ *
+ * Therefore we need an Addition chain containing 1, 2, 3, 17, 127 (the lengths of the repunits)
+ * We use: [1], [2], [3], 4, 7, 14, [17], 31, 62, 124, [127]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat160.IsZero(x1) || Nat160.IsOne(x1))
+ {
+ return this;
+ }
+
+ uint[] x2 = Nat160.Create();
+ SecP160R2Field.Square(x1, x2);
+ SecP160R2Field.Multiply(x2, x1, x2);
+ uint[] x3 = Nat160.Create();
+ SecP160R2Field.Square(x2, x3);
+ SecP160R2Field.Multiply(x3, x1, x3);
+ uint[] x4 = Nat160.Create();
+ SecP160R2Field.Square(x3, x4);
+ SecP160R2Field.Multiply(x4, x1, x4);
+ uint[] x7 = Nat160.Create();
+ SecP160R2Field.SquareN(x4, 3, x7);
+ SecP160R2Field.Multiply(x7, x3, x7);
+ uint[] x14 = x4;
+ SecP160R2Field.SquareN(x7, 7, x14);
+ SecP160R2Field.Multiply(x14, x7, x14);
+ uint[] x17 = x7;
+ SecP160R2Field.SquareN(x14, 3, x17);
+ SecP160R2Field.Multiply(x17, x3, x17);
+ uint[] x31 = Nat160.Create();
+ SecP160R2Field.SquareN(x17, 14, x31);
+ SecP160R2Field.Multiply(x31, x14, x31);
+ uint[] x62 = x14;
+ SecP160R2Field.SquareN(x31, 31, x62);
+ SecP160R2Field.Multiply(x62, x31, x62);
+ uint[] x124 = x31;
+ SecP160R2Field.SquareN(x62, 62, x124);
+ SecP160R2Field.Multiply(x124, x62, x124);
+ uint[] x127 = x62;
+ SecP160R2Field.SquareN(x124, 3, x127);
+ SecP160R2Field.Multiply(x127, x3, x127);
+
+ uint[] t1 = x127;
+ SecP160R2Field.SquareN(t1, 18, t1);
+ SecP160R2Field.Multiply(t1, x17, t1);
+ SecP160R2Field.SquareN(t1, 2, t1);
+ SecP160R2Field.Multiply(t1, x1, t1);
+ SecP160R2Field.SquareN(t1, 3, t1);
+ SecP160R2Field.Multiply(t1, x2, t1);
+ SecP160R2Field.SquareN(t1, 6, t1);
+ SecP160R2Field.Multiply(t1, x3, t1);
+ SecP160R2Field.SquareN(t1, 2, t1);
+ SecP160R2Field.Multiply(t1, x1, t1);
+
+ uint[] t2 = x2;
+ SecP160R2Field.Square(t1, t2);
+
+ return Nat160.Eq(x1, t2) ? new SecP160R2FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP160R2FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP160R2FieldElement);
+ }
+
+ public virtual bool Equals(SecP160R2FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat160.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 5);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Point.cs b/crypto/src/math/ec/custom/sec/SecP160R2Point.cs
new file mode 100644
index 000000000..343cf8c16
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R2Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R2Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.CreatePoint to construct points
+ */
+ public SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP160R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Y1 = (SecP160R2FieldElement)this.RawYCoord;
+ SecP160R2FieldElement X2 = (SecP160R2FieldElement)b.RawXCoord, Y2 = (SecP160R2FieldElement)b.RawYCoord;
+
+ SecP160R2FieldElement Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+ SecP160R2FieldElement Z2 = (SecP160R2FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat160.CreateExt();
+ uint[] t2 = Nat160.Create();
+ uint[] t3 = Nat160.Create();
+ uint[] t4 = Nat160.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP160R2Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP160R2Field.Multiply(S2, X2.x, U2);
+
+ SecP160R2Field.Multiply(S2, Z1.x, S2);
+ SecP160R2Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP160R2Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP160R2Field.Multiply(S1, X1.x, U1);
+
+ SecP160R2Field.Multiply(S1, Z2.x, S1);
+ SecP160R2Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat160.Create();
+ SecP160R2Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP160R2Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat160.IsZero(H))
+ {
+ if (Nat160.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP160R2Field.Square(H, HSquared);
+
+ uint[] G = Nat160.Create();
+ SecP160R2Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP160R2Field.Multiply(HSquared, U1, V);
+
+ SecP160R2Field.Negate(G, G);
+ Nat160.Mul(S1, G, tt1);
+
+ c = Nat160.AddBothTo(V, V, G);
+ SecP160R2Field.Reduce32(c, G);
+
+ SecP160R2FieldElement X3 = new SecP160R2FieldElement(t4);
+ SecP160R2Field.Square(R, X3.x);
+ SecP160R2Field.Subtract(X3.x, G, X3.x);
+
+ SecP160R2FieldElement Y3 = new SecP160R2FieldElement(G);
+ SecP160R2Field.Subtract(V, X3.x, Y3.x);
+ SecP160R2Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP160R2Field.Reduce(tt1, Y3.x);
+
+ SecP160R2FieldElement Z3 = new SecP160R2FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP160R2Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP160R2FieldElement Y1 = (SecP160R2FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat160.Create();
+ uint[] t2 = Nat160.Create();
+
+ uint[] Y1Squared = Nat160.Create();
+ SecP160R2Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat160.Create();
+ SecP160R2Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP160R2Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP160R2Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP160R2Field.Add(X1.x, Z1Squared, M);
+ SecP160R2Field.Multiply(M, t1, M);
+ c = Nat160.AddBothTo(M, M, M);
+ SecP160R2Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP160R2Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(5, S, 2, 0);
+ SecP160R2Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+ SecP160R2Field.Reduce32(c, t1);
+
+ SecP160R2FieldElement X3 = new SecP160R2FieldElement(T);
+ SecP160R2Field.Square(M, X3.x);
+ SecP160R2Field.Subtract(X3.x, S, X3.x);
+ SecP160R2Field.Subtract(X3.x, S, X3.x);
+
+ SecP160R2FieldElement Y3 = new SecP160R2FieldElement(S);
+ SecP160R2Field.Subtract(S, X3.x, Y3.x);
+ SecP160R2Field.Multiply(Y3.x, M, Y3.x);
+ SecP160R2Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP160R2FieldElement Z3 = new SecP160R2FieldElement(M);
+ SecP160R2Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP160R2Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP160R2Point(Curve, this.RawXCoord, this.RawYCoord.Negate(), this.RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
index 54b87588b..81f77197e 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
@@ -1,12 +1,11 @@
using System;
-using Org.BouncyCastle.Math.Field;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP192K1Curve
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = new BigInteger(1,
Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37"));
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
protected readonly SecP192K1Point m_infinity;
public SecP192K1Curve()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new SecP192K1Point(this, null, null);
@@ -72,27 +71,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
return new SecP192K1Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new SecP192K1Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Field.cs b/crypto/src/math/ec/custom/sec/SecP192K1Field.cs
index d5ca903d1..a00360360 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Field.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP192K1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
index 78886dd8c..dce377035 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Point.cs b/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
index 561324f8e..58eb09102 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
@@ -1,9 +1,11 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP192K1Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -55,11 +57,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new SecP192K1Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECPoint Add(ECPoint b)
{
if (this.IsInfinity)
@@ -259,14 +256,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return Twice().Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
index 57b20d31e..cb3a981c8 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
@@ -1,12 +1,11 @@
using System;
-using Org.BouncyCastle.Math.Field;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP192R1Curve
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = new BigInteger(1,
Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"));
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
protected readonly SecP192R1Point m_infinity;
public SecP192R1Curve()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new SecP192R1Point(this, null, null);
@@ -75,27 +74,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
return new SecP192R1Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Add(A).Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new SecP192R1Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Field.cs b/crypto/src/math/ec/custom/sec/SecP192R1Field.cs
index 85e3a0394..096c2b51f 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Field.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP192R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
index 020c5cdbb..45bcb00f0 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Point.cs b/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
index c249c1269..3b53e341e 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
@@ -1,9 +1,11 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP192R1Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -54,11 +56,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new SecP192R1Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECPoint Add(ECPoint b)
{
if (this.IsInfinity)
@@ -271,14 +268,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return Twice().Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
index 70de308bb..d4be7d8de 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
@@ -1,12 +1,11 @@
using System;
-using Org.BouncyCastle.Math.Field;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP224K1Curve
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = new BigInteger(1,
Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D"));
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
protected readonly SecP224K1Point m_infinity;
public SecP224K1Curve()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new SecP224K1Point(this, null, null);
@@ -72,27 +71,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
return new SecP224K1Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new SecP224K1Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Field.cs b/crypto/src/math/ec/custom/sec/SecP224K1Field.cs
index a55810c6d..98cf777a5 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Field.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP224K1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
index 72ff4b099..fec07436a 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Point.cs b/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
index dd6faa829..98cb29274 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
@@ -1,9 +1,11 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP224K1Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -55,11 +57,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new SecP224K1Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECPoint Add(ECPoint b)
{
if (this.IsInfinity)
@@ -259,14 +256,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return Twice().Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
index 33b66be82..cda8781ff 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
@@ -1,12 +1,11 @@
using System;
-using Org.BouncyCastle.Math.Field;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP224R1Curve
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = new BigInteger(1,
Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"));
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
protected readonly SecP224R1Point m_infinity;
public SecP224R1Curve()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new SecP224R1Point(this, null, null);
@@ -75,27 +74,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
return new SecP224R1Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Add(A).Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new SecP224R1Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Field.cs b/crypto/src/math/ec/custom/sec/SecP224R1Field.cs
index 559593c66..4f5c3bbda 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Field.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP224R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
index 06f47cded..2b9a06564 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Point.cs b/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
index 3b339720d..73c4f1948 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
@@ -1,9 +1,11 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP224R1Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -54,11 +56,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new SecP224R1Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECPoint Add(ECPoint b)
{
if (this.IsInfinity)
@@ -271,14 +268,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return Twice().Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
index 89de61706..59e2cefb2 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
@@ -1,12 +1,11 @@
using System;
-using Org.BouncyCastle.Math.Field;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP256K1Curve
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = new BigInteger(1,
Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"));
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
protected readonly SecP256K1Point m_infinity;
public SecP256K1Curve()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new SecP256K1Point(this, null, null);
@@ -72,27 +71,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
return new SecP256K1Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new SecP256K1Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Field.cs b/crypto/src/math/ec/custom/sec/SecP256K1Field.cs
index ba3a070a9..b0646e93f 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Field.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP256K1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
index d9a039a4f..473113d0f 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Point.cs b/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
index b12eadb72..072a0b969 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
@@ -1,9 +1,11 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP256K1Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -55,11 +57,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new SecP256K1Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECPoint Add(ECPoint b)
{
if (this.IsInfinity)
@@ -259,14 +256,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return Twice().Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
index 9a94eb8d1..6b3448f06 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
@@ -1,12 +1,11 @@
using System;
-using Org.BouncyCastle.Math.Field;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP256R1Curve
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = new BigInteger(1,
Hex.Decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"));
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
protected readonly SecP256R1Point m_infinity;
public SecP256R1Curve()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new SecP256R1Point(this, null, null);
@@ -74,27 +73,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
return new SecP256R1Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Add(A).Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new SecP256R1Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Field.cs b/crypto/src/math/ec/custom/sec/SecP256R1Field.cs
index 9ed9dcd41..11594b2ba 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Field.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP256R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
index b22763cfa..d7838aead 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Point.cs b/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
index 0e4b95a10..83320824d 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
@@ -1,9 +1,11 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP256R1Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -54,11 +56,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new SecP256R1Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECPoint Add(ECPoint b)
{
if (this.IsInfinity)
@@ -271,14 +268,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return Twice().Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
index f3dec05c9..7fd58276a 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
@@ -1,12 +1,11 @@
using System;
-using Org.BouncyCastle.Math.Field;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP384R1Curve
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = new BigInteger(1,
Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"));
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
protected readonly SecP384R1Point m_infinity;
public SecP384R1Curve()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new SecP384R1Point(this, null, null);
@@ -74,27 +73,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
return new SecP384R1Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Add(A).Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new SecP384R1Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Field.cs b/crypto/src/math/ec/custom/sec/SecP384R1Field.cs
index 508b01e3c..7820775ee 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Field.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP384R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
index 40086978d..18d48a57d 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Point.cs b/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
index 1ca8489dc..83159ce61 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
@@ -1,9 +1,11 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP384R1Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -54,11 +56,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new SecP384R1Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECPoint Add(ECPoint b)
{
if (this.IsInfinity)
@@ -272,14 +269,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return Twice().Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
index cb42304ef..e5083c7f0 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
@@ -1,12 +1,11 @@
using System;
-using Org.BouncyCastle.Math.Field;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP521R1Curve
- : ECCurve
+ : AbstractFpCurve
{
public static readonly BigInteger q = new BigInteger(1,
Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
protected readonly SecP521R1Point m_infinity;
public SecP521R1Curve()
- : base(FiniteFields.GetPrimeField(q))
+ : base(q)
{
this.m_infinity = new SecP521R1Point(this, null, null);
@@ -74,27 +73,5 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
return new SecP521R1Point(this, x, y, zs, withCompression);
}
-
- protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
- {
- ECFieldElement x = FromBigInteger(X1);
- ECFieldElement alpha = x.Square().Add(A).Multiply(x).Add(B);
- ECFieldElement beta = alpha.Sqrt();
-
- //
- // if we can't find a sqrt we haven't got a point on the
- // curve - run!
- //
- if (beta == null)
- throw new ArithmeticException("Invalid point compression");
-
- if (beta.TestBitZero() != (yTilde == 1))
- {
- // Use the other root
- beta = beta.Negate();
- }
-
- return new SecP521R1Point(this, x, beta, true);
- }
}
}
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Field.cs b/crypto/src/math/ec/custom/sec/SecP521R1Field.cs
index 3568156d8..b7f8eb146 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Field.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP521R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
index 83a615928..6f02a7eb5 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Point.cs b/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
index 44d590f08..7ad97f76f 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
@@ -1,9 +1,11 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP521R1Point
- : ECPointBase
+ : AbstractFpPoint
{
/**
* Create a point which encodes with point compression.
@@ -54,11 +56,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new SecP521R1Point(null, AffineXCoord, AffineYCoord);
}
- protected internal override bool CompressionYTilde
- {
- get { return this.AffineYCoord.TestBitZero(); }
- }
-
public override ECPoint Add(ECPoint b)
{
if (this.IsInfinity)
@@ -267,14 +264,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return Twice().Add(this);
}
- public override ECPoint Subtract(ECPoint b)
- {
- if (b.IsInfinity)
- return this;
-
- return Add(b.Negate());
- }
-
public override ECPoint Negate()
{
if (IsInfinity)
diff --git a/crypto/src/math/ec/custom/sec/SecT113Field.cs b/crypto/src/math/ec/custom/sec/SecT113Field.cs
new file mode 100644
index 000000000..640c6e787
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113Field.cs
@@ -0,0 +1,209 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113Field
+ {
+ private const ulong M49 = ulong.MaxValue >> 15;
+ private const ulong M57 = ulong.MaxValue >> 7;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat128.FromBigInteger64(x);
+ Reduce15(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat128.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat128.Create64();
+ ulong[] t1 = Nat128.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 3, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 7, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 14, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 28, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 56, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat128.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat128.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+
+ x1 ^= (x3 << 15) ^ (x3 << 24);
+ x2 ^= (x3 >> 49) ^ (x3 >> 40);
+
+ x0 ^= (x2 << 15) ^ (x2 << 24);
+ x1 ^= (x2 >> 49) ^ (x2 >> 40);
+
+ ulong t = x1 >> 49;
+ z[0] = x0 ^ t ^ (t << 9);
+ z[1] = x1 & M49;
+ }
+
+ public static void Reduce15(ulong[] z, int zOff)
+ {
+ ulong z1 = z[zOff + 1], t = z1 >> 49;
+ z[zOff ] ^= t ^ (t << 9);
+ z[zOff + 1] = z1 & M49;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat128.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat128.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat128.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Three-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong f0 = x[0], f1 = x[1];
+ f1 = ((f0 >> 57) ^ (f1 << 7)) & M57;
+ f0 &= M57;
+
+ ulong g0 = y[0], g1 = y[1];
+ g1 = ((g0 >> 57) ^ (g1 << 7)) & M57;
+ g0 &= M57;
+
+ ulong[] H = new ulong[6];
+
+ ImplMulw(f0, g0, H, 0); // H(0) 57/56 bits
+ ImplMulw(f1, g1, H, 2); // H(INF) 57/54 bits
+ ImplMulw(f0 ^ f1, g0 ^ g1, H, 4); // H(1) 57/56 bits
+
+ ulong r = H[1] ^ H[2];
+ ulong z0 = H[0],
+ z3 = H[3],
+ z1 = H[4] ^ z0 ^ r,
+ z2 = H[5] ^ z3 ^ r;
+
+ zz[0] = z0 ^ (z1 << 57);
+ zz[1] = (z1 >> 7) ^ (z2 << 50);
+ zz[2] = (z2 >> 14) ^ (z3 << 43);
+ zz[3] = (z3 >> 21);
+ }
+
+ protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 57 == 0);
+ Debug.Assert(y >> 57 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7];
+ int k = 48;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 9) > 0);
+
+ h ^= ((x & 0x0100804020100800UL) & (ulong)(((long)y << 7) >> 63)) >> 8;
+
+ Debug.Assert(h >> 49 == 0);
+
+ z[zOff ] = l & M57;
+ z[zOff + 1] = (l >> 57) ^ (h << 7);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
new file mode 100644
index 000000000..f217e28cb
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113FieldElement
+ : ECFieldElement
+ {
+ protected internal readonly ulong[] x;
+
+ public SecT113FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 113)
+ throw new ArgumentException("value invalid for SecT113FieldElement", "x");
+
+ this.x = SecT113Field.FromBigInteger(x);
+ }
+
+ public SecT113FieldElement()
+ {
+ this.x = Nat128.Create64();
+ }
+
+ protected internal SecT113FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat128.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat128.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1L) != 0L;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat128.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT113Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 113; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Add(x, ((SecT113FieldElement)b).x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.AddOne(x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Multiply(x, ((SecT113FieldElement)b).x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT113FieldElement)b).x;
+ ulong[] xx = ((SecT113FieldElement)x).x, yx = ((SecT113FieldElement)y).x;
+
+ ulong[] tt = Nat128.CreateExt64();
+ SecT113Field.MultiplyAddToExt(ax, bx, tt);
+ SecT113Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Reduce(tt, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Square(x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT113FieldElement)x).x, yx = ((SecT113FieldElement)y).x;
+
+ ulong[] tt = Nat128.CreateExt64();
+ SecT113Field.SquareAddToExt(ax, tt);
+ SecT113Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Reduce(tt, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat128.Create64();
+ SecT113Field.SquareN(x, pow, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Invert(x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 113; }
+ }
+
+ public virtual int K1
+ {
+ get { return 9; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT113FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT113FieldElement);
+ }
+
+ public virtual bool Equals(SecT113FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat128.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 113009 ^ Arrays.GetHashCode(x, 0, 2);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
new file mode 100644
index 000000000..2705c94aa
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT113R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT113R1Point m_infinity;
+
+ public SecT113R1Curve()
+ : base(113, 9, 0, 0)
+ {
+ this.m_infinity = new SecT113R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("003088250CA6E7C7FE649CE85820F7")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("00E8BEE4D3E2260744188BE0E9C723")));
+ this.m_order = new BigInteger(1, Hex.Decode("0100000000000000D9CCEC8A39E56F"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT113R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT113R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 113; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT113FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT113R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT113R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 113; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 9; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113R1Point.cs b/crypto/src/math/ec/custom/sec/SecT113R1Point.cs
new file mode 100644
index 000000000..6ecc8b01a
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R1Point.cs
@@ -0,0 +1,281 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT113R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT113R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT113R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT113R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT113R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT113R1Point(Curve, X, L.Add(Z), new ECFieldElement[]{ Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
new file mode 100644
index 000000000..abfd26d5b
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113R2Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT113R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT113R2Point m_infinity;
+
+ public SecT113R2Curve()
+ : base(113, 9, 0, 0)
+ {
+ this.m_infinity = new SecT113R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("00689918DBEC7E5A0DD6DFC0AA55C7")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0095E9A9EC9B297BD4BF36E059184F")));
+ this.m_order = new BigInteger(1, Hex.Decode("010000000000000108789B2496AF93"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT113R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT113R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 113; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT113FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT113R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT113R2Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 113; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 9; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113R2Point.cs b/crypto/src/math/ec/custom/sec/SecT113R2Point.cs
new file mode 100644
index 000000000..1453d78c3
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R2Point.cs
@@ -0,0 +1,291 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113R2Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT113R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ {
+ return b;
+ }
+ if (b.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT113R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT113R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT113R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ {
+ return b;
+ }
+ if (b.IsInfinity)
+ {
+ return Twice();
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT113R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT113R2Point(Curve, X, L.Add(Z), new ECFieldElement[]{ Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131Field.cs b/crypto/src/math/ec/custom/sec/SecT131Field.cs
new file mode 100644
index 000000000..47f97078c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131Field.cs
@@ -0,0 +1,303 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131Field
+ {
+ private const ulong M03 = ulong.MaxValue >> 61;
+ private const ulong M44 = ulong.MaxValue >> 20;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat192.FromBigInteger64(x);
+ Reduce61(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat192.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat192.Create64();
+ ulong[] t1 = Nat192.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 2, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 4, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 8, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 16, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 32, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 65, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4];
+
+ x1 ^= (x4 << 61) ^ (x4 << 63);
+ x2 ^= (x4 >> 3) ^ (x4 >> 1) ^ x4 ^ (x4 << 5);
+ x3 ^= (x4 >> 59);
+
+ x0 ^= (x3 << 61) ^ (x3 << 63);
+ x1 ^= (x3 >> 3) ^ (x3 >> 1) ^ x3 ^ (x3 << 5);
+ x2 ^= (x3 >> 59);
+
+ ulong t = x2 >> 3;
+ z[0] = x0 ^ t ^ (t << 2) ^ (t << 3) ^ (t << 8);
+ z[1] = x1 ^ (t >> 56);
+ z[2] = x2 & M03;
+ }
+
+ public static void Reduce61(ulong[] z, int zOff)
+ {
+ ulong z2 = z[zOff + 2], t = z2 >> 3;
+ z[zOff ] ^= t ^ (t << 2) ^ (t << 3) ^ (t << 8);
+ z[zOff + 1] ^= (t >> 56);
+ z[zOff + 2] = z2 & M03;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat.Create64(5);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat.Create64(5);
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat.Create64(5);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5];
+ zz[0] = z0 ^ (z1 << 44);
+ zz[1] = (z1 >> 20) ^ (z2 << 24);
+ zz[2] = (z2 >> 40) ^ (z3 << 4)
+ ^ (z4 << 48);
+ zz[3] = (z3 >> 60) ^ (z5 << 28)
+ ^ (z4 >> 16);
+ zz[4] = (z5 >> 36);
+ zz[5] = 0;
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Five-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong f0 = x[0], f1 = x[1], f2 = x[2];
+ f2 = ((f1 >> 24) ^ (f2 << 40)) & M44;
+ f1 = ((f0 >> 44) ^ (f1 << 20)) & M44;
+ f0 &= M44;
+
+ ulong g0 = y[0], g1 = y[1], g2 = y[2];
+ g2 = ((g1 >> 24) ^ (g2 << 40)) & M44;
+ g1 = ((g0 >> 44) ^ (g1 << 20)) & M44;
+ g0 &= M44;
+
+ ulong[] H = new ulong[10];
+
+ ImplMulw(f0, g0, H, 0); // H(0) 44/43 bits
+ ImplMulw(f2, g2, H, 2); // H(INF) 44/41 bits
+
+ ulong t0 = f0 ^ f1 ^ f2;
+ ulong t1 = g0 ^ g1 ^ g2;
+
+ ImplMulw(t0, t1, H, 4); // H(1) 44/43 bits
+
+ ulong t2 = (f1 << 1) ^ (f2 << 2);
+ ulong t3 = (g1 << 1) ^ (g2 << 2);
+
+ ImplMulw(f0 ^ t2, g0 ^ t3, H, 6); // H(t) 44/45 bits
+ ImplMulw(t0 ^ t2, t1 ^ t3, H, 8); // H(t + 1) 44/45 bits
+
+ ulong t4 = H[6] ^ H[8];
+ ulong t5 = H[7] ^ H[9];
+
+ Debug.Assert(t5 >> 44 == 0);
+
+ // Calculate V
+ ulong v0 = (t4 << 1) ^ H[6];
+ ulong v1 = t4 ^ (t5 << 1) ^ H[7];
+ ulong v2 = t5;
+
+ // Calculate U
+ ulong u0 = H[0];
+ ulong u1 = H[1] ^ H[0] ^ H[4];
+ ulong u2 = H[1] ^ H[5];
+
+ // Calculate W
+ ulong w0 = u0 ^ v0 ^ (H[2] << 4) ^ (H[2] << 1);
+ ulong w1 = u1 ^ v1 ^ (H[3] << 4) ^ (H[3] << 1);
+ ulong w2 = u2 ^ v2;
+
+ // Propagate carries
+ w1 ^= (w0 >> 44); w0 &= M44;
+ w2 ^= (w1 >> 44); w1 &= M44;
+
+ Debug.Assert((w0 & 1UL) == 0);
+
+ // Divide W by t
+
+ w0 = (w0 >> 1) ^ ((w1 & 1UL) << 43);
+ w1 = (w1 >> 1) ^ ((w2 & 1UL) << 43);
+ w2 = (w2 >> 1);
+
+ // Divide W by (t + 1)
+
+ w0 ^= (w0 << 1);
+ w0 ^= (w0 << 2);
+ w0 ^= (w0 << 4);
+ w0 ^= (w0 << 8);
+ w0 ^= (w0 << 16);
+ w0 ^= (w0 << 32);
+
+ w0 &= M44; w1 ^= (w0 >> 43);
+
+ w1 ^= (w1 << 1);
+ w1 ^= (w1 << 2);
+ w1 ^= (w1 << 4);
+ w1 ^= (w1 << 8);
+ w1 ^= (w1 << 16);
+ w1 ^= (w1 << 32);
+
+ w1 &= M44; w2 ^= (w1 >> 43);
+
+ w2 ^= (w2 << 1);
+ w2 ^= (w2 << 2);
+ w2 ^= (w2 << 4);
+ w2 ^= (w2 << 8);
+ w2 ^= (w2 << 16);
+ w2 ^= (w2 << 32);
+
+ Debug.Assert(w2 >> 42 == 0);
+
+ zz[0] = u0;
+ zz[1] = u1 ^ w0 ^ H[2];
+ zz[2] = u2 ^ w1 ^ w0 ^ H[3];
+ zz[3] = w2 ^ w1;
+ zz[4] = w2 ^ H[2];
+ zz[5] = H[3];
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 45 == 0);
+ Debug.Assert(y >> 45 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6;
+ int k = 33;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6
+ ^ u[(j >> 9) & 7] << 9;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 12) > 0);
+
+ Debug.Assert(h >> 25 == 0);
+
+ z[zOff ] = l & M44;
+ z[zOff + 1] = (l >> 44) ^ (h << 20);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+
+ zz[4] = Interleave.Expand8to16((uint)x[2]);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
new file mode 100644
index 000000000..0ea00ea07
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT131FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 131)
+ throw new ArgumentException("value invalid for SecT131FieldElement", "x");
+
+ this.x = SecT131Field.FromBigInteger(x);
+ }
+
+ public SecT131FieldElement()
+ {
+ this.x = Nat192.Create64();
+ }
+
+ protected internal SecT131FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat192.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat192.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat192.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT131Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 131; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Add(x, ((SecT131FieldElement)b).x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.AddOne(x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Multiply(x, ((SecT131FieldElement)b).x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT131FieldElement)b).x;
+ ulong[] xx = ((SecT131FieldElement)x).x, yx = ((SecT131FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(5);
+ SecT131Field.MultiplyAddToExt(ax, bx, tt);
+ SecT131Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Reduce(tt, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Square(x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT131FieldElement)x).x, yx = ((SecT131FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(5);
+ SecT131Field.SquareAddToExt(ax, tt);
+ SecT131Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Reduce(tt, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat192.Create64();
+ SecT131Field.SquareN(x, pow, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Invert(x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Ppb; }
+ }
+
+ public virtual int M
+ {
+ get { return 131; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 3; }
+ }
+
+ public virtual int K3
+ {
+ get { return 8; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT131FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT131FieldElement);
+ }
+
+ public virtual bool Equals(SecT131FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat192.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 131832 ^ Arrays.GetHashCode(x, 0, 3);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
new file mode 100644
index 000000000..b73964c39
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT131R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT131R1Point m_infinity;
+
+ public SecT131R1Curve()
+ : base(131, 2, 3, 8)
+ {
+ this.m_infinity = new SecT131R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("07A11B09A76B562144418FF3FF8C2570B8")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0217C05610884B63B9C6C7291678F9D341")));
+ this.m_order = new BigInteger(1, Hex.Decode("0400000000000000023123953A9464B54D"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT131R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT131R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 131; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT131FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT131R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT131R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 131; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 3; }
+ }
+
+ public virtual int K3
+ {
+ get { return 8; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131R1Point.cs b/crypto/src/math/ec/custom/sec/SecT131R1Point.cs
new file mode 100644
index 000000000..7afdad89c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R1Point.cs
@@ -0,0 +1,287 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT131R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT131R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT131R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT131R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ {
+ return b;
+ }
+ if (b.IsInfinity)
+ {
+ return Twice();
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT131R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT131R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
new file mode 100644
index 000000000..724921c94
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131R2Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT131R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT131R2Point m_infinity;
+
+ public SecT131R2Curve()
+ : base(131, 2, 3, 8)
+ {
+ this.m_infinity = new SecT131R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("03E5A88919D7CAFCBF415F07C2176573B2")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("04B8266A46C55657AC734CE38F018F2192")));
+ this.m_order = new BigInteger(1, Hex.Decode("0400000000000000016954A233049BA98F"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT131R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT131R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override int FieldSize
+ {
+ get { return 131; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT131FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT131R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT131R2Point(this, x, y, zs, withCompression);
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 131; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 3; }
+ }
+
+ public virtual int K3
+ {
+ get { return 8; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131R2Point.cs b/crypto/src/math/ec/custom/sec/SecT131R2Point.cs
new file mode 100644
index 000000000..be61561da
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R2Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131R2Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT131R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT131R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT131R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT131R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT131R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT131R2Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163Field.cs b/crypto/src/math/ec/custom/sec/SecT163Field.cs
new file mode 100644
index 000000000..f921a5bc7
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163Field.cs
@@ -0,0 +1,313 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163Field
+ {
+ private const ulong M35 = ulong.MaxValue >> 29;
+ private const ulong M55 = ulong.MaxValue >> 9;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat192.FromBigInteger64(x);
+ Reduce29(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat192.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion with bases { 2, 3 }
+
+ ulong[] t0 = Nat192.Create64();
+ ulong[] t1 = Nat192.Create64();
+
+ Square(x, t0);
+
+ // 3 | 162
+ SquareN(t0, 1, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 1, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 54
+ SquareN(t0, 3, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 3, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 18
+ SquareN(t0, 9, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 9, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 6
+ SquareN(t0, 27, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 27, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 2
+ SquareN(t0, 81, t1);
+ Multiply(t0, t1, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4], x5 = xx[5];
+
+ x2 ^= (x5 << 29) ^ (x5 << 32) ^ (x5 << 35) ^ (x5 << 36);
+ x3 ^= (x5 >> 35) ^ (x5 >> 32) ^ (x5 >> 29) ^ (x5 >> 28);
+
+ x1 ^= (x4 << 29) ^ (x4 << 32) ^ (x4 << 35) ^ (x4 << 36);
+ x2 ^= (x4 >> 35) ^ (x4 >> 32) ^ (x4 >> 29) ^ (x4 >> 28);
+
+ x0 ^= (x3 << 29) ^ (x3 << 32) ^ (x3 << 35) ^ (x3 << 36);
+ x1 ^= (x3 >> 35) ^ (x3 >> 32) ^ (x3 >> 29) ^ (x3 >> 28);
+
+ ulong t = x2 >> 35;
+ z[0] = x0 ^ t ^ (t << 3) ^ (t << 6) ^ (t << 7);
+ z[1] = x1;
+ z[2] = x2 & M35;
+ }
+
+ public static void Reduce29(ulong[] z, int zOff)
+ {
+ ulong z2 = z[zOff + 2], t = z2 >> 35;
+ z[zOff ] ^= t ^ (t << 3) ^ (t << 6) ^ (t << 7);
+ z[zOff + 2] = z2 & M35;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat192.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5];
+ zz[0] = z0 ^ (z1 << 55);
+ zz[1] = (z1 >> 9) ^ (z2 << 46);
+ zz[2] = (z2 >> 18) ^ (z3 << 37);
+ zz[3] = (z3 >> 27) ^ (z4 << 28);
+ zz[4] = (z4 >> 36) ^ (z5 << 19);
+ zz[5] = (z5 >> 45);
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Five-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong f0 = x[0], f1 = x[1], f2 = x[2];
+ f2 = ((f1 >> 46) ^ (f2 << 18));
+ f1 = ((f0 >> 55) ^ (f1 << 9)) & M55;
+ f0 &= M55;
+
+ ulong g0 = y[0], g1 = y[1], g2 = y[2];
+ g2 = ((g1 >> 46) ^ (g2 << 18));
+ g1 = ((g0 >> 55) ^ (g1 << 9)) & M55;
+ g0 &= M55;
+
+ ulong[] H = new ulong[10];
+
+ ImplMulw(f0, g0, H, 0); // H(0) 55/54 bits
+ ImplMulw(f2, g2, H, 2); // H(INF) 55/50 bits
+
+ ulong t0 = f0 ^ f1 ^ f2;
+ ulong t1 = g0 ^ g1 ^ g2;
+
+ ImplMulw(t0, t1, H, 4); // H(1) 55/54 bits
+
+ ulong t2 = (f1 << 1) ^ (f2 << 2);
+ ulong t3 = (g1 << 1) ^ (g2 << 2);
+
+ ImplMulw(f0 ^ t2, g0 ^ t3, H, 6); // H(t) 55/56 bits
+ ImplMulw(t0 ^ t2, t1 ^ t3, H, 8); // H(t + 1) 55/56 bits
+
+ ulong t4 = H[6] ^ H[8];
+ ulong t5 = H[7] ^ H[9];
+
+ Debug.Assert(t5 >> 55 == 0);
+
+ // Calculate V
+ ulong v0 = (t4 << 1) ^ H[6];
+ ulong v1 = t4 ^ (t5 << 1) ^ H[7];
+ ulong v2 = t5;
+
+ // Calculate U
+ ulong u0 = H[0];
+ ulong u1 = H[1] ^ H[0] ^ H[4];
+ ulong u2 = H[1] ^ H[5];
+
+ // Calculate W
+ ulong w0 = u0 ^ v0 ^ (H[2] << 4) ^ (H[2] << 1);
+ ulong w1 = u1 ^ v1 ^ (H[3] << 4) ^ (H[3] << 1);
+ ulong w2 = u2 ^ v2;
+
+ // Propagate carries
+ w1 ^= (w0 >> 55); w0 &= M55;
+ w2 ^= (w1 >> 55); w1 &= M55;
+
+ Debug.Assert((w0 & 1UL) == 0UL);
+
+ // Divide W by t
+
+ w0 = (w0 >> 1) ^ ((w1 & 1UL) << 54);
+ w1 = (w1 >> 1) ^ ((w2 & 1UL) << 54);
+ w2 = (w2 >> 1);
+
+ // Divide W by (t + 1)
+
+ w0 ^= (w0 << 1);
+ w0 ^= (w0 << 2);
+ w0 ^= (w0 << 4);
+ w0 ^= (w0 << 8);
+ w0 ^= (w0 << 16);
+ w0 ^= (w0 << 32);
+
+ w0 &= M55; w1 ^= (w0 >> 54);
+
+ w1 ^= (w1 << 1);
+ w1 ^= (w1 << 2);
+ w1 ^= (w1 << 4);
+ w1 ^= (w1 << 8);
+ w1 ^= (w1 << 16);
+ w1 ^= (w1 << 32);
+
+ w1 &= M55; w2 ^= (w1 >> 54);
+
+ w2 ^= (w2 << 1);
+ w2 ^= (w2 << 2);
+ w2 ^= (w2 << 4);
+ w2 ^= (w2 << 8);
+ w2 ^= (w2 << 16);
+ w2 ^= (w2 << 32);
+
+ Debug.Assert(w2 >> 52 == 0);
+
+ zz[0] = u0;
+ zz[1] = u1 ^ w0 ^ H[2];
+ zz[2] = u2 ^ w1 ^ w0 ^ H[3];
+ zz[3] = w2 ^ w1;
+ zz[4] = w2 ^ H[2];
+ zz[5] = H[3];
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 56 == 0);
+ Debug.Assert(y >> 56 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 3];
+ int k = 47;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 9) > 0);
+
+ Debug.Assert(h >> 47 == 0);
+
+ z[zOff ] = l & M55;
+ z[zOff + 1] = (l >> 55) ^ (h << 9);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+
+ ulong x2 = x[2];
+ zz[4] = Interleave.Expand32to64((uint)x2);
+ zz[5] = Interleave.Expand8to16((uint)(x2 >> 32));
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
new file mode 100644
index 000000000..c7a0b5639
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT163FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 163)
+ throw new ArgumentException("value invalid for SecT163FieldElement", "x");
+
+ this.x = SecT163Field.FromBigInteger(x);
+ }
+
+ public SecT163FieldElement()
+ {
+ this.x = Nat192.Create64();
+ }
+
+ protected internal SecT163FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat192.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat192.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1L) != 0L;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat192.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT163Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 163; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Add(x, ((SecT163FieldElement)b).x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.AddOne(x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Multiply(x, ((SecT163FieldElement)b).x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT163FieldElement)b).x;
+ ulong[] xx = ((SecT163FieldElement)x).x, yx = ((SecT163FieldElement)y).x;
+
+ ulong[] tt = Nat192.CreateExt64();
+ SecT163Field.MultiplyAddToExt(ax, bx, tt);
+ SecT163Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Reduce(tt, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Square(x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT163FieldElement)x).x, yx = ((SecT163FieldElement)y).x;
+
+ ulong[] tt = Nat192.CreateExt64();
+ SecT163Field.SquareAddToExt(ax, tt);
+ SecT163Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Reduce(tt, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat192.Create64();
+ SecT163Field.SquareN(x, pow, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Invert(x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Ppb; }
+ }
+
+ public virtual int M
+ {
+ get { return 163; }
+ }
+
+ public virtual int K1
+ {
+ get { return 3; }
+ }
+
+ public virtual int K2
+ {
+ get { return 6; }
+ }
+
+ public virtual int K3
+ {
+ get { return 7; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT163FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT163FieldElement);
+ }
+
+ public virtual bool Equals(SecT163FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat192.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 163763 ^ Arrays.GetHashCode(x, 0, 3);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
new file mode 100644
index 000000000..68ff646ca
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT163K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT163K1Point m_infinity;
+
+ public SecT163K1Curve()
+ : base(163, 3, 6, 7)
+ {
+ this.m_infinity = new SecT163K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = this.m_a;
+ this.m_order = new BigInteger(1, Hex.Decode("04000000000000000000020108A2E0CC0D99F8A5EF"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT163K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT163K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 163; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT163FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT163K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT163K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 163; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 3; }
+ }
+
+ public virtual int K2
+ {
+ get { return 6; }
+ }
+
+ public virtual int K3
+ {
+ get { return 7; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163K1Point.cs b/crypto/src/math/ec/custom/sec/SecT163K1Point.cs
new file mode 100644
index 000000000..2e3ba57d0
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163K1Point.cs
@@ -0,0 +1,289 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT163K1Point(null, this.AffineXCoord, this.AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.getA());
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ //return new SecT163K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT163K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ //return new SecT163K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT163K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ //return new SecT163K1Point(curve, T, curve.B.sqrt(), withCompression);
+ return new SecT163K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(X3);
+
+ return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.getA().Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.getA().Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ //return new SecT163K1Point(curve, A, curve.B.sqrt(), withCompression);
+ return new SecT163K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT163K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
new file mode 100644
index 000000000..8ae58ccef
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT163R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT163R1Point m_infinity;
+
+ public SecT163R1Curve()
+ : base(163, 3, 6, 7)
+ {
+ this.m_infinity = new SecT163R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9")));
+ this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT163R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT163R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 163; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT163FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT163R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT163R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 163; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 3; }
+ }
+
+ public virtual int K2
+ {
+ get { return 6; }
+ }
+
+ public virtual int K3
+ {
+ get { return 7; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163R1Point.cs b/crypto/src/math/ec/custom/sec/SecT163R1Point.cs
new file mode 100644
index 000000000..811a09f14
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R1Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT163R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT163R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT163R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT163R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT163R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT163R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
new file mode 100644
index 000000000..5a4fa5ad1
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163R2Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT163R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT163R2Point m_infinity;
+
+ public SecT163R2Curve()
+ : base(163, 3, 6, 7)
+ {
+ this.m_infinity = new SecT163R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("020A601907B8C953CA1481EB10512F78744A3205FD")));
+ this.m_order = new BigInteger(1, Hex.Decode("040000000000000000000292FE77E70C12A4234C33"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT163R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT163R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 163; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT163FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT163R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT163R2Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 163; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 3; }
+ }
+
+ public virtual int K2
+ {
+ get { return 6; }
+ }
+
+ public virtual int K3
+ {
+ get { return 7; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163R2Point.cs b/crypto/src/math/ec/custom/sec/SecT163R2Point.cs
new file mode 100644
index 000000000..07b3f1fd9
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R2Point.cs
@@ -0,0 +1,290 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163R2Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT163R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ {
+ return Twice();
+ }
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT163R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT163R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT163R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ {
+ return b;
+ }
+ if (b.IsInfinity)
+ {
+ return Twice();
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT163R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT163R2Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT193Field.cs b/crypto/src/math/ec/custom/sec/SecT193Field.cs
new file mode 100644
index 000000000..5154f1e0a
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT193Field.cs
@@ -0,0 +1,282 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193Field
+ {
+ private const ulong M01 = 1UL;
+ private const ulong M49 = ulong.MaxValue >> 15;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ zz[6] = xx[6] ^ yy[6];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat256.FromBigInteger64(x);
+ Reduce63(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat256.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion with bases { 2, 3 }
+
+ ulong[] t0 = Nat256.Create64();
+ ulong[] t1 = Nat256.Create64();
+
+ Square(x, t0);
+
+ // 3 | 192
+ SquareN(t0, 1, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 1, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 64
+ SquareN(t0, 3, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 32
+ SquareN(t0, 6, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 16
+ SquareN(t0, 12, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 8
+ SquareN(t0, 24, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 4
+ SquareN(t0, 48, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 2
+ SquareN(t0, 96, t1);
+ Multiply(t0, t1, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4], x5 = xx[5], x6 = xx[6];
+
+ x2 ^= (x6 << 63);
+ x3 ^= (x6 >> 1) ^ (x6 << 14);
+ x4 ^= (x6 >> 50);
+
+ x1 ^= (x5 << 63);
+ x2 ^= (x5 >> 1) ^ (x5 << 14);
+ x3 ^= (x5 >> 50);
+
+ x0 ^= (x4 << 63);
+ x1 ^= (x4 >> 1) ^ (x4 << 14);
+ x2 ^= (x4 >> 50);
+
+ ulong t = x3 >> 1;
+ z[0] = x0 ^ t ^ (t << 15);
+ z[1] = x1 ^ (t >> 49);
+ z[2] = x2;
+ z[3] = x3 & M01;
+ }
+
+ public static void Reduce63(ulong[] z, int zOff)
+ {
+ ulong z3 = z[zOff + 3], t = z3 >> 1;
+ z[zOff ] ^= t ^ (t << 15);
+ z[zOff + 1] ^= (t >> 49);
+ z[zOff + 3] = z3 & M01;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5], z6 = zz[6], z7 = zz[7];
+ zz[0] = z0 ^ (z1 << 49);
+ zz[1] = (z1 >> 15) ^ (z2 << 34);
+ zz[2] = (z2 >> 30) ^ (z3 << 19);
+ zz[3] = (z3 >> 45) ^ (z4 << 4)
+ ^ (z5 << 53);
+ zz[4] = (z4 >> 60) ^ (z6 << 38)
+ ^ (z5 >> 11);
+ zz[5] = (z6 >> 26) ^ (z7 << 23);
+ zz[6] = (z7 >> 41);
+ zz[7] = 0;
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+ z[0] = x0 & M49;
+ z[1] = ((x0 >> 49) ^ (x1 << 15)) & M49;
+ z[2] = ((x1 >> 34) ^ (x2 << 30)) & M49;
+ z[3] = ((x2 >> 19) ^ (x3 << 45));
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong[] f = new ulong[4], g = new ulong[4];
+ ImplExpand(x, f);
+ ImplExpand(y, g);
+
+ ImplMulwAcc(f[0], g[0], zz, 0);
+ ImplMulwAcc(f[1], g[1], zz, 1);
+ ImplMulwAcc(f[2], g[2], zz, 2);
+ ImplMulwAcc(f[3], g[3], zz, 3);
+
+ // U *= (1 - t^n)
+ for (int i = 5; i > 0; --i)
+ {
+ zz[i] ^= zz[i - 1];
+ }
+
+ ImplMulwAcc(f[0] ^ f[1], g[0] ^ g[1], zz, 1);
+ ImplMulwAcc(f[2] ^ f[3], g[2] ^ g[3], zz, 3);
+
+ // V *= (1 - t^2n)
+ for (int i = 7; i > 1; --i)
+ {
+ zz[i] ^= zz[i - 2];
+ }
+
+ // Double-length recursion
+ {
+ ulong c0 = f[0] ^ f[2], c1 = f[1] ^ f[3];
+ ulong d0 = g[0] ^ g[2], d1 = g[1] ^ g[3];
+ ImplMulwAcc(c0 ^ c1, d0 ^ d1, zz, 3);
+ ulong[] t = new ulong[3];
+ ImplMulwAcc(c0, d0, t, 0);
+ ImplMulwAcc(c1, d1, t, 1);
+ ulong t0 = t[0], t1 = t[1], t2 = t[2];
+ zz[2] ^= t0;
+ zz[3] ^= t0 ^ t1;
+ zz[4] ^= t2 ^ t1;
+ zz[5] ^= t2;
+ }
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulwAcc(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 49 == 0);
+ Debug.Assert(y >> 49 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ (u[(j >> 3) & 7] << 3);
+ int k = 36;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6
+ ^ u[(j >> 9) & 7] << 9
+ ^ u[(j >> 12) & 7] << 12;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 15) > 0);
+
+ Debug.Assert(h >> 33 == 0);
+
+ z[zOff ] ^= l & M49;
+ z[zOff + 1] ^= (l >> 49) ^ (h << 15);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+ Interleave.Expand64To128(x[2], zz, 4);
+ zz[6] = (x[3] & M01);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
new file mode 100644
index 000000000..eba4d10e6
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT193FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 193)
+ throw new ArgumentException("value invalid for SecT193FieldElement", "x");
+
+ this.x = SecT193Field.FromBigInteger(x);
+ }
+
+ public SecT193FieldElement()
+ {
+ this.x = Nat256.Create64();
+ }
+
+ protected internal SecT193FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT193Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 193; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Add(x, ((SecT193FieldElement)b).x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.AddOne(x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Multiply(x, ((SecT193FieldElement)b).x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT193FieldElement)b).x;
+ ulong[] xx = ((SecT193FieldElement)x).x, yx = ((SecT193FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT193Field.MultiplyAddToExt(ax, bx, tt);
+ SecT193Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Reduce(tt, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Square(x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT193FieldElement)x).x, yx = ((SecT193FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT193Field.SquareAddToExt(ax, tt);
+ SecT193Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Reduce(tt, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat256.Create64();
+ SecT193Field.SquareN(x, pow, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Invert(x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 193; }
+ }
+
+ public virtual int K1
+ {
+ get { return 15; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT193FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT193FieldElement);
+ }
+
+ public virtual bool Equals(SecT193FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 1930015 ^ Arrays.GetHashCode(x, 0, 4);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
new file mode 100644
index 000000000..a2cb5a8ac
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT193R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT193R1Point m_infinity;
+
+ public SecT193R1Curve()
+ : base(193, 15, 0, 0)
+ {
+ this.m_infinity = new SecT193R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814")));
+ this.m_order = new BigInteger(1, Hex.Decode("01000000000000000000000000C7F34A778F443ACC920EBA49"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT193R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT193R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 193; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT193FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT193R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT193R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 193; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 15; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT193R1Point.cs b/crypto/src/math/ec/custom/sec/SecT193R1Point.cs
new file mode 100644
index 000000000..062fce9d4
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT193R1Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT193R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT193R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT193R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT193R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT193R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT193R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT193R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT193R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT193R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
new file mode 100644
index 000000000..1c84a3eac
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193R2Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT193R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT193R2Point m_infinity;
+
+ public SecT193R2Curve()
+ : base(193, 15, 0, 0)
+ {
+ this.m_infinity = new SecT193R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE")));
+ this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000015AAB561B005413CCD4EE99D5"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT193R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT193R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 193; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT193FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT193R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT193R2Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 193; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 15; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT193R2Point.cs b/crypto/src/math/ec/custom/sec/SecT193R2Point.cs
new file mode 100644
index 000000000..18d89e316
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT193R2Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193R2Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT193R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT193R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT193R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT193R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT193R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT193R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT193R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT193R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT193R2Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233Field.cs b/crypto/src/math/ec/custom/sec/SecT233Field.cs
new file mode 100644
index 000000000..a2f73fd5d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233Field.cs
@@ -0,0 +1,276 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233Field
+ {
+ private const ulong M41 = ulong.MaxValue >> 23;
+ private const ulong M59 = ulong.MaxValue >> 5;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ zz[6] = xx[6] ^ yy[6];
+ zz[7] = xx[7] ^ yy[7];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat256.FromBigInteger64(x);
+ Reduce23(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat256.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat256.Create64();
+ ulong[] t1 = Nat256.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 3, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 7, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 14, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 29, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 58, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 116, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+ ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+ x3 ^= (x7 << 23);
+ x4 ^= (x7 >> 41) ^ (x7 << 33);
+ x5 ^= (x7 >> 31);
+
+ x2 ^= (x6 << 23);
+ x3 ^= (x6 >> 41) ^ (x6 << 33);
+ x4 ^= (x6 >> 31);
+
+ x1 ^= (x5 << 23);
+ x2 ^= (x5 >> 41) ^ (x5 << 33);
+ x3 ^= (x5 >> 31);
+
+ x0 ^= (x4 << 23);
+ x1 ^= (x4 >> 41) ^ (x4 << 33);
+ x2 ^= (x4 >> 31);
+
+ ulong t = x3 >> 41;
+ z[0] = x0 ^ t;
+ z[1] = x1 ^ (t << 10);
+ z[2] = x2;
+ z[3] = x3 & M41;
+ }
+
+ public static void Reduce23(ulong[] z, int zOff)
+ {
+ ulong z3 = z[zOff + 3], t = z3 >> 41;
+ z[zOff ] ^= t;
+ z[zOff + 1] ^= (t << 10);
+ z[zOff + 3] = z3 & M41;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5], z6 = zz[6], z7 = zz[7];
+ zz[0] = z0 ^ (z1 << 59);
+ zz[1] = (z1 >> 5) ^ (z2 << 54);
+ zz[2] = (z2 >> 10) ^ (z3 << 49);
+ zz[3] = (z3 >> 15) ^ (z4 << 44);
+ zz[4] = (z4 >> 20) ^ (z5 << 39);
+ zz[5] = (z5 >> 25) ^ (z6 << 34);
+ zz[6] = (z6 >> 30) ^ (z7 << 29);
+ zz[7] = (z7 >> 35);
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+ z[0] = x0 & M59;
+ z[1] = ((x0 >> 59) ^ (x1 << 5)) & M59;
+ z[2] = ((x1 >> 54) ^ (x2 << 10)) & M59;
+ z[3] = ((x2 >> 49) ^ (x3 << 15));
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong[] f = new ulong[4], g = new ulong[4];
+ ImplExpand(x, f);
+ ImplExpand(y, g);
+
+ ImplMulwAcc(f[0], g[0], zz, 0);
+ ImplMulwAcc(f[1], g[1], zz, 1);
+ ImplMulwAcc(f[2], g[2], zz, 2);
+ ImplMulwAcc(f[3], g[3], zz, 3);
+
+ // U *= (1 - t^n)
+ for (int i = 5; i > 0; --i)
+ {
+ zz[i] ^= zz[i - 1];
+ }
+
+ ImplMulwAcc(f[0] ^ f[1], g[0] ^ g[1], zz, 1);
+ ImplMulwAcc(f[2] ^ f[3], g[2] ^ g[3], zz, 3);
+
+ // V *= (1 - t^2n)
+ for (int i = 7; i > 1; --i)
+ {
+ zz[i] ^= zz[i - 2];
+ }
+
+ // Double-length recursion
+ {
+ ulong c0 = f[0] ^ f[2], c1 = f[1] ^ f[3];
+ ulong d0 = g[0] ^ g[2], d1 = g[1] ^ g[3];
+ ImplMulwAcc(c0 ^ c1, d0 ^ d1, zz, 3);
+ ulong[] t = new ulong[3];
+ ImplMulwAcc(c0, d0, t, 0);
+ ImplMulwAcc(c1, d1, t, 1);
+ ulong t0 = t[0], t1 = t[1], t2 = t[2];
+ zz[2] ^= t0;
+ zz[3] ^= t0 ^ t1;
+ zz[4] ^= t2 ^ t1;
+ zz[5] ^= t2;
+ }
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulwAcc(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 59 == 0);
+ Debug.Assert(y >> 59 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ (u[(j >> 3) & 7] << 3);
+ int k = 54;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 6) > 0);
+
+ Debug.Assert(h >> 53 == 0);
+
+ z[zOff ] ^= l & M59;
+ z[zOff + 1] ^= (l >> 59) ^ (h << 5);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+ Interleave.Expand64To128(x[2], zz, 4);
+
+ ulong x3 = x[3];
+ zz[6] = Interleave.Expand32to64((uint)x3);
+ zz[7] = Interleave.Expand16to32((uint)(x3 >> 32));
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
new file mode 100644
index 000000000..a9041efde
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT233FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 233)
+ throw new ArgumentException("value invalid for SecT233FieldElement", "x");
+
+ this.x = SecT233Field.FromBigInteger(x);
+ }
+
+ public SecT233FieldElement()
+ {
+ this.x = Nat256.Create64();
+ }
+
+ protected internal SecT233FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT233Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 233; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Add(x, ((SecT233FieldElement)b).x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.AddOne(x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Multiply(x, ((SecT233FieldElement)b).x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT233FieldElement)b).x;
+ ulong[] xx = ((SecT233FieldElement)x).x, yx = ((SecT233FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT233Field.MultiplyAddToExt(ax, bx, tt);
+ SecT233Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Reduce(tt, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Square(x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT233FieldElement)x).x, yx = ((SecT233FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT233Field.SquareAddToExt(ax, tt);
+ SecT233Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Reduce(tt, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat256.Create64();
+ SecT233Field.SquareN(x, pow, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Invert(x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 233; }
+ }
+
+ public virtual int K1
+ {
+ get { return 74; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT233FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT233FieldElement);
+ }
+
+ public virtual bool Equals(SecT233FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 2330074 ^ Arrays.GetHashCode(x, 0, 4);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
new file mode 100644
index 000000000..72935913d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT233K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT233K1Point m_infinity;
+
+ public SecT233K1Curve()
+ : base(233, 74, 0, 0)
+ {
+ this.m_infinity = new SecT233K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT233K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT233K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override int FieldSize
+ {
+ get { return 233; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT233FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT233K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT233K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 233; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 74; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233K1Point.cs b/crypto/src/math/ec/custom/sec/SecT233K1Point.cs
new file mode 100644
index 000000000..7e7ee8f0b
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233K1Point.cs
@@ -0,0 +1,302 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT233K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ {
+ return curve.Infinity;
+ }
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ //return new SecT233K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT233K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ //return new SecT233K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT233K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ //return new SecT233K1Point(curve, T, curve.B.sqrt(), withCompression);
+ return new SecT233K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ {
+ return b.Twice();
+ }
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ //return new SecT233K1Point(curve, A, curve.B.sqrt(), withCompression);
+ return new SecT233K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT233K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
new file mode 100644
index 000000000..db6e6e1d4
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT233R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT233R1Point m_infinity;
+
+ public SecT233R1Curve()
+ : base(233, 74, 0, 0)
+ {
+ this.m_infinity = new SecT233R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD")));
+ this.m_order = new BigInteger(1, Hex.Decode("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT233R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT233R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 233; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT233FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT233R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT233R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 233; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 74; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233R1Point.cs b/crypto/src/math/ec/custom/sec/SecT233R1Point.cs
new file mode 100644
index 000000000..ffac89d15
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233R1Point.cs
@@ -0,0 +1,282 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT233R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT233R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT233R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT233R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT233R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT233R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT239Field.cs b/crypto/src/math/ec/custom/sec/SecT239Field.cs
new file mode 100644
index 000000000..6b8ad696f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239Field.cs
@@ -0,0 +1,286 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT239Field
+ {
+ private const ulong M47 = ulong.MaxValue >> 17;
+ private const ulong M60 = ulong.MaxValue >> 4;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ zz[6] = xx[6] ^ yy[6];
+ zz[7] = xx[7] ^ yy[7];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat256.FromBigInteger64(x);
+ Reduce17(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat256.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat256.Create64();
+ ulong[] t1 = Nat256.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 3, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 7, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 14, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 29, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 59, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 119, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+ ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+ x3 ^= (x7 << 17);
+ x4 ^= (x7 >> 47);
+ x5 ^= (x7 << 47);
+ x6 ^= (x7 >> 17);
+
+ x2 ^= (x6 << 17);
+ x3 ^= (x6 >> 47);
+ x4 ^= (x6 << 47);
+ x5 ^= (x6 >> 17);
+
+ x1 ^= (x5 << 17);
+ x2 ^= (x5 >> 47);
+ x3 ^= (x5 << 47);
+ x4 ^= (x5 >> 17);
+
+ x0 ^= (x4 << 17);
+ x1 ^= (x4 >> 47);
+ x2 ^= (x4 << 47);
+ x3 ^= (x4 >> 17);
+
+ ulong t = x3 >> 47;
+ z[0] = x0 ^ t;
+ z[1] = x1;
+ z[2] = x2 ^ (t << 30);
+ z[3] = x3 & M47;
+ }
+
+ public static void Reduce17(ulong[] z, int zOff)
+ {
+ ulong z3 = z[zOff + 3], t = z3 >> 47;
+ z[zOff ] ^= t;
+ z[zOff + 2] ^= (t << 30);
+ z[zOff + 3] = z3 & M47;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5], z6 = zz[6], z7 = zz[7];
+ zz[0] = z0 ^ (z1 << 60);
+ zz[1] = (z1 >> 4) ^ (z2 << 56);
+ zz[2] = (z2 >> 8) ^ (z3 << 52);
+ zz[3] = (z3 >> 12) ^ (z4 << 48);
+ zz[4] = (z4 >> 16) ^ (z5 << 44);
+ zz[5] = (z5 >> 20) ^ (z6 << 40);
+ zz[6] = (z6 >> 24) ^ (z7 << 36);
+ zz[7] = (z7 >> 28);
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+ z[0] = x0 & M60;
+ z[1] = ((x0 >> 60) ^ (x1 << 4)) & M60;
+ z[2] = ((x1 >> 56) ^ (x2 << 8)) & M60;
+ z[3] = ((x2 >> 52) ^ (x3 << 12));
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong[] f = new ulong[4], g = new ulong[4];
+ ImplExpand(x, f);
+ ImplExpand(y, g);
+
+ ImplMulwAcc(f[0], g[0], zz, 0);
+ ImplMulwAcc(f[1], g[1], zz, 1);
+ ImplMulwAcc(f[2], g[2], zz, 2);
+ ImplMulwAcc(f[3], g[3], zz, 3);
+
+ // U *= (1 - t^n)
+ for (int i = 5; i > 0; --i)
+ {
+ zz[i] ^= zz[i - 1];
+ }
+
+ ImplMulwAcc(f[0] ^ f[1], g[0] ^ g[1], zz, 1);
+ ImplMulwAcc(f[2] ^ f[3], g[2] ^ g[3], zz, 3);
+
+ // V *= (1 - t^2n)
+ for (int i = 7; i > 1; --i)
+ {
+ zz[i] ^= zz[i - 2];
+ }
+
+ // Double-length recursion
+ {
+ ulong c0 = f[0] ^ f[2], c1 = f[1] ^ f[3];
+ ulong d0 = g[0] ^ g[2], d1 = g[1] ^ g[3];
+ ImplMulwAcc(c0 ^ c1, d0 ^ d1, zz, 3);
+ ulong[] t = new ulong[3];
+ ImplMulwAcc(c0, d0, t, 0);
+ ImplMulwAcc(c1, d1, t, 1);
+ ulong t0 = t[0], t1 = t[1], t2 = t[2];
+ zz[2] ^= t0;
+ zz[3] ^= t0 ^ t1;
+ zz[4] ^= t2 ^ t1;
+ zz[5] ^= t2;
+ }
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulwAcc(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 60 == 0);
+ Debug.Assert(y >> 60 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ (u[(j >> 3) & 7] << 3);
+ int k = 54;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 6) > 0);
+
+ h ^= ((x & 0x0820820820820820L) & (ulong)(((long)y << 4) >> 63)) >> 5;
+
+ Debug.Assert(h >> 55 == 0);
+
+ z[zOff ] ^= l & M60;
+ z[zOff + 1] ^= (l >> 60) ^ (h << 4);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+ Interleave.Expand64To128(x[2], zz, 4);
+
+ ulong x3 = x[3];
+ zz[6] = Interleave.Expand32to64((uint)x3);
+ zz[7] = Interleave.Expand16to32((uint)(x3 >> 32));
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
new file mode 100644
index 000000000..de074c55f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT239FieldElement
+ : ECFieldElement
+ {
+ protected ulong[] x;
+
+ public SecT239FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 239)
+ throw new ArgumentException("value invalid for SecT239FieldElement", "x");
+
+ this.x = SecT239Field.FromBigInteger(x);
+ }
+
+ public SecT239FieldElement()
+ {
+ this.x = Nat256.Create64();
+ }
+
+ protected internal SecT239FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1L) != 0L;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT239Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 239; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Add(x, ((SecT239FieldElement)b).x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.AddOne(x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Multiply(x, ((SecT239FieldElement)b).x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT239FieldElement)b).x;
+ ulong[] xx = ((SecT239FieldElement)x).x, yx = ((SecT239FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT239Field.MultiplyAddToExt(ax, bx, tt);
+ SecT239Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Reduce(tt, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Square(x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT239FieldElement)x).x, yx = ((SecT239FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT239Field.SquareAddToExt(ax, tt);
+ SecT239Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Reduce(tt, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat256.Create64();
+ SecT239Field.SquareN(x, pow, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Invert(x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 239; }
+ }
+
+ public virtual int K1
+ {
+ get { return 158; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT239FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT239FieldElement);
+ }
+
+ public virtual bool Equals(SecT239FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 23900158 ^ Arrays.GetHashCode(x, 0, 4);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
new file mode 100644
index 000000000..a499d48b4
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT239K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT239K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT239K1Point m_infinity;
+
+ public SecT239K1Curve()
+ : base(239, 158, 0, 0)
+ {
+ this.m_infinity = new SecT239K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT239K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT239K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 239; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT239FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT239K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT239K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 239; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 158; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT239K1Point.cs b/crypto/src/math/ec/custom/sec/SecT239K1Point.cs
new file mode 100644
index 000000000..ac079ad1e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239K1Point.cs
@@ -0,0 +1,297 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT239K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT239K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ // X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ //return new SecT239K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT239K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ //return new SecT239K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT239K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ //return new SecT239K1Point(curve, T, curve.B.sqrt(), withCompression);
+ return new SecT239K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ //return new SecT239K1Point(curve, A, curve.B.sqrt(), withCompression);
+ return new SecT239K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT239K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283Field.cs b/crypto/src/math/ec/custom/sec/SecT283Field.cs
new file mode 100644
index 000000000..903ea02ff
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283Field.cs
@@ -0,0 +1,370 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283Field
+ {
+ private const ulong M27 = ulong.MaxValue >> 37;
+ private const ulong M57 = ulong.MaxValue >> 7;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ z[4] = x[4] ^ y[4];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ zz[6] = xx[6] ^ yy[6];
+ zz[7] = xx[7] ^ yy[7];
+ zz[8] = xx[8] ^ yy[8];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat320.FromBigInteger64(x);
+ Reduce37(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat320.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat320.Create64();
+ ulong[] t1 = Nat320.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 2, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 4, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 8, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 17, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 35, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 70, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 141, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat320.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat320.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4];
+ ulong x5 = xx[5], x6 = xx[6], x7 = xx[7], x8 = xx[8];
+
+ x3 ^= (x8 << 37) ^ (x8 << 42) ^ (x8 << 44) ^ (x8 << 49);
+ x4 ^= (x8 >> 27) ^ (x8 >> 22) ^ (x8 >> 20) ^ (x8 >> 15);
+
+ x2 ^= (x7 << 37) ^ (x7 << 42) ^ (x7 << 44) ^ (x7 << 49);
+ x3 ^= (x7 >> 27) ^ (x7 >> 22) ^ (x7 >> 20) ^ (x7 >> 15);
+
+ x1 ^= (x6 << 37) ^ (x6 << 42) ^ (x6 << 44) ^ (x6 << 49);
+ x2 ^= (x6 >> 27) ^ (x6 >> 22) ^ (x6 >> 20) ^ (x6 >> 15);
+
+ x0 ^= (x5 << 37) ^ (x5 << 42) ^ (x5 << 44) ^ (x5 << 49);
+ x1 ^= (x5 >> 27) ^ (x5 >> 22) ^ (x5 >> 20) ^ (x5 >> 15);
+
+ ulong t = x4 >> 27;
+ z[0] = x0 ^ t ^ (t << 5) ^ (t << 7) ^ (t << 12);
+ z[1] = x1;
+ z[2] = x2;
+ z[3] = x3;
+ z[4] = x4 & M27;
+ }
+
+ public static void Reduce37(ulong[] z, int zOff)
+ {
+ ulong z4 = z[zOff + 4], t = z4 >> 27;
+ z[zOff ] ^= t ^ (t << 5) ^ (t << 7) ^ (t << 12);
+ z[zOff + 4] = z4 & M27;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat.Create64(9);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat.Create64(9);
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat.Create64(9);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4];
+ ulong z5 = zz[5], z6 = zz[6], z7 = zz[7], z8 = zz[8], z9 = zz[9];
+ zz[0] = z0 ^ (z1 << 57);
+ zz[1] = (z1 >> 7) ^ (z2 << 50);
+ zz[2] = (z2 >> 14) ^ (z3 << 43);
+ zz[3] = (z3 >> 21) ^ (z4 << 36);
+ zz[4] = (z4 >> 28) ^ (z5 << 29);
+ zz[5] = (z5 >> 35) ^ (z6 << 22);
+ zz[6] = (z6 >> 42) ^ (z7 << 15);
+ zz[7] = (z7 >> 49) ^ (z8 << 8);
+ zz[8] = (z8 >> 56) ^ (z9 << 1);
+ zz[9] = (z9 >> 63); // Zero!
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4];
+ z[0] = x0 & M57;
+ z[1] = ((x0 >> 57) ^ (x1 << 7)) & M57;
+ z[2] = ((x1 >> 50) ^ (x2 << 14)) & M57;
+ z[3] = ((x2 >> 43) ^ (x3 << 21)) & M57;
+ z[4] = ((x3 >> 36) ^ (x4 << 28));
+ }
+
+ //protected static void AddMs(ulong[] zz, int zOff, ulong[] p, params int[] ms)
+ //{
+ // ulong t0 = 0, t1 = 0;
+ // foreach (int m in ms)
+ // {
+ // int i = (m - 1) << 1;
+ // t0 ^= p[i ];
+ // t1 ^= p[i + 1];
+ // }
+ // zz[zOff ] ^= t0;
+ // zz[zOff + 1] ^= t1;
+ //}
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * Formula (17) from "Some New Results on Binary Polynomial Multiplication",
+ * Murat Cenk and M. Anwar Hasan.
+ *
+ * The formula as given contained an error in the term t25, as noted below
+ */
+ ulong[] a = new ulong[5], b = new ulong[5];
+ ImplExpand(x, a);
+ ImplExpand(y, b);
+
+ ulong[] p = new ulong[26];
+
+ ImplMulw(a[0], b[0], p, 0); // m1
+ ImplMulw(a[1], b[1], p, 2); // m2
+ ImplMulw(a[2], b[2], p, 4); // m3
+ ImplMulw(a[3], b[3], p, 6); // m4
+ ImplMulw(a[4], b[4], p, 8); // m5
+
+ ulong u0 = a[0] ^ a[1], v0 = b[0] ^ b[1];
+ ulong u1 = a[0] ^ a[2], v1 = b[0] ^ b[2];
+ ulong u2 = a[2] ^ a[4], v2 = b[2] ^ b[4];
+ ulong u3 = a[3] ^ a[4], v3 = b[3] ^ b[4];
+
+ ImplMulw(u1 ^ a[3], v1 ^ b[3], p, 18); // m10
+ ImplMulw(u2 ^ a[1], v2 ^ b[1], p, 20); // m11
+
+ ulong A4 = u0 ^ u3 , B4 = v0 ^ v3;
+ ulong A5 = A4 ^ a[2], B5 = B4 ^ b[2];
+
+ ImplMulw(A4, B4, p, 22); // m12
+ ImplMulw(A5, B5, p, 24); // m13
+
+ ImplMulw(u0, v0, p, 10); // m6
+ ImplMulw(u1, v1, p, 12); // m7
+ ImplMulw(u2, v2, p, 14); // m8
+ ImplMulw(u3, v3, p, 16); // m9
+
+
+ // Original method, corresponding to formula (16)
+ //AddMs(zz, 0, p, 1);
+ //AddMs(zz, 1, p, 1, 2, 6);
+ //AddMs(zz, 2, p, 1, 2, 3, 7);
+ //AddMs(zz, 3, p, 1, 3, 4, 5, 8, 10, 12, 13);
+ //AddMs(zz, 4, p, 1, 2, 4, 5, 6, 9, 10, 11, 13);
+ //AddMs(zz, 5, p, 1, 2, 3, 5, 7, 11, 12, 13);
+ //AddMs(zz, 6, p, 3, 4, 5, 8);
+ //AddMs(zz, 7, p, 4, 5, 9);
+ //AddMs(zz, 8, p, 5);
+
+ // Improved method factors out common single-word terms
+ // NOTE: p1,...,p26 in the paper maps to p[0],...,p[25] here
+
+ zz[0] = p[ 0];
+ zz[9] = p[ 9];
+
+ ulong t1 = p[ 0] ^ p[ 1];
+ ulong t2 = t1 ^ p[ 2];
+ ulong t3 = t2 ^ p[10];
+
+ zz[1] = t3;
+
+ ulong t4 = p[ 3] ^ p[ 4];
+ ulong t5 = p[11] ^ p[12];
+ ulong t6 = t4 ^ t5;
+ ulong t7 = t2 ^ t6;
+
+ zz[2] = t7;
+
+ ulong t8 = t1 ^ t4;
+ ulong t9 = p[ 5] ^ p[ 6];
+ ulong t10 = t8 ^ t9;
+ ulong t11 = t10 ^ p[ 8];
+ ulong t12 = p[13] ^ p[14];
+ ulong t13 = t11 ^ t12;
+ ulong t14 = p[18] ^ p[22];
+ ulong t15 = t14 ^ p[24];
+ ulong t16 = t13 ^ t15;
+
+ zz[3] = t16;
+
+ ulong t17 = p[ 7] ^ p[ 8];
+ ulong t18 = t17 ^ p[ 9];
+ ulong t19 = t18 ^ p[17];
+
+ zz[8] = t19;
+
+ ulong t20 = t18 ^ t9;
+ ulong t21 = p[15] ^ p[16];
+ ulong t22 = t20 ^ t21;
+
+ zz[7] = t22;
+
+ ulong t23 = t22 ^ t3;
+ ulong t24 = p[19] ^ p[20];
+ // ulong t25 = p[23] ^ p[24];
+ ulong t25 = p[25] ^ p[24]; // Fixes an error in the paper: p[23] -> p{25]
+ ulong t26 = p[18] ^ p[23];
+ ulong t27 = t24 ^ t25;
+ ulong t28 = t27 ^ t26;
+ ulong t29 = t28 ^ t23;
+
+ zz[4] = t29;
+
+ ulong t30 = t7 ^ t19;
+ ulong t31 = t27 ^ t30;
+ ulong t32 = p[21] ^ p[22];
+ ulong t33 = t31 ^ t32;
+
+ zz[5] = t33;
+
+ ulong t34 = t11 ^ p[0];
+ ulong t35 = t34 ^ p[9];
+ ulong t36 = t35 ^ t12;
+ ulong t37 = t36 ^ p[21];
+ ulong t38 = t37 ^ p[23];
+ ulong t39 = t38 ^ p[25];
+
+ zz[6] = t39;
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 57 == 0);
+ Debug.Assert(y >> 57 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7];
+ int k = 48;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 9) > 0);
+
+ h ^= ((x & 0x0100804020100800L) & (ulong)(((long)y << 7) >> 63)) >> 8;
+
+ Debug.Assert(h >> 49 == 0);
+
+ z[zOff ] = l & M57;
+ z[zOff + 1] = (l >> 57) ^ (h << 7);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ Interleave.Expand64To128(x[i], zz, i << 1);
+ }
+ zz[8] = Interleave.Expand32to64((uint)x[4]);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
new file mode 100644
index 000000000..e02108f73
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT283FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 283)
+ throw new ArgumentException("value invalid for SecT283FieldElement", "x");
+
+ this.x = SecT283Field.FromBigInteger(x);
+ }
+
+ public SecT283FieldElement()
+ {
+ this.x = Nat320.Create64();
+ }
+
+ protected internal SecT283FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat320.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat320.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat320.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT283Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 283; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Add(x, ((SecT283FieldElement)b).x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.AddOne(x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Multiply(x, ((SecT283FieldElement)b).x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT283FieldElement)b).x;
+ ulong[] xx = ((SecT283FieldElement)x).x, yx = ((SecT283FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(9);
+ SecT283Field.MultiplyAddToExt(ax, bx, tt);
+ SecT283Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Reduce(tt, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Square(x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT283FieldElement)x).x, yx = ((SecT283FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(9);
+ SecT283Field.SquareAddToExt(ax, tt);
+ SecT283Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Reduce(tt, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat320.Create64();
+ SecT283Field.SquareN(x, pow, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Invert(x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Ppb; }
+ }
+
+ public virtual int M
+ {
+ get { return 283; }
+ }
+
+ public virtual int K1
+ {
+ get { return 5; }
+ }
+
+ public virtual int K2
+ {
+ get { return 7; }
+ }
+
+ public virtual int K3
+ {
+ get { return 12; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT283FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT283FieldElement);
+ }
+
+ public virtual bool Equals(SecT283FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat320.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 2831275 ^ Arrays.GetHashCode(x, 0, 5);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
new file mode 100644
index 000000000..4053287ec
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT283K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT283K1Point m_infinity;
+
+ public SecT283K1Curve()
+ : base(283, 5, 7, 12)
+ {
+ this.m_infinity = new SecT283K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT283K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT283K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 283; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT283FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT283K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT283K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 283; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 5; }
+ }
+
+ public virtual int K2
+ {
+ get { return 7; }
+ }
+
+ public virtual int K3
+ {
+ get { return 12; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283K1Point.cs b/crypto/src/math/ec/custom/sec/SecT283K1Point.cs
new file mode 100644
index 000000000..f85706c63
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283K1Point.cs
@@ -0,0 +1,296 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT283K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ //return new SecT283K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT283K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ //return new SecT283K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT283K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ //return new SecT283K1Point(curve, T, curve.B.sqrt(), withCompression);
+ return new SecT283K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ //return new SecT283K1Point(curve, A, curve.B.sqrt(), withCompression);
+ return new SecT283K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT283K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
new file mode 100644
index 000000000..e659675ce
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT283R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT283R1Point m_infinity;
+
+ public SecT283R1Curve()
+ : base(283, 5, 7, 12)
+ {
+ this.m_infinity = new SecT283R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5")));
+ this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT283R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT283R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 283; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT283FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT283R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT283R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 283; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 5; }
+ }
+
+ public virtual int K2
+ {
+ get { return 7; }
+ }
+
+ public virtual int K3
+ {
+ get { return 12; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283R1Point.cs b/crypto/src/math/ec/custom/sec/SecT283R1Point.cs
new file mode 100644
index 000000000..340bbdae6
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283R1Point.cs
@@ -0,0 +1,282 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT283R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT283R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT283R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT283R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT283R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT283R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409Field.cs b/crypto/src/math/ec/custom/sec/SecT409Field.cs
new file mode 100644
index 000000000..84eada96e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409Field.cs
@@ -0,0 +1,295 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409Field
+ {
+ private const ulong M25 = ulong.MaxValue >> 39;
+ private const ulong M59 = ulong.MaxValue >> 5;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ z[4] = x[4] ^ y[4];
+ z[5] = x[5] ^ y[5];
+ z[6] = x[6] ^ y[6];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ for (int i = 0; i < 13; ++i)
+ {
+ zz[i] = xx[i] ^ yy[i];
+ }
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat448.FromBigInteger64(x);
+ Reduce39(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat448.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion with bases { 2, 3 }
+
+ ulong[] t0 = Nat448.Create64();
+ ulong[] t1 = Nat448.Create64();
+ ulong[] t2 = Nat448.Create64();
+
+ Square(x, t0);
+
+ // 3 | 408
+ SquareN(t0, 1, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 1, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 136
+ SquareN(t0, 3, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 68
+ SquareN(t0, 6, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 34
+ SquareN(t0, 12, t1);
+ Multiply(t0, t1, t2);
+
+ // ! {2,3} | 17
+ SquareN(t2, 24, t0);
+ SquareN(t0, 24, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 8
+ SquareN(t0, 48, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 4
+ SquareN(t0, 96, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 2
+ SquareN(t0, 192, t1);
+ Multiply(t0, t1, t0);
+
+ Multiply(t0, t2, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat448.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat448.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x00 = xx[0], x01 = xx[1], x02 = xx[2], x03 = xx[3];
+ ulong x04 = xx[4], x05 = xx[5], x06 = xx[6], x07 = xx[7];
+
+ ulong u = xx[12];
+ x05 ^= (u << 39);
+ x06 ^= (u >> 25) ^ (u << 62);
+ x07 ^= (u >> 2);
+
+ u = xx[11];
+ x04 ^= (u << 39);
+ x05 ^= (u >> 25) ^ (u << 62);
+ x06 ^= (u >> 2);
+
+ u = xx[10];
+ x03 ^= (u << 39);
+ x04 ^= (u >> 25) ^ (u << 62);
+ x05 ^= (u >> 2);
+
+ u = xx[9];
+ x02 ^= (u << 39);
+ x03 ^= (u >> 25) ^ (u << 62);
+ x04 ^= (u >> 2);
+
+ u = xx[8];
+ x01 ^= (u << 39);
+ x02 ^= (u >> 25) ^ (u << 62);
+ x03 ^= (u >> 2);
+
+ u = x07;
+ x00 ^= (u << 39);
+ x01 ^= (u >> 25) ^ (u << 62);
+ x02 ^= (u >> 2);
+
+ ulong t = x06 >> 25;
+ z[0] = x00 ^ t;
+ z[1] = x01 ^ (t << 23);
+ z[2] = x02;
+ z[3] = x03;
+ z[4] = x04;
+ z[5] = x05;
+ z[6] = x06 & M25;
+ }
+
+ public static void Reduce39(ulong[] z, int zOff)
+ {
+ ulong z6 = z[zOff + 6], t = z6 >> 25;
+ z[zOff ] ^= t;
+ z[zOff + 1] ^= (t << 23);
+ z[zOff + 6] = z6 & M25;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat.Create64(13);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat.Create64(13);
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat.Create64(13);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z00 = zz[ 0], z01 = zz[ 1], z02 = zz[ 2], z03 = zz[ 3], z04 = zz[ 4], z05 = zz[ 5], z06 = zz[ 6];
+ ulong z07 = zz[ 7], z08 = zz[ 8], z09 = zz[ 9], z10 = zz[10], z11 = zz[11], z12 = zz[12], z13 = zz[13];
+ zz[ 0] = z00 ^ (z01 << 59);
+ zz[ 1] = (z01 >> 5) ^ (z02 << 54);
+ zz[ 2] = (z02 >> 10) ^ (z03 << 49);
+ zz[ 3] = (z03 >> 15) ^ (z04 << 44);
+ zz[ 4] = (z04 >> 20) ^ (z05 << 39);
+ zz[ 5] = (z05 >> 25) ^ (z06 << 34);
+ zz[ 6] = (z06 >> 30) ^ (z07 << 29);
+ zz[ 7] = (z07 >> 35) ^ (z08 << 24);
+ zz[ 8] = (z08 >> 40) ^ (z09 << 19);
+ zz[ 9] = (z09 >> 45) ^ (z10 << 14);
+ zz[10] = (z10 >> 50) ^ (z11 << 9);
+ zz[11] = (z11 >> 55) ^ (z12 << 4)
+ ^ (z13 << 63);
+ zz[12] = (z12 >> 60)
+ ^ (z13 >> 1);
+ zz[13] = 0;
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6];
+ z[0] = x0 & M59;
+ z[1] = ((x0 >> 59) ^ (x1 << 5)) & M59;
+ z[2] = ((x1 >> 54) ^ (x2 << 10)) & M59;
+ z[3] = ((x2 >> 49) ^ (x3 << 15)) & M59;
+ z[4] = ((x3 >> 44) ^ (x4 << 20)) & M59;
+ z[5] = ((x4 >> 39) ^ (x5 << 25)) & M59;
+ z[6] = ((x5 >> 34) ^ (x6 << 30));
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] a = new ulong[7], b = new ulong[7];
+ ImplExpand(x, a);
+ ImplExpand(y, b);
+
+ for (int i = 0; i < 7; ++i)
+ {
+ ImplMulwAcc(a, b[i], zz, i);
+ }
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulwAcc(ulong[] xs, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(y >> 59 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ for (int i = 0; i < 7; ++i)
+ {
+ ulong x = xs[i];
+
+ Debug.Assert(x >> 59 == 0);
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ (u[(j >> 3) & 7] << 3);
+ int k = 54;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 6) > 0);
+
+ Debug.Assert(h >> 53 == 0);
+
+ z[zOff + i ] ^= l & M59;
+ z[zOff + i + 1] ^= (l >> 59) ^ (h << 5);
+ }
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ for (int i = 0; i < 6; ++i)
+ {
+ Interleave.Expand64To128(x[i], zz, i << 1);
+ }
+ zz[12] = Interleave.Expand32to64((uint)x[6]);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
new file mode 100644
index 000000000..581ea73df
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409FieldElement
+ : ECFieldElement
+ {
+ protected ulong[] x;
+
+ public SecT409FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 409)
+ throw new ArgumentException("value invalid for SecT409FieldElement", "x");
+
+ this.x = SecT409Field.FromBigInteger(x);
+ }
+
+ public SecT409FieldElement()
+ {
+ this.x = Nat448.Create64();
+ }
+
+ protected internal SecT409FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat448.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat448.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat448.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT409Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 409; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Add(x, ((SecT409FieldElement)b).x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.AddOne(x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Multiply(x, ((SecT409FieldElement)b).x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT409FieldElement)b).x;
+ ulong[] xx = ((SecT409FieldElement)x).x, yx = ((SecT409FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(13);
+ SecT409Field.MultiplyAddToExt(ax, bx, tt);
+ SecT409Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Reduce(tt, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Square(x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT409FieldElement)x).x, yx = ((SecT409FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(13);
+ SecT409Field.SquareAddToExt(ax, tt);
+ SecT409Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Reduce(tt, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat448.Create64();
+ SecT409Field.SquareN(x, pow, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Invert(x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 409; }
+ }
+
+ public virtual int K1
+ {
+ get { return 87; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT409FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT409FieldElement);
+ }
+
+ public virtual bool Equals(SecT409FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat448.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 4090087 ^ Arrays.GetHashCode(x, 0, 7);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
new file mode 100644
index 000000000..4f573553e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT409K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT409K1Point m_infinity;
+
+ public SecT409K1Curve()
+ : base(409, 87, 0, 0)
+ {
+ this.m_infinity = new SecT409K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT409K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT409K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 409; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT409FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT409K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT409K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 409; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 87; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409K1Point.cs b/crypto/src/math/ec/custom/sec/SecT409K1Point.cs
new file mode 100644
index 000000000..71adc7af2
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409K1Point.cs
@@ -0,0 +1,296 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT409K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ //return new SecT409K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT409K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ //return new SecT409K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT409K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ //return new SecT409K1Point(curve, T, curve.B.sqrt(), withCompression);
+ return new SecT409K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ //return new SecT409K1Point(curve, A, curve.B.sqrt(), withCompression);
+ return new SecT409K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT409K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
new file mode 100644
index 000000000..9212fb5d2
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT409R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT409R1Point m_infinity;
+
+ public SecT409R1Curve()
+ : base(409, 87, 0, 0)
+ {
+ this.m_infinity = new SecT409R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F")));
+ this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT409R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT409R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 409; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT409FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT409R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT409R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 409; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 87; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409R1Point.cs b/crypto/src/math/ec/custom/sec/SecT409R1Point.cs
new file mode 100644
index 000000000..af69fe656
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409R1Point.cs
@@ -0,0 +1,282 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT409R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT409R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT409R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT409R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT409R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT409R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571Field.cs b/crypto/src/math/ec/custom/sec/SecT571Field.cs
new file mode 100644
index 000000000..fc84e336b
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571Field.cs
@@ -0,0 +1,302 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571Field
+ {
+ private const ulong M59 = ulong.MaxValue >> 5;
+
+ private const ulong RM = 0xEF7BDEF7BDEF7BDEUL;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ z[i] = x[i] ^ y[i];
+ }
+ }
+
+ private static void Add(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+ }
+ }
+
+ private static void AddBothTo(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ z[zOff + i] ^= x[xOff + i] ^ y[yOff + i];
+ }
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ for (int i = 0; i < 18; ++i)
+ {
+ zz[i] = xx[i] ^ yy[i];
+ }
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ for (int i = 1; i < 9; ++i)
+ {
+ z[i] = x[i];
+ }
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat576.FromBigInteger64(x);
+ Reduce5(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat576.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion with bases { 2, 3, 5 }
+
+ ulong[] t0 = Nat576.Create64();
+ ulong[] t1 = Nat576.Create64();
+ ulong[] t2 = Nat576.Create64();
+
+ Square(x, t2);
+
+ // 5 | 570
+ Square(t2, t0);
+ Square(t0, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 2, t1);
+ Multiply(t0, t1, t0);
+ Multiply(t0, t2, t0);
+
+ // 3 | 114
+ SquareN(t0, 5, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 5, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 38
+ SquareN(t0, 15, t1);
+ Multiply(t0, t1, t2);
+
+ // ! {2,3,5} | 19
+ SquareN(t2, 30, t0);
+ SquareN(t0, 30, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 9
+ SquareN(t0, 60, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 60, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 3
+ SquareN(t0, 180, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 180, t1);
+ Multiply(t0, t1, t0);
+
+ Multiply(t0, t2, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat576.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat576.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong xx09 = xx[9];
+ ulong u = xx[17], v = xx09;
+
+ xx09 = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+ v = xx[8] ^ (u << 5) ^ (u << 7) ^ (u << 10) ^ (u << 15);
+
+ for (int i = 16; i >= 10; --i)
+ {
+ u = xx[i];
+ z[i - 8] = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+ v = xx[i - 9] ^ (u << 5) ^ (u << 7) ^ (u << 10) ^ (u << 15);
+ }
+
+ u = xx09;
+ z[1] = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+ v = xx[0] ^ (u << 5) ^ (u << 7) ^ (u << 10) ^ (u << 15);
+
+ ulong x08 = z[8];
+ ulong t = x08 >> 59;
+ z[0] = v ^ t ^ (t << 2) ^ (t << 5) ^ (t << 10);
+ z[8] = x08 & M59;
+ }
+
+ public static void Reduce5(ulong[] z, int zOff)
+ {
+ ulong z8 = z[zOff + 8], t = z8 >> 59;
+ z[zOff ] ^= t ^ (t << 2) ^ (t << 5) ^ (t << 10);
+ z[zOff + 8] = z8 & M59;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat576.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat576.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat576.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ //for (int i = 0; i < 9; ++i)
+ //{
+ // ImplMulwAcc(x, y[i], zz, i);
+ //}
+
+ /*
+ * Precompute table of all 4-bit products of y
+ */
+ ulong[] T0 = new ulong[9 << 4];
+ Array.Copy(y, 0, T0, 9, 9);
+ // Reduce5(T0, 9);
+ int tOff = 0;
+ for (int i = 7; i > 0; --i)
+ {
+ tOff += 18;
+ Nat.ShiftUpBit64(9, T0, tOff >> 1, 0UL, T0, tOff);
+ Reduce5(T0, tOff);
+ Add(T0, 9, T0, tOff, T0, tOff + 9);
+ }
+
+ /*
+ * Second table with all 4-bit products of B shifted 4 bits
+ */
+ ulong[] T1 = new ulong[T0.Length];
+ Nat.ShiftUpBits64(T0.Length, T0, 0, 4, 0L, T1, 0);
+
+ uint MASK = 0xF;
+
+ /*
+ * Lopez-Dahab algorithm
+ */
+
+ for (int k = 56; k >= 0; k -= 8)
+ {
+ for (int j = 1; j < 9; j += 2)
+ {
+ uint aVal = (uint)(x[j] >> k);
+ uint u = aVal & MASK;
+ uint v = (aVal >> 4) & MASK;
+ AddBothTo(T0, (int)(9 * u), T1, (int)(9 * v), zz, j - 1);
+ }
+ Nat.ShiftUpBits64(16, zz, 0, 8, 0L);
+ }
+
+ for (int k = 56; k >= 0; k -= 8)
+ {
+ for (int j = 0; j < 9; j += 2)
+ {
+ uint aVal = (uint)(x[j] >> k);
+ uint u = aVal & MASK;
+ uint v = (aVal >> 4) & MASK;
+ AddBothTo(T0, (int)(9 * u), T1, (int)(9 * v), zz, j);
+ }
+ if (k > 0)
+ {
+ Nat.ShiftUpBits64(18, zz, 0, 8, 0L);
+ }
+ }
+ }
+
+ protected static void ImplMulwAcc(ulong[] xs, ulong y, ulong[] z, int zOff)
+ {
+ ulong[] u = new ulong[32];
+ //u[0] = 0;
+ u[1] = y;
+ for (int i = 2; i < 32; i += 2)
+ {
+ u[i ] = u[i >> 1] << 1;
+ u[i + 1] = u[i ] ^ y;
+ }
+
+ ulong l = 0;
+ for (int i = 0; i < 9; ++i)
+ {
+ ulong x = xs[i];
+
+ uint j = (uint)x;
+
+ l ^= u[j & 31];
+
+ ulong g, h = 0;
+ int k = 60;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 31];
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 5) > 0);
+
+ for (int p = 0; p < 4; ++p)
+ {
+ x = (x & RM) >> 1;
+ h ^= x & (ulong)(((long)y << p) >> 63);
+ }
+
+ z[zOff + i] ^= l;
+
+ l = h;
+ }
+ z[zOff + 9] ^= l;
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ Interleave.Expand64To128(x[i], zz, i << 1);
+ }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
new file mode 100644
index 000000000..5d5458412
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT571FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 571)
+ throw new ArgumentException("value invalid for SecT571FieldElement", "x");
+
+ this.x = SecT571Field.FromBigInteger(x);
+ }
+
+ public SecT571FieldElement()
+ {
+ this.x = Nat576.Create64();
+ }
+
+ protected internal SecT571FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat576.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat576.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat576.ToBigInteger64(x);
+ }
+
+ public override String FieldName
+ {
+ get { return "SecT571Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 571; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Add(x, ((SecT571FieldElement)b).x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.AddOne(x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Multiply(x, ((SecT571FieldElement)b).x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT571FieldElement)b).x;
+ ulong[] xx = ((SecT571FieldElement)x).x, yx = ((SecT571FieldElement)y).x;
+
+ ulong[] tt = Nat576.CreateExt64();
+ SecT571Field.MultiplyAddToExt(ax, bx, tt);
+ SecT571Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Reduce(tt, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Square(x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT571FieldElement)x).x, yx = ((SecT571FieldElement)y).x;
+
+ ulong[] tt = Nat576.CreateExt64();
+ SecT571Field.SquareAddToExt(ax, tt);
+ SecT571Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Reduce(tt, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat576.Create64();
+ SecT571Field.SquareN(x, pow, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Invert(x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return SquarePow(M - 1);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Ppb; }
+ }
+
+ public virtual int M
+ {
+ get { return 571; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 5; }
+ }
+
+ public virtual int K3
+ {
+ get { return 10; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT571FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT571FieldElement);
+ }
+
+ public virtual bool Equals(SecT571FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat576.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 5711052 ^ Arrays.GetHashCode(x, 0, 9);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
new file mode 100644
index 000000000..f5806f09c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT571K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT571K1Point m_infinity;
+
+ public SecT571K1Curve()
+ : base(571, 2, 5, 10)
+ {
+ this.m_infinity = new SecT571K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT571K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT571K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 571; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT571FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT571K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT571K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 571; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 5; }
+ }
+
+ public virtual int K3
+ {
+ get { return 10; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571K1Point.cs b/crypto/src/math/ec/custom/sec/SecT571K1Point.cs
new file mode 100644
index 000000000..62ed7bda0
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571K1Point.cs
@@ -0,0 +1,296 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT571K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ //return new SecT571K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT571K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ //return new SecT571K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT571K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ //return new SecT571K1Point(curve, T, curve.B.sqrt(), withCompression);
+ return new SecT571K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ //return new SecT571K1Point(curve, A, curve.B.sqrt(), withCompression);
+ return new SecT571K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT571K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
new file mode 100644
index 000000000..082afa5bd
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT571R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT571R1Point m_infinity;
+
+ internal static readonly SecT571FieldElement SecT571R1_B = new SecT571FieldElement(
+ new BigInteger(1, Hex.Decode("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A")));
+ internal static readonly SecT571FieldElement SecT571R1_B_SQRT = (SecT571FieldElement)SecT571R1_B.Sqrt();
+
+ public SecT571R1Curve()
+ : base(571, 2, 5, 10)
+ {
+ this.m_infinity = new SecT571R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = SecT571R1_B;
+ this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT571R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT571R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 571; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT571FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT571R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT571R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 571; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 5; }
+ }
+
+ public virtual int K3
+ {
+ get { return 10; }
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571R1Point.cs b/crypto/src/math/ec/custom/sec/SecT571R1Point.cs
new file mode 100644
index 000000000..0cbc98cf3
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571R1Point.cs
@@ -0,0 +1,286 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT571R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ //return new SecT571R1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ //return new SecT571R1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+ return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ //return new SecT571R1Point(curve, T, curve.B.sqrt(), withCompression);
+ return new SecT571R1Point(curve, T, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ //return new SecT571R1Point(curve, A, curve.B.sqrt(), withCompression);
+ return new SecT571R1Point(curve, A, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT571R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs b/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
index fe683726f..517881323 100644
--- a/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
@@ -10,7 +10,13 @@
return p.Curve.Infinity;
ECPoint positive = MultiplyPositive(p, k.Abs());
- return sign > 0 ? positive : positive.Negate();
+ ECPoint result = sign > 0 ? positive : positive.Negate();
+
+ /*
+ * Although the various multipliers ought not to produce invalid output under normal
+ * circumstances, a final check here is advised to guard against fault attacks.
+ */
+ return ECAlgorithms.ValidatePoint(result);
}
protected abstract ECPoint MultiplyPositive(ECPoint p, BigInteger k);
diff --git a/crypto/src/math/ec/multiplier/ReferenceMultiplier.cs b/crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
index 832fd7be4..4848ada39 100644
--- a/crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
@@ -3,35 +3,9 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
public class ReferenceMultiplier
: AbstractECMultiplier
{
- /**
- * Simple shift-and-add multiplication. Serves as reference implementation
- * to verify (possibly faster) implementations in
- * {@link org.bouncycastle.math.ec.ECPoint ECPoint}.
- *
- * @param p The point to multiply.
- * @param k The factor by which to multiply.
- * @return The result of the point multiplication <code>k * p</code>.
- */
protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
{
- ECPoint q = p.Curve.Infinity;
- int t = k.BitLength;
- if (t > 0)
- {
- if (k.TestBit(0))
- {
- q = p;
- }
- for (int i = 1; i < t; i++)
- {
- p = p.Twice();
- if (k.TestBit(i))
- {
- q = q.Add(p);
- }
- }
- }
- return q;
+ return ECAlgorithms.ReferenceMultiply(p, k);
}
}
}
diff --git a/crypto/src/math/ec/multiplier/WNafUtilities.cs b/crypto/src/math/ec/multiplier/WNafUtilities.cs
index 865b9073e..5491297d7 100644
--- a/crypto/src/math/ec/multiplier/WNafUtilities.cs
+++ b/crypto/src/math/ec/multiplier/WNafUtilities.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
private static readonly byte[] EMPTY_BYTES = new byte[0];
private static readonly int[] EMPTY_INTS = new int[0];
+ private static readonly ECPoint[] EMPTY_POINTS = new ECPoint[0];
public static int[] GenerateCompactNaf(BigInteger k)
{
@@ -368,46 +369,100 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
{
ECCurve c = p.Curve;
WNafPreCompInfo wnafPreCompInfo = GetWNafPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
-
+
+ int iniPreCompLen = 0, reqPreCompLen = 1 << System.Math.Max(0, width - 2);
+
ECPoint[] preComp = wnafPreCompInfo.PreComp;
if (preComp == null)
{
- preComp = new ECPoint[]{ p };
+ preComp = EMPTY_POINTS;
+ }
+ else
+ {
+ iniPreCompLen = preComp.Length;
}
- int preCompLen = preComp.Length;
- int reqPreCompLen = 1 << System.Math.Max(0, width - 2);
-
- if (preCompLen < reqPreCompLen)
+ if (iniPreCompLen < reqPreCompLen)
{
preComp = ResizeTable(preComp, reqPreCompLen);
- if (reqPreCompLen == 2)
+
+ if (reqPreCompLen == 1)
{
- preComp[1] = preComp[0].ThreeTimes();
+ preComp[0] = p.Normalize();
}
else
{
- ECPoint twiceP = wnafPreCompInfo.Twice;
- if (twiceP == null)
+ int curPreCompLen = iniPreCompLen;
+ if (curPreCompLen == 0)
{
- twiceP = preComp[0].Twice();
- wnafPreCompInfo.Twice = twiceP;
+ preComp[0] = p;
+ curPreCompLen = 1;
}
- for (int i = preCompLen; i < reqPreCompLen; i++)
+ ECFieldElement iso = null;
+
+ if (reqPreCompLen == 2)
{
- /*
- * Compute the new ECPoints for the precomputation array. The values 1, 3, 5, ...,
- * 2^(width-1)-1 times p are computed
- */
- preComp[i] = twiceP.Add(preComp[i - 1]);
+ preComp[1] = p.ThreeTimes();
+ }
+ else
+ {
+ ECPoint twiceP = wnafPreCompInfo.Twice, last = preComp[curPreCompLen - 1];
+ if (twiceP == null)
+ {
+ twiceP = preComp[0].Twice();
+ wnafPreCompInfo.Twice = twiceP;
+
+ /*
+ * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism
+ * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This
+ * also requires scaling the initial point's X, Y coordinates, and reversing the
+ * isomorphism as part of the subsequent normalization.
+ *
+ * NOTE: The correctness of this optimization depends on:
+ * 1) additions do not use the curve's A, B coefficients.
+ * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
+ */
+ if (ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64)
+ {
+ switch (c.CoordinateSystem)
+ {
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ iso = twiceP.GetZCoord(0);
+ twiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(),
+ twiceP.YCoord.ToBigInteger());
+
+ ECFieldElement iso2 = iso.Square(), iso3 = iso2.Multiply(iso);
+ last = last.ScaleX(iso2).ScaleY(iso3);
+
+ if (iniPreCompLen == 0)
+ {
+ preComp[0] = last;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ while (curPreCompLen < reqPreCompLen)
+ {
+ /*
+ * Compute the new ECPoints for the precomputation array. The values 1, 3,
+ * 5, ..., 2^(width-1)-1 times p are computed
+ */
+ preComp[curPreCompLen++] = last = last.Add(twiceP);
+ }
}
- }
- /*
- * Having oft-used operands in affine form makes operations faster.
- */
- c.NormalizeAll(preComp);
+ /*
+ * Having oft-used operands in affine form makes operations faster.
+ */
+ c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso);
+ }
}
wnafPreCompInfo.PreComp = preComp;
diff --git a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
index dda778eea..1e7ddae91 100644
--- a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
@@ -15,23 +15,23 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
internal static readonly string PRECOMP_NAME = "bc_wtnaf";
/**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
* by <code>k</code> using the reduced <code>τ</code>-adic NAF (RTNAF)
* method.
- * @param p The F2mPoint to multiply.
+ * @param p The AbstractF2mPoint to multiply.
* @param k The integer by which to multiply <code>k</code>.
* @return <code>p</code> multiplied by <code>k</code>.
*/
protected override ECPoint MultiplyPositive(ECPoint point, BigInteger k)
{
- if (!(point is F2mPoint))
- throw new ArgumentException("Only F2mPoint can be used in WTauNafMultiplier");
-
- F2mPoint p = (F2mPoint)point;
- F2mCurve curve = (F2mCurve)p.Curve;
- int m = curve.M;
- sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
- sbyte mu = curve.GetMu();
+ if (!(point is AbstractF2mPoint))
+ throw new ArgumentException("Only AbstractF2mPoint can be used in WTauNafMultiplier");
+
+ AbstractF2mPoint p = (AbstractF2mPoint)point;
+ AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+ int m = curve.FieldSize;
+ sbyte a = (sbyte)curve.A.ToBigInteger().IntValue;
+ sbyte mu = Tnaf.GetMu(a);
BigInteger[] s = curve.GetSi();
ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10);
@@ -40,16 +40,16 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
}
/**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
* by an element <code>λ</code> of <code><b>Z</b>[τ]</code> using
* the <code>τ</code>-adic NAF (TNAF) method.
- * @param p The F2mPoint to multiply.
+ * @param p The AbstractF2mPoint to multiply.
* @param lambda The element <code>λ</code> of
* <code><b>Z</b>[τ]</code> of which to compute the
* <code>[τ]</code>-adic NAF.
* @return <code>p</code> multiplied by <code>λ</code>.
*/
- private F2mPoint MultiplyWTnaf(F2mPoint p, ZTauElement lambda,
+ private AbstractF2mPoint MultiplyWTnaf(AbstractF2mPoint p, ZTauElement lambda,
PreCompInfo preCompInfo, sbyte a, sbyte mu)
{
ZTauElement[] alpha = (a == 0) ? Tnaf.Alpha0 : Tnaf.Alpha1;
@@ -63,20 +63,20 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
}
/**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
* by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
* using the window <code>τ</code>-adic NAF (TNAF) method, given the
* WTNAF of <code>λ</code>.
- * @param p The F2mPoint to multiply.
+ * @param p The AbstractF2mPoint to multiply.
* @param u The the WTNAF of <code>λ</code>..
* @return <code>λ * p</code>
*/
- private static F2mPoint MultiplyFromWTnaf(F2mPoint p, sbyte[] u, PreCompInfo preCompInfo)
+ private static AbstractF2mPoint MultiplyFromWTnaf(AbstractF2mPoint p, sbyte[] u, PreCompInfo preCompInfo)
{
- F2mCurve curve = (F2mCurve)p.Curve;
+ AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
sbyte a = (sbyte)curve.A.ToBigInteger().IntValue;
- F2mPoint[] pu;
+ AbstractF2mPoint[] pu;
if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo))
{
pu = Tnaf.GetPreComp(p, a);
@@ -90,26 +90,35 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
pu = ((WTauNafPreCompInfo)preCompInfo).PreComp;
}
+ // TODO Include negations in precomp (optionally) and use from here
+ AbstractF2mPoint[] puNeg = new AbstractF2mPoint[pu.Length];
+ for (int i = 0; i < pu.Length; ++i)
+ {
+ puNeg[i] = (AbstractF2mPoint)pu[i].Negate();
+ }
+
+
// q = infinity
- F2mPoint q = (F2mPoint)curve.Infinity;
+ AbstractF2mPoint q = (AbstractF2mPoint) p.Curve.Infinity;
+
+ int tauCount = 0;
for (int i = u.Length - 1; i >= 0; i--)
{
- q = Tnaf.Tau(q);
- sbyte ui = u[i];
+ ++tauCount;
+ int ui = u[i];
if (ui != 0)
{
- if (ui > 0)
- {
- q = q.AddSimple(pu[ui]);
- }
- else
- {
- // u[i] < 0
- q = q.SubtractSimple(pu[-ui]);
- }
+ q = q.TauPow(tauCount);
+ tauCount = 0;
+
+ ECPoint x = ui > 0 ? pu[ui >> 1] : puNeg[(-ui) >> 1];
+ q = (AbstractF2mPoint)q.Add(x);
}
}
-
+ if (tauCount > 0)
+ {
+ q = q.TauPow(tauCount);
+ }
return q;
}
}
diff --git a/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs b/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
index 3c18404c0..72659b3ec 100644
--- a/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
+++ b/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
@@ -8,14 +8,14 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
: PreCompInfo
{
/**
- * Array holding the precomputed <code>F2mPoint</code>s used for the
+ * Array holding the precomputed <code>AbstractF2mPoint</code>s used for the
* WTNAF multiplication in <code>
* {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
* WTauNafMultiplier.multiply()}</code>.
*/
- protected F2mPoint[] m_preComp;
+ protected AbstractF2mPoint[] m_preComp;
- public virtual F2mPoint[] PreComp
+ public virtual AbstractF2mPoint[] PreComp
{
get { return m_preComp; }
set { this.m_preComp = value; }
diff --git a/crypto/src/math/raw/Interleave.cs b/crypto/src/math/raw/Interleave.cs
new file mode 100644
index 000000000..a45ee1e08
--- /dev/null
+++ b/crypto/src/math/raw/Interleave.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Interleave
+ {
+ private const ulong M32 = 0x55555555UL;
+ private const ulong M64 = 0x5555555555555555UL;
+
+ /*
+ * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
+ * In a binary field, this operation is the same as squaring an 8 bit number.
+ */
+ //private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
+ //{
+ // 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+ // 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+ // 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+ // 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+ // 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+ // 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+ // 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+ // 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+ // 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+ // 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+ // 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+ // 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+ // 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+ // 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+ // 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+ // 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+ // 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+ // 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+ // 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+ // 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+ // 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+ // 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+ // 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+ // 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+ // 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+ // 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+ // 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+ // 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+ // 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+ // 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+ // 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+ // 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+ //};
+
+ internal static uint Expand8to16(uint x)
+ {
+ x &= 0xFFU;
+ x = (x | (x << 4)) & 0x0F0FU;
+ x = (x | (x << 2)) & 0x3333U;
+ x = (x | (x << 1)) & 0x5555U;
+ return x;
+ }
+
+ internal static uint Expand16to32(uint x)
+ {
+ x &= 0xFFFFU;
+ x = (x | (x << 8)) & 0x00FF00FFU;
+ x = (x | (x << 4)) & 0x0F0F0F0FU;
+ x = (x | (x << 2)) & 0x33333333U;
+ x = (x | (x << 1)) & 0x55555555U;
+ return x;
+ }
+
+ internal static ulong Expand32to64(uint x)
+ {
+ // "shuffle" low half to even bits and high half to odd bits
+ uint t;
+ t = (x ^ (x >> 8)) & 0x0000FF00U; x ^= (t ^ (t << 8));
+ t = (x ^ (x >> 4)) & 0x00F000F0U; x ^= (t ^ (t << 4));
+ t = (x ^ (x >> 2)) & 0x0C0C0C0CU; x ^= (t ^ (t << 2));
+ t = (x ^ (x >> 1)) & 0x22222222U; x ^= (t ^ (t << 1));
+
+ return ((x >> 1) & M32) << 32 | (x & M32);
+ }
+
+ internal static void Expand64To128(ulong x, ulong[] z, int zOff)
+ {
+ // "shuffle" low half to even bits and high half to odd bits
+ ulong t;
+ t = (x ^ (x >> 16)) & 0x00000000FFFF0000UL; x ^= (t ^ (t << 16));
+ t = (x ^ (x >> 8)) & 0x0000FF000000FF00UL; x ^= (t ^ (t << 8));
+ t = (x ^ (x >> 4)) & 0x00F000F000F000F0UL; x ^= (t ^ (t << 4));
+ t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CUL; x ^= (t ^ (t << 2));
+ t = (x ^ (x >> 1)) & 0x2222222222222222UL; x ^= (t ^ (t << 1));
+
+ z[zOff ] = (x ) & M64;
+ z[zOff + 1] = (x >> 1) & M64;
+ }
+ }
+}
diff --git a/crypto/src/math/ec/Mod.cs b/crypto/src/math/raw/Mod.cs
index 37958e57e..63467e668 100644
--- a/crypto/src/math/ec/Mod.cs
+++ b/crypto/src/math/raw/Mod.cs
@@ -4,7 +4,7 @@ using System.Diagnostics;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
-namespace Org.BouncyCastle.Math.EC
+namespace Org.BouncyCastle.Math.Raw
{
internal abstract class Mod
{
@@ -49,9 +49,9 @@ namespace Org.BouncyCastle.Math.EC
if (Nat.Gte(len, u, v))
{
- Nat.Sub(len, u, v, u);
+ Nat.SubFrom(len, v, u);
Debug.Assert((u[0] & 1) == 0);
- ac += Nat.Sub(len, a, b, a) - bc;
+ ac += Nat.SubFrom(len, b, a) - bc;
InversionStep(p, u, uvLen, a, ref ac);
if (Nat.IsOne(len, u))
{
@@ -61,9 +61,9 @@ namespace Org.BouncyCastle.Math.EC
}
else
{
- Nat.Sub(len, v, u, v);
+ Nat.SubFrom(len, u, v);
Debug.Assert((v[0] & 1) == 0);
- bc += Nat.Sub(len, b, a, b) - ac;
+ bc += Nat.SubFrom(len, a, b) - ac;
InversionStep(p, v, uvLen, b, ref bc);
if (Nat.IsOne(len, v))
{
@@ -99,13 +99,23 @@ namespace Org.BouncyCastle.Math.EC
return s;
}
+ public static void Add(uint[] p, uint[] x, uint[] y, uint[] z)
+ {
+ int len = p.Length;
+ uint c = Nat.Add(len, x, y, z);
+ if (c != 0)
+ {
+ Nat.SubFrom(len, p, z);
+ }
+ }
+
public static void Subtract(uint[] p, uint[] x, uint[] y, uint[] z)
{
int len = p.Length;
int c = Nat.Sub(len, x, y, z);
if (c != 0)
{
- Nat.Add(len, z, p, z);
+ Nat.AddTo(len, p, z);
}
}
@@ -146,11 +156,11 @@ namespace Org.BouncyCastle.Math.EC
{
if (xc < 0)
{
- xc += (int)Nat.Add(len, x, p, x);
+ xc += (int)Nat.AddTo(len, p, x);
}
else
{
- xc += Nat.Sub(len, x, p, x);
+ xc += Nat.SubFrom(len, p, x);
}
}
diff --git a/crypto/src/math/ec/Nat.cs b/crypto/src/math/raw/Nat.cs
index 17b632f26..1f9ab00ec 100644
--- a/crypto/src/math/ec/Nat.cs
+++ b/crypto/src/math/raw/Nat.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
using Org.BouncyCastle.Crypto.Utilities;
-namespace Org.BouncyCastle.Math.EC
+namespace Org.BouncyCastle.Math.Raw
{
internal abstract class Nat
{
@@ -212,6 +212,11 @@ namespace Org.BouncyCastle.Math.EC
return new uint[len];
}
+ public static ulong[] Create64(int len)
+ {
+ return new ulong[len];
+ }
+
public static int Dec(int len, uint[] z)
{
for (int i = 0; i < len; ++i)
@@ -666,6 +671,17 @@ namespace Org.BouncyCastle.Math.EC
return c >> 31;
}
+ public static ulong ShiftUpBit64(int len, ulong[] x, int xOff, ulong c, ulong[] z, int zOff)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ ulong next = x[xOff + i];
+ z[zOff + i] = (next << 1) | (c >> 63);
+ c = next;
+ }
+ return c >> 63;
+ }
+
public static uint ShiftUpBits(int len, uint[] z, int bits, uint c)
{
Debug.Assert(bits > 0 && bits < 32);
@@ -690,6 +706,18 @@ namespace Org.BouncyCastle.Math.EC
return c >> -bits;
}
+ public static ulong ShiftUpBits64(int len, ulong[] z, int zOff, int bits, ulong c)
+ {
+ Debug.Assert(bits > 0 && bits < 64);
+ for (int i = 0; i < len; ++i)
+ {
+ ulong next = z[zOff + i];
+ z[zOff + i] = (next << bits) | (c >> -bits);
+ c = next;
+ }
+ return c >> -bits;
+ }
+
public static uint ShiftUpBits(int len, uint[] x, int bits, uint c, uint[] z)
{
Debug.Assert(bits > 0 && bits < 32);
@@ -714,6 +742,18 @@ namespace Org.BouncyCastle.Math.EC
return c >> -bits;
}
+ public static ulong ShiftUpBits64(int len, ulong[] x, int xOff, int bits, ulong c, ulong[] z, int zOff)
+ {
+ Debug.Assert(bits > 0 && bits < 64);
+ for (int i = 0; i < len; ++i)
+ {
+ ulong next = x[xOff + i];
+ z[zOff + i] = (next << bits) | (c >> -bits);
+ c = next;
+ }
+ return c >> -bits;
+ }
+
public static void Square(int len, uint[] x, uint[] zz)
{
int extLen = len << 1;
diff --git a/crypto/src/math/raw/Nat128.cs b/crypto/src/math/raw/Nat128.cs
new file mode 100644
index 000000000..819c52062
--- /dev/null
+++ b/crypto/src/math/raw/Nat128.cs
@@ -0,0 +1,856 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat128
+ {
+ private const ulong M = 0xFFFFFFFFUL;
+
+ public static uint Add(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+ {
+ ulong c = cIn;
+ c += (ulong)x[xOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+ {
+ ulong c = 0;
+ c += (ulong)u[uOff + 0] + v[vOff + 0];
+ u[uOff + 0] = (uint)c;
+ v[vOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 1] + v[vOff + 1];
+ u[uOff + 1] = (uint)c;
+ v[vOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 2] + v[vOff + 2];
+ u[uOff + 2] = (uint)c;
+ v[vOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 3] + v[vOff + 3];
+ u[uOff + 3] = (uint)c;
+ v[vOff + 3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static void Copy(uint[] x, uint[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ }
+
+ public static uint[] Create()
+ {
+ return new uint[4];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[2];
+ }
+
+ public static uint[] CreateExt()
+ {
+ return new uint[8];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[4];
+ }
+
+ public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ bool pos = Gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ Sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
+ {
+ Sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static bool Eq(uint[] x, uint[] y)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 1; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 128)
+ throw new ArgumentException();
+
+ uint[] z = Create();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (uint)x.IntValue;
+ x = x.ShiftRight(32);
+ }
+ return z;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 128)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static uint GetBit(uint[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ if ((bit & 127) != bit)
+ {
+ return 0;
+ }
+ int w = bit >> 5;
+ int b = bit & 31;
+ return (x[w] >> b) & 1;
+ }
+
+ public static bool Gte(uint[] x, uint[] y)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ uint x_i = x[i], y_i = y[i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ uint x_i = x[xOff + i], y_i = y[yOff + i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool IsOne(uint[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < 4; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 2; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero(uint[] x)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 2; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+
+ {
+ ulong c = 0, x_0 = x[0];
+ c += x_0 * y_0;
+ zz[0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[3] = (uint)c;
+ c >>= 32;
+ zz[4] = (uint)c;
+ }
+
+ for (int i = 1; i < 4; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ zz[i + 4] = (uint)c;
+ }
+ }
+
+ public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+
+ {
+ ulong c = 0, x_0 = x[xOff + 0];
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 4] = (uint)c;
+ }
+
+ for (int i = 1; i < 4; ++i)
+ {
+ ++zzOff;
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 4] = (uint)c;
+ }
+ }
+
+ public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+
+ ulong zc = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += zc + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ zc = c >> 32;
+ }
+ return (uint)zc;
+ }
+
+ public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+
+ ulong zc = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += zc + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ zc = c >> 32;
+ ++zzOff;
+ }
+ return (uint)zc;
+ }
+
+ public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ Debug.Assert(w >> 31 == 0);
+
+ ulong c = 0, wVal = w;
+ ulong x0 = x[xOff + 0];
+ c += wVal * x0 + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong x1 = x[xOff + 1];
+ c += wVal * x1 + x0 + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ ulong x2 = x[xOff + 2];
+ c += wVal * x2 + x1 + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ ulong x3 = x[xOff + 3];
+ c += wVal * x3 + x2 + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += x3;
+ return c;
+ }
+
+ public static uint MulWordAddExt(uint x, uint[] yy, int yyOff, uint[] zz, int zzOff)
+ {
+ Debug.Assert(yyOff <= 4);
+ Debug.Assert(zzOff <= 4);
+
+ ulong c = 0, xVal = x;
+ c += xVal * yy[yyOff + 0] + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 1] + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 2] + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 3] + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 0);
+ ulong c = 0, xVal = x;
+ ulong y00 = y & M;
+ c += xVal * y00 + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong y01 = y >> 32;
+ c += xVal * y01 + y00 + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += y01 + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 1);
+ ulong c = 0, yVal = y;
+ c += yVal * x + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += yVal + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 3);
+ }
+
+ public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 1);
+ ulong c = 0, xVal = x;
+ c += xVal * y + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * (y >> 32) + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 3);
+ }
+
+ public static uint MulWordsAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 2);
+
+ ulong c = 0, xVal = x, yVal = y;
+ c += yVal * xVal + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 2);
+ }
+
+ public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < 4);
+ return (uint)c;
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ ulong x_0 = x[0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 3, j = 8;
+ do
+ {
+ ulong xVal = x[i--];
+ ulong p = xVal * xVal;
+ zz[--j] = (c << 31) | (uint)(p >> 33);
+ zz[--j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[1];
+ ulong zz_2 = zz[2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[2];
+ ulong zz_3 = zz[3];
+ ulong zz_4 = zz[4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[3];
+ ulong zz_5 = zz[5];
+ ulong zz_6 = zz[6];
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_6 += zz_5 >> 32;
+ }
+
+ w = (uint)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[7] + (uint)(zz_6 >> 32);
+ zz[7] = (w << 1) | c;
+ }
+
+ public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+ {
+ ulong x_0 = x[xOff + 0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 3, j = 8;
+ do
+ {
+ ulong xVal = x[xOff + i--];
+ ulong p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+ zz[zzOff + --j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[zzOff + 0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[xOff + 1];
+ ulong zz_2 = zz[zzOff + 2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[xOff + 2];
+ ulong zz_3 = zz[zzOff + 3];
+ ulong zz_4 = zz[zzOff + 4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[xOff + 3];
+ ulong zz_5 = zz[zzOff + 5];
+ ulong zz_6 = zz[zzOff + 6];
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_6 += zz_5 >> 32;
+ }
+
+ w = (uint)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[zzOff + 7] + (uint)(zz_6 >> 32);
+ zz[zzOff + 7] = (w << 1) | c;
+ }
+
+ public static int Sub(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)x[xOff + 0] - y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 1] - y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 2] - y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 3] - y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)z[zOff + 0] - x[xOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - x[xOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 2] - x[xOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 3] - x[xOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static BigInteger ToBigInteger(uint[] x)
+ {
+ byte[] bs = new byte[16];
+ for (int i = 0; i < 4; ++i)
+ {
+ uint x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.UInt32_To_BE(x_i, bs, (3 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[16];
+ for (int i = 0; i < 2; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0UL)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (1 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void Zero(uint[] z)
+ {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 0;
+ z[3] = 0;
+ }
+ }
+}
diff --git a/crypto/src/math/raw/Nat160.cs b/crypto/src/math/raw/Nat160.cs
new file mode 100644
index 000000000..153ac0a43
--- /dev/null
+++ b/crypto/src/math/raw/Nat160.cs
@@ -0,0 +1,874 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat160
+ {
+ private const ulong M = 0xFFFFFFFFUL;
+
+ public static uint Add(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+ {
+ ulong c = cIn;
+ c += (ulong)x[xOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + z[zOff + 5];
+ return (uint)c;
+ }
+
+ public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+ {
+ ulong c = 0;
+ c += (ulong)u[uOff + 0] + v[vOff + 0];
+ u[uOff + 0] = (uint)c;
+ v[vOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 1] + v[vOff + 1];
+ u[uOff + 1] = (uint)c;
+ v[vOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 2] + v[vOff + 2];
+ u[uOff + 2] = (uint)c;
+ v[vOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 3] + v[vOff + 3];
+ u[uOff + 3] = (uint)c;
+ v[vOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 4] + v[vOff + 4];
+ u[uOff + 4] = (uint)c;
+ v[vOff + 4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static void Copy(uint[] x, uint[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ }
+
+ public static uint[] Create()
+ {
+ return new uint[5];
+ }
+
+ public static uint[] CreateExt()
+ {
+ return new uint[10];
+ }
+
+ public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ bool pos = Gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ Sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
+ {
+ Sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static bool Eq(uint[] x, uint[] y)
+ {
+ for (int i = 4; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 160)
+ throw new ArgumentException();
+
+ uint[] z = Create();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (uint)x.IntValue;
+ x = x.ShiftRight(32);
+ }
+ return z;
+ }
+
+ public static uint GetBit(uint[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ int w = bit >> 5;
+ if (w < 0 || w >= 5)
+ {
+ return 0;
+ }
+ int b = bit & 31;
+ return (x[w] >> b) & 1;
+ }
+
+ public static bool Gte(uint[] x, uint[] y)
+ {
+ for (int i = 4; i >= 0; --i)
+ {
+ uint x_i = x[i], y_i = y[i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+ {
+ for (int i = 4; i >= 0; --i)
+ {
+ uint x_i = x[xOff + i], y_i = y[yOff + i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool IsOne(uint[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < 5; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero(uint[] x)
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+
+ {
+ ulong c = 0, x_0 = x[0];
+ c += x_0 * y_0;
+ zz[0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[4] = (uint)c;
+ c >>= 32;
+ zz[5] = (uint)c;
+ }
+
+ for (int i = 1; i < 5; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ zz[i + 5] = (uint)c;
+ }
+ }
+
+ public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+
+ {
+ ulong c = 0, x_0 = x[xOff + 0];
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 5] = (uint)c;
+ }
+
+ for (int i = 1; i < 5; ++i)
+ {
+ ++zzOff;
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 5] = (uint)c;
+ }
+ }
+
+ public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+
+ ulong zc = 0;
+ for (int i = 0; i < 5; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ c += zc + zz[i + 5];
+ zz[i + 5] = (uint)c;
+ zc = c >> 32;
+ }
+ return (uint)zc;
+ }
+
+ public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+
+ ulong zc = 0;
+ for (int i = 0; i < 5; ++i)
+ {
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += zc + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ zc = c >> 32;
+ ++zzOff;
+ }
+ return (uint)zc;
+ }
+
+ public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ Debug.Assert(w >> 31 == 0);
+
+ ulong c = 0, wVal = w;
+ ulong x0 = x[xOff + 0];
+ c += wVal * x0 + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong x1 = x[xOff + 1];
+ c += wVal * x1 + x0 + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ ulong x2 = x[xOff + 2];
+ c += wVal * x2 + x1 + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ ulong x3 = x[xOff + 3];
+ c += wVal * x3 + x2 + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ ulong x4 = x[xOff + 4];
+ c += wVal * x4 + x3 + y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += x4;
+ return c;
+ }
+
+ public static uint MulWordAddExt(uint x, uint[] yy, int yyOff, uint[] zz, int zzOff)
+ {
+ Debug.Assert(yyOff <= 5);
+ Debug.Assert(zzOff <= 5);
+
+ ulong c = 0, xVal = x;
+ c += xVal * yy[yyOff + 0] + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 1] + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 2] + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 3] + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 4] + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 1);
+ ulong c = 0, xVal = x;
+ ulong y00 = y & M;
+ c += xVal * y00 + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong y01 = y >> 32;
+ c += xVal * y01 + y00 + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += y01 + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 4);
+ }
+
+ public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 2);
+ ulong c = 0, yVal = y;
+ c += yVal * x + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += yVal + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 3);
+ }
+
+ public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 2);
+ ulong c = 0, xVal = x;
+ c += xVal * y + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * (y >> 32) + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 3);
+ }
+
+ public static uint MulWordsAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 3);
+
+ ulong c = 0, xVal = x, yVal = y;
+ c += yVal * xVal + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 2);
+ }
+
+ public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < 5);
+ return (uint)c;
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ ulong x_0 = x[0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 4, j = 10;
+ do
+ {
+ ulong xVal = x[i--];
+ ulong p = xVal * xVal;
+ zz[--j] = (c << 31) | (uint)(p >> 33);
+ zz[--j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[1];
+ ulong zz_2 = zz[2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[2];
+ ulong zz_3 = zz[3];
+ ulong zz_4 = zz[4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[3];
+ ulong zz_5 = zz[5];
+ ulong zz_6 = zz[6];
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[4];
+ ulong zz_7 = zz[7];
+ ulong zz_8 = zz[8];
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_8 += zz_7 >> 32;
+ }
+
+ w = (uint)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_7;
+ zz[7] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_8;
+ zz[8] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[9] + (uint)(zz_8 >> 32);
+ zz[9] = (w << 1) | c;
+ }
+
+ public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+ {
+ ulong x_0 = x[xOff + 0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 4, j = 10;
+ do
+ {
+ ulong xVal = x[xOff + i--];
+ ulong p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+ zz[zzOff + --j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[zzOff + 0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[xOff + 1];
+ ulong zz_2 = zz[zzOff + 2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[xOff + 2];
+ ulong zz_3 = zz[zzOff + 3];
+ ulong zz_4 = zz[zzOff + 4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[xOff + 3];
+ ulong zz_5 = zz[zzOff + 5];
+ ulong zz_6 = zz[zzOff + 6];
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[xOff + 4];
+ ulong zz_7 = zz[zzOff + 7];
+ ulong zz_8 = zz[zzOff + 8];
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_8 += zz_7 >> 32;
+ }
+
+ w = (uint)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_7;
+ zz[zzOff + 7] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_8;
+ zz[zzOff + 8] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[zzOff + 9] + (uint)(zz_8 >> 32);
+ zz[zzOff + 9] = (w << 1) | c;
+ }
+
+ public static int Sub(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)x[xOff + 0] - y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 1] - y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 2] - y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 3] - y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 4] - y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)z[zOff + 0] - x[xOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - x[xOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 2] - x[xOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 3] - x[xOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 4] - x[xOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static BigInteger ToBigInteger(uint[] x)
+ {
+ byte[] bs = new byte[20];
+ for (int i = 0; i < 5; ++i)
+ {
+ uint x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.UInt32_To_BE(x_i, bs, (4 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void Zero(uint[] z)
+ {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 0;
+ z[3] = 0;
+ z[4] = 0;
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat192.cs b/crypto/src/math/raw/Nat192.cs
index 94d7ed17c..4797609ee 100644
--- a/crypto/src/math/ec/custom/sec/Nat192.cs
+++ b/crypto/src/math/raw/Nat192.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
using Org.BouncyCastle.Crypto.Utilities;
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
{
internal abstract class Nat192
{
@@ -145,16 +145,33 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
z[5] = x[5];
}
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ }
+
public static uint[] Create()
{
return new uint[6];
}
+ public static ulong[] Create64()
+ {
+ return new ulong[3];
+ }
+
public static uint[] CreateExt()
{
return new uint[12];
}
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[6];
+ }
+
public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
{
bool pos = Gte(x, xOff, y, yOff);
@@ -179,6 +196,18 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return true;
}
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 2; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static uint[] FromBigInteger(BigInteger x)
{
if (x.SignValue < 0 || x.BitLength > 192)
@@ -194,6 +223,21 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return z;
}
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 192)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
public static uint GetBit(uint[] x, int bit)
{
if (bit == 0)
@@ -251,6 +295,22 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return true;
}
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 3; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static bool IsZero(uint[] x)
{
for (int i = 0; i < 6; ++i)
@@ -263,6 +323,18 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return true;
}
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 3; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static void Mul(uint[] x, uint[] y, uint[] zz)
{
ulong y_0 = y[0];
@@ -949,6 +1021,20 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new BigInteger(1, bs);
}
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[24];
+ for (int i = 0; i < 3; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (2 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
public static void Zero(uint[] z)
{
z[0] = 0;
diff --git a/crypto/src/math/ec/custom/sec/Nat224.cs b/crypto/src/math/raw/Nat224.cs
index d5b916a54..940e930ac 100644
--- a/crypto/src/math/ec/custom/sec/Nat224.cs
+++ b/crypto/src/math/raw/Nat224.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
using Org.BouncyCastle.Crypto.Utilities;
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
{
internal abstract class Nat224
{
diff --git a/crypto/src/math/ec/custom/sec/Nat256.cs b/crypto/src/math/raw/Nat256.cs
index bd2d6da47..19455031a 100644
--- a/crypto/src/math/ec/custom/sec/Nat256.cs
+++ b/crypto/src/math/raw/Nat256.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
using Org.BouncyCastle.Crypto.Utilities;
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
{
internal abstract class Nat256
{
@@ -239,16 +239,34 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
z[7] = x[7];
}
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
public static uint[] Create()
{
return new uint[8];
}
+ public static ulong[] Create64()
+ {
+ return new ulong[4];
+ }
+
public static uint[] CreateExt()
{
return new uint[16];
}
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[8];
+ }
+
public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
{
bool pos = Gte(x, xOff, y, yOff);
@@ -273,6 +291,18 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return true;
}
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static uint[] FromBigInteger(BigInteger x)
{
if (x.SignValue < 0 || x.BitLength > 256)
@@ -288,6 +318,21 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return z;
}
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 256)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
public static uint GetBit(uint[] x, int bit)
{
if (bit == 0)
@@ -345,6 +390,22 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return true;
}
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 4; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static bool IsZero(uint[] x)
{
for (int i = 0; i < 8; ++i)
@@ -357,6 +418,18 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return true;
}
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static void Mul(uint[] x, uint[] y, uint[] zz)
{
ulong y_0 = y[0];
@@ -1285,6 +1358,20 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
return new BigInteger(1, bs);
}
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[32];
+ for (int i = 0; i < 4; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (3 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
public static void Zero(uint[] z)
{
z[0] = 0;
diff --git a/crypto/src/math/raw/Nat320.cs b/crypto/src/math/raw/Nat320.cs
new file mode 100644
index 000000000..c7daa71e2
--- /dev/null
+++ b/crypto/src/math/raw/Nat320.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat320
+ {
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[5];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[10];
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 4; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 320)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 5; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[40];
+ for (int i = 0; i < 5; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (4 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat384.cs b/crypto/src/math/raw/Nat384.cs
index dd93e68b6..ed1c47e8c 100644
--- a/crypto/src/math/ec/custom/sec/Nat384.cs
+++ b/crypto/src/math/raw/Nat384.cs
@@ -1,7 +1,7 @@
using System;
using System.Diagnostics;
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
{
internal abstract class Nat384
{
diff --git a/crypto/src/math/raw/Nat448.cs b/crypto/src/math/raw/Nat448.cs
new file mode 100644
index 000000000..52a253f1b
--- /dev/null
+++ b/crypto/src/math/raw/Nat448.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat448
+ {
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[7];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[14];
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 6; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 448)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 7; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 7; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[56];
+ for (int i = 0; i < 7; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (6 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+ }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat512.cs b/crypto/src/math/raw/Nat512.cs
index 46e10f995..a9ef2b3b6 100644
--- a/crypto/src/math/ec/custom/sec/Nat512.cs
+++ b/crypto/src/math/raw/Nat512.cs
@@ -1,7 +1,7 @@
using System;
using System.Diagnostics;
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
{
internal abstract class Nat512
{
diff --git a/crypto/src/math/raw/Nat576.cs b/crypto/src/math/raw/Nat576.cs
new file mode 100644
index 000000000..813fb86be
--- /dev/null
+++ b/crypto/src/math/raw/Nat576.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat576
+ {
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ z[7] = x[7];
+ z[8] = x[8];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[9];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[18];
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 8; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 576)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 9; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[72];
+ for (int i = 0; i < 9; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (8 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+ }
+}
diff --git a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
index f46f99d37..2a2e63961 100644
--- a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
+++ b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
@@ -3,10 +3,13 @@ using System.Collections;
using System.Diagnostics;
using System.IO;
+using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
@@ -79,70 +82,133 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
: EncMethod
{
internal PgpPublicKey pubKey;
- internal BigInteger[] data;
+ internal byte[][] data;
- internal PubMethod(
- PgpPublicKey pubKey)
+ internal PubMethod(PgpPublicKey pubKey)
{
this.pubKey = pubKey;
}
- public override void AddSessionInfo(
- byte[] si,
+ public override void AddSessionInfo(
+ byte[] sessionInfo,
SecureRandom random)
{
- IBufferedCipher c;
+ byte[] encryptedSessionInfo = EncryptSessionInfo(sessionInfo, random);
+
+ this.data = ProcessSessionInfo(encryptedSessionInfo);
+ }
- switch (pubKey.Algorithm)
+ private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random)
+ {
+ if (pubKey.Algorithm != PublicKeyAlgorithmTag.ECDH)
{
- case PublicKeyAlgorithmTag.RsaEncrypt:
- case PublicKeyAlgorithmTag.RsaGeneral:
- c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
- break;
- case PublicKeyAlgorithmTag.ElGamalEncrypt:
- case PublicKeyAlgorithmTag.ElGamalGeneral:
- c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
- break;
- case PublicKeyAlgorithmTag.Dsa:
- throw new PgpException("Can't use DSA for encryption.");
- case PublicKeyAlgorithmTag.ECDsa:
- throw new PgpException("Can't use ECDSA for encryption.");
- default:
- throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
+ IBufferedCipher c;
+ switch (pubKey.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ throw new PgpException("Can't use DSA for encryption.");
+ case PublicKeyAlgorithmTag.ECDsa:
+ throw new PgpException("Can't use ECDSA for encryption.");
+ default:
+ throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
+ }
+
+ AsymmetricKeyParameter akp = pubKey.GetKey();
+ c.Init(true, new ParametersWithRandom(akp, random));
+ return c.DoFinal(sessionInfo);
}
- AsymmetricKeyParameter akp = pubKey.GetKey();
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key;
+
+ // Generate the ephemeral key pair
+ IAsymmetricCipherKeyPairGenerator gen = GeneratorUtilities.GetKeyPairGenerator("ECDH");
+ gen.Init(new ECKeyGenerationParameters(ecKey.CurveOid, random));
+
+ AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair();
+ ECPrivateKeyParameters ephPriv = (ECPrivateKeyParameters)ephKp.Private;
+ ECPublicKeyParameters ephPub = (ECPublicKeyParameters)ephKp.Public;
+
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey.GetKey();
+ ECPoint S = pub.Q.Multiply(ephPriv.D).Normalize();
+
+ KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, S));
+
+ IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm);
+ w.Init(true, new ParametersWithRandom(key, random));
+
+ byte[] paddedSessionData = PgpPad.PadSessionData(sessionInfo);
+
+ byte[] C = w.Wrap(paddedSessionData, 0, paddedSessionData.Length);
+ byte[] VB = new MPInteger(new BigInteger(1, ephPub.Q.GetEncoded(false))).GetEncoded();
- c.Init(true, new ParametersWithRandom(akp, random));
+ byte[] rv = new byte[VB.Length + 1 + C.Length];
- byte[] encKey = c.DoFinal(si);
+ Array.Copy(VB, 0, rv, 0, VB.Length);
+ rv[VB.Length] = (byte)C.Length;
+ Array.Copy(C, 0, rv, VB.Length + 1, C.Length);
- switch (pubKey.Algorithm)
+ return rv;
+ }
+
+ private byte[][] ProcessSessionInfo(byte[] encryptedSessionInfo)
+ {
+ byte[][] data;
+
+ switch (pubKey.Algorithm)
{
- case PublicKeyAlgorithmTag.RsaEncrypt:
- case PublicKeyAlgorithmTag.RsaGeneral:
- data = new BigInteger[]{ new BigInteger(1, encKey) };
- break;
- case PublicKeyAlgorithmTag.ElGamalEncrypt:
- case PublicKeyAlgorithmTag.ElGamalGeneral:
- int halfLength = encKey.Length / 2;
- data = new BigInteger[]
- {
- new BigInteger(1, encKey, 0, halfLength),
- new BigInteger(1, encKey, halfLength, halfLength)
- };
- break;
- default:
- throw new PgpException("unknown asymmetric algorithm: " + encAlgorithm);
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ data = new byte[][] { ConvertToEncodedMpi(encryptedSessionInfo) };
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ int halfLength = encryptedSessionInfo.Length / 2;
+ byte[] b1 = new byte[halfLength];
+ byte[] b2 = new byte[halfLength];
+
+ Array.Copy(encryptedSessionInfo, 0, b1, 0, halfLength);
+ Array.Copy(encryptedSessionInfo, halfLength, b2, 0, halfLength);
+
+ data = new byte[][] {
+ ConvertToEncodedMpi(b1),
+ ConvertToEncodedMpi(b2),
+ };
+ break;
+ case PublicKeyAlgorithmTag.ECDH:
+ data = new byte[][]{ encryptedSessionInfo };
+ break;
+ default:
+ throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
}
+
+ return data;
}
- public override void Encode(BcpgOutputStream pOut)
+ private byte[] ConvertToEncodedMpi(byte[] encryptedSessionInfo)
+ {
+ try
+ {
+ return new MPInteger(new BigInteger(1, encryptedSessionInfo)).GetEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("Invalid MPI encoding: " + e.Message, e);
+ }
+ }
+
+ public override void Encode(BcpgOutputStream pOut)
{
- PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(
- pubKey.KeyId, pubKey.Algorithm, data);
+ PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(pubKey.KeyId, pubKey.Algorithm, data);
- pOut.WritePacket(pk);
+ pOut.WritePacket(pk);
}
}
diff --git a/crypto/src/openpgp/PgpKeyPair.cs b/crypto/src/openpgp/PgpKeyPair.cs
index 6efb03a42..9cf78fa6f 100644
--- a/crypto/src/openpgp/PgpKeyPair.cs
+++ b/crypto/src/openpgp/PgpKeyPair.cs
@@ -34,7 +34,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
DateTime time)
{
this.pub = new PgpPublicKey(algorithm, pubKey, time);
- this.priv = new PgpPrivateKey(privKey, pub.KeyId);
+ this.priv = new PgpPrivateKey(pub.KeyId, pub.PublicKeyPacket, privKey);
}
/// <summary>Create a key pair from a PgpPrivateKey and a PgpPublicKey.</summary>
diff --git a/crypto/src/openpgp/PgpPad.cs b/crypto/src/openpgp/PgpPad.cs
new file mode 100644
index 000000000..48f7f2f44
--- /dev/null
+++ b/crypto/src/openpgp/PgpPad.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// <remarks>Padding functions.</remarks>
+ public sealed class PgpPad
+ {
+ private PgpPad()
+ {
+ }
+
+ public static byte[] PadSessionData(byte[] sessionInfo)
+ {
+ byte[] result = new byte[40];
+
+ Array.Copy(sessionInfo, 0, result, 0, sessionInfo.Length);
+
+ byte padValue = (byte)(result.Length - sessionInfo.Length);
+
+ for (int i = sessionInfo.Length; i != result.Length; i++)
+ {
+ result[i] = padValue;
+ }
+
+ return result;
+ }
+
+ public static byte[] UnpadSessionData(byte[] encoded)
+ {
+ byte padValue = encoded[encoded.Length - 1];
+
+ for (int i = encoded.Length - padValue; i != encoded.Length; i++)
+ {
+ if (encoded[i] != padValue)
+ throw new PgpException("bad padding found in session data");
+ }
+
+ byte[] taggedKey = new byte[encoded.Length - padValue];
+
+ Array.Copy(encoded, 0, taggedKey, 0, taggedKey.Length);
+
+ return taggedKey;
+ }
+ }
+}
diff --git a/crypto/src/openpgp/PgpPrivateKey.cs b/crypto/src/openpgp/PgpPrivateKey.cs
index 154c87cd7..61487a5b2 100644
--- a/crypto/src/openpgp/PgpPrivateKey.cs
+++ b/crypto/src/openpgp/PgpPrivateKey.cs
@@ -7,33 +7,42 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
/// <remarks>General class to contain a private key for use with other OpenPGP objects.</remarks>
public class PgpPrivateKey
{
- private readonly long keyId;
+ private readonly long keyID;
+ private readonly PublicKeyPacket publicKeyPacket;
private readonly AsymmetricKeyParameter privateKey;
- /// <summary>
- /// Create a PgpPrivateKey from a regular private key and the ID of its
- /// associated public key.
+ /// <summary>
+ /// Create a PgpPrivateKey from a keyID, the associated public data packet, and a regular private key.
/// </summary>
- /// <param name="privateKey">Private key to use.</param>
- /// <param name="keyId">ID of the corresponding public key.</param>
- public PgpPrivateKey(
- AsymmetricKeyParameter privateKey,
- long keyId)
+ /// <param name="keyID">ID of the corresponding public key.</param>
+ /// <param name="publicKeyPacket">the public key data packet to be associated with this private key.</param>
+ /// <param name="privateKey">the private key data packet to be associated with this private key.</param>
+ public PgpPrivateKey(
+ long keyID,
+ PublicKeyPacket publicKeyPacket,
+ AsymmetricKeyParameter privateKey)
{
if (!privateKey.IsPrivate)
throw new ArgumentException("Expected a private key", "privateKey");
- this.privateKey = privateKey;
- this.keyId = keyId;
+ this.keyID = keyID;
+ this.publicKeyPacket = publicKeyPacket;
+ this.privateKey = privateKey;
}
- /// <summary>The keyId associated with the contained private key.</summary>
+ /// <summary>The keyId associated with the contained private key.</summary>
public long KeyId
{
- get { return keyId; }
+ get { return keyID; }
}
- /// <summary>The contained private key.</summary>
+ /// <summary>The public key packet associated with this private key, if available.</summary>
+ public PublicKeyPacket PublicKeyPacket
+ {
+ get { return publicKeyPacket; }
+ }
+
+ /// <summary>The contained private key.</summary>
public AsymmetricKeyParameter Key
{
get { return privateKey; }
diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs
index b0720146c..904e29913 100644
--- a/crypto/src/openpgp/PgpPublicKey.cs
+++ b/crypto/src/openpgp/PgpPublicKey.cs
@@ -2,88 +2,107 @@ using System;
using System.Collections;
using System.IO;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Collections;
namespace Org.BouncyCastle.Bcpg.OpenPgp
{
- /// <remarks>General class to handle a PGP public key object.</remarks>
+ /// <remarks>General class to handle a PGP public key object.</remarks>
public class PgpPublicKey
{
- private static readonly int[] MasterKeyCertificationTypes = new int[]
- {
- PgpSignature.PositiveCertification,
- PgpSignature.CasualCertification,
- PgpSignature.NoCertification,
- PgpSignature.DefaultCertification
- };
-
- private long keyId;
- private byte[] fingerprint;
- private int keyStrength;
-
- internal PublicKeyPacket publicPk;
- internal TrustPacket trustPk;
- internal IList keySigs = Platform.CreateArrayList();
- internal IList ids = Platform.CreateArrayList();
- internal IList idTrusts = Platform.CreateArrayList();
- internal IList idSigs = Platform.CreateArrayList();
- internal IList subSigs;
-
- private void Init()
+ public static byte[] CalculateFingerprint(PublicKeyPacket publicPk)
{
IBcpgKey key = publicPk.Key;
+ IDigest digest;
- if (publicPk.Version <= 3)
+ if (publicPk.Version <= 3)
{
- RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key;
+ RsaPublicBcpgKey rK = (RsaPublicBcpgKey)key;
- this.keyId = rK.Modulus.LongValue;
-
- try
+ try
{
- IDigest digest = DigestUtilities.GetDigest("MD5");
-
- byte[] bytes = rK.Modulus.ToByteArrayUnsigned();
- digest.BlockUpdate(bytes, 0, bytes.Length);
-
- bytes = rK.PublicExponent.ToByteArrayUnsigned();
- digest.BlockUpdate(bytes, 0, bytes.Length);
-
- this.fingerprint = DigestUtilities.DoFinal(digest);
+ digest = DigestUtilities.GetDigest("MD5");
+ UpdateDigest(digest, rK.Modulus);
+ UpdateDigest(digest, rK.PublicExponent);
}
- //catch (NoSuchAlgorithmException)
- catch (Exception e)
+ catch (Exception e)
{
- throw new IOException("can't find MD5", e);
+ throw new PgpException("can't encode key components: " + e.Message, e);
}
-
- this.keyStrength = rK.Modulus.BitLength;
}
else
{
- byte[] kBytes = publicPk.GetEncodedContents();
-
- try
+ try
{
- IDigest digest = DigestUtilities.GetDigest("SHA1");
+ byte[] kBytes = publicPk.GetEncodedContents();
- digest.Update(0x99);
+ digest = DigestUtilities.GetDigest("SHA1");
+
+ digest.Update(0x99);
digest.Update((byte)(kBytes.Length >> 8));
digest.Update((byte)kBytes.Length);
digest.BlockUpdate(kBytes, 0, kBytes.Length);
- this.fingerprint = DigestUtilities.DoFinal(digest);
}
catch (Exception e)
{
- throw new IOException("can't find SHA1", e);
+ throw new PgpException("can't encode key components: " + e.Message, e);
}
+ }
+
+ return DigestUtilities.DoFinal(digest);
+ }
+
+ private static void UpdateDigest(IDigest d, BigInteger b)
+ {
+ byte[] bytes = b.ToByteArrayUnsigned();
+ d.BlockUpdate(bytes, 0, bytes.Length);
+ }
+
+ private static readonly int[] MasterKeyCertificationTypes = new int[]
+ {
+ PgpSignature.PositiveCertification,
+ PgpSignature.CasualCertification,
+ PgpSignature.NoCertification,
+ PgpSignature.DefaultCertification
+ };
- this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56)
+ private long keyId;
+ private byte[] fingerprint;
+ private int keyStrength;
+
+ internal PublicKeyPacket publicPk;
+ internal TrustPacket trustPk;
+ internal IList keySigs = Platform.CreateArrayList();
+ internal IList ids = Platform.CreateArrayList();
+ internal IList idTrusts = Platform.CreateArrayList();
+ internal IList idSigs = Platform.CreateArrayList();
+ internal IList subSigs;
+
+ private void Init()
+ {
+ IBcpgKey key = publicPk.Key;
+
+ this.fingerprint = CalculateFingerprint(publicPk);
+
+ if (publicPk.Version <= 3)
+ {
+ RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key;
+
+ this.keyId = rK.Modulus.LongValue;
+ this.keyStrength = rK.Modulus.BitLength;
+ }
+ else
+ {
+ this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56)
| ((ulong)fingerprint[fingerprint.Length - 7] << 48)
| ((ulong)fingerprint[fingerprint.Length - 6] << 40)
| ((ulong)fingerprint[fingerprint.Length - 5] << 32)
@@ -92,7 +111,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
| ((ulong)fingerprint[fingerprint.Length - 2] << 8)
| (ulong)fingerprint[fingerprint.Length - 1]);
- if (key is RsaPublicBcpgKey)
+ if (key is RsaPublicBcpgKey)
{
this.keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength;
}
@@ -104,60 +123,81 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
{
this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength;
}
+ else if (key is ECPublicBcpgKey)
+ {
+ this.keyStrength = ECKeyPairGenerator.FindECCurveByOid(((ECPublicBcpgKey)key).CurveOid).Curve.FieldSize;
+ }
}
}
- /// <summary>
- /// Create a PgpPublicKey from the passed in lightweight one.
- /// </summary>
- /// <remarks>
- /// Note: the time passed in affects the value of the key's keyId, so you probably only want
- /// to do this once for a lightweight key, or make sure you keep track of the time you used.
- /// </remarks>
- /// <param name="algorithm">Asymmetric algorithm type representing the public key.</param>
- /// <param name="pubKey">Actual public key to associate.</param>
- /// <param name="time">Date of creation.</param>
- /// <exception cref="ArgumentException">If <c>pubKey</c> is not public.</exception>
- /// <exception cref="PgpException">On key creation problem.</exception>
+ /// <summary>
+ /// Create a PgpPublicKey from the passed in lightweight one.
+ /// </summary>
+ /// <remarks>
+ /// Note: the time passed in affects the value of the key's keyId, so you probably only want
+ /// to do this once for a lightweight key, or make sure you keep track of the time you used.
+ /// </remarks>
+ /// <param name="algorithm">Asymmetric algorithm type representing the public key.</param>
+ /// <param name="pubKey">Actual public key to associate.</param>
+ /// <param name="time">Date of creation.</param>
+ /// <exception cref="ArgumentException">If <c>pubKey</c> is not public.</exception>
+ /// <exception cref="PgpException">On key creation problem.</exception>
public PgpPublicKey(
PublicKeyAlgorithmTag algorithm,
AsymmetricKeyParameter pubKey,
DateTime time)
{
- if (pubKey.IsPrivate)
- throw new ArgumentException("Expected a public key", "pubKey");
+ if (pubKey.IsPrivate)
+ throw new ArgumentException("Expected a public key", "pubKey");
- IBcpgKey bcpgKey;
+ IBcpgKey bcpgKey;
if (pubKey is RsaKeyParameters)
{
RsaKeyParameters rK = (RsaKeyParameters) pubKey;
- bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent);
+ bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent);
}
else if (pubKey is DsaPublicKeyParameters)
{
DsaPublicKeyParameters dK = (DsaPublicKeyParameters) pubKey;
DsaParameters dP = dK.Parameters;
- bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y);
+ bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y);
+ }
+ else if (pubKey is ECPublicKeyParameters)
+ {
+ ECPublicKeyParameters ecK = (ECPublicKeyParameters)pubKey;
+
+ if (algorithm == PublicKeyAlgorithmTag.ECDH)
+ {
+ bcpgKey = new ECDHPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q, HashAlgorithmTag.Sha256, SymmetricKeyAlgorithmTag.Aes128);
+ }
+ else if (algorithm == PublicKeyAlgorithmTag.ECDsa)
+ {
+ bcpgKey = new ECDsaPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q);
+ }
+ else
+ {
+ throw new PgpException("unknown EC algorithm");
+ }
}
else if (pubKey is ElGamalPublicKeyParameters)
{
ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey;
ElGamalParameters eS = eK.Parameters;
- bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y);
+ bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y);
}
else
{
throw new PgpException("unknown key class");
}
- this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey);
+ this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey);
this.ids = Platform.CreateArrayList();
this.idSigs = Platform.CreateArrayList();
- try
+ try
{
Init();
}
@@ -167,7 +207,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- /// <summary>Constructor for a sub-key.</summary>
+ public PgpPublicKey(PublicKeyPacket publicPk)
+ : this(publicPk, Platform.CreateArrayList(), Platform.CreateArrayList())
+ {
+ }
+
+ /// <summary>Constructor for a sub-key.</summary>
internal PgpPublicKey(
PublicKeyPacket publicPk,
TrustPacket trustPk,
@@ -177,10 +222,10 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
this.trustPk = trustPk;
this.subSigs = sigs;
- Init();
+ Init();
}
- internal PgpPublicKey(
+ internal PgpPublicKey(
PgpPublicKey key,
TrustPacket trust,
IList subSigs)
@@ -189,19 +234,19 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
this.trustPk = trust;
this.subSigs = subSigs;
- this.fingerprint = key.fingerprint;
+ this.fingerprint = key.fingerprint;
this.keyId = key.keyId;
this.keyStrength = key.keyStrength;
}
- /// <summary>Copy constructor.</summary>
- /// <param name="pubKey">The public key to copy.</param>
+ /// <summary>Copy constructor.</summary>
+ /// <param name="pubKey">The public key to copy.</param>
internal PgpPublicKey(
PgpPublicKey pubKey)
{
this.publicPk = pubKey.publicPk;
- this.keySigs = Platform.CreateArrayList(pubKey.keySigs);
+ this.keySigs = Platform.CreateArrayList(pubKey.keySigs);
this.ids = Platform.CreateArrayList(pubKey.ids);
this.idTrusts = Platform.CreateArrayList(pubKey.idTrusts);
this.idSigs = Platform.CreateArrayList(pubKey.idSigs.Count);
@@ -210,7 +255,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
this.idSigs.Add(Platform.CreateArrayList((IList)pubKey.idSigs[i]));
}
- if (pubKey.subSigs != null)
+ if (pubKey.subSigs != null)
{
this.subSigs = Platform.CreateArrayList(pubKey.subSigs.Count);
for (int i = 0; i != pubKey.subSigs.Count; i++)
@@ -219,12 +264,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- this.fingerprint = pubKey.fingerprint;
+ this.fingerprint = pubKey.fingerprint;
this.keyId = pubKey.keyId;
this.keyStrength = pubKey.keyStrength;
}
- internal PgpPublicKey(
+ internal PgpPublicKey(
PublicKeyPacket publicPk,
TrustPacket trustPk,
IList keySigs,
@@ -239,10 +284,10 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
this.idTrusts = idTrusts;
this.idSigs = idSigs;
- Init();
+ Init();
}
- internal PgpPublicKey(
+ internal PgpPublicKey(
PublicKeyPacket publicPk,
IList ids,
IList idSigs)
@@ -253,159 +298,165 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
Init();
}
- /// <summary>The version of this key.</summary>
+ /// <summary>The version of this key.</summary>
public int Version
{
- get { return publicPk.Version; }
+ get { return publicPk.Version; }
}
- /// <summary>The creation time of this key.</summary>
- public DateTime CreationTime
+ /// <summary>The creation time of this key.</summary>
+ public DateTime CreationTime
{
- get { return publicPk.GetTime(); }
+ get { return publicPk.GetTime(); }
}
- /// <summary>The number of valid days from creation time - zero means no expiry.</summary>
+ /// <summary>The number of valid days from creation time - zero means no expiry.</summary>
+ /// <remarks>WARNING: This method will return 1 for keys with version > 3 that expire in less than 1 day</remarks>
+ [Obsolete("Use 'GetValidSeconds' instead")]
public int ValidDays
{
- get
- {
- if (publicPk.Version > 3)
- {
- return (int)(GetValidSeconds() / (24 * 60 * 60));
- }
-
- return publicPk.ValidDays;
- }
- }
-
- /// <summary>Return the trust data associated with the public key, if present.</summary>
- /// <returns>A byte array with trust data, null otherwise.</returns>
- public byte[] GetTrustData()
- {
- if (trustPk == null)
- {
- return null;
- }
-
- return trustPk.GetLevelAndTrustAmount();
- }
-
- /// <summary>The number of valid seconds from creation time - zero means no expiry.</summary>
- public long GetValidSeconds()
- {
- if (publicPk.Version > 3)
- {
- if (IsMasterKey)
- {
- for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
- {
- long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]);
-
- if (seconds >= 0)
- {
- return seconds;
- }
- }
- }
- else
- {
- long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding);
-
- if (seconds >= 0)
- {
- return seconds;
- }
- }
-
- return 0;
- }
-
- return (long) publicPk.ValidDays * 24 * 60 * 60;
- }
-
- private long GetExpirationTimeFromSig(
- bool selfSigned,
- int signatureType)
- {
- foreach (PgpSignature sig in GetSignaturesOfType(signatureType))
- {
- if (!selfSigned || sig.KeyId == KeyId)
- {
- PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets();
-
- if (hashed != null)
- {
- return hashed.GetKeyExpirationTime();
- }
-
- return 0;
- }
- }
-
- return -1;
- }
-
- /// <summary>The keyId associated with the public key.</summary>
+ get
+ {
+ if (publicPk.Version <= 3)
+ {
+ return publicPk.ValidDays;
+ }
+
+ long expSecs = GetValidSeconds();
+ if (expSecs <= 0)
+ return 0;
+
+ int days = (int)(expSecs / (24 * 60 * 60));
+ return System.Math.Max(1, days);
+ }
+ }
+
+ /// <summary>Return the trust data associated with the public key, if present.</summary>
+ /// <returns>A byte array with trust data, null otherwise.</returns>
+ public byte[] GetTrustData()
+ {
+ if (trustPk == null)
+ {
+ return null;
+ }
+
+ return Arrays.Clone(trustPk.GetLevelAndTrustAmount());
+ }
+
+ /// <summary>The number of valid seconds from creation time - zero means no expiry.</summary>
+ public long GetValidSeconds()
+ {
+ if (publicPk.Version <= 3)
+ {
+ return (long)publicPk.ValidDays * (24 * 60 * 60);
+ }
+
+ if (IsMasterKey)
+ {
+ for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
+ {
+ long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]);
+ if (seconds >= 0)
+ {
+ return seconds;
+ }
+ }
+ }
+ else
+ {
+ long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding);
+ if (seconds >= 0)
+ {
+ return seconds;
+ }
+ }
+
+ return 0;
+ }
+
+ private long GetExpirationTimeFromSig(
+ bool selfSigned,
+ int signatureType)
+ {
+ foreach (PgpSignature sig in GetSignaturesOfType(signatureType))
+ {
+ if (!selfSigned || sig.KeyId == KeyId)
+ {
+ PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets();
+
+ if (hashed != null)
+ {
+ return hashed.GetKeyExpirationTime();
+ }
+
+ return 0;
+ }
+ }
+
+ return -1;
+ }
+
+ /// <summary>The keyId associated with the public key.</summary>
public long KeyId
{
get { return keyId; }
}
- /// <summary>The fingerprint of the key</summary>
+ /// <summary>The fingerprint of the key</summary>
public byte[] GetFingerprint()
{
- return (byte[]) fingerprint.Clone();
+ return (byte[]) fingerprint.Clone();
}
- /// <summary>
- /// Check if this key has an algorithm type that makes it suitable to use for encryption.
- /// </summary>
- /// <remarks>
- /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for
- /// determining the preferred use of the key.
- /// </remarks>
- /// <returns>
- /// <c>true</c> if this key algorithm is suitable for encryption.
- /// </returns>
- public bool IsEncryptionKey
+ /// <summary>
+ /// Check if this key has an algorithm type that makes it suitable to use for encryption.
+ /// </summary>
+ /// <remarks>
+ /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for
+ /// determining the preferred use of the key.
+ /// </remarks>
+ /// <returns>
+ /// <c>true</c> if this key algorithm is suitable for encryption.
+ /// </returns>
+ public bool IsEncryptionKey
{
get
{
- switch (publicPk.Algorithm)
- {
- case PublicKeyAlgorithmTag.ElGamalEncrypt:
- case PublicKeyAlgorithmTag.ElGamalGeneral:
- case PublicKeyAlgorithmTag.RsaEncrypt:
- case PublicKeyAlgorithmTag.RsaGeneral:
- return true;
- default:
- return false;
- }
+ switch (publicPk.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.ECDH:
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ return true;
+ default:
+ return false;
+ }
}
}
- /// <summary>True, if this is a master key.</summary>
+ /// <summary>True, if this is a master key.</summary>
public bool IsMasterKey
{
get { return subSigs == null; }
}
- /// <summary>The algorithm code associated with the public key.</summary>
+ /// <summary>The algorithm code associated with the public key.</summary>
public PublicKeyAlgorithmTag Algorithm
{
- get { return publicPk.Algorithm; }
+ get { return publicPk.Algorithm; }
}
- /// <summary>The strength of the key in bits.</summary>
+ /// <summary>The strength of the key in bits.</summary>
public int BitStrength
{
get { return keyStrength; }
}
- /// <summary>The public key contained in the object.</summary>
- /// <returns>A lightweight public key.</returns>
- /// <exception cref="PgpException">If the key algorithm is not recognised.</exception>
+ /// <summary>The public key contained in the object.</summary>
+ /// <returns>A lightweight public key.</returns>
+ /// <exception cref="PgpException">If the key algorithm is not recognised.</exception>
public AsymmetricKeyParameter GetKey()
{
try
@@ -415,14 +466,18 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
case PublicKeyAlgorithmTag.RsaEncrypt:
case PublicKeyAlgorithmTag.RsaGeneral:
case PublicKeyAlgorithmTag.RsaSign:
- RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key;
+ RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey)publicPk.Key;
return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent);
case PublicKeyAlgorithmTag.Dsa:
- DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key;
+ DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey)publicPk.Key;
return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G));
+ case PublicKeyAlgorithmTag.ECDsa:
+ return GetECKey("ECDSA");
+ case PublicKeyAlgorithmTag.ECDH:
+ return GetECKey("ECDH");
case PublicKeyAlgorithmTag.ElGamalEncrypt:
case PublicKeyAlgorithmTag.ElGamalGeneral:
- ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key;
+ ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey)publicPk.Key;
return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G));
default:
throw new PgpException("unknown public key algorithm encountered");
@@ -438,50 +493,58 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- /// <summary>Allows enumeration of any user IDs associated with the key.</summary>
- /// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+ private ECPublicKeyParameters GetECKey(string algorithm)
+ {
+ ECPublicBcpgKey ecK = (ECPublicBcpgKey)publicPk.Key;
+ X9ECParameters x9 = ECKeyPairGenerator.FindECCurveByOid(ecK.CurveOid);
+ ECPoint q = x9.Curve.DecodePoint(BigIntegers.AsUnsignedByteArray(ecK.EncodedPoint));
+ return new ECPublicKeyParameters(algorithm, q, ecK.CurveOid);
+ }
+
+ /// <summary>Allows enumeration of any user IDs associated with the key.</summary>
+ /// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
public IEnumerable GetUserIds()
{
IList temp = Platform.CreateArrayList();
- foreach (object o in ids)
- {
- if (o is string)
- {
- temp.Add(o);
+ foreach (object o in ids)
+ {
+ if (o is string)
+ {
+ temp.Add(o);
}
}
- return new EnumerableProxy(temp);
+ return new EnumerableProxy(temp);
}
- /// <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
- /// <returns>An <c>IEnumerable</c> of <c>PgpUserAttributeSubpacketVector</c> objects.</returns>
+ /// <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
+ /// <returns>An <c>IEnumerable</c> of <c>PgpUserAttributeSubpacketVector</c> objects.</returns>
public IEnumerable GetUserAttributes()
{
IList temp = Platform.CreateArrayList();
- foreach (object o in ids)
- {
- if (o is PgpUserAttributeSubpacketVector)
- {
- temp.Add(o);
- }
- }
+ foreach (object o in ids)
+ {
+ if (o is PgpUserAttributeSubpacketVector)
+ {
+ temp.Add(o);
+ }
+ }
- return new EnumerableProxy(temp);
+ return new EnumerableProxy(temp);
}
- /// <summary>Allows enumeration of any signatures associated with the passed in id.</summary>
- /// <param name="id">The ID to be matched.</param>
- /// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
+ /// <summary>Allows enumeration of any signatures associated with the passed in id.</summary>
+ /// <param name="id">The ID to be matched.</param>
+ /// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
public IEnumerable GetSignaturesForId(
string id)
{
- if (id == null)
- throw new ArgumentNullException("id");
+ if (id == null)
+ throw new ArgumentNullException("id");
- for (int i = 0; i != ids.Count; i++)
+ for (int i = 0; i != ids.Count; i++)
{
if (id.Equals(ids[i]))
{
@@ -489,12 +552,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- return null;
+ return null;
}
- /// <summary>Allows enumeration of signatures associated with the passed in user attributes.</summary>
- /// <param name="userAttributes">The vector of user attributes to be matched.</param>
- /// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
+ /// <summary>Allows enumeration of signatures associated with the passed in user attributes.</summary>
+ /// <param name="userAttributes">The vector of user attributes to be matched.</param>
+ /// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
public IEnumerable GetSignaturesForUserAttribute(
PgpUserAttributeSubpacketVector userAttributes)
{
@@ -506,18 +569,18 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- return null;
+ return null;
}
- /// <summary>Allows enumeration of signatures of the passed in type that are on this key.</summary>
- /// <param name="signatureType">The type of the signature to be returned.</param>
- /// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
+ /// <summary>Allows enumeration of signatures of the passed in type that are on this key.</summary>
+ /// <param name="signatureType">The type of the signature to be returned.</param>
+ /// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
public IEnumerable GetSignaturesOfType(
int signatureType)
{
IList temp = Platform.CreateArrayList();
- foreach (PgpSignature sig in GetSignatures())
+ foreach (PgpSignature sig in GetSignatures())
{
if (sig.SignatureType == signatureType)
{
@@ -525,63 +588,79 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- return new EnumerableProxy(temp);
+ return new EnumerableProxy(temp);
}
- /// <summary>Allows enumeration of all signatures/certifications associated with this key.</summary>
- /// <returns>An <c>IEnumerable</c> with all signatures/certifications.</returns>
+ /// <summary>Allows enumeration of all signatures/certifications associated with this key.</summary>
+ /// <returns>An <c>IEnumerable</c> with all signatures/certifications.</returns>
public IEnumerable GetSignatures()
{
- IList sigs;
- if (subSigs != null)
- {
- sigs = subSigs;
- }
- else
- {
+ IList sigs = subSigs;
+ if (sigs == null)
+ {
sigs = Platform.CreateArrayList(keySigs);
- foreach (ICollection extraSigs in idSigs)
- {
+ foreach (ICollection extraSigs in idSigs)
+ {
CollectionUtilities.AddRange(sigs, extraSigs);
- }
- }
+ }
+ }
+
+ return new EnumerableProxy(sigs);
+ }
- return new EnumerableProxy(sigs);
+ /**
+ * Return all signatures/certifications directly associated with this key (ie, not to a user id).
+ *
+ * @return an iterator (possibly empty) with all signatures/certifications.
+ */
+ public IEnumerable GetKeySignatures()
+ {
+ IList sigs = subSigs;
+ if (sigs == null)
+ {
+ sigs = Platform.CreateArrayList(keySigs);
+ }
+ return new EnumerableProxy(sigs);
}
- public byte[] GetEncoded()
+ public PublicKeyPacket PublicKeyPacket
+ {
+ get { return publicPk; }
+ }
+
+ public byte[] GetEncoded()
{
MemoryStream bOut = new MemoryStream();
Encode(bOut);
return bOut.ToArray();
}
- public void Encode(
+ public void Encode(
Stream outStr)
{
BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
- bcpgOut.WritePacket(publicPk);
+ bcpgOut.WritePacket(publicPk);
if (trustPk != null)
{
bcpgOut.WritePacket(trustPk);
}
- if (subSigs == null) // not a sub-key
+ if (subSigs == null) // not a sub-key
{
- foreach (PgpSignature keySig in keySigs)
- {
- keySig.Encode(bcpgOut);
- }
+ foreach (PgpSignature keySig in keySigs)
+ {
+ keySig.Encode(bcpgOut);
+ }
- for (int i = 0; i != ids.Count; i++)
+ for (int i = 0; i != ids.Count; i++)
{
if (ids[i] is string)
{
string id = (string) ids[i];
- bcpgOut.WritePacket(new UserIdPacket(id));
+ bcpgOut.WritePacket(new UserIdPacket(id));
}
else
{
@@ -589,28 +668,28 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
}
- if (idTrusts[i] != null)
+ if (idTrusts[i] != null)
{
bcpgOut.WritePacket((ContainedPacket)idTrusts[i]);
}
- foreach (PgpSignature sig in (IList) idSigs[i])
- {
- sig.Encode(bcpgOut);
- }
+ foreach (PgpSignature sig in (IList) idSigs[i])
+ {
+ sig.Encode(bcpgOut);
+ }
}
}
else
{
- foreach (PgpSignature subSig in subSigs)
- {
- subSig.Encode(bcpgOut);
- }
+ foreach (PgpSignature subSig in subSigs)
+ {
+ subSig.Encode(bcpgOut);
+ }
}
}
- /// <summary>Check whether this (sub)key has a revocation signature on it.</summary>
- /// <returns>True, if this (sub)key has been revoked.</returns>
+ /// <summary>Check whether this (sub)key has a revocation signature on it.</summary>
+ /// <returns>True, if this (sub)key has been revoked.</returns>
public bool IsRevoked()
{
int ns = 0;
@@ -638,98 +717,98 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return revoked;
}
- /// <summary>Add a certification for an id to the given public key.</summary>
- /// <param name="key">The key the certification is to be added to.</param>
- /// <param name="id">The ID the certification is associated with.</param>
- /// <param name="certification">The new certification.</param>
- /// <returns>The re-certified key.</returns>
+ /// <summary>Add a certification for an id to the given public key.</summary>
+ /// <param name="key">The key the certification is to be added to.</param>
+ /// <param name="id">The ID the certification is associated with.</param>
+ /// <param name="certification">The new certification.</param>
+ /// <returns>The re-certified key.</returns>
public static PgpPublicKey AddCertification(
PgpPublicKey key,
string id,
PgpSignature certification)
{
- return AddCert(key, id, certification);
- }
-
- /// <summary>Add a certification for the given UserAttributeSubpackets to the given public key.</summary>
- /// <param name="key">The key the certification is to be added to.</param>
- /// <param name="userAttributes">The attributes the certification is associated with.</param>
- /// <param name="certification">The new certification.</param>
- /// <returns>The re-certified key.</returns>
- public static PgpPublicKey AddCertification(
- PgpPublicKey key,
- PgpUserAttributeSubpacketVector userAttributes,
- PgpSignature certification)
- {
- return AddCert(key, userAttributes, certification);
- }
-
- private static PgpPublicKey AddCert(
- PgpPublicKey key,
- object id,
- PgpSignature certification)
- {
- PgpPublicKey returnKey = new PgpPublicKey(key);
- IList sigList = null;
-
- for (int i = 0; i != returnKey.ids.Count; i++)
- {
- if (id.Equals(returnKey.ids[i]))
- {
- sigList = (IList) returnKey.idSigs[i];
- }
- }
-
- if (sigList != null)
- {
- sigList.Add(certification);
- }
- else
- {
- sigList = Platform.CreateArrayList();
- sigList.Add(certification);
- returnKey.ids.Add(id);
- returnKey.idTrusts.Add(null);
- returnKey.idSigs.Add(sigList);
- }
-
- return returnKey;
- }
-
- /// <summary>
- /// Remove any certifications associated with a user attribute subpacket on a key.
- /// </summary>
- /// <param name="key">The key the certifications are to be removed from.</param>
- /// <param name="userAttributes">The attributes to be removed.</param>
- /// <returns>
- /// The re-certified key, or null if the user attribute subpacket was not found on the key.
- /// </returns>
- public static PgpPublicKey RemoveCertification(
- PgpPublicKey key,
- PgpUserAttributeSubpacketVector userAttributes)
- {
- return RemoveCert(key, userAttributes);
- }
-
- /// <summary>Remove any certifications associated with a given ID on a key.</summary>
- /// <param name="key">The key the certifications are to be removed from.</param>
- /// <param name="id">The ID that is to be removed.</param>
- /// <returns>The re-certified key, or null if the ID was not found on the key.</returns>
+ return AddCert(key, id, certification);
+ }
+
+ /// <summary>Add a certification for the given UserAttributeSubpackets to the given public key.</summary>
+ /// <param name="key">The key the certification is to be added to.</param>
+ /// <param name="userAttributes">The attributes the certification is associated with.</param>
+ /// <param name="certification">The new certification.</param>
+ /// <returns>The re-certified key.</returns>
+ public static PgpPublicKey AddCertification(
+ PgpPublicKey key,
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpSignature certification)
+ {
+ return AddCert(key, userAttributes, certification);
+ }
+
+ private static PgpPublicKey AddCert(
+ PgpPublicKey key,
+ object id,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ IList sigList = null;
+
+ for (int i = 0; i != returnKey.ids.Count; i++)
+ {
+ if (id.Equals(returnKey.ids[i]))
+ {
+ sigList = (IList) returnKey.idSigs[i];
+ }
+ }
+
+ if (sigList != null)
+ {
+ sigList.Add(certification);
+ }
+ else
+ {
+ sigList = Platform.CreateArrayList();
+ sigList.Add(certification);
+ returnKey.ids.Add(id);
+ returnKey.idTrusts.Add(null);
+ returnKey.idSigs.Add(sigList);
+ }
+
+ return returnKey;
+ }
+
+ /// <summary>
+ /// Remove any certifications associated with a user attribute subpacket on a key.
+ /// </summary>
+ /// <param name="key">The key the certifications are to be removed from.</param>
+ /// <param name="userAttributes">The attributes to be removed.</param>
+ /// <returns>
+ /// The re-certified key, or null if the user attribute subpacket was not found on the key.
+ /// </returns>
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ PgpUserAttributeSubpacketVector userAttributes)
+ {
+ return RemoveCert(key, userAttributes);
+ }
+
+ /// <summary>Remove any certifications associated with a given ID on a key.</summary>
+ /// <param name="key">The key the certifications are to be removed from.</param>
+ /// <param name="id">The ID that is to be removed.</param>
+ /// <returns>The re-certified key, or null if the ID was not found on the key.</returns>
public static PgpPublicKey RemoveCertification(
PgpPublicKey key,
string id)
{
- return RemoveCert(key, id);
- }
+ return RemoveCert(key, id);
+ }
- private static PgpPublicKey RemoveCert(
- PgpPublicKey key,
- object id)
- {
- PgpPublicKey returnKey = new PgpPublicKey(key);
+ private static PgpPublicKey RemoveCert(
+ PgpPublicKey key,
+ object id)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
bool found = false;
- for (int i = 0; i < returnKey.ids.Count; i++)
+ for (int i = 0; i < returnKey.ids.Count; i++)
{
if (id.Equals(returnKey.ids[i]))
{
@@ -740,64 +819,64 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- return found ? returnKey : null;
+ return found ? returnKey : null;
}
- /// <summary>Remove a certification associated with a given ID on a key.</summary>
- /// <param name="key">The key the certifications are to be removed from.</param>
- /// <param name="id">The ID that the certfication is to be removed from.</param>
- /// <param name="certification">The certfication to be removed.</param>
- /// <returns>The re-certified key, or null if the certification was not found.</returns>
+ /// <summary>Remove a certification associated with a given ID on a key.</summary>
+ /// <param name="key">The key the certifications are to be removed from.</param>
+ /// <param name="id">The ID that the certfication is to be removed from.</param>
+ /// <param name="certification">The certfication to be removed.</param>
+ /// <returns>The re-certified key, or null if the certification was not found.</returns>
public static PgpPublicKey RemoveCertification(
PgpPublicKey key,
string id,
PgpSignature certification)
{
- return RemoveCert(key, id, certification);
- }
-
- /// <summary>Remove a certification associated with a given user attributes on a key.</summary>
- /// <param name="key">The key the certifications are to be removed from.</param>
- /// <param name="userAttributes">The user attributes that the certfication is to be removed from.</param>
- /// <param name="certification">The certification to be removed.</param>
- /// <returns>The re-certified key, or null if the certification was not found.</returns>
- public static PgpPublicKey RemoveCertification(
- PgpPublicKey key,
- PgpUserAttributeSubpacketVector userAttributes,
- PgpSignature certification)
- {
- return RemoveCert(key, userAttributes, certification);
- }
-
- private static PgpPublicKey RemoveCert(
- PgpPublicKey key,
- object id,
- PgpSignature certification)
- {
- PgpPublicKey returnKey = new PgpPublicKey(key);
+ return RemoveCert(key, id, certification);
+ }
+
+ /// <summary>Remove a certification associated with a given user attributes on a key.</summary>
+ /// <param name="key">The key the certifications are to be removed from.</param>
+ /// <param name="userAttributes">The user attributes that the certfication is to be removed from.</param>
+ /// <param name="certification">The certification to be removed.</param>
+ /// <returns>The re-certified key, or null if the certification was not found.</returns>
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpSignature certification)
+ {
+ return RemoveCert(key, userAttributes, certification);
+ }
+
+ private static PgpPublicKey RemoveCert(
+ PgpPublicKey key,
+ object id,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
bool found = false;
- for (int i = 0; i < returnKey.ids.Count; i++)
+ for (int i = 0; i < returnKey.ids.Count; i++)
{
if (id.Equals(returnKey.ids[i]))
{
IList certs = (IList) returnKey.idSigs[i];
found = certs.Contains(certification);
- if (found)
- {
- certs.Remove(certification);
- }
+ if (found)
+ {
+ certs.Remove(certification);
+ }
}
}
- return found ? returnKey : null;
+ return found ? returnKey : null;
}
- /// <summary>Add a revocation or some other key certification to a key.</summary>
- /// <param name="key">The key the revocation is to be added to.</param>
- /// <param name="certification">The key signature to be added.</param>
- /// <returns>The new changed public key object.</returns>
+ /// <summary>Add a revocation or some other key certification to a key.</summary>
+ /// <param name="key">The key the revocation is to be added to.</param>
+ /// <param name="certification">The key signature to be added.</param>
+ /// <returns>The new changed public key object.</returns>
public static PgpPublicKey AddCertification(
PgpPublicKey key,
PgpSignature certification)
@@ -817,9 +896,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- PgpPublicKey returnKey = new PgpPublicKey(key);
+ PgpPublicKey returnKey = new PgpPublicKey(key);
- if (returnKey.subSigs != null)
+ if (returnKey.subSigs != null)
{
returnKey.subSigs.Add(certification);
}
@@ -828,63 +907,63 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
returnKey.keySigs.Add(certification);
}
- return returnKey;
+ return returnKey;
}
- /// <summary>Remove a certification from the key.</summary>
- /// <param name="key">The key the certifications are to be removed from.</param>
- /// <param name="certification">The certfication to be removed.</param>
- /// <returns>The modified key, null if the certification was not found.</returns>
- public static PgpPublicKey RemoveCertification(
- PgpPublicKey key,
- PgpSignature certification)
- {
- PgpPublicKey returnKey = new PgpPublicKey(key);
- IList sigs = returnKey.subSigs != null
- ? returnKey.subSigs
- : returnKey.keySigs;
+ /// <summary>Remove a certification from the key.</summary>
+ /// <param name="key">The key the certifications are to be removed from.</param>
+ /// <param name="certification">The certfication to be removed.</param>
+ /// <returns>The modified key, null if the certification was not found.</returns>
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ IList sigs = returnKey.subSigs != null
+ ? returnKey.subSigs
+ : returnKey.keySigs;
// bool found = sigs.Remove(certification);
- int pos = sigs.IndexOf(certification);
- bool found = pos >= 0;
-
- if (found)
- {
- sigs.RemoveAt(pos);
- }
- else
- {
- foreach (String id in key.GetUserIds())
- {
- foreach (object sig in key.GetSignaturesForId(id))
- {
- // TODO Is this the right type of equality test?
- if (certification == sig)
- {
- found = true;
- returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
- }
- }
- }
-
- if (!found)
- {
- foreach (PgpUserAttributeSubpacketVector id in key.GetUserAttributes())
- {
- foreach (object sig in key.GetSignaturesForUserAttribute(id))
- {
- // TODO Is this the right type of equality test?
- if (certification == sig)
- {
- found = true;
- returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
- }
- }
- }
- }
- }
-
- return returnKey;
- }
- }
+ int pos = sigs.IndexOf(certification);
+ bool found = pos >= 0;
+
+ if (found)
+ {
+ sigs.RemoveAt(pos);
+ }
+ else
+ {
+ foreach (String id in key.GetUserIds())
+ {
+ foreach (object sig in key.GetSignaturesForId(id))
+ {
+ // TODO Is this the right type of equality test?
+ if (certification == sig)
+ {
+ found = true;
+ returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
+ }
+ }
+ }
+
+ if (!found)
+ {
+ foreach (PgpUserAttributeSubpacketVector id in key.GetUserAttributes())
+ {
+ foreach (object sig in key.GetSignaturesForUserAttribute(id))
+ {
+ // TODO Is this the right type of equality test?
+ if (certification == sig)
+ {
+ found = true;
+ returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
+ }
+ }
+ }
+ }
+ }
+
+ return returnKey;
+ }
+ }
}
diff --git a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
index b6504cbcd..c2a351182 100644
--- a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
+++ b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
@@ -1,10 +1,13 @@
using System;
using System.IO;
+using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.IO;
@@ -77,22 +80,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
public SymmetricKeyAlgorithmTag GetSymmetricAlgorithm(
PgpPrivateKey privKey)
{
- byte[] plain = fetchSymmetricKeyData(privKey);
+ byte[] sessionData = RecoverSessionData(privKey);
- return (SymmetricKeyAlgorithmTag) plain[0];
+ return (SymmetricKeyAlgorithmTag)sessionData[0];
}
- /// <summary>Return the decrypted data stream for the packet.</summary>
+ /// <summary>Return the decrypted data stream for the packet.</summary>
public Stream GetDataStream(
PgpPrivateKey privKey)
{
- byte[] plain = fetchSymmetricKeyData(privKey);
+ byte[] sessionData = RecoverSessionData(privKey);
- IBufferedCipher c2;
- string cipherName = PgpUtilities.GetSymmetricCipherName((SymmetricKeyAlgorithmTag) plain[0]);
+ if (!ConfirmCheckSum(sessionData))
+ throw new PgpKeyValidationException("key checksum failed");
+
+ SymmetricKeyAlgorithmTag symmAlg = (SymmetricKeyAlgorithmTag)sessionData[0];
+ if (symmAlg == SymmetricKeyAlgorithmTag.Null)
+ return encData.GetInputStream();
+
+ IBufferedCipher cipher;
+ string cipherName = PgpUtilities.GetSymmetricCipherName(symmAlg);
string cName = cipherName;
- try
+ try
{
if (encData is SymmetricEncIntegrityPacket)
{
@@ -103,7 +113,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
cName += "/OpenPGPCFB/NoPadding";
}
- c2 = CipherUtilities.GetCipher(cName);
+ cipher = CipherUtilities.GetCipher(cName);
}
catch (PgpException e)
{
@@ -114,19 +124,16 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
throw new PgpException("exception creating cipher", e);
}
- if (c2 == null)
- return encData.GetInputStream();
-
- try
+ try
{
KeyParameter key = ParameterUtilities.CreateKeyParameter(
- cipherName, plain, 1, plain.Length - 3);
+ cipherName, sessionData, 1, sessionData.Length - 3);
- byte[] iv = new byte[c2.GetBlockSize()];
+ byte[] iv = new byte[cipher.GetBlockSize()];
- c2.Init(false, new ParametersWithIV(key, iv));
+ cipher.Init(false, new ParametersWithIV(key, iv));
- encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c2, null));
+ encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), cipher, null));
if (encData is SymmetricEncIntegrityPacket)
{
@@ -178,75 +185,88 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- private byte[] fetchSymmetricKeyData(
- PgpPrivateKey privKey)
+ private byte[] RecoverSessionData(PgpPrivateKey privKey)
{
- IBufferedCipher c1 = GetKeyCipher(keyData.Algorithm);
+ byte[][] secKeyData = keyData.GetEncSessionKey();
+
+ if (keyData.Algorithm == PublicKeyAlgorithmTag.ECDH)
+ {
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key;
+ X9ECParameters x9Params = ECKeyPairGenerator.FindECCurveByOid(ecKey.CurveOid);
+
+ byte[] enc = secKeyData[0];
+
+ int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+ byte[] pEnc = new byte[pLen];
+
+ Array.Copy(enc, 2, pEnc, 0, pLen);
+
+ byte[] keyEnc = new byte[enc[pLen + 2]];
+
+ Array.Copy(enc, 2 + pLen + 1, keyEnc, 0, keyEnc.Length);
+
+ ECPoint publicPoint = x9Params.Curve.DecodePoint(pEnc);
+
+ ECPrivateKeyParameters privKeyParams = (ECPrivateKeyParameters)privKey.Key;
+ ECPoint S = publicPoint.Multiply(privKeyParams.D).Normalize();
+
+ KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, S));
+
+ IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm);
+ w.Init(false, key);
- try
+ return PgpPad.UnpadSessionData(w.Unwrap(keyEnc, 0, keyEnc.Length));
+ }
+
+ IBufferedCipher cipher = GetKeyCipher(keyData.Algorithm);
+
+ try
{
- c1.Init(false, privKey.Key);
+ cipher.Init(false, privKey.Key);
}
catch (InvalidKeyException e)
{
throw new PgpException("error setting asymmetric cipher", e);
}
- BigInteger[] keyD = keyData.GetEncSessionKey();
-
- if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt
+ if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt
|| keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral)
{
- c1.ProcessBytes(keyD[0].ToByteArrayUnsigned());
+ byte[] bi = secKeyData[0];
+
+ cipher.ProcessBytes(bi, 2, bi.Length - 2);
}
else
{
ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key;
int size = (k.Parameters.P.BitLength + 7) / 8;
- byte[] bi = keyD[0].ToByteArray();
-
- int diff = bi.Length - size;
- if (diff >= 0)
- {
- c1.ProcessBytes(bi, diff, size);
- }
- else
- {
- byte[] zeros = new byte[-diff];
- c1.ProcessBytes(zeros);
- c1.ProcessBytes(bi);
- }
-
- bi = keyD[1].ToByteArray();
-
- diff = bi.Length - size;
- if (diff >= 0)
- {
- c1.ProcessBytes(bi, diff, size);
- }
- else
- {
- byte[] zeros = new byte[-diff];
- c1.ProcessBytes(zeros);
- c1.ProcessBytes(bi);
- }
+ ProcessEncodedMpi(cipher, size, secKeyData[0]);
+ ProcessEncodedMpi(cipher, size, secKeyData[1]);
}
- byte[] plain;
- try
+ try
{
- plain = c1.DoFinal();
+ return cipher.DoFinal();
}
catch (Exception e)
{
throw new PgpException("exception decrypting secret key", e);
}
-
- if (!ConfirmCheckSum(plain))
- throw new PgpKeyValidationException("key checksum failed");
-
- return plain;
}
+
+ private static void ProcessEncodedMpi(IBufferedCipher cipher, int size, byte[] mpiEnc)
+ {
+ if (mpiEnc.Length - 2 > size) // leading Zero? Shouldn't happen but...
+ {
+ cipher.ProcessBytes(mpiEnc, 3, mpiEnc.Length - 3);
+ }
+ else
+ {
+ byte[] tmp = new byte[size];
+ Array.Copy(mpiEnc, 2, tmp, tmp.Length - (mpiEnc.Length - 2), mpiEnc.Length - 2);
+ cipher.ProcessBytes(tmp, 0, tmp.Length);
+ }
+ }
}
}
diff --git a/crypto/src/openpgp/PgpPublicKeyRing.cs b/crypto/src/openpgp/PgpPublicKeyRing.cs
index 0f5e04516..592ca86c8 100644
--- a/crypto/src/openpgp/PgpPublicKeyRing.cs
+++ b/crypto/src/openpgp/PgpPublicKeyRing.cs
@@ -7,164 +7,164 @@ using Org.BouncyCastle.Utilities.Collections;
namespace Org.BouncyCastle.Bcpg.OpenPgp
{
- /// <remarks>
- /// Class to hold a single master public key and its subkeys.
- /// <p>
- /// Often PGP keyring files consist of multiple master keys, if you are trying to process
- /// or construct one of these you should use the <c>PgpPublicKeyRingBundle</c> class.
- /// </p>
- /// </remarks>
- public class PgpPublicKeyRing
- : PgpKeyRing
+ /// <remarks>
+ /// Class to hold a single master public key and its subkeys.
+ /// <p>
+ /// Often PGP keyring files consist of multiple master keys, if you are trying to process
+ /// or construct one of these you should use the <c>PgpPublicKeyRingBundle</c> class.
+ /// </p>
+ /// </remarks>
+ public class PgpPublicKeyRing
+ : PgpKeyRing
{
private readonly IList keys;
- public PgpPublicKeyRing(
+ public PgpPublicKeyRing(
byte[] encoding)
: this(new MemoryStream(encoding, false))
{
}
- internal PgpPublicKeyRing(
+ internal PgpPublicKeyRing(
IList pubKeys)
{
this.keys = pubKeys;
}
- public PgpPublicKeyRing(
+ public PgpPublicKeyRing(
Stream inputStream)
{
- this.keys = Platform.CreateArrayList();
+ this.keys = Platform.CreateArrayList();
BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
- PacketTag initialTag = bcpgInput.NextPacketTag();
+ PacketTag initialTag = bcpgInput.NextPacketTag();
if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey)
{
throw new IOException("public key ring doesn't start with public key tag: "
- + "tag 0x" + ((int)initialTag).ToString("X"));
+ + "tag 0x" + ((int)initialTag).ToString("X"));
}
- PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
- TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
+ PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
+ TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
// direct signatures and revocations
- IList keySigs = ReadSignaturesAndTrust(bcpgInput);
+ IList keySigs = ReadSignaturesAndTrust(bcpgInput);
- IList ids, idTrusts, idSigs;
- ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+ IList ids, idTrusts, idSigs;
+ ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
- keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
+ keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
- // Read subkeys
- while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
+ // Read subkeys
+ while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
{
- keys.Add(ReadSubkey(bcpgInput));
+ keys.Add(ReadSubkey(bcpgInput));
}
}
- /// <summary>Return the first public key in the ring.</summary>
- public PgpPublicKey GetPublicKey()
+ /// <summary>Return the first public key in the ring.</summary>
+ public virtual PgpPublicKey GetPublicKey()
{
return (PgpPublicKey) keys[0];
}
- /// <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
- public PgpPublicKey GetPublicKey(
+ /// <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
+ public virtual PgpPublicKey GetPublicKey(
long keyId)
{
- foreach (PgpPublicKey k in keys)
- {
- if (keyId == k.KeyId)
+ foreach (PgpPublicKey k in keys)
+ {
+ if (keyId == k.KeyId)
{
return k;
}
}
- return null;
+ return null;
}
- /// <summary>Allows enumeration of all the public keys.</summary>
- /// <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
- public IEnumerable GetPublicKeys()
+ /// <summary>Allows enumeration of all the public keys.</summary>
+ /// <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
+ public virtual IEnumerable GetPublicKeys()
{
return new EnumerableProxy(keys);
}
- public byte[] GetEncoded()
+ public virtual byte[] GetEncoded()
{
MemoryStream bOut = new MemoryStream();
- Encode(bOut);
+ Encode(bOut);
- return bOut.ToArray();
+ return bOut.ToArray();
}
- public void Encode(
+ public virtual void Encode(
Stream outStr)
{
- if (outStr == null)
- throw new ArgumentNullException("outStr");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
- foreach (PgpPublicKey k in keys)
- {
- k.Encode(outStr);
+ foreach (PgpPublicKey k in keys)
+ {
+ k.Encode(outStr);
}
}
- /// <summary>
- /// Returns a new key ring with the public key passed in either added or
- /// replacing an existing one.
- /// </summary>
- /// <param name="pubRing">The public key ring to be modified.</param>
- /// <param name="pubKey">The public key to be inserted.</param>
- /// <returns>A new <c>PgpPublicKeyRing</c></returns>
+ /// <summary>
+ /// Returns a new key ring with the public key passed in either added or
+ /// replacing an existing one.
+ /// </summary>
+ /// <param name="pubRing">The public key ring to be modified.</param>
+ /// <param name="pubKey">The public key to be inserted.</param>
+ /// <returns>A new <c>PgpPublicKeyRing</c></returns>
public static PgpPublicKeyRing InsertPublicKey(
PgpPublicKeyRing pubRing,
PgpPublicKey pubKey)
{
IList keys = Platform.CreateArrayList(pubRing.keys);
bool found = false;
- bool masterFound = false;
+ bool masterFound = false;
- for (int i = 0; i != keys.Count; i++)
+ for (int i = 0; i != keys.Count; i++)
{
PgpPublicKey key = (PgpPublicKey) keys[i];
- if (key.KeyId == pubKey.KeyId)
+ if (key.KeyId == pubKey.KeyId)
{
found = true;
keys[i] = pubKey;
}
- if (key.IsMasterKey)
- {
- masterFound = true;
- }
- }
+ if (key.IsMasterKey)
+ {
+ masterFound = true;
+ }
+ }
- if (!found)
+ if (!found)
{
- if (pubKey.IsMasterKey)
- {
- if (masterFound)
- throw new ArgumentException("cannot add a master key to a ring that already has one");
-
- keys.Insert(0, pubKey);
- }
- else
- {
- keys.Add(pubKey);
- }
- }
-
- return new PgpPublicKeyRing(keys);
+ if (pubKey.IsMasterKey)
+ {
+ if (masterFound)
+ throw new ArgumentException("cannot add a master key to a ring that already has one");
+
+ keys.Insert(0, pubKey);
+ }
+ else
+ {
+ keys.Add(pubKey);
+ }
+ }
+
+ return new PgpPublicKeyRing(keys);
}
- /// <summary>Returns a new key ring with the public key passed in removed from the key ring.</summary>
- /// <param name="pubRing">The public key ring to be modified.</param>
- /// <param name="pubKey">The public key to be removed.</param>
- /// <returns>A new <c>PgpPublicKeyRing</c>, or null if pubKey is not found.</returns>
+ /// <summary>Returns a new key ring with the public key passed in removed from the key ring.</summary>
+ /// <param name="pubRing">The public key ring to be modified.</param>
+ /// <param name="pubKey">The public key to be removed.</param>
+ /// <returns>A new <c>PgpPublicKeyRing</c>, or null if pubKey is not found.</returns>
public static PgpPublicKeyRing RemovePublicKey(
PgpPublicKeyRing pubRing,
PgpPublicKey pubKey)
@@ -173,29 +173,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
IList keys = Platform.CreateArrayList(pubRing.keys);
bool found = false;
- for (int i = 0; i < keys.Count; i++)
+ for (int i = 0; i < keys.Count; i++)
{
PgpPublicKey key = (PgpPublicKey) keys[i];
- if (key.KeyId == pubKey.KeyId)
+ if (key.KeyId == pubKey.KeyId)
{
found = true;
keys.RemoveAt(i);
}
}
- return found ? new PgpPublicKeyRing(keys) : null;
+ return found ? new PgpPublicKeyRing(keys) : null;
}
- internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
- {
+ internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
+ {
PublicKeyPacket pk = (PublicKeyPacket) bcpgInput.ReadPacket();
- TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
+ TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
- // PGP 8 actually leaves out the signature.
- IList sigList = ReadSignaturesAndTrust(bcpgInput);
+ // PGP 8 actually leaves out the signature.
+ IList sigList = ReadSignaturesAndTrust(bcpgInput);
- return new PgpPublicKey(pk, kTrust, sigList);
- }
+ return new PgpPublicKey(pk, kTrust, sigList);
+ }
}
}
diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs
index 84d23614f..1027393ce 100644
--- a/crypto/src/openpgp/PgpSecretKey.cs
+++ b/crypto/src/openpgp/PgpSecretKey.cs
@@ -2,8 +2,11 @@ using System;
using System.Collections;
using System.IO;
+using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
@@ -59,6 +62,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) privKey.Key;
secKey = new DsaSecretBcpgKey(dsK.X);
break;
+ case PublicKeyAlgorithmTag.ECDH:
+ case PublicKeyAlgorithmTag.ECDsa:
+ ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey.Key;
+ secKey = new ECSecretBcpgKey(ecK.D);
+ break;
case PublicKeyAlgorithmTag.ElGamalEncrypt:
case PublicKeyAlgorithmTag.ElGamalGeneral:
ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key;
@@ -362,24 +370,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
private byte[] ExtractKeyData(
char[] passPhrase)
{
- SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm;
+ SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm;
byte[] encData = secret.GetSecretKeyData();
- if (alg == SymmetricKeyAlgorithmTag.Null)
+ if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
// TODO Check checksum here?
return encData;
- IBufferedCipher c = null;
- try
- {
- string cName = PgpUtilities.GetSymmetricCipherName(alg);
- c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
- }
- catch (Exception e)
- {
- throw new PgpException("Exception creating cipher", e);
- }
-
// TODO Factor this block out as 'decryptData'
try
{
@@ -389,9 +386,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
if (secret.PublicKeyPacket.Version >= 4)
{
- c.Init(false, new ParametersWithIV(key, iv));
-
- data = c.DoFinal(encData);
+ data = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iv, encData, 0, encData.Length);
bool useSha1 = secret.S2kUsage == SecretKeyPacket.UsageSha1;
byte[] check = Checksum(useSha1, data, (useSha1) ? data.Length - 20 : data.Length - 2);
@@ -417,15 +412,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
for (int i = 0; i != 4; i++)
{
- c.Init(false, new ParametersWithIV(key, iv));
-
int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;
data[pos] = encData[pos];
data[pos + 1] = encData[pos + 1];
pos += 2;
- c.DoFinal(encData, pos, encLen, data, pos);
+ byte[] tmp = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iv, encData, pos, encLen);
+ Array.Copy(tmp, 0, data, pos, encLen);
pos += encLen;
if (i != 3)
@@ -469,6 +463,25 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
+ private static byte[] RecoverKeyData(SymmetricKeyAlgorithmTag encAlgorithm, string modeAndPadding,
+ KeyParameter key, byte[] iv, byte[] keyData, int keyOff, int keyLen)
+ {
+ IBufferedCipher c;
+ try
+ {
+ string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+ c = CipherUtilities.GetCipher(cName + modeAndPadding);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+
+ c.Init(false, new ParametersWithIV(key, iv));
+
+ return c.DoFinal(keyData, keyOff, keyLen);
+ }
+
/// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
public PgpPrivateKey ExtractPrivateKey(
char[] passPhrase)
@@ -506,6 +519,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G);
privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams);
break;
+ case PublicKeyAlgorithmTag.ECDH:
+ privateKey = GetECKey("ECDH", bcpgIn);
+ break;
+ case PublicKeyAlgorithmTag.ECDsa:
+ privateKey = GetECKey("ECDSA", bcpgIn);
+ break;
case PublicKeyAlgorithmTag.ElGamalEncrypt:
case PublicKeyAlgorithmTag.ElGamalGeneral:
ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key;
@@ -517,7 +536,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
throw new PgpException("unknown public key algorithm encountered");
}
- return new PgpPrivateKey(privateKey, KeyId);
+ return new PgpPrivateKey(KeyId, pubPk, privateKey);
}
catch (PgpException e)
{
@@ -529,6 +548,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
+ private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn)
+ {
+ ECPublicBcpgKey ecdsaPub = (ECPublicBcpgKey)secret.PublicKeyPacket.Key;
+ ECSecretBcpgKey ecdsaPriv = new ECSecretBcpgKey(bcpgIn);
+ return new ECPrivateKeyParameters(algorithm, ecdsaPriv.X, ecdsaPub.CurveOid);
+ }
+
private static byte[] Checksum(
bool useSha1,
byte[] bytes,
@@ -752,5 +778,174 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return c.DoFinal(rawKeyData);
}
+
+ /**
+ * Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+ *
+ * @return a secret key object.
+ */
+ public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("protected-private-key"))
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string curveName;
+
+ string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (keyType.Equals("ecc"))
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+ }
+ else
+ {
+ throw new PgpException("no curve details found");
+ }
+
+ byte[] qVal;
+
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("q"))
+ {
+ qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+ }
+ else
+ {
+ throw new PgpException("no q value found");
+ }
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+
+ byte[] dValue = GetDValue(inputStream, passPhrase, curveName);
+ // TODO: check SHA-1 hash.
+
+ return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null,
+ new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), pubKey);
+ }
+
+ throw new PgpException("unknown key type found");
+ }
+
+ /**
+ * Parse a secret key from one of the GPG S expression keys.
+ *
+ * @return a secret key object.
+ */
+ public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase)
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("protected-private-key"))
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string curveName;
+
+ string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (keyType.Equals("ecc"))
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+ if (curveName.StartsWith("NIST "))
+ {
+ curveName = curveName.Substring("NIST ".Length);
+ }
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+ }
+ else
+ {
+ throw new PgpException("no curve details found");
+ }
+
+ byte[] qVal;
+
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("q"))
+ {
+ qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+ }
+ else
+ {
+ throw new PgpException("no q value found");
+ }
+
+ PublicKeyPacket pubPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow,
+ new ECDsaPublicBcpgKey(ECNamedCurveTable.GetOid(curveName), new BigInteger(1, qVal)));
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+
+ byte[] dValue = GetDValue(inputStream, passPhrase, curveName);
+ // TODO: check SHA-1 hash.
+
+ return new PgpSecretKey(new SecretKeyPacket(pubPacket, SymmetricKeyAlgorithmTag.Null, null, null,
+ new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), new PgpPublicKey(pubPacket));
+ }
+
+ throw new PgpException("unknown key type found");
+ }
+
+ private static byte[] GetDValue(Stream inputStream, char[] passPhrase, string curveName)
+ {
+ string type;
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string protection;
+ S2k s2k;
+ byte[] iv;
+ byte[] secKeyData;
+
+ type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("protected"))
+ {
+ protection = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ s2k = SXprUtilities.ParseS2k(inputStream);
+
+ iv = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+
+ secKeyData = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+ }
+ else
+ {
+ throw new PgpException("protected block not found");
+ }
+
+ // TODO: recognise other algorithms
+ KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, passPhrase);
+
+ byte[] data = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, secKeyData, 0, secKeyData.Length);
+
+ //
+ // parse the secret key S-expr
+ //
+ Stream keyIn = new MemoryStream(data, false);
+
+ SXprUtilities.SkipOpenParenthesis(keyIn);
+ SXprUtilities.SkipOpenParenthesis(keyIn);
+ SXprUtilities.SkipOpenParenthesis(keyIn);
+ String name = SXprUtilities.ReadString(keyIn, keyIn.ReadByte());
+ return SXprUtilities.ReadBytes(keyIn, keyIn.ReadByte());
+ }
}
}
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
index 4adf64012..d2177d09c 100644
--- a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
+++ b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
@@ -25,7 +25,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
list.Add(new Exportable(isCritical, isExportable));
}
- /// <summary>
+ public void SetFeature(
+ bool isCritical,
+ byte feature)
+ {
+ list.Add(new Features(isCritical, feature));
+ }
+
+ /// <summary>
/// Add a TrustSignature packet to the signature. The values for depth and trust are largely
/// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13.
/// </summary>
@@ -117,7 +124,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
list.Add(new SignerUserId(isCritical, userId));
}
- public void SetEmbeddedSignature(
+ public void SetSignerUserId(
+ bool isCritical,
+ byte[] rawUserId)
+ {
+ if (rawUserId == null)
+ throw new ArgumentNullException("rawUserId");
+
+ list.Add(new SignerUserId(isCritical, false, rawUserId));
+ }
+
+ public void SetEmbeddedSignature(
bool isCritical,
PgpSignature pgpSignature)
{
@@ -136,7 +153,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
Array.Copy(sig, sig.Length - data.Length, data, 0, data.Length);
- list.Add(new EmbeddedSignature(isCritical, data));
+ list.Add(new EmbeddedSignature(isCritical, false, data));
}
public void SetPrimaryUserId(
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
index 68fe4b594..156243f4e 100644
--- a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
+++ b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
@@ -209,7 +209,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return list;
}
- [Obsolete("Use 'Count' property instead")]
+ public Features GetFeatures()
+ {
+ SignatureSubpacket p = this.GetSubpacket(SignatureSubpacketTag.Features);
+
+ if (p == null)
+ return null;
+
+ return new Features(p.IsCritical(), p.IsLongLength(), p.GetData());
+ }
+
+ [Obsolete("Use 'Count' property instead")]
public int Size
{
get { return packets.Length; }
diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs
index 32e37b819..e4551db07 100644
--- a/crypto/src/openpgp/PgpUtilities.cs
+++ b/crypto/src/openpgp/PgpUtilities.cs
@@ -86,7 +86,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
case PublicKeyAlgorithmTag.Dsa:
encAlg = "DSA";
break;
- case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
+ case PublicKeyAlgorithmTag.ECDH:
+ encAlg = "ECDH";
+ break;
+ case PublicKeyAlgorithmTag.ECDsa:
+ encAlg = "ECDSA";
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
case PublicKeyAlgorithmTag.ElGamalGeneral:
encAlg = "ElGamal";
break;
@@ -135,7 +141,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
+ public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
{
int keySize;
switch (algorithm)
@@ -193,7 +199,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
char[] passPhrase)
{
int keySize = GetKeySize(algorithm);
- byte[] pBytes = Strings.ToByteArray(new string(passPhrase));
+ byte[] pBytes = Encoding.UTF8.GetBytes(passPhrase);
byte[] keyBytes = new byte[(keySize + 7) / 8];
int generatedBytes = 0;
@@ -431,5 +437,22 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return new ArmoredInputStream(inputStream, hasHeaders);
}
}
+
+ internal static IWrapper CreateWrapper(SymmetricKeyAlgorithmTag encAlgorithm)
+ {
+ switch (encAlgorithm)
+ {
+ case SymmetricKeyAlgorithmTag.Aes128:
+ case SymmetricKeyAlgorithmTag.Aes192:
+ case SymmetricKeyAlgorithmTag.Aes256:
+ return WrapperUtilities.GetWrapper("AESWRAP");
+ case SymmetricKeyAlgorithmTag.Camellia128:
+ case SymmetricKeyAlgorithmTag.Camellia192:
+ case SymmetricKeyAlgorithmTag.Camellia256:
+ return WrapperUtilities.GetWrapper("CAMELLIAWRAP");
+ default:
+ throw new PgpException("unknown wrap algorithm: " + encAlgorithm);
+ }
+ }
}
}
diff --git a/crypto/src/openpgp/Rfc6637Utilities.cs b/crypto/src/openpgp/Rfc6637Utilities.cs
new file mode 100644
index 000000000..5d992ec51
--- /dev/null
+++ b/crypto/src/openpgp/Rfc6637Utilities.cs
@@ -0,0 +1,138 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public sealed class Rfc6637Utilities
+ {
+ private Rfc6637Utilities()
+ {
+ }
+
+ // "Anonymous Sender ", which is the octet sequence
+ private static readonly byte[] ANONYMOUS_SENDER = Hex.Decode("416E6F6E796D6F75732053656E64657220202020");
+
+ public static string GetAgreementAlgorithm(PublicKeyPacket pubKeyData)
+ {
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+
+ switch (ecKey.HashAlgorithm)
+ {
+ case HashAlgorithmTag.Sha256:
+ return "ECCDHwithSHA256CKDF";
+ case HashAlgorithmTag.Sha384:
+ return "ECCDHwithSHA384CKDF";
+ case HashAlgorithmTag.Sha512:
+ return "ECCDHwithSHA512CKDF";
+ default:
+ throw new ArgumentException("Unknown hash algorithm specified: " + ecKey.HashAlgorithm);
+ }
+ }
+
+ public static DerObjectIdentifier GetKeyEncryptionOID(SymmetricKeyAlgorithmTag algID)
+ {
+ switch (algID)
+ {
+ case SymmetricKeyAlgorithmTag.Aes128:
+ return NistObjectIdentifiers.IdAes128Wrap;
+ case SymmetricKeyAlgorithmTag.Aes192:
+ return NistObjectIdentifiers.IdAes192Wrap;
+ case SymmetricKeyAlgorithmTag.Aes256:
+ return NistObjectIdentifiers.IdAes256Wrap;
+ default:
+ throw new PgpException("unknown symmetric algorithm ID: " + algID);
+ }
+ }
+
+ public static int GetKeyLength(SymmetricKeyAlgorithmTag algID)
+ {
+ switch (algID)
+ {
+ case SymmetricKeyAlgorithmTag.Aes128:
+ return 16;
+ case SymmetricKeyAlgorithmTag.Aes192:
+ return 24;
+ case SymmetricKeyAlgorithmTag.Aes256:
+ return 32;
+ default:
+ throw new PgpException("unknown symmetric algorithm ID: " + algID);
+ }
+ }
+
+ public static byte[] CreateKey(PublicKeyPacket pubKeyData, ECPoint s)
+ {
+ byte[] userKeyingMaterial = CreateUserKeyingMaterial(pubKeyData);
+
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+
+ return Kdf(ecKey.HashAlgorithm, s, GetKeyLength(ecKey.SymmetricKeyAlgorithm), userKeyingMaterial);
+ }
+
+ // RFC 6637 - Section 8
+ // curve_OID_len = (byte)len(curve_OID);
+ // Param = curve_OID_len || curve_OID || public_key_alg_ID || 03
+ // || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous
+ // Sender " || recipient_fingerprint;
+ // Z_len = the key size for the KEK_alg_ID used with AESKeyWrap
+ // Compute Z = KDF( S, Z_len, Param );
+ public static byte[] CreateUserKeyingMaterial(PublicKeyPacket pubKeyData)
+ {
+ MemoryStream pOut = new MemoryStream();
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+ byte[] encOid = ecKey.CurveOid.GetEncoded();
+
+ pOut.Write(encOid, 1, encOid.Length - 1);
+ pOut.WriteByte((byte)pubKeyData.Algorithm);
+ pOut.WriteByte(0x03);
+ pOut.WriteByte(0x01);
+ pOut.WriteByte((byte)ecKey.HashAlgorithm);
+ pOut.WriteByte((byte)ecKey.SymmetricKeyAlgorithm);
+ pOut.Write(ANONYMOUS_SENDER, 0, ANONYMOUS_SENDER.Length);
+
+ byte[] fingerprint = PgpPublicKey.CalculateFingerprint(pubKeyData);
+ pOut.Write(fingerprint, 0, fingerprint.Length);
+
+ return pOut.ToArray();
+ }
+
+ // RFC 6637 - Section 7
+ // Implements KDF( X, oBits, Param );
+ // Input: point X = (x,y)
+ // oBits - the desired size of output
+ // hBits - the size of output of hash function Hash
+ // Param - octets representing the parameters
+ // Assumes that oBits <= hBits
+ // Convert the point X to the octet string, see section 6:
+ // ZB' = 04 || x || y
+ // and extract the x portion from ZB'
+ // ZB = x;
+ // MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param );
+ // return oBits leftmost bits of MB.
+ private static byte[] Kdf(HashAlgorithmTag digestAlg, ECPoint s, int keyLen, byte[] parameters)
+ {
+ byte[] ZB = s.XCoord.GetEncoded();
+
+ string digestName = PgpUtilities.GetDigestName(digestAlg);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ digest.Update(0x00);
+ digest.Update(0x00);
+ digest.Update(0x00);
+ digest.Update(0x01);
+ digest.BlockUpdate(ZB, 0, ZB.Length);
+ digest.BlockUpdate(parameters, 0, parameters.Length);
+
+ byte[] hash = DigestUtilities.DoFinal(digest);
+
+ return Arrays.CopyOfRange(hash, 0, keyLen);
+ }
+ }
+}
diff --git a/crypto/src/openpgp/SXprUtilities.cs b/crypto/src/openpgp/SXprUtilities.cs
new file mode 100644
index 000000000..68ff373a8
--- /dev/null
+++ b/crypto/src/openpgp/SXprUtilities.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /**
+ * Utility functions for looking a S-expression keys. This class will move when it finds a better home!
+ * <p>
+ * Format documented here:
+ * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master
+ * </p>
+ */
+ public sealed class SXprUtilities
+ {
+ private SXprUtilities()
+ {
+ }
+
+ private static int ReadLength(Stream input, int ch)
+ {
+ int len = ch - '0';
+
+ while ((ch = input.ReadByte()) >= 0 && ch != ':')
+ {
+ len = len * 10 + ch - '0';
+ }
+
+ return len;
+ }
+
+ internal static string ReadString(Stream input, int ch)
+ {
+ int len = ReadLength(input, ch);
+
+ char[] chars = new char[len];
+
+ for (int i = 0; i != chars.Length; i++)
+ {
+ chars[i] = (char)input.ReadByte();
+ }
+
+ return new string(chars);
+ }
+
+ internal static byte[] ReadBytes(Stream input, int ch)
+ {
+ int len = ReadLength(input, ch);
+
+ byte[] data = new byte[len];
+
+ Streams.ReadFully(input, data);
+
+ return data;
+ }
+
+ internal static S2k ParseS2k(Stream input)
+ {
+ SkipOpenParenthesis(input);
+
+ string alg = ReadString(input, input.ReadByte());
+ byte[] iv = ReadBytes(input, input.ReadByte());
+ long iterationCount = Int64.Parse(ReadString(input, input.ReadByte()));
+
+ SkipCloseParenthesis(input);
+
+ // we have to return the actual iteration count provided.
+ return new MyS2k(HashAlgorithmTag.Sha1, iv, iterationCount);
+ }
+
+ internal static void SkipOpenParenthesis(Stream input)
+ {
+ int ch = input.ReadByte();
+ if (ch != '(')
+ throw new IOException("unknown character encountered");
+ }
+
+ internal static void SkipCloseParenthesis(Stream input)
+ {
+ int ch = input.ReadByte();
+ if (ch != ')')
+ throw new IOException("unknown character encountered");
+ }
+
+ private class MyS2k : S2k
+ {
+ private readonly long mIterationCount64;
+
+ internal MyS2k(HashAlgorithmTag algorithm, byte[] iv, long iterationCount64)
+ : base(algorithm, iv, (int)iterationCount64)
+ {
+ this.mIterationCount64 = iterationCount64;
+ }
+
+ public override long IterationCount
+ {
+ get { return mIterationCount64; }
+ }
+ }
+ }
+}
diff --git a/crypto/src/openpgp/WrappedGeneratorStream.cs b/crypto/src/openpgp/WrappedGeneratorStream.cs
index 6fc7329af..cdc9befb3 100644
--- a/crypto/src/openpgp/WrappedGeneratorStream.cs
+++ b/crypto/src/openpgp/WrappedGeneratorStream.cs
@@ -1,6 +1,6 @@
using System.IO;
-using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg.OpenPgp
{
diff --git a/crypto/src/openssl/MiscPemGenerator.cs b/crypto/src/openssl/MiscPemGenerator.cs
index c4c537904..6b91e8b1c 100644
--- a/crypto/src/openssl/MiscPemGenerator.cs
+++ b/crypto/src/openssl/MiscPemGenerator.cs
@@ -21,117 +21,117 @@ using Org.BouncyCastle.X509;
namespace Org.BouncyCastle.OpenSsl
{
- /**
- * PEM generator for the original set of PEM objects used in Open SSL.
- */
- public class MiscPemGenerator
- : PemObjectGenerator
- {
- private object obj;
- private string algorithm;
- private char[] password;
- private SecureRandom random;
-
- public MiscPemGenerator(object obj)
- {
- this.obj = obj;
- }
-
- public MiscPemGenerator(
- object obj,
- string algorithm,
- char[] password,
- SecureRandom random)
- {
- this.obj = obj;
- this.algorithm = algorithm;
- this.password = password;
- this.random = random;
- }
-
- private static PemObject CreatePemObject(object obj)
- {
- if (obj == null)
- throw new ArgumentNullException("obj");
-
- if (obj is AsymmetricCipherKeyPair)
- {
- return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private);
- }
-
- string type;
- byte[] encoding;
-
- if (obj is PemObject)
- return (PemObject)obj;
-
- if (obj is PemObjectGenerator)
- return ((PemObjectGenerator)obj).Generate();
-
- if (obj is X509Certificate)
- {
- // TODO Should we prefer "X509 CERTIFICATE" here?
- type = "CERTIFICATE";
- try
- {
- encoding = ((X509Certificate)obj).GetEncoded();
- }
- catch (CertificateEncodingException e)
- {
- throw new IOException("Cannot Encode object: " + e.ToString());
- }
- }
- else if (obj is X509Crl)
- {
- type = "X509 CRL";
- try
- {
- encoding = ((X509Crl)obj).GetEncoded();
- }
- catch (CrlException e)
- {
- throw new IOException("Cannot Encode object: " + e.ToString());
- }
- }
- else if (obj is AsymmetricKeyParameter)
- {
- AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
- if (akp.IsPrivate)
- {
- string keyType;
- encoding = EncodePrivateKey(akp, out keyType);
-
- type = keyType + " PRIVATE KEY";
- }
- else
- {
- type = "PUBLIC KEY";
-
- encoding = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(akp).GetDerEncoded();
- }
- }
- else if (obj is IX509AttributeCertificate)
- {
- type = "ATTRIBUTE CERTIFICATE";
- encoding = ((X509V2AttributeCertificate)obj).GetEncoded();
- }
- else if (obj is Pkcs10CertificationRequest)
- {
- type = "CERTIFICATE REQUEST";
- encoding = ((Pkcs10CertificationRequest)obj).GetEncoded();
- }
- else if (obj is Asn1.Cms.ContentInfo)
- {
- type = "PKCS7";
- encoding = ((Asn1.Cms.ContentInfo)obj).GetEncoded();
- }
- else
- {
- throw new PemGenerationException("Object type not supported: " + obj.GetType().FullName);
- }
-
- return new PemObject(type, encoding);
- }
+ /**
+ * PEM generator for the original set of PEM objects used in Open SSL.
+ */
+ public class MiscPemGenerator
+ : PemObjectGenerator
+ {
+ private object obj;
+ private string algorithm;
+ private char[] password;
+ private SecureRandom random;
+
+ public MiscPemGenerator(object obj)
+ {
+ this.obj = obj;
+ }
+
+ public MiscPemGenerator(
+ object obj,
+ string algorithm,
+ char[] password,
+ SecureRandom random)
+ {
+ this.obj = obj;
+ this.algorithm = algorithm;
+ this.password = password;
+ this.random = random;
+ }
+
+ private static PemObject CreatePemObject(object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ if (obj is AsymmetricCipherKeyPair)
+ {
+ return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private);
+ }
+
+ string type;
+ byte[] encoding;
+
+ if (obj is PemObject)
+ return (PemObject)obj;
+
+ if (obj is PemObjectGenerator)
+ return ((PemObjectGenerator)obj).Generate();
+
+ if (obj is X509Certificate)
+ {
+ // TODO Should we prefer "X509 CERTIFICATE" here?
+ type = "CERTIFICATE";
+ try
+ {
+ encoding = ((X509Certificate)obj).GetEncoded();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Cannot Encode object: " + e.ToString());
+ }
+ }
+ else if (obj is X509Crl)
+ {
+ type = "X509 CRL";
+ try
+ {
+ encoding = ((X509Crl)obj).GetEncoded();
+ }
+ catch (CrlException e)
+ {
+ throw new IOException("Cannot Encode object: " + e.ToString());
+ }
+ }
+ else if (obj is AsymmetricKeyParameter)
+ {
+ AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
+ if (akp.IsPrivate)
+ {
+ string keyType;
+ encoding = EncodePrivateKey(akp, out keyType);
+
+ type = keyType + " PRIVATE KEY";
+ }
+ else
+ {
+ type = "PUBLIC KEY";
+
+ encoding = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(akp).GetDerEncoded();
+ }
+ }
+ else if (obj is IX509AttributeCertificate)
+ {
+ type = "ATTRIBUTE CERTIFICATE";
+ encoding = ((X509V2AttributeCertificate)obj).GetEncoded();
+ }
+ else if (obj is Pkcs10CertificationRequest)
+ {
+ type = "CERTIFICATE REQUEST";
+ encoding = ((Pkcs10CertificationRequest)obj).GetEncoded();
+ }
+ else if (obj is Asn1.Cms.ContentInfo)
+ {
+ type = "PKCS7";
+ encoding = ((Asn1.Cms.ContentInfo)obj).GetEncoded();
+ }
+ else
+ {
+ throw new PemGenerationException("Object type not supported: " + obj.GetType().FullName);
+ }
+
+ return new PemObject(type, encoding);
+ }
// private string GetHexEncoded(byte[] bytes)
// {
@@ -147,130 +147,130 @@ namespace Org.BouncyCastle.OpenSsl
// return new string(chars);
// }
- private static PemObject CreatePemObject(
- object obj,
- string algorithm,
- char[] password,
- SecureRandom random)
- {
- if (obj == null)
- throw new ArgumentNullException("obj");
- if (algorithm == null)
- throw new ArgumentNullException("algorithm");
- if (password == null)
- throw new ArgumentNullException("password");
- if (random == null)
- throw new ArgumentNullException("random");
-
- if (obj is AsymmetricCipherKeyPair)
- {
- return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private, algorithm, password, random);
- }
-
- string type = null;
- byte[] keyData = null;
-
- if (obj is AsymmetricKeyParameter)
- {
- AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
- if (akp.IsPrivate)
- {
- string keyType;
- keyData = EncodePrivateKey(akp, out keyType);
-
- type = keyType + " PRIVATE KEY";
- }
- }
-
- if (type == null || keyData == null)
- {
- // TODO Support other types?
- throw new PemGenerationException("Object type not supported: " + obj.GetType().FullName);
- }
-
-
- string dekAlgName = Platform.ToUpperInvariant(algorithm);
+ private static PemObject CreatePemObject(
+ object obj,
+ string algorithm,
+ char[] password,
+ SecureRandom random)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (password == null)
+ throw new ArgumentNullException("password");
+ if (random == null)
+ throw new ArgumentNullException("random");
+
+ if (obj is AsymmetricCipherKeyPair)
+ {
+ return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private, algorithm, password, random);
+ }
+
+ string type = null;
+ byte[] keyData = null;
+
+ if (obj is AsymmetricKeyParameter)
+ {
+ AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
+ if (akp.IsPrivate)
+ {
+ string keyType;
+ keyData = EncodePrivateKey(akp, out keyType);
+
+ type = keyType + " PRIVATE KEY";
+ }
+ }
+
+ if (type == null || keyData == null)
+ {
+ // TODO Support other types?
+ throw new PemGenerationException("Object type not supported: " + obj.GetType().FullName);
+ }
+
+
+ string dekAlgName = Platform.ToUpperInvariant(algorithm);
// Note: For backward compatibility
- if (dekAlgName == "DESEDE")
- {
- dekAlgName = "DES-EDE3-CBC";
- }
-
- int ivLength = dekAlgName.StartsWith("AES-") ? 16 : 8;
-
- byte[] iv = new byte[ivLength];
- random.NextBytes(iv);
-
- byte[] encData = PemUtilities.Crypt(true, keyData, password, dekAlgName, iv);
-
- IList headers = Platform.CreateArrayList(2);
-
- headers.Add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
- headers.Add(new PemHeader("DEK-Info", dekAlgName + "," + Hex.ToHexString(iv)));
-
- return new PemObject(type, headers, encData);
- }
-
- private static byte[] EncodePrivateKey(
- AsymmetricKeyParameter akp,
- out string keyType)
- {
- PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp);
-
- DerObjectIdentifier oid = info.AlgorithmID.ObjectID;
-
- if (oid.Equals(X9ObjectIdentifiers.IdDsa))
- {
- keyType = "DSA";
-
- DsaParameter p = DsaParameter.GetInstance(info.AlgorithmID.Parameters);
-
- BigInteger x = ((DsaPrivateKeyParameters) akp).X;
- BigInteger y = p.G.ModPow(x, p.P);
-
- // TODO Create an ASN1 object somewhere for this?
- return new DerSequence(
- new DerInteger(0),
- new DerInteger(p.P),
- new DerInteger(p.Q),
- new DerInteger(p.G),
- new DerInteger(y),
- new DerInteger(x)).GetEncoded();
- }
-
- if (oid.Equals(PkcsObjectIdentifiers.RsaEncryption))
- {
- keyType = "RSA";
- }
- else if (oid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)
- || oid.Equals(X9ObjectIdentifiers.IdECPublicKey))
- {
- keyType = "EC";
- }
- else
- {
- throw new ArgumentException("Cannot handle private key of type: " + akp.GetType().FullName, "akp");
- }
-
- return info.PrivateKey.GetEncoded();
- }
-
- public PemObject Generate()
- {
- try
- {
- if (algorithm != null)
- {
- return CreatePemObject(obj, algorithm, password, random);
- }
-
- return CreatePemObject(obj);
- }
- catch (IOException e)
- {
- throw new PemGenerationException("encoding exception", e);
- }
- }
- }
+ if (dekAlgName == "DESEDE")
+ {
+ dekAlgName = "DES-EDE3-CBC";
+ }
+
+ int ivLength = dekAlgName.StartsWith("AES-") ? 16 : 8;
+
+ byte[] iv = new byte[ivLength];
+ random.NextBytes(iv);
+
+ byte[] encData = PemUtilities.Crypt(true, keyData, password, dekAlgName, iv);
+
+ IList headers = Platform.CreateArrayList(2);
+
+ headers.Add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
+ headers.Add(new PemHeader("DEK-Info", dekAlgName + "," + Hex.ToHexString(iv)));
+
+ return new PemObject(type, headers, encData);
+ }
+
+ private static byte[] EncodePrivateKey(
+ AsymmetricKeyParameter akp,
+ out string keyType)
+ {
+ PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp);
+ AlgorithmIdentifier algID = info.PrivateKeyAlgorithm;
+ DerObjectIdentifier oid = algID.ObjectID;
+
+ if (oid.Equals(X9ObjectIdentifiers.IdDsa))
+ {
+ keyType = "DSA";
+
+ DsaParameter p = DsaParameter.GetInstance(algID.Parameters);
+
+ BigInteger x = ((DsaPrivateKeyParameters) akp).X;
+ BigInteger y = p.G.ModPow(x, p.P);
+
+ // TODO Create an ASN1 object somewhere for this?
+ return new DerSequence(
+ new DerInteger(0),
+ new DerInteger(p.P),
+ new DerInteger(p.Q),
+ new DerInteger(p.G),
+ new DerInteger(y),
+ new DerInteger(x)).GetEncoded();
+ }
+
+ if (oid.Equals(PkcsObjectIdentifiers.RsaEncryption))
+ {
+ keyType = "RSA";
+ }
+ else if (oid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)
+ || oid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+ {
+ keyType = "EC";
+ }
+ else
+ {
+ throw new ArgumentException("Cannot handle private key of type: " + akp.GetType().FullName, "akp");
+ }
+
+ return info.ParsePrivateKey().GetEncoded();
+ }
+
+ public PemObject Generate()
+ {
+ try
+ {
+ if (algorithm != null)
+ {
+ return CreatePemObject(obj, algorithm, password, random);
+ }
+
+ return CreatePemObject(obj);
+ }
+ catch (IOException e)
+ {
+ throw new PemGenerationException("encoding exception", e);
+ }
+ }
+ }
}
diff --git a/crypto/src/openssl/PEMReader.cs b/crypto/src/openssl/PEMReader.cs
index 9d3560838..ec5d1b414 100644
--- a/crypto/src/openssl/PEMReader.cs
+++ b/crypto/src/openssl/PEMReader.cs
@@ -109,6 +109,7 @@ namespace Org.BouncyCastle.OpenSsl
case "X509 CERTIFICATE":
return ReadCertificate(obj);
case "PKCS7":
+ case "CMS":
return ReadPkcs7(obj);
case "X509 CRL":
return ReadCrl(obj);
@@ -276,7 +277,7 @@ namespace Org.BouncyCastle.OpenSsl
if (seq.Count != 9)
throw new PemException("malformed sequence in RSA private key");
- RsaPrivateKeyStructure rsa = new RsaPrivateKeyStructure(seq);
+ RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(seq);
pubSpec = new RsaKeyParameters(false, rsa.Modulus, rsa.PublicExponent);
privSpec = new RsaPrivateCrtKeyParameters(
diff --git a/crypto/src/pkcs/Pkcs10CertificationRequest.cs b/crypto/src/pkcs/Pkcs10CertificationRequest.cs
index 9f24eb18a..b68979cad 100644
--- a/crypto/src/pkcs/Pkcs10CertificationRequest.cs
+++ b/crypto/src/pkcs/Pkcs10CertificationRequest.cs
@@ -15,6 +15,7 @@ using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Collections;
using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Crypto.Operators;
namespace Org.BouncyCastle.Pkcs
{
@@ -198,17 +199,18 @@ namespace Org.BouncyCastle.Pkcs
Stream input)
: base((Asn1Sequence) Asn1Object.FromStream(input))
{
- }
-
- /// <summary>
- /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
- /// </summary>
- ///<param name="signatureAlgorithm">Name of Sig Alg.</param>
- /// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
- /// <param name="publicKey">Public Key to be included in cert reqest.</param>
- /// <param name="attributes">ASN1Set of Attributes.</param>
- /// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
- public Pkcs10CertificationRequest(
+ }
+
+ /// <summary>
+ /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+ /// </summary>
+ ///<param name="signatureAlgorithm">Name of Sig Alg.</param>
+ /// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+ /// <param name="publicKey">Public Key to be included in cert reqest.</param>
+ /// <param name="attributes">ASN1Set of Attributes.</param>
+ /// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
+ [Obsolete("Use constructor with an ISignatureCalculator")]
+ public Pkcs10CertificationRequest(
string signatureAlgorithm,
X509Name subject,
AsymmetricKeyParameter publicKey,
@@ -226,79 +228,84 @@ namespace Org.BouncyCastle.Pkcs
if (!signingKey.IsPrivate)
throw new ArgumentException("key for signing must be private", "signingKey");
-// DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm);
- string algorithmName = Platform.ToUpperInvariant(signatureAlgorithm);
- DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName];
-
- if (sigOid == null)
- {
- try
- {
- sigOid = new DerObjectIdentifier(algorithmName);
- }
- catch (Exception e)
- {
- throw new ArgumentException("Unknown signature type requested", e);
- }
- }
-
- if (noParams.Contains(sigOid))
- {
- this.sigAlgId = new AlgorithmIdentifier(sigOid);
- }
- else if (exParams.Contains(algorithmName))
- {
- this.sigAlgId = new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
- }
- else
- {
- this.sigAlgId = new AlgorithmIdentifier(sigOid, DerNull.Instance);
- }
-
- SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
-
- this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
-
- ISigner sig = SignerUtilities.GetSigner(signatureAlgorithm);
-
- sig.Init(true, signingKey);
-
- try
- {
- // Encode.
- byte[] b = reqInfo.GetDerEncoded();
- sig.BlockUpdate(b, 0, b.Length);
- }
- catch (Exception e)
- {
- throw new ArgumentException("exception encoding TBS cert request", e);
- }
-
- // Generate Signature.
- sigBits = new DerBitString(sig.GenerateSignature());
+ init(new Asn1SignatureCalculator(signatureAlgorithm, signingKey), subject, publicKey, attributes, signingKey);
}
-// internal Pkcs10CertificationRequest(
-// Asn1InputStream seqStream)
-// {
-// Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject();
-// try
-// {
-// this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
-// this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
-// this.sigBits = (DerBitString) seq[2];
-// }
-// catch (Exception ex)
-// {
-// throw new ArgumentException("Create From Asn1Sequence: " + ex.Message);
-// }
-// }
-
- /// <summary>
- /// Get the public key.
- /// </summary>
- /// <returns>The public key.</returns>
- public AsymmetricKeyParameter GetPublicKey()
+ /// <summary>
+ /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+ /// </summary>
+ ///<param name="signatureCalculator">The signature calculator to sign the PKCS#10 request with.</param>
+ /// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+ /// <param name="publicKey">Public Key to be included in cert reqest.</param>
+ /// <param name="attributes">ASN1Set of Attributes.</param>
+ /// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
+ public Pkcs10CertificationRequest(
+ ISignatureCalculator signatureCalculator,
+ X509Name subject,
+ AsymmetricKeyParameter publicKey,
+ Asn1Set attributes,
+ AsymmetricKeyParameter signingKey)
+ {
+ if (signatureCalculator == null)
+ throw new ArgumentNullException("signatureCalculator");
+ if (subject == null)
+ throw new ArgumentNullException("subject");
+ if (publicKey == null)
+ throw new ArgumentNullException("publicKey");
+ if (publicKey.IsPrivate)
+ throw new ArgumentException("expected public key", "publicKey");
+ if (!signingKey.IsPrivate)
+ throw new ArgumentException("key for signing must be private", "signingKey");
+
+ init(signatureCalculator, subject, publicKey, attributes, signingKey);
+ }
+
+ private void init(
+ ISignatureCalculator signatureCalculator,
+ X509Name subject,
+ AsymmetricKeyParameter publicKey,
+ Asn1Set attributes,
+ AsymmetricKeyParameter signingKey)
+ {
+ this.sigAlgId = (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails;
+
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+ this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
+
+ IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+ byte[] reqInfoData = reqInfo.GetDerEncoded();
+
+ streamCalculator.Stream.Write(reqInfoData, 0, reqInfoData.Length);
+
+ streamCalculator.Stream.Close();
+
+ // Generate Signature.
+ sigBits = new DerBitString(((IBlockResult)streamCalculator.GetResult()).DoFinal());
+ }
+
+ // internal Pkcs10CertificationRequest(
+ // Asn1InputStream seqStream)
+ // {
+ // Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject();
+ // try
+ // {
+ // this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
+ // this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
+ // this.sigBits = (DerBitString) seq[2];
+ // }
+ // catch (Exception ex)
+ // {
+ // throw new ArgumentException("Create From Asn1Sequence: " + ex.Message);
+ // }
+ // }
+
+ /// <summary>
+ /// Get the public key.
+ /// </summary>
+ /// <returns>The public key.</returns>
+ public AsymmetricKeyParameter GetPublicKey()
{
return PublicKeyFactory.CreateKey(reqInfo.SubjectPublicKeyInfo);
}
@@ -315,55 +322,47 @@ namespace Org.BouncyCastle.Pkcs
public bool Verify(
AsymmetricKeyParameter publicKey)
{
- ISigner sig;
-
- try
- {
- sig = SignerUtilities.GetSigner(GetSignatureName(sigAlgId));
- }
- catch (Exception e)
- {
- // try an alternate
- string alt = (string) oids[sigAlgId.ObjectID];
-
- if (alt != null)
- {
- sig = SignerUtilities.GetSigner(alt);
- }
- else
- {
- throw e;
- }
- }
-
- SetSignatureParameters(sig, sigAlgId.Parameters);
-
- sig.Init(false, publicKey);
-
- try
- {
- byte[] b = reqInfo.GetDerEncoded();
- sig.BlockUpdate(b, 0, b.Length);
- }
- catch (Exception e)
- {
- throw new SignatureException("exception encoding TBS cert request", e);
- }
-
- return sig.VerifySignature(sigBits.GetBytes());
+ return Verify(new Asn1SignatureVerifierProvider(publicKey));
}
-// /// <summary>
-// /// Get the Der Encoded Pkcs10 Certification Request.
-// /// </summary>
-// /// <returns>A byte array.</returns>
-// public byte[] GetEncoded()
-// {
-// return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded();
-// }
-
- // TODO Figure out how to set parameters on an ISigner
- private void SetSignatureParameters(
+ public bool Verify(
+ ISignatureVerifierProvider verifierProvider)
+ {
+ return Verify(verifierProvider.CreateSignatureVerifier(sigAlgId));
+ }
+
+ public bool Verify(
+ ISignatureVerifier verifier)
+ {
+ try
+ {
+ byte[] b = reqInfo.GetDerEncoded();
+
+ IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+ streamCalculator.Stream.Write(b, 0, b.Length);
+
+ streamCalculator.Stream.Close();
+
+ return ((IVerifier)streamCalculator.GetResult()).IsVerified(sigBits.GetBytes());
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("exception encoding TBS cert request", e);
+ }
+ }
+
+ // /// <summary>
+ // /// Get the Der Encoded Pkcs10 Certification Request.
+ // /// </summary>
+ // /// <returns>A byte array.</returns>
+ // public byte[] GetEncoded()
+ // {
+ // return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded();
+ // }
+
+ // TODO Figure out how to set parameters on an ISigner
+ private void SetSignatureParameters(
ISigner signature,
Asn1Encodable asn1Params)
{
diff --git a/crypto/src/pkcs/Pkcs12Store.cs b/crypto/src/pkcs/Pkcs12Store.cs
index 40364eec7..e4fe29401 100644
--- a/crypto/src/pkcs/Pkcs12Store.cs
+++ b/crypto/src/pkcs/Pkcs12Store.cs
@@ -28,6 +28,8 @@ namespace Org.BouncyCastle.Pkcs
private readonly DerObjectIdentifier certAlgorithm;
private readonly bool useDerEncoding;
+ private AsymmetricKeyEntry unmarkedKeyEntry = null;
+
private const int MinIterations = 1024;
private const int SaltSize = 20;
@@ -107,22 +109,101 @@ namespace Org.BouncyCastle.Pkcs
Load(input, password);
}
+ protected virtual void LoadKeyBag(PrivateKeyInfo privKeyInfo, Asn1Set bagAttributes)
+ {
+ AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo);
+
+ IDictionary attributes = Platform.CreateHashtable();
+ AsymmetricKeyEntry keyEntry = new AsymmetricKeyEntry(privKey, attributes);
+
+ string alias = null;
+ Asn1OctetString localId = null;
+
+ if (bagAttributes != null)
+ {
+ foreach (Asn1Sequence sq in bagAttributes)
+ {
+ DerObjectIdentifier aOid = DerObjectIdentifier.GetInstance(sq[0]);
+ Asn1Set attrSet = Asn1Set.GetInstance(sq[1]);
+ Asn1Encodable attr = null;
+
+ if (attrSet.Count > 0)
+ {
+ // TODO We should be adding all attributes in the set
+ attr = attrSet[0];
+
+ // TODO We might want to "merge" attribute sets with
+ // the same OID - currently, differing values give an error
+ if (attributes.Contains(aOid.Id))
+ {
+ // OK, but the value has to be the same
+ if (!attributes[aOid.Id].Equals(attr))
+ throw new IOException("attempt to add existing attribute with different value");
+ }
+ else
+ {
+ attributes.Add(aOid.Id, attr);
+ }
+
+ if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+ {
+ alias = ((DerBmpString)attr).GetString();
+ // TODO Do these in a separate loop, just collect aliases here
+ keys[alias] = keyEntry;
+ }
+ else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+ {
+ localId = (Asn1OctetString)attr;
+ }
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ string name = Hex.ToHexString(localId.GetOctets());
+
+ if (alias == null)
+ {
+ keys[name] = keyEntry;
+ }
+ else
+ {
+ // TODO There may have been more than one alias
+ localIds[alias] = name;
+ }
+ }
+ else
+ {
+ unmarkedKeyEntry = keyEntry;
+ }
+ }
+
+ protected virtual void LoadPkcs8ShroudedKeyBag(EncryptedPrivateKeyInfo encPrivKeyInfo, Asn1Set bagAttributes,
+ char[] password, bool wrongPkcs12Zero)
+ {
+ if (password != null)
+ {
+ PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
+ password, wrongPkcs12Zero, encPrivKeyInfo);
+
+ LoadKeyBag(privInfo, bagAttributes);
+ }
+ }
+
public void Load(
Stream input,
char[] password)
{
if (input == null)
throw new ArgumentNullException("input");
- if (password == null)
- throw new ArgumentNullException("password");
Asn1Sequence obj = (Asn1Sequence) Asn1Object.FromStream(input);
Pfx bag = new Pfx(obj);
ContentInfo info = bag.AuthSafe;
- bool unmarkedKey = false;
bool wrongPkcs12Zero = false;
- if (bag.MacData != null) // check the mac code
+ if (password != null && bag.MacData != null) // check the mac code
{
MacData mData = bag.MacData;
DigestInfo dInfo = mData.Mac;
@@ -152,8 +233,9 @@ namespace Org.BouncyCastle.Pkcs
keys.Clear();
localIds.Clear();
+ unmarkedKeyEntry = null;
- IList chain = Platform.CreateArrayList();
+ IList certBags = Platform.CreateArrayList();
if (info.ContentType.Equals(PkcsObjectIdentifiers.Data))
{
@@ -166,109 +248,28 @@ namespace Org.BouncyCastle.Pkcs
{
DerObjectIdentifier oid = ci.ContentType;
+ byte[] octets = null;
if (oid.Equals(PkcsObjectIdentifiers.Data))
{
- byte[] octets = ((Asn1OctetString)ci.Content).GetOctets();
- Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
-
- foreach (Asn1Sequence subSeq in seq)
+ octets = ((Asn1OctetString)ci.Content).GetOctets();
+ }
+ else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
+ {
+ if (password != null)
{
- SafeBag b = new SafeBag(subSeq);
-
- if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
- {
- EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
- PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
- password, wrongPkcs12Zero, eIn);
- AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
-
- //
- // set the attributes on the key
- //
- IDictionary attributes = Platform.CreateHashtable();
- AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
- string alias = null;
- Asn1OctetString localId = null;
-
- if (b.BagAttributes != null)
- {
- foreach (Asn1Sequence sq in b.BagAttributes)
- {
- DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
- Asn1Set attrSet = (Asn1Set) sq[1];
- Asn1Encodable attr = null;
-
- if (attrSet.Count > 0)
- {
- // TODO We should be adding all attributes in the set
- attr = attrSet[0];
-
- // TODO We might want to "merge" attribute sets with
- // the same OID - currently, differing values give an error
- if (attributes.Contains(aOid.Id))
- {
- // OK, but the value has to be the same
- if (!attributes[aOid.Id].Equals(attr))
- {
- throw new IOException("attempt to add existing attribute with different value");
- }
- }
- else
- {
- attributes.Add(aOid.Id, attr);
- }
-
- if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
- {
- alias = ((DerBmpString)attr).GetString();
- // TODO Do these in a separate loop, just collect aliases here
- keys[alias] = pkcs12Key;
- }
- else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
- {
- localId = (Asn1OctetString)attr;
- }
- }
- }
- }
-
- if (localId != null)
- {
- string name = Hex.ToHexString(localId.GetOctets());
-
- if (alias == null)
- {
- keys[name] = pkcs12Key;
- }
- else
- {
- // TODO There may have been more than one alias
- localIds[alias] = name;
- }
- }
- else
- {
- unmarkedKey = true;
- keys["unmarked"] = pkcs12Key;
- }
- }
- else if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
- {
- chain.Add(b);
- }
- else
- {
- Console.WriteLine("extra " + b.BagID);
- Console.WriteLine("extra " + Asn1Dump.DumpAsString(b));
- }
+ EncryptedData d = EncryptedData.GetInstance(ci.Content);
+ octets = CryptPbeData(false, d.EncryptionAlgorithm,
+ password, wrongPkcs12Zero, d.Content.GetOctets());
}
}
- else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
+ else
+ {
+ // TODO Other data types
+ }
+
+ if (octets != null)
{
- EncryptedData d = EncryptedData.GetInstance(ci.Content);
- byte[] octets = CryptPbeData(false, d.EncryptionAlgorithm,
- password, wrongPkcs12Zero, d.Content.GetOctets());
- Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
+ Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(octets);
foreach (Asn1Sequence subSeq in seq)
{
@@ -276,156 +277,23 @@ namespace Org.BouncyCastle.Pkcs
if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
{
- chain.Add(b);
+ certBags.Add(b);
}
else if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
{
- EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
- PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
- password, wrongPkcs12Zero, eIn);
- AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
-
- //
- // set the attributes on the key
- //
- IDictionary attributes = Platform.CreateHashtable();
- AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
- string alias = null;
- Asn1OctetString localId = null;
-
- foreach (Asn1Sequence sq in b.BagAttributes)
- {
- DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
- Asn1Set attrSet = (Asn1Set) sq[1];
- Asn1Encodable attr = null;
-
- if (attrSet.Count > 0)
- {
- // TODO We should be adding all attributes in the set
- attr = attrSet[0];
-
- // TODO We might want to "merge" attribute sets with
- // the same OID - currently, differing values give an error
- if (attributes.Contains(aOid.Id))
- {
- // OK, but the value has to be the same
- if (!attributes[aOid.Id].Equals(attr))
- {
- throw new IOException("attempt to add existing attribute with different value");
- }
- }
- else
- {
- attributes.Add(aOid.Id, attr);
- }
-
- if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
- {
- alias = ((DerBmpString)attr).GetString();
- // TODO Do these in a separate loop, just collect aliases here
- keys[alias] = pkcs12Key;
- }
- else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
- {
- localId = (Asn1OctetString)attr;
- }
- }
- }
-
- // TODO Should we be checking localIds != null here
- // as for PkcsObjectIdentifiers.Data version above?
-
- string name = Hex.ToHexString(localId.GetOctets());
-
- if (alias == null)
- {
- keys[name] = pkcs12Key;
- }
- else
- {
- // TODO There may have been more than one alias
- localIds[alias] = name;
- }
+ LoadPkcs8ShroudedKeyBag(EncryptedPrivateKeyInfo.GetInstance(b.BagValue),
+ b.BagAttributes, password, wrongPkcs12Zero);
}
else if (b.BagID.Equals(PkcsObjectIdentifiers.KeyBag))
{
- PrivateKeyInfo privKeyInfo = PrivateKeyInfo.GetInstance(b.BagValue);
- AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo);
-
- //
- // set the attributes on the key
- //
- string alias = null;
- Asn1OctetString localId = null;
- IDictionary attributes = Platform.CreateHashtable();
- AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
-
- foreach (Asn1Sequence sq in b.BagAttributes)
- {
- DerObjectIdentifier aOid = DerObjectIdentifier.GetInstance(sq[0]);
- Asn1Set attrSet = Asn1Set.GetInstance(sq[1]);
- Asn1Encodable attr = null;
-
- if (attrSet.Count > 0)
- {
- // TODO We should be adding all attributes in the set
- attr = attrSet[0];
-
- // TODO We might want to "merge" attribute sets with
- // the same OID - currently, differing values give an error
- if (attributes.Contains(aOid.Id))
- {
- // OK, but the value has to be the same
- if (!attributes[aOid.Id].Equals(attr))
- {
- throw new IOException("attempt to add existing attribute with different value");
- }
- }
- else
- {
- attributes.Add(aOid.Id, attr);
- }
-
- if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
- {
- alias = ((DerBmpString)attr).GetString();
- // TODO Do these in a separate loop, just collect aliases here
- keys[alias] = pkcs12Key;
- }
- else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
- {
- localId = (Asn1OctetString)attr;
- }
- }
- }
-
- // TODO Should we be checking localIds != null here
- // as for PkcsObjectIdentifiers.Data version above?
-
- string name = Hex.ToHexString(localId.GetOctets());
-
- if (alias == null)
- {
- keys[name] = pkcs12Key;
- }
- else
- {
- // TODO There may have been more than one alias
- localIds[alias] = name;
- }
+ LoadKeyBag(PrivateKeyInfo.GetInstance(b.BagValue), b.BagAttributes);
}
else
{
- Console.WriteLine("extra " + b.BagID);
- Console.WriteLine("extra " + Asn1Dump.DumpAsString(b));
+ // TODO Other bag types
}
}
}
- else
- {
- Console.WriteLine("extra " + oid);
- Console.WriteLine("extra " + Asn1Dump.DumpAsString(ci.Content));
- }
}
}
@@ -433,10 +301,10 @@ namespace Org.BouncyCastle.Pkcs
chainCerts.Clear();
keyCerts.Clear();
- foreach (SafeBag b in chain)
+ foreach (SafeBag b in certBags)
{
- CertBag cb = new CertBag((Asn1Sequence)b.BagValue);
- byte[] octets = ((Asn1OctetString) cb.CertValue).GetOctets();
+ CertBag certBag = new CertBag((Asn1Sequence)b.BagValue);
+ byte[] octets = ((Asn1OctetString)certBag.CertValue).GetOctets();
X509Certificate cert = new X509CertificateParser().ReadCertificate(octets);
//
@@ -486,21 +354,18 @@ namespace Org.BouncyCastle.Pkcs
}
CertId certId = new CertId(cert.GetPublicKey());
- X509CertificateEntry pkcs12Cert = new X509CertificateEntry(cert, attributes);
+ X509CertificateEntry certEntry = new X509CertificateEntry(cert, attributes);
- chainCerts[certId] = pkcs12Cert;
+ chainCerts[certId] = certEntry;
- if (unmarkedKey)
+ if (unmarkedKeyEntry != null)
{
if (keyCerts.Count == 0)
{
string name = Hex.ToHexString(certId.Id);
- keyCerts[name] = pkcs12Cert;
-
- object temp = keys["unmarked"];
- keys.Remove("unmarked");
- keys[name] = temp;
+ keyCerts[name] = certEntry;
+ keys[name] = unmarkedKeyEntry;
}
}
else
@@ -509,13 +374,13 @@ namespace Org.BouncyCastle.Pkcs
{
string name = Hex.ToHexString(localId.GetOctets());
- keyCerts[name] = pkcs12Cert;
+ keyCerts[name] = certEntry;
}
if (alias != null)
{
// TODO There may have been more than one alias
- certs[alias] = pkcs12Cert;
+ certs[alias] = certEntry;
}
}
}
@@ -841,24 +706,34 @@ namespace Org.BouncyCastle.Pkcs
{
if (stream == null)
throw new ArgumentNullException("stream");
- if (password == null)
- throw new ArgumentNullException("password");
if (random == null)
throw new ArgumentNullException("random");
//
- // handle the key
+ // handle the keys
//
- Asn1EncodableVector keyS = new Asn1EncodableVector();
+ Asn1EncodableVector keyBags = new Asn1EncodableVector();
foreach (string name in keys.Keys)
{
byte[] kSalt = new byte[SaltSize];
random.NextBytes(kSalt);
- AsymmetricKeyEntry privKey = (AsymmetricKeyEntry) keys[name];
- EncryptedPrivateKeyInfo kInfo =
- EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
- keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+ AsymmetricKeyEntry privKey = (AsymmetricKeyEntry)keys[name];
+
+ DerObjectIdentifier bagOid;
+ Asn1Encodable bagData;
+
+ if (password == null)
+ {
+ bagOid = PkcsObjectIdentifiers.KeyBag;
+ bagData = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privKey.Key);
+ }
+ else
+ {
+ bagOid = PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag;
+ bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+ keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+ }
Asn1EncodableVector kName = new Asn1EncodableVector();
@@ -903,13 +778,11 @@ namespace Org.BouncyCastle.Pkcs
new DerSet(subjectKeyID)));
}
- SafeBag kBag = new SafeBag(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag, kInfo.ToAsn1Object(), new DerSet(kName));
- keyS.Add(kBag);
+ keyBags.Add(new SafeBag(bagOid, bagData.ToAsn1Object(), new DerSet(kName)));
}
- byte[] derEncodedBytes = new DerSequence(keyS).GetDerEncoded();
-
- BerOctetString keyString = new BerOctetString(derEncodedBytes);
+ byte[] keyBagsEncoding = new DerSequence(keyBags).GetDerEncoded();
+ ContentInfo keysInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(keyBagsEncoding));
//
// certificate processing
@@ -918,7 +791,7 @@ namespace Org.BouncyCastle.Pkcs
random.NextBytes(cSalt);
- Asn1EncodableVector certSeq = new Asn1EncodableVector();
+ Asn1EncodableVector certBags = new Asn1EncodableVector();
Pkcs12PbeParams cParams = new Pkcs12PbeParams(cSalt, MinIterations);
AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.ToAsn1Object());
ISet doneCerts = new HashSet();
@@ -972,10 +845,7 @@ namespace Org.BouncyCastle.Pkcs
new DerSet(subjectKeyID)));
}
- SafeBag sBag = new SafeBag(
- PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
-
- certSeq.Add(sBag);
+ certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
doneCerts.Add(certEntry.Certificate);
}
@@ -1026,10 +896,7 @@ namespace Org.BouncyCastle.Pkcs
new DerSet(new DerBmpString(certId))));
}
- SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag,
- cBag.ToAsn1Object(), new DerSet(fName));
-
- certSeq.Add(sBag);
+ certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
doneCerts.Add(cert.Certificate);
}
@@ -1062,22 +929,24 @@ namespace Org.BouncyCastle.Pkcs
new DerSet(cert[oid])));
}
- SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
-
- certSeq.Add(sBag);
+ certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
}
- derEncodedBytes = new DerSequence(certSeq).GetDerEncoded();
-
- byte[] certBytes = CryptPbeData(true, cAlgId, password, false, derEncodedBytes);
+ byte[] certBagsEncoding = new DerSequence(certBags).GetDerEncoded();
- EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
-
- ContentInfo[] info = new ContentInfo[]
+ ContentInfo certsInfo;
+ if (password == null)
{
- new ContentInfo(PkcsObjectIdentifiers.Data, keyString),
- new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object())
- };
+ certsInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(certBagsEncoding));
+ }
+ else
+ {
+ byte[] certBytes = CryptPbeData(true, cAlgId, password, false, certBagsEncoding);
+ EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
+ certsInfo = new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object());
+ }
+
+ ContentInfo[] info = new ContentInfo[]{ keysInfo, certsInfo };
byte[] data = new AuthenticatedSafe(info).GetEncoded(
useDerEncoding ? Asn1Encodable.Der : Asn1Encodable.Ber);
@@ -1087,22 +956,26 @@ namespace Org.BouncyCastle.Pkcs
//
// create the mac
//
- byte[] mSalt = new byte[20];
- random.NextBytes(mSalt);
+ MacData macData = null;
+ if (password != null)
+ {
+ byte[] mSalt = new byte[20];
+ random.NextBytes(mSalt);
- byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
- mSalt, MinIterations, password, false, data);
+ byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
+ mSalt, MinIterations, password, false, data);
- AlgorithmIdentifier algId = new AlgorithmIdentifier(
- OiwObjectIdentifiers.IdSha1, DerNull.Instance);
- DigestInfo dInfo = new DigestInfo(algId, mac);
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(
+ OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ DigestInfo dInfo = new DigestInfo(algId, mac);
- MacData mData = new MacData(dInfo, mSalt, MinIterations);
+ macData = new MacData(dInfo, mSalt, MinIterations);
+ }
//
// output the Pfx
//
- Pfx pfx = new Pfx(mainInfo, mData);
+ Pfx pfx = new Pfx(mainInfo, macData);
DerOutputStream derOut;
if (useDerEncoding)
diff --git a/crypto/src/pkix/PkixCertPathChecker.cs b/crypto/src/pkix/PkixCertPathChecker.cs
index f22738d89..da7e82b46 100644
--- a/crypto/src/pkix/PkixCertPathChecker.cs
+++ b/crypto/src/pkix/PkixCertPathChecker.cs
@@ -1,5 +1,3 @@
-using System;
-using System.Collections;
using Org.BouncyCastle.Utilities.Collections;
using Org.BouncyCastle.X509;
@@ -82,7 +80,7 @@ namespace Org.BouncyCastle.Pkix
* @exception CertPathValidatorException
* if the specified certificate does not pass the check
*/
- public abstract void Check(X509Certificate cert, ICollection unresolvedCritExts);
+ public abstract void Check(X509Certificate cert, ISet unresolvedCritExts);
//throws CertPathValidatorException;
/**
diff --git a/crypto/src/pkix/PkixParameters.cs b/crypto/src/pkix/PkixParameters.cs
index 6df1b646f..47d3b5e37 100644
--- a/crypto/src/pkix/PkixParameters.cs
+++ b/crypto/src/pkix/PkixParameters.cs
@@ -745,7 +745,7 @@ namespace Org.BouncyCastle.Pkix
}
/**
- * Returns the neccessary attributes which must be contained in an attribute
+ * Returns the necessary attributes which must be contained in an attribute
* certificate.
* <p>
* The returned <code>ISet</code> is immutable and contains
@@ -760,7 +760,7 @@ namespace Org.BouncyCastle.Pkix
}
/**
- * Sets the neccessary which must be contained in an attribute certificate.
+ * Sets the necessary which must be contained in an attribute certificate.
* <p>
* The <code>ISet</code> must contain <code>String</code>s with the
* OIDs.
diff --git a/crypto/src/security/AgreementUtilities.cs b/crypto/src/security/AgreementUtilities.cs
index 4c61ac354..12d427c8c 100644
--- a/crypto/src/security/AgreementUtilities.cs
+++ b/crypto/src/security/AgreementUtilities.cs
@@ -22,14 +22,14 @@ namespace Org.BouncyCastle.Security
private static readonly IDictionary algorithms = Platform.CreateHashtable();
//private static readonly IDictionary oids = Platform.CreateHashtable();
- static AgreementUtilities()
+ static AgreementUtilities()
{
- //algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = ?;
+ algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = "ECCDHWITHSHA1KDF";
algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "ECDHWITHSHA1KDF";
algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = "ECMQVWITHSHA1KDF";
}
- public static IBasicAgreement GetBasicAgreement(
+ public static IBasicAgreement GetBasicAgreement(
DerObjectIdentifier oid)
{
return GetBasicAgreement(oid.Id);
@@ -52,8 +52,8 @@ namespace Org.BouncyCastle.Security
if (mechanism == "ECDH")
return new ECDHBasicAgreement();
- if (mechanism == "ECDHC")
- return new ECDHCBasicAgreement();
+ if (mechanism == "ECDHC" || mechanism == "ECCDH")
+ return new ECDHCBasicAgreement();
if (mechanism == "ECMQV")
return new ECMqvBasicAgreement();
diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs
index ec3f63940..7ddf6c8e4 100644
--- a/crypto/src/security/DigestUtilities.cs
+++ b/crypto/src/security/DigestUtilities.cs
@@ -21,11 +21,13 @@ namespace Org.BouncyCastle.Security
{
private enum DigestAlgorithm {
GOST3411,
+ KECCAK_224, KECCAK_256, KECCAK_288, KECCAK_384, KECCAK_512,
MD2, MD4, MD5,
RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320,
SHA_1, SHA_224, SHA_256, SHA_384, SHA_512,
SHA_512_224, SHA_512_256,
SHA3_224, SHA3_256, SHA3_384, SHA3_512,
+ SHAKE128, SHAKE256,
TIGER,
WHIRLPOOL,
};
@@ -72,7 +74,12 @@ namespace Org.BouncyCastle.Security
algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411";
-
+ algorithms[NistObjectIdentifiers.IdSha3_224.Id] = "SHA3-224";
+ algorithms[NistObjectIdentifiers.IdSha3_256.Id] = "SHA3-256";
+ algorithms[NistObjectIdentifiers.IdSha3_384.Id] = "SHA3-384";
+ algorithms[NistObjectIdentifiers.IdSha3_512.Id] = "SHA3-512";
+ algorithms[NistObjectIdentifiers.IdShake128.Id] = "SHAKE128";
+ algorithms[NistObjectIdentifiers.IdShake256.Id] = "SHAKE256";
oids["MD2"] = PkcsObjectIdentifiers.MD2;
oids["MD4"] = PkcsObjectIdentifiers.MD4;
@@ -84,6 +91,12 @@ namespace Org.BouncyCastle.Security
oids["SHA-512"] = NistObjectIdentifiers.IdSha512;
oids["SHA-512/224"] = NistObjectIdentifiers.IdSha512_224;
oids["SHA-512/256"] = NistObjectIdentifiers.IdSha512_256;
+ oids["SHA3-224"] = NistObjectIdentifiers.IdSha3_224;
+ oids["SHA3-256"] = NistObjectIdentifiers.IdSha3_256;
+ oids["SHA3-384"] = NistObjectIdentifiers.IdSha3_384;
+ oids["SHA3-512"] = NistObjectIdentifiers.IdSha3_512;
+ oids["SHAKE128"] = NistObjectIdentifiers.IdShake128;
+ oids["SHAKE256"] = NistObjectIdentifiers.IdShake256;
oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
@@ -141,7 +154,12 @@ namespace Org.BouncyCastle.Security
switch (digestAlgorithm)
{
case DigestAlgorithm.GOST3411: return new Gost3411Digest();
- case DigestAlgorithm.MD2: return new MD2Digest();
+ case DigestAlgorithm.KECCAK_224: return new KeccakDigest(224);
+ case DigestAlgorithm.KECCAK_256: return new KeccakDigest(256);
+ case DigestAlgorithm.KECCAK_288: return new KeccakDigest(288);
+ case DigestAlgorithm.KECCAK_384: return new KeccakDigest(384);
+ case DigestAlgorithm.KECCAK_512: return new KeccakDigest(512);
+ case DigestAlgorithm.MD2: return new MD2Digest();
case DigestAlgorithm.MD4: return new MD4Digest();
case DigestAlgorithm.MD5: return new MD5Digest();
case DigestAlgorithm.RIPEMD128: return new RipeMD128Digest();
@@ -159,6 +177,8 @@ namespace Org.BouncyCastle.Security
case DigestAlgorithm.SHA3_256: return new Sha3Digest(256);
case DigestAlgorithm.SHA3_384: return new Sha3Digest(384);
case DigestAlgorithm.SHA3_512: return new Sha3Digest(512);
+ case DigestAlgorithm.SHAKE128: return new ShakeDigest(128);
+ case DigestAlgorithm.SHAKE256: return new ShakeDigest(256);
case DigestAlgorithm.TIGER: return new TigerDigest();
case DigestAlgorithm.WHIRLPOOL: return new WhirlpoolDigest();
}
diff --git a/crypto/src/security/DotNetUtilities.cs b/crypto/src/security/DotNetUtilities.cs
index d50e17d39..732b5e075 100644
--- a/crypto/src/security/DotNetUtilities.cs
+++ b/crypto/src/security/DotNetUtilities.cs
@@ -233,7 +233,9 @@ namespace Org.BouncyCastle.Security
private static RSA CreateRSAProvider(RSAParameters rp)
{
- RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
+ CspParameters csp = new CspParameters();
+ csp.KeyContainerName = string.Format("BouncyCastle-{0}", Guid.NewGuid());
+ RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(csp);
rsaCsp.ImportParameters(rp);
return rsaCsp;
}
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index c5ddd5d78..edc5ef85a 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -15,6 +15,7 @@ using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Security
{
@@ -43,7 +44,7 @@ namespace Org.BouncyCastle.Security
public static AsymmetricKeyParameter CreateKey(
PrivateKeyInfo keyInfo)
{
- AlgorithmIdentifier algID = keyInfo.AlgorithmID;
+ AlgorithmIdentifier algID = keyInfo.PrivateKeyAlgorithm;
DerObjectIdentifier algOid = algID.ObjectID;
// TODO See RSAUtil.isRsaOid in Java build
@@ -52,8 +53,7 @@ namespace Org.BouncyCastle.Security
|| algOid.Equals(PkcsObjectIdentifiers.IdRsassaPss)
|| algOid.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
{
- RsaPrivateKeyStructure keyStructure = new RsaPrivateKeyStructure(
- Asn1Sequence.GetInstance(keyInfo.PrivateKey));
+ RsaPrivateKeyStructure keyStructure = RsaPrivateKeyStructure.GetInstance(keyInfo.ParsePrivateKey());
return new RsaPrivateCrtKeyParameters(
keyStructure.Modulus,
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Security
{
DHParameter para = new DHParameter(
Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
- DerInteger derX = (DerInteger)keyInfo.PrivateKey;
+ DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
BigInteger lVal = para.L;
int l = lVal == null ? 0 : lVal.IntValue;
@@ -83,7 +83,7 @@ namespace Org.BouncyCastle.Security
{
ElGamalParameter para = new ElGamalParameter(
Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
- DerInteger derX = (DerInteger)keyInfo.PrivateKey;
+ DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
return new ElGamalPrivateKeyParameters(
derX.Value,
@@ -91,7 +91,7 @@ namespace Org.BouncyCastle.Security
}
else if (algOid.Equals(X9ObjectIdentifiers.IdDsa))
{
- DerInteger derX = (DerInteger) keyInfo.PrivateKey;
+ DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
Asn1Encodable ae = algID.Parameters;
DsaParameters parameters = null;
@@ -118,7 +118,7 @@ namespace Org.BouncyCastle.Security
}
ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
- Asn1Sequence.GetInstance(keyInfo.PrivateKey));
+ Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey()));
BigInteger d = ec.GetKey();
if (para.IsNamedCurve)
@@ -134,13 +134,23 @@ namespace Org.BouncyCastle.Security
Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
- ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
- Asn1Sequence.GetInstance(keyInfo.PrivateKey));
+ Asn1Object privKey = keyInfo.ParsePrivateKey();
+ ECPrivateKeyStructure ec;
+
+ if (privKey is DerInteger)
+ {
+ // TODO Do we need to pass any parameters here?
+ ec = new ECPrivateKeyStructure(((DerInteger)privKey).Value);
+ }
+ else
+ {
+ ec = ECPrivateKeyStructure.GetInstance(privKey);
+ }
ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
if (ecP == null)
- return null;
+ throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key");
return new ECPrivateKeyParameters("ECGOST3410", ec.GetKey(), gostParams.PublicKeyParamSet);
}
@@ -149,16 +159,8 @@ namespace Org.BouncyCastle.Security
Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
- DerOctetString derX = (DerOctetString) keyInfo.PrivateKey;
- byte[] keyEnc = derX.GetOctets();
- byte[] keyBytes = new byte[keyEnc.Length];
-
- for (int i = 0; i != keyEnc.Length; i++)
- {
- keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian
- }
-
- BigInteger x = new BigInteger(1, keyBytes);
+ DerOctetString derX = (DerOctetString)keyInfo.ParsePrivateKey();
+ BigInteger x = new BigInteger(1, Arrays.Reverse(derX.GetOctets()));
return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
}
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index ac9d98158..137a471c1 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
@@ -8,221 +9,256 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Security
{
public class SecureRandom
- : Random
+ : Random
{
- // Note: all objects of this class should be deriving their random data from
- // a single generator appropriate to the digest being used.
- private static readonly IRandomGenerator sha1Generator = new DigestRandomGenerator(new Sha1Digest());
- private static readonly IRandomGenerator sha256Generator = new DigestRandomGenerator(new Sha256Digest());
-
- private static readonly SecureRandom[] master = { null };
- private static SecureRandom Master
- {
- get
- {
- if (master[0] == null)
- {
- IRandomGenerator gen = sha256Generator;
- gen = new ReversedWindowGenerator(gen, 32);
- SecureRandom sr = master[0] = new SecureRandom(gen);
-
- sr.SetSeed(DateTime.Now.Ticks);
- sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(24, true));
- sr.GenerateSeed(1 + sr.Next(32));
- }
-
- return master[0];
- }
- }
-
- public static SecureRandom GetInstance(
- string algorithm)
- {
- // TODO Compared to JDK, we don't auto-seed if the client forgets - problem?
-
- // TODO Support all digests more generally, by stripping PRNG and calling DigestUtilities?
- string drgName = Platform.ToUpperInvariant(algorithm);
-
- IRandomGenerator drg = null;
- if (drgName == "SHA1PRNG")
- {
- drg = sha1Generator;
- }
- else if (drgName == "SHA256PRNG")
- {
- drg = sha256Generator;
- }
-
- if (drg != null)
- {
- return new SecureRandom(drg);
- }
-
- throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
- }
-
- public static byte[] GetSeed(
- int length)
- {
- return Master.GenerateSeed(length);
- }
-
- protected IRandomGenerator generator;
-
- public SecureRandom()
- : this(sha1Generator)
- {
- SetSeed(GetSeed(8));
- }
-
- public SecureRandom(
- byte[] inSeed)
- : this(sha1Generator)
- {
- SetSeed(inSeed);
- }
-
- /// <summary>Use the specified instance of IRandomGenerator as random source.</summary>
- /// <remarks>
- /// This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
- /// constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
- /// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
- /// implementation.
- /// </remarks>
- /// <param name="generator">The source to generate all random bytes from.</param>
- public SecureRandom(
- IRandomGenerator generator)
- : base(0)
- {
- this.generator = generator;
- }
-
- public virtual byte[] GenerateSeed(
- int length)
- {
- SetSeed(DateTime.Now.Ticks);
-
- byte[] rv = new byte[length];
- NextBytes(rv);
- return rv;
- }
-
- public virtual void SetSeed(
- byte[] inSeed)
- {
- generator.AddSeedMaterial(inSeed);
- }
-
- public virtual void SetSeed(
- long seed)
- {
- generator.AddSeedMaterial(seed);
- }
-
- public override int Next()
- {
- for (;;)
- {
- int i = NextInt() & int.MaxValue;
-
- if (i != int.MaxValue)
- return i;
- }
- }
-
- public override int Next(
- int maxValue)
- {
- if (maxValue < 2)
- {
- if (maxValue < 0)
- throw new ArgumentOutOfRangeException("maxValue", "cannot be negative");
-
- return 0;
- }
-
- // Test whether maxValue is a power of 2
- if ((maxValue & -maxValue) == maxValue)
- {
- int val = NextInt() & int.MaxValue;
- long lr = ((long) maxValue * (long) val) >> 31;
- return (int) lr;
- }
-
- int bits, result;
- do
- {
- bits = NextInt() & int.MaxValue;
- result = bits % maxValue;
- }
- while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
-
- return result;
- }
-
- public override int Next(
- int minValue,
- int maxValue)
- {
- if (maxValue <= minValue)
- {
- if (maxValue == minValue)
- return minValue;
-
- throw new ArgumentException("maxValue cannot be less than minValue");
- }
-
- int diff = maxValue - minValue;
- if (diff > 0)
- return minValue + Next(diff);
-
- for (;;)
- {
- int i = NextInt();
-
- if (i >= minValue && i < maxValue)
- return i;
- }
- }
-
- public override void NextBytes(
- byte[] buffer)
- {
- generator.NextBytes(buffer);
- }
-
- public virtual void NextBytes(
- byte[] buffer,
- int start,
- int length)
- {
- generator.NextBytes(buffer, start, length);
- }
-
- private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
-
- public override double NextDouble()
- {
- return Convert.ToDouble((ulong) NextLong()) / DoubleScale;
- }
-
- public virtual int NextInt()
- {
- byte[] intBytes = new byte[4];
+ private static long counter = Times.NanoTime();
+
+#if NETCF_1_0
+ private static object counterLock = new object();
+ private static long NextCounterValue()
+ {
+ lock (counterLock)
+ {
+ return ++counter;
+ }
+ }
+
+ private static readonly SecureRandom[] master = { null };
+ private static SecureRandom Master
+ {
+ get
+ {
+ lock (master)
+ {
+ if (master[0] == null)
+ {
+ SecureRandom sr = master[0] = GetInstance("SHA256PRNG", false);
+
+ // Even though Ticks has at most 8 or 14 bits of entropy, there's no harm in adding it.
+ sr.SetSeed(DateTime.Now.Ticks);
+
+ // 32 will be enough when ThreadedSeedGenerator is fixed. Until then, ThreadedSeedGenerator returns low
+ // entropy, and this is not sufficient to be secure. http://www.bouncycastle.org/csharpdevmailarchive/msg00814.html
+ sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(32, true));
+ }
+
+ return master[0];
+ }
+ }
+ }
+#else
+ private static long NextCounterValue()
+ {
+ return Interlocked.Increment(ref counter);
+ }
+
+ private static readonly SecureRandom master = new SecureRandom(new CryptoApiRandomGenerator());
+ private static SecureRandom Master
+ {
+ get { return master; }
+ }
+#endif
+
+ private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed)
+ {
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+ if (digest == null)
+ return null;
+ DigestRandomGenerator prng = new DigestRandomGenerator(digest);
+ if (autoSeed)
+ {
+ prng.AddSeedMaterial(NextCounterValue());
+ prng.AddSeedMaterial(GetSeed(digest.GetDigestSize()));
+ }
+ return prng;
+ }
+
+ /// <summary>
+ /// Create and auto-seed an instance based on the given algorithm.
+ /// </summary>
+ /// <remarks>Equivalent to GetInstance(algorithm, true)</remarks>
+ /// <param name="algorithm">e.g. "SHA256PRNG"</param>
+ public static SecureRandom GetInstance(string algorithm)
+ {
+ return GetInstance(algorithm, true);
+ }
+
+ /// <summary>
+ /// Create an instance based on the given algorithm, with optional auto-seeding
+ /// </summary>
+ /// <param name="algorithm">e.g. "SHA256PRNG"</param>
+ /// <param name="autoSeed">If true, the instance will be auto-seeded.</param>
+ public static SecureRandom GetInstance(string algorithm, bool autoSeed)
+ {
+ string upper = Platform.ToUpperInvariant(algorithm);
+ if (upper.EndsWith("PRNG"))
+ {
+ string digestName = upper.Substring(0, upper.Length - "PRNG".Length);
+ DigestRandomGenerator prng = CreatePrng(digestName, autoSeed);
+ if (prng != null)
+ {
+ return new SecureRandom(prng);
+ }
+ }
+
+ throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
+ }
+
+ public static byte[] GetSeed(int length)
+ {
+#if NETCF_1_0
+ lock (master)
+#endif
+ return Master.GenerateSeed(length);
+ }
+
+ protected readonly IRandomGenerator generator;
+
+ public SecureRandom()
+ : this(CreatePrng("SHA256", true))
+ {
+ }
+
+ /// <remarks>
+ /// To replicate existing predictable output, replace with GetInstance("SHA1PRNG", false), followed by SetSeed(seed)
+ /// </remarks>
+ [Obsolete("Use GetInstance/SetSeed instead")]
+ public SecureRandom(byte[] seed)
+ : this(CreatePrng("SHA1", false))
+ {
+ SetSeed(seed);
+ }
+
+ /// <summary>Use the specified instance of IRandomGenerator as random source.</summary>
+ /// <remarks>
+ /// This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
+ /// constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
+ /// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
+ /// implementation.
+ /// </remarks>
+ /// <param name="generator">The source to generate all random bytes from.</param>
+ public SecureRandom(IRandomGenerator generator)
+ : base(0)
+ {
+ this.generator = generator;
+ }
+
+ public virtual byte[] GenerateSeed(int length)
+ {
+ SetSeed(DateTime.Now.Ticks);
+
+ byte[] rv = new byte[length];
+ NextBytes(rv);
+ return rv;
+ }
+
+ public virtual void SetSeed(byte[] seed)
+ {
+ generator.AddSeedMaterial(seed);
+ }
+
+ public virtual void SetSeed(long seed)
+ {
+ generator.AddSeedMaterial(seed);
+ }
+
+ public override int Next()
+ {
+ for (;;)
+ {
+ int i = NextInt() & int.MaxValue;
+
+ if (i != int.MaxValue)
+ return i;
+ }
+ }
+
+ public override int Next(int maxValue)
+ {
+ if (maxValue < 2)
+ {
+ if (maxValue < 0)
+ throw new ArgumentOutOfRangeException("maxValue", "cannot be negative");
+
+ return 0;
+ }
+
+ // Test whether maxValue is a power of 2
+ if ((maxValue & -maxValue) == maxValue)
+ {
+ int val = NextInt() & int.MaxValue;
+ long lr = ((long) maxValue * (long) val) >> 31;
+ return (int) lr;
+ }
+
+ int bits, result;
+ do
+ {
+ bits = NextInt() & int.MaxValue;
+ result = bits % maxValue;
+ }
+ while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
+
+ return result;
+ }
+
+ public override int Next(int minValue, int maxValue)
+ {
+ if (maxValue <= minValue)
+ {
+ if (maxValue == minValue)
+ return minValue;
+
+ throw new ArgumentException("maxValue cannot be less than minValue");
+ }
+
+ int diff = maxValue - minValue;
+ if (diff > 0)
+ return minValue + Next(diff);
+
+ for (;;)
+ {
+ int i = NextInt();
+
+ if (i >= minValue && i < maxValue)
+ return i;
+ }
+ }
+
+ public override void NextBytes(byte[] buf)
+ {
+ generator.NextBytes(buf);
+ }
+
+ public virtual void NextBytes(byte[] buf, int off, int len)
+ {
+ generator.NextBytes(buf, off, len);
+ }
+
+ private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
+
+ public override double NextDouble()
+ {
+ return Convert.ToDouble((ulong) NextLong()) / DoubleScale;
+ }
+
+ public virtual int NextInt()
+ {
+ byte[] intBytes = new byte[4];
NextBytes(intBytes);
- int result = 0;
+ int result = 0;
for (int i = 0; i < 4; i++)
{
result = (result << 8) + (intBytes[i] & 0xff);
}
- return result;
+ return result;
}
- public virtual long NextLong()
- {
- return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt();
- }
+ public virtual long NextLong()
+ {
+ return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt();
+ }
}
}
diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs
index 136361532..bd1515147 100644
--- a/crypto/src/security/SignerUtilities.cs
+++ b/crypto/src/security/SignerUtilities.cs
@@ -23,16 +23,16 @@ namespace Org.BouncyCastle.Security
/// </summary>
public sealed class SignerUtilities
{
- private SignerUtilities()
- {
- }
+ private SignerUtilities()
+ {
+ }
- internal static readonly IDictionary algorithms = Platform.CreateHashtable();
+ internal static readonly IDictionary algorithms = Platform.CreateHashtable();
internal static readonly IDictionary oids = Platform.CreateHashtable();
- static SignerUtilities()
+ static SignerUtilities()
{
- algorithms["MD2WITHRSA"] = "MD2withRSA";
+ algorithms["MD2WITHRSA"] = "MD2withRSA";
algorithms["MD2WITHRSAENCRYPTION"] = "MD2withRSA";
algorithms[PkcsObjectIdentifiers.MD2WithRsaEncryption.Id] = "MD2withRSA";
@@ -69,41 +69,41 @@ namespace Org.BouncyCastle.Security
algorithms[PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id] = "SHA-512withRSA";
algorithms["SHA-512WITHRSA"] = "SHA-512withRSA";
- algorithms["PSSWITHRSA"] = "PSSwithRSA";
- algorithms["RSASSA-PSS"] = "PSSwithRSA";
- algorithms[PkcsObjectIdentifiers.IdRsassaPss.Id] = "PSSwithRSA";
- algorithms["RSAPSS"] = "PSSwithRSA";
+ algorithms["PSSWITHRSA"] = "PSSwithRSA";
+ algorithms["RSASSA-PSS"] = "PSSwithRSA";
+ algorithms[PkcsObjectIdentifiers.IdRsassaPss.Id] = "PSSwithRSA";
+ algorithms["RSAPSS"] = "PSSwithRSA";
- algorithms["SHA1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
- algorithms["SHA-1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
- algorithms["SHA1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
- algorithms["SHA-1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA-1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA-1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
- algorithms["SHA224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
- algorithms["SHA-224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
- algorithms["SHA224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
- algorithms["SHA-224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA-224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA-224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
- algorithms["SHA256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
algorithms["SHA-256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
- algorithms["SHA256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
- algorithms["SHA-256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA-256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
algorithms["SHA384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1";
algorithms["SHA-384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1";
- algorithms["SHA384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
- algorithms["SHA-384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
+ algorithms["SHA384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
+ algorithms["SHA-384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
algorithms["SHA512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
algorithms["SHA-512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
- algorithms["SHA512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
- algorithms["SHA-512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+ algorithms["SHA512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+ algorithms["SHA-512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
- algorithms["RIPEMD128WITHRSA"] = "RIPEMD128withRSA";
+ algorithms["RIPEMD128WITHRSA"] = "RIPEMD128withRSA";
algorithms["RIPEMD128WITHRSAENCRYPTION"] = "RIPEMD128withRSA";
algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128.Id] = "RIPEMD128withRSA";
- algorithms["RIPEMD160WITHRSA"] = "RIPEMD160withRSA";
+ algorithms["RIPEMD160WITHRSA"] = "RIPEMD160withRSA";
algorithms["RIPEMD160WITHRSAENCRYPTION"] = "RIPEMD160withRSA";
algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160.Id] = "RIPEMD160withRSA";
@@ -111,126 +111,123 @@ namespace Org.BouncyCastle.Security
algorithms["RIPEMD256WITHRSAENCRYPTION"] = "RIPEMD256withRSA";
algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256.Id] = "RIPEMD256withRSA";
- algorithms["NONEWITHRSA"] = "RSA";
- algorithms["RSAWITHNONE"] = "RSA";
- algorithms["RAWRSA"] = "RSA";
-
- algorithms["RAWRSAPSS"] = "RAWRSASSA-PSS";
- algorithms["NONEWITHRSAPSS"] = "RAWRSASSA-PSS";
- algorithms["NONEWITHRSASSA-PSS"] = "RAWRSASSA-PSS";
-
- algorithms["NONEWITHDSA"] = "NONEwithDSA";
- algorithms["DSAWITHNONE"] = "NONEwithDSA";
- algorithms["RAWDSA"] = "NONEwithDSA";
-
- algorithms["DSA"] = "SHA-1withDSA";
- algorithms["DSAWITHSHA1"] = "SHA-1withDSA";
- algorithms["DSAWITHSHA-1"] = "SHA-1withDSA";
- algorithms["SHA/DSA"] = "SHA-1withDSA";
- algorithms["SHA1/DSA"] = "SHA-1withDSA";
- algorithms["SHA-1/DSA"] = "SHA-1withDSA";
- algorithms["SHA1WITHDSA"] = "SHA-1withDSA";
+ algorithms["NONEWITHRSA"] = "RSA";
+ algorithms["RSAWITHNONE"] = "RSA";
+ algorithms["RAWRSA"] = "RSA";
+
+ algorithms["RAWRSAPSS"] = "RAWRSASSA-PSS";
+ algorithms["NONEWITHRSAPSS"] = "RAWRSASSA-PSS";
+ algorithms["NONEWITHRSASSA-PSS"] = "RAWRSASSA-PSS";
+
+ algorithms["NONEWITHDSA"] = "NONEwithDSA";
+ algorithms["DSAWITHNONE"] = "NONEwithDSA";
+ algorithms["RAWDSA"] = "NONEwithDSA";
+
+ algorithms["DSA"] = "SHA-1withDSA";
+ algorithms["DSAWITHSHA1"] = "SHA-1withDSA";
+ algorithms["DSAWITHSHA-1"] = "SHA-1withDSA";
+ algorithms["SHA/DSA"] = "SHA-1withDSA";
+ algorithms["SHA1/DSA"] = "SHA-1withDSA";
+ algorithms["SHA-1/DSA"] = "SHA-1withDSA";
+ algorithms["SHA1WITHDSA"] = "SHA-1withDSA";
algorithms["SHA-1WITHDSA"] = "SHA-1withDSA";
algorithms[X9ObjectIdentifiers.IdDsaWithSha1.Id] = "SHA-1withDSA";
- algorithms["DSAWITHSHA224"] = "SHA-224withDSA";
- algorithms["DSAWITHSHA-224"] = "SHA-224withDSA";
- algorithms["SHA224/DSA"] = "SHA-224withDSA";
- algorithms["SHA-224/DSA"] = "SHA-224withDSA";
- algorithms["SHA224WITHDSA"] = "SHA-224withDSA";
- algorithms["SHA-224WITHDSA"] = "SHA-224withDSA";
- algorithms[NistObjectIdentifiers.DsaWithSha224.Id] = "SHA-224withDSA";
-
- algorithms["DSAWITHSHA256"] = "SHA-256withDSA";
- algorithms["DSAWITHSHA-256"] = "SHA-256withDSA";
- algorithms["SHA256/DSA"] = "SHA-256withDSA";
- algorithms["SHA-256/DSA"] = "SHA-256withDSA";
- algorithms["SHA256WITHDSA"] = "SHA-256withDSA";
- algorithms["SHA-256WITHDSA"] = "SHA-256withDSA";
- algorithms[NistObjectIdentifiers.DsaWithSha256.Id] = "SHA-256withDSA";
-
- algorithms["DSAWITHSHA384"] = "SHA-384withDSA";
- algorithms["DSAWITHSHA-384"] = "SHA-384withDSA";
- algorithms["SHA384/DSA"] = "SHA-384withDSA";
- algorithms["SHA-384/DSA"] = "SHA-384withDSA";
- algorithms["SHA384WITHDSA"] = "SHA-384withDSA";
- algorithms["SHA-384WITHDSA"] = "SHA-384withDSA";
- algorithms[NistObjectIdentifiers.DsaWithSha384.Id] = "SHA-384withDSA";
-
- algorithms["DSAWITHSHA512"] = "SHA-512withDSA";
- algorithms["DSAWITHSHA-512"] = "SHA-512withDSA";
- algorithms["SHA512/DSA"] = "SHA-512withDSA";
- algorithms["SHA-512/DSA"] = "SHA-512withDSA";
- algorithms["SHA512WITHDSA"] = "SHA-512withDSA";
- algorithms["SHA-512WITHDSA"] = "SHA-512withDSA";
- algorithms[NistObjectIdentifiers.DsaWithSha512.Id] = "SHA-512withDSA";
-
- algorithms["NONEWITHECDSA"] = "NONEwithECDSA";
- algorithms["ECDSAWITHNONE"] = "NONEwithECDSA";
-
- algorithms["ECDSA"] = "SHA-1withECDSA";
- algorithms["SHA1/ECDSA"] = "SHA-1withECDSA";
- algorithms["SHA-1/ECDSA"] = "SHA-1withECDSA";
- algorithms["ECDSAWITHSHA1"] = "SHA-1withECDSA";
- algorithms["ECDSAWITHSHA-1"] = "SHA-1withECDSA";
- algorithms["SHA1WITHECDSA"] = "SHA-1withECDSA";
+ algorithms["DSAWITHSHA224"] = "SHA-224withDSA";
+ algorithms["DSAWITHSHA-224"] = "SHA-224withDSA";
+ algorithms["SHA224/DSA"] = "SHA-224withDSA";
+ algorithms["SHA-224/DSA"] = "SHA-224withDSA";
+ algorithms["SHA224WITHDSA"] = "SHA-224withDSA";
+ algorithms["SHA-224WITHDSA"] = "SHA-224withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha224.Id] = "SHA-224withDSA";
+
+ algorithms["DSAWITHSHA256"] = "SHA-256withDSA";
+ algorithms["DSAWITHSHA-256"] = "SHA-256withDSA";
+ algorithms["SHA256/DSA"] = "SHA-256withDSA";
+ algorithms["SHA-256/DSA"] = "SHA-256withDSA";
+ algorithms["SHA256WITHDSA"] = "SHA-256withDSA";
+ algorithms["SHA-256WITHDSA"] = "SHA-256withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha256.Id] = "SHA-256withDSA";
+
+ algorithms["DSAWITHSHA384"] = "SHA-384withDSA";
+ algorithms["DSAWITHSHA-384"] = "SHA-384withDSA";
+ algorithms["SHA384/DSA"] = "SHA-384withDSA";
+ algorithms["SHA-384/DSA"] = "SHA-384withDSA";
+ algorithms["SHA384WITHDSA"] = "SHA-384withDSA";
+ algorithms["SHA-384WITHDSA"] = "SHA-384withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha384.Id] = "SHA-384withDSA";
+
+ algorithms["DSAWITHSHA512"] = "SHA-512withDSA";
+ algorithms["DSAWITHSHA-512"] = "SHA-512withDSA";
+ algorithms["SHA512/DSA"] = "SHA-512withDSA";
+ algorithms["SHA-512/DSA"] = "SHA-512withDSA";
+ algorithms["SHA512WITHDSA"] = "SHA-512withDSA";
+ algorithms["SHA-512WITHDSA"] = "SHA-512withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha512.Id] = "SHA-512withDSA";
+
+ algorithms["NONEWITHECDSA"] = "NONEwithECDSA";
+ algorithms["ECDSAWITHNONE"] = "NONEwithECDSA";
+
+ algorithms["ECDSA"] = "SHA-1withECDSA";
+ algorithms["SHA1/ECDSA"] = "SHA-1withECDSA";
+ algorithms["SHA-1/ECDSA"] = "SHA-1withECDSA";
+ algorithms["ECDSAWITHSHA1"] = "SHA-1withECDSA";
+ algorithms["ECDSAWITHSHA-1"] = "SHA-1withECDSA";
+ algorithms["SHA1WITHECDSA"] = "SHA-1withECDSA";
algorithms["SHA-1WITHECDSA"] = "SHA-1withECDSA";
- algorithms[X9ObjectIdentifiers.ECDsaWithSha1.Id] = "SHA-1withECDSA";
- algorithms[TeleTrusTObjectIdentifiers.ECSignWithSha1.Id] = "SHA-1withECDSA";
-
- algorithms["SHA224/ECDSA"] = "SHA-224withECDSA";
- algorithms["SHA-224/ECDSA"] = "SHA-224withECDSA";
- algorithms["ECDSAWITHSHA224"] = "SHA-224withECDSA";
- algorithms["ECDSAWITHSHA-224"] = "SHA-224withECDSA";
- algorithms["SHA224WITHECDSA"] = "SHA-224withECDSA";
- algorithms["SHA-224WITHECDSA"] = "SHA-224withECDSA";
- algorithms[X9ObjectIdentifiers.ECDsaWithSha224.Id] = "SHA-224withECDSA";
-
- algorithms["SHA256/ECDSA"] = "SHA-256withECDSA";
- algorithms["SHA-256/ECDSA"] = "SHA-256withECDSA";
- algorithms["ECDSAWITHSHA256"] = "SHA-256withECDSA";
- algorithms["ECDSAWITHSHA-256"] = "SHA-256withECDSA";
- algorithms["SHA256WITHECDSA"] = "SHA-256withECDSA";
- algorithms["SHA-256WITHECDSA"] = "SHA-256withECDSA";
- algorithms[X9ObjectIdentifiers.ECDsaWithSha256.Id] = "SHA-256withECDSA";
-
- algorithms["SHA384/ECDSA"] = "SHA-384withECDSA";
- algorithms["SHA-384/ECDSA"] = "SHA-384withECDSA";
- algorithms["ECDSAWITHSHA384"] = "SHA-384withECDSA";
- algorithms["ECDSAWITHSHA-384"] = "SHA-384withECDSA";
- algorithms["SHA384WITHECDSA"] = "SHA-384withECDSA";
- algorithms["SHA-384WITHECDSA"] = "SHA-384withECDSA";
- algorithms[X9ObjectIdentifiers.ECDsaWithSha384.Id] = "SHA-384withECDSA";
-
- algorithms["SHA512/ECDSA"] = "SHA-512withECDSA";
- algorithms["SHA-512/ECDSA"] = "SHA-512withECDSA";
- algorithms["ECDSAWITHSHA512"] = "SHA-512withECDSA";
- algorithms["ECDSAWITHSHA-512"] = "SHA-512withECDSA";
- algorithms["SHA512WITHECDSA"] = "SHA-512withECDSA";
- algorithms["SHA-512WITHECDSA"] = "SHA-512withECDSA";
- algorithms[X9ObjectIdentifiers.ECDsaWithSha512.Id] = "SHA-512withECDSA";
-
- algorithms["RIPEMD160/ECDSA"] = "RIPEMD160withECDSA";
- algorithms["SHA-512/ECDSA"] = "RIPEMD160withECDSA";
- algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
- algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
- algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
- algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
- algorithms[TeleTrusTObjectIdentifiers.ECSignWithRipeMD160.Id] = "RIPEMD160withECDSA";
-
- algorithms["GOST-3410"] = "GOST3410";
- algorithms["GOST-3410-94"] = "GOST3410";
- algorithms["GOST3411WITHGOST3410"] = "GOST3410";
- algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94.Id] = "GOST3410";
-
- algorithms["ECGOST-3410"] = "ECGOST3410";
- algorithms["ECGOST-3410-2001"] = "ECGOST3410";
- algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410";
- algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
-
-
-
- oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha1.Id] = "SHA-1withECDSA";
+ algorithms[TeleTrusTObjectIdentifiers.ECSignWithSha1.Id] = "SHA-1withECDSA";
+
+ algorithms["SHA224/ECDSA"] = "SHA-224withECDSA";
+ algorithms["SHA-224/ECDSA"] = "SHA-224withECDSA";
+ algorithms["ECDSAWITHSHA224"] = "SHA-224withECDSA";
+ algorithms["ECDSAWITHSHA-224"] = "SHA-224withECDSA";
+ algorithms["SHA224WITHECDSA"] = "SHA-224withECDSA";
+ algorithms["SHA-224WITHECDSA"] = "SHA-224withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha224.Id] = "SHA-224withECDSA";
+
+ algorithms["SHA256/ECDSA"] = "SHA-256withECDSA";
+ algorithms["SHA-256/ECDSA"] = "SHA-256withECDSA";
+ algorithms["ECDSAWITHSHA256"] = "SHA-256withECDSA";
+ algorithms["ECDSAWITHSHA-256"] = "SHA-256withECDSA";
+ algorithms["SHA256WITHECDSA"] = "SHA-256withECDSA";
+ algorithms["SHA-256WITHECDSA"] = "SHA-256withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha256.Id] = "SHA-256withECDSA";
+
+ algorithms["SHA384/ECDSA"] = "SHA-384withECDSA";
+ algorithms["SHA-384/ECDSA"] = "SHA-384withECDSA";
+ algorithms["ECDSAWITHSHA384"] = "SHA-384withECDSA";
+ algorithms["ECDSAWITHSHA-384"] = "SHA-384withECDSA";
+ algorithms["SHA384WITHECDSA"] = "SHA-384withECDSA";
+ algorithms["SHA-384WITHECDSA"] = "SHA-384withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha384.Id] = "SHA-384withECDSA";
+
+ algorithms["SHA512/ECDSA"] = "SHA-512withECDSA";
+ algorithms["SHA-512/ECDSA"] = "SHA-512withECDSA";
+ algorithms["ECDSAWITHSHA512"] = "SHA-512withECDSA";
+ algorithms["ECDSAWITHSHA-512"] = "SHA-512withECDSA";
+ algorithms["SHA512WITHECDSA"] = "SHA-512withECDSA";
+ algorithms["SHA-512WITHECDSA"] = "SHA-512withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha512.Id] = "SHA-512withECDSA";
+
+ algorithms["RIPEMD160/ECDSA"] = "RIPEMD160withECDSA";
+ algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
+ algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
+ algorithms[TeleTrusTObjectIdentifiers.ECSignWithRipeMD160.Id] = "RIPEMD160withECDSA";
+
+ algorithms["GOST-3410"] = "GOST3410";
+ algorithms["GOST-3410-94"] = "GOST3410";
+ algorithms["GOST3411WITHGOST3410"] = "GOST3410";
+ algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94.Id] = "GOST3410";
+
+ algorithms["ECGOST-3410"] = "ECGOST3410";
+ algorithms["ECGOST-3410-2001"] = "ECGOST3410";
+ algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410";
+ algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
+
+
+
+ oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
oids["MD5withRSA"] = PkcsObjectIdentifiers.MD5WithRsaEncryption;
@@ -240,129 +237,129 @@ namespace Org.BouncyCastle.Security
oids["SHA-384withRSA"] = PkcsObjectIdentifiers.Sha384WithRsaEncryption;
oids["SHA-512withRSA"] = PkcsObjectIdentifiers.Sha512WithRsaEncryption;
- oids["PSSwithRSA"] = PkcsObjectIdentifiers.IdRsassaPss;
- oids["SHA-1withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
- oids["SHA-224withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
- oids["SHA-256withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
- oids["SHA-384withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
- oids["SHA-512withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["PSSwithRSA"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-1withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-224withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-256withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-384withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-512withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
- oids["RIPEMD128withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128;
- oids["RIPEMD160withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160;
- oids["RIPEMD256withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256;
+ oids["RIPEMD128withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128;
+ oids["RIPEMD160withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160;
+ oids["RIPEMD256withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256;
- oids["SHA-1withDSA"] = X9ObjectIdentifiers.IdDsaWithSha1;
+ oids["SHA-1withDSA"] = X9ObjectIdentifiers.IdDsaWithSha1;
- oids["SHA-1withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha1;
- oids["SHA-224withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha224;
- oids["SHA-256withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha256;
- oids["SHA-384withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha384;
- oids["SHA-512withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha512;
+ oids["SHA-1withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha1;
+ oids["SHA-224withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha224;
+ oids["SHA-256withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha256;
+ oids["SHA-384withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha384;
+ oids["SHA-512withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha512;
- oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
- oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
- }
+ oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
+ oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
+ }
- /// <summary>
- /// Returns a ObjectIdentifier for a give encoding.
+ /// <summary>
+ /// Returns an ObjectIdentifier for a given encoding.
/// </summary>
/// <param name="mechanism">A string representation of the encoding.</param>
- /// <returns>A DerObjectIdentifier, null if the Oid is not available.</returns>
- // TODO Don't really want to support this
+ /// <returns>A DerObjectIdentifier, null if the OID is not available.</returns>
+ // TODO Don't really want to support this
public static DerObjectIdentifier GetObjectIdentifier(
- string mechanism)
+ string mechanism)
{
- if (mechanism == null)
- throw new ArgumentNullException("mechanism");
+ if (mechanism == null)
+ throw new ArgumentNullException("mechanism");
- mechanism = Platform.ToUpperInvariant(mechanism);
- string aliased = (string) algorithms[mechanism];
+ mechanism = Platform.ToUpperInvariant(mechanism);
+ string aliased = (string) algorithms[mechanism];
- if (aliased != null)
- mechanism = aliased;
+ if (aliased != null)
+ mechanism = aliased;
- return (DerObjectIdentifier) oids[mechanism];
- }
+ return (DerObjectIdentifier) oids[mechanism];
+ }
- public static ICollection Algorithms
+ public static ICollection Algorithms
{
get { return oids.Keys; }
}
- public static Asn1Encodable GetDefaultX509Parameters(
- DerObjectIdentifier id)
- {
- return GetDefaultX509Parameters(id.Id);
- }
-
- public static Asn1Encodable GetDefaultX509Parameters(
- string algorithm)
- {
- if (algorithm == null)
- throw new ArgumentNullException("algorithm");
-
- algorithm = Platform.ToUpperInvariant(algorithm);
-
- string mechanism = (string) algorithms[algorithm];
-
- if (mechanism == null)
- mechanism = algorithm;
-
- if (mechanism == "PSSwithRSA")
- {
- // TODO The Sha1Digest here is a default. In JCE version, the actual digest
- // to be used can be overridden by subsequent parameter settings.
- return GetPssX509Parameters("SHA-1");
- }
-
- if (mechanism.EndsWith("withRSAandMGF1"))
- {
- string digestName = mechanism.Substring(0, mechanism.Length - "withRSAandMGF1".Length);
- return GetPssX509Parameters(digestName);
- }
-
- return DerNull.Instance;
- }
-
- private static Asn1Encodable GetPssX509Parameters(
- string digestName)
- {
- AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
- DigestUtilities.GetObjectIdentifier(digestName), DerNull.Instance);
-
- // TODO Is it possible for the MGF hash alg to be different from the PSS one?
- AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
- PkcsObjectIdentifiers.IdMgf1, hashAlgorithm);
-
- int saltLen = DigestUtilities.GetDigest(digestName).GetDigestSize();
- return new RsassaPssParameters(hashAlgorithm, maskGenAlgorithm,
- new DerInteger(saltLen), new DerInteger(1));
- }
-
- public static ISigner GetSigner(
- DerObjectIdentifier id)
+ public static Asn1Encodable GetDefaultX509Parameters(
+ DerObjectIdentifier id)
+ {
+ return GetDefaultX509Parameters(id.Id);
+ }
+
+ public static Asn1Encodable GetDefaultX509Parameters(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ algorithm = Platform.ToUpperInvariant(algorithm);
+
+ string mechanism = (string) algorithms[algorithm];
+
+ if (mechanism == null)
+ mechanism = algorithm;
+
+ if (mechanism == "PSSwithRSA")
+ {
+ // TODO The Sha1Digest here is a default. In JCE version, the actual digest
+ // to be used can be overridden by subsequent parameter settings.
+ return GetPssX509Parameters("SHA-1");
+ }
+
+ if (mechanism.EndsWith("withRSAandMGF1"))
+ {
+ string digestName = mechanism.Substring(0, mechanism.Length - "withRSAandMGF1".Length);
+ return GetPssX509Parameters(digestName);
+ }
+
+ return DerNull.Instance;
+ }
+
+ private static Asn1Encodable GetPssX509Parameters(
+ string digestName)
+ {
+ AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+ DigestUtilities.GetObjectIdentifier(digestName), DerNull.Instance);
+
+ // TODO Is it possible for the MGF hash alg to be different from the PSS one?
+ AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.IdMgf1, hashAlgorithm);
+
+ int saltLen = DigestUtilities.GetDigest(digestName).GetDigestSize();
+ return new RsassaPssParameters(hashAlgorithm, maskGenAlgorithm,
+ new DerInteger(saltLen), new DerInteger(1));
+ }
+
+ public static ISigner GetSigner(
+ DerObjectIdentifier id)
{
return GetSigner(id.Id);
}
- public static ISigner GetSigner(
- string algorithm)
+ public static ISigner GetSigner(
+ string algorithm)
{
- if (algorithm == null)
- throw new ArgumentNullException("algorithm");
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
algorithm = Platform.ToUpperInvariant(algorithm);
- string mechanism = (string) algorithms[algorithm];
+ string mechanism = (string) algorithms[algorithm];
- if (mechanism == null)
- mechanism = algorithm;
+ if (mechanism == null)
+ mechanism = algorithm;
- if (mechanism.Equals("RSA"))
- {
- return (new RsaDigestSigner(new NullDigest()));
- }
- if (mechanism.Equals("MD2withRSA"))
+ if (mechanism.Equals("RSA"))
+ {
+ return (new RsaDigestSigner(new NullDigest(), (AlgorithmIdentifier)null));
+ }
+ if (mechanism.Equals("MD2withRSA"))
{
return (new RsaDigestSigner(new MD2Digest()));
}
@@ -394,7 +391,7 @@ namespace Org.BouncyCastle.Security
{
return (new RsaDigestSigner(new Sha512Digest()));
}
- if (mechanism.Equals("RIPEMD128withRSA"))
+ if (mechanism.Equals("RIPEMD128withRSA"))
{
return (new RsaDigestSigner(new RipeMD128Digest()));
}
@@ -407,141 +404,161 @@ namespace Org.BouncyCastle.Security
return (new RsaDigestSigner(new RipeMD256Digest()));
}
- if (mechanism.Equals("RAWRSASSA-PSS"))
- {
- // TODO Add support for other parameter settings
- return PssSigner.CreateRawSigner(new RsaBlindedEngine(), new Sha1Digest());
- }
- if (mechanism.Equals("PSSwithRSA"))
- {
- // TODO The Sha1Digest here is a default. In JCE version, the actual digest
- // to be used can be overridden by subsequent parameter settings.
- return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
- }
- if (mechanism.Equals("SHA-1withRSAandMGF1"))
- {
- return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
- }
- if (mechanism.Equals("SHA-224withRSAandMGF1"))
- {
- return (new PssSigner(new RsaBlindedEngine(), new Sha224Digest()));
- }
- if (mechanism.Equals("SHA-256withRSAandMGF1"))
- {
- return (new PssSigner(new RsaBlindedEngine(), new Sha256Digest()));
- }
- if (mechanism.Equals("SHA-384withRSAandMGF1"))
- {
- return (new PssSigner(new RsaBlindedEngine(), new Sha384Digest()));
- }
- if (mechanism.Equals("SHA-512withRSAandMGF1"))
- {
- return (new PssSigner(new RsaBlindedEngine(), new Sha512Digest()));
- }
-
- if (mechanism.Equals("NONEwithDSA"))
- {
- return (new DsaDigestSigner(new DsaSigner(), new NullDigest()));
- }
- if (mechanism.Equals("SHA-1withDSA"))
+ if (mechanism.Equals("RAWRSASSA-PSS"))
+ {
+ // TODO Add support for other parameter settings
+ return PssSigner.CreateRawSigner(new RsaBlindedEngine(), new Sha1Digest());
+ }
+ if (mechanism.Equals("PSSwithRSA"))
+ {
+ // TODO The Sha1Digest here is a default. In JCE version, the actual digest
+ // to be used can be overridden by subsequent parameter settings.
+ return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-1withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("NONEwithDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new NullDigest()));
+ }
+ if (mechanism.Equals("SHA-1withDSA"))
{
return (new DsaDigestSigner(new DsaSigner(), new Sha1Digest()));
}
- if (mechanism.Equals("SHA-224withDSA"))
- {
- return (new DsaDigestSigner(new DsaSigner(), new Sha224Digest()));
- }
- if (mechanism.Equals("SHA-256withDSA"))
- {
- return (new DsaDigestSigner(new DsaSigner(), new Sha256Digest()));
- }
- if (mechanism.Equals("SHA-384withDSA"))
- {
- return (new DsaDigestSigner(new DsaSigner(), new Sha384Digest()));
- }
- if (mechanism.Equals("SHA-512withDSA"))
- {
- return (new DsaDigestSigner(new DsaSigner(), new Sha512Digest()));
- }
-
- if (mechanism.Equals("NONEwithECDSA"))
- {
- return (new DsaDigestSigner(new ECDsaSigner(), new NullDigest()));
- }
- if (mechanism.Equals("SHA-1withECDSA"))
+ if (mechanism.Equals("SHA-224withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("NONEwithECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new NullDigest()));
+ }
+ if (mechanism.Equals("SHA-1withECDSA"))
{
return (new DsaDigestSigner(new ECDsaSigner(), new Sha1Digest()));
}
- if (mechanism.Equals("SHA-224withECDSA"))
- {
- return (new DsaDigestSigner(new ECDsaSigner(), new Sha224Digest()));
- }
- if (mechanism.Equals("SHA-256withECDSA"))
- {
- return (new DsaDigestSigner(new ECDsaSigner(), new Sha256Digest()));
- }
- if (mechanism.Equals("SHA-384withECDSA"))
- {
- return (new DsaDigestSigner(new ECDsaSigner(), new Sha384Digest()));
- }
- if (mechanism.Equals("SHA-512withECDSA"))
- {
- return (new DsaDigestSigner(new ECDsaSigner(), new Sha512Digest()));
- }
-
- if (mechanism.Equals("RIPEMD160withECDSA"))
- {
- return (new DsaDigestSigner(new ECDsaSigner(), new RipeMD160Digest()));
- }
-
- if (mechanism.Equals("SHA1WITHECNR"))
- {
- return (new DsaDigestSigner(new ECNRSigner(), new Sha1Digest()));
- }
- if (mechanism.Equals("SHA224WITHECNR"))
- {
- return (new DsaDigestSigner(new ECNRSigner(), new Sha224Digest()));
- }
- if (mechanism.Equals("SHA256WITHECNR"))
- {
- return (new DsaDigestSigner(new ECNRSigner(), new Sha256Digest()));
- }
- if (mechanism.Equals("SHA384WITHECNR"))
- {
- return (new DsaDigestSigner(new ECNRSigner(), new Sha384Digest()));
- }
- if (mechanism.Equals("SHA512WITHECNR"))
- {
- return (new DsaDigestSigner(new ECNRSigner(), new Sha512Digest()));
- }
-
- if (mechanism.Equals("GOST3410"))
- {
- return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest());
- }
- if (mechanism.Equals("ECGOST3410"))
- {
- return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
- }
-
- if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
- {
- return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
- }
- if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
- {
- return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
- }
- if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
- {
- return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
- }
-
- throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+ if (mechanism.Equals("SHA-224withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("RIPEMD160withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new RipeMD160Digest()));
+ }
+
+ if (mechanism.Equals("SHA1WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA224WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA256WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA384WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA512WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("GOST3410"))
+ {
+ return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest());
+ }
+ if (mechanism.Equals("ECGOST3410"))
+ {
+ return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
+ }
+
+ if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
+ }
+ if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
+ }
+ if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
+ }
+
+ if (mechanism.EndsWith("/X9.31"))
+ {
+ string x931 = mechanism.Substring(0, mechanism.Length - "/X9.31".Length);
+ int withPos = x931.IndexOf("WITH");
+ if (withPos > 0)
+ {
+ int endPos = withPos + "WITH".Length;
+
+ string digestName = x931.Substring(0, withPos);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ string cipherName = x931.Substring(endPos, x931.Length - endPos);
+ if (cipherName.Equals("RSA"))
+ {
+ IAsymmetricBlockCipher cipher = new RsaBlindedEngine();
+ return new X931Signer(cipher, digest);
+ }
+ }
+ }
+
+ throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
}
public static string GetEncodingName(
- DerObjectIdentifier oid)
+ DerObjectIdentifier oid)
{
return (string) algorithms[oid.Id];
}
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index a21dd00b1..1f9711555 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -1,6 +1,8 @@
using System;
using System.Text;
+using Org.BouncyCastle.Math;
+
namespace Org.BouncyCastle.Utilities
{
/// <summary> General array utilities.</summary>
@@ -309,6 +311,48 @@ namespace Org.BouncyCastle.Utilities
return hc;
}
+ [CLSCompliantAttribute(false)]
+ public static int GetHashCode(ulong[] data)
+ {
+ if (data == null)
+ return 0;
+
+ int i = data.Length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ ulong di = data[i];
+ hc *= 257;
+ hc ^= (int)di;
+ hc *= 257;
+ hc ^= (int)(di >> 32);
+ }
+
+ return hc;
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static int GetHashCode(ulong[] data, int off, int len)
+ {
+ if (data == null)
+ return 0;
+
+ int i = len;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ ulong di = data[off + i];
+ hc *= 257;
+ hc ^= (int)di;
+ hc *= 257;
+ hc ^= (int)(di >> 32);
+ }
+
+ return hc;
+ }
+
public static byte[] Clone(
byte[] data)
{
@@ -337,6 +381,11 @@ namespace Org.BouncyCastle.Utilities
return data == null ? null : (int[])data.Clone();
}
+ internal static uint[] Clone(uint[] data)
+ {
+ return data == null ? null : (uint[])data.Clone();
+ }
+
public static long[] Clone(long[] data)
{
return data == null ? null : (long[])data.Clone();
@@ -366,6 +415,36 @@ namespace Org.BouncyCastle.Utilities
return existing;
}
+ public static bool Contains(byte[] a, byte n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
+ public static bool Contains(short[] a, short n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
+ public static bool Contains(int[] a, int n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
public static void Fill(
byte[] buf,
byte b)
@@ -377,10 +456,125 @@ namespace Org.BouncyCastle.Utilities
}
}
- public static byte[] Copy(byte[] data, int off, int len)
+ public static byte[] CopyOf(byte[] data, int newLength)
+ {
+ byte[] tmp = new byte[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ public static char[] CopyOf(char[] data, int newLength)
+ {
+ char[] tmp = new char[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ public static int[] CopyOf(int[] data, int newLength)
+ {
+ int[] tmp = new int[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ public static long[] CopyOf(long[] data, int newLength)
+ {
+ long[] tmp = new long[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ public static BigInteger[] CopyOf(BigInteger[] data, int newLength)
+ {
+ BigInteger[] tmp = new BigInteger[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ /**
+ * Make a copy of a range of bytes from the passed in data array. The range can
+ * extend beyond the end of the input array, in which case the return array will
+ * be padded with zeroes.
+ *
+ * @param data the array from which the data is to be copied.
+ * @param from the start index at which the copying should take place.
+ * @param to the final index of the range (exclusive).
+ *
+ * @return a new byte array containing the range given.
+ */
+ public static byte[] CopyOfRange(byte[] data, int from, int to)
+ {
+ int newLength = GetLength(from, to);
+ byte[] tmp = new byte[newLength];
+ Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+ return tmp;
+ }
+
+ public static int[] CopyOfRange(int[] data, int from, int to)
+ {
+ int newLength = GetLength(from, to);
+ int[] tmp = new int[newLength];
+ Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+ return tmp;
+ }
+
+ public static long[] CopyOfRange(long[] data, int from, int to)
{
- byte[] result = new byte[len];
- Array.Copy(data, off, result, 0, len);
+ int newLength = GetLength(from, to);
+ long[] tmp = new long[newLength];
+ Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+ return tmp;
+ }
+
+ public static BigInteger[] CopyOfRange(BigInteger[] data, int from, int to)
+ {
+ int newLength = GetLength(from, to);
+ BigInteger[] tmp = new BigInteger[newLength];
+ Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+ return tmp;
+ }
+
+ private static int GetLength(int from, int to)
+ {
+ int newLength = to - from;
+ if (newLength < 0)
+ throw new ArgumentException(from + " > " + to);
+ return newLength;
+ }
+
+ public static byte[] Append(byte[] a, byte b)
+ {
+ if (a == null)
+ return new byte[] { b };
+
+ int length = a.Length;
+ byte[] result = new byte[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
+ return result;
+ }
+
+ public static short[] Append(short[] a, short b)
+ {
+ if (a == null)
+ return new short[] { b };
+
+ int length = a.Length;
+ short[] result = new short[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
+ return result;
+ }
+
+ public static int[] Append(int[] a, int b)
+ {
+ if (a == null)
+ return new int[] { b };
+
+ int length = a.Length;
+ int[] result = new int[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
return result;
}
@@ -396,5 +590,86 @@ namespace Org.BouncyCastle.Utilities
Array.Copy(b, 0, rv, a.Length, b.Length);
return rv;
}
+
+ public static int[] Concatenate(int[] a, int[] b)
+ {
+ if (a == null)
+ return Clone(b);
+ if (b == null)
+ return Clone(a);
+
+ int[] rv = new int[a.Length + b.Length];
+ Array.Copy(a, 0, rv, 0, a.Length);
+ Array.Copy(b, 0, rv, a.Length, b.Length);
+ return rv;
+ }
+
+ public static byte[] Prepend(byte[] a, byte b)
+ {
+ if (a == null)
+ return new byte[] { b };
+
+ int length = a.Length;
+ byte[] result = new byte[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
+ public static short[] Prepend(short[] a, short b)
+ {
+ if (a == null)
+ return new short[] { b };
+
+ int length = a.Length;
+ short[] result = new short[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
+ public static int[] Prepend(int[] a, int b)
+ {
+ if (a == null)
+ return new int[] { b };
+
+ int length = a.Length;
+ int[] result = new int[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
+ public static byte[] Reverse(byte[] a)
+ {
+ if (a == null)
+ return null;
+
+ int p1 = 0, p2 = a.Length;
+ byte[] result = new byte[p2];
+
+ while (--p2 >= 0)
+ {
+ result[p2] = a[p1++];
+ }
+
+ return result;
+ }
+
+ public static int[] Reverse(int[] a)
+ {
+ if (a == null)
+ return null;
+
+ int p1 = 0, p2 = a.Length;
+ int[] result = new int[p2];
+
+ while (--p2 >= 0)
+ {
+ result[p2] = a[p1++];
+ }
+
+ return result;
+ }
}
}
diff --git a/crypto/src/util/Times.cs b/crypto/src/util/Times.cs
new file mode 100644
index 000000000..99a78d21a
--- /dev/null
+++ b/crypto/src/util/Times.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+ public sealed class Times
+ {
+ private static long NanosecondsPerTick = 100L;
+
+ public static long NanoTime()
+ {
+ return DateTime.UtcNow.Ticks * NanosecondsPerTick;
+ }
+ }
+}
diff --git a/crypto/src/util/io/FilterStream.cs b/crypto/src/util/io/FilterStream.cs
new file mode 100644
index 000000000..260ce1789
--- /dev/null
+++ b/crypto/src/util/io/FilterStream.cs
@@ -0,0 +1,66 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public class FilterStream : Stream
+ {
+ public FilterStream(Stream s)
+ {
+ this.s = s;
+ }
+ public override bool CanRead
+ {
+ get { return s.CanRead; }
+ }
+ public override bool CanSeek
+ {
+ get { return s.CanSeek; }
+ }
+ public override bool CanWrite
+ {
+ get { return s.CanWrite; }
+ }
+ public override long Length
+ {
+ get { return s.Length; }
+ }
+ public override long Position
+ {
+ get { return s.Position; }
+ set { s.Position = value; }
+ }
+ public override void Close()
+ {
+ s.Close();
+ }
+ public override void Flush()
+ {
+ s.Flush();
+ }
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return s.Seek(offset, origin);
+ }
+ public override void SetLength(long value)
+ {
+ s.SetLength(value);
+ }
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return s.Read(buffer, offset, count);
+ }
+ public override int ReadByte()
+ {
+ return s.ReadByte();
+ }
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ s.Write(buffer, offset, count);
+ }
+ public override void WriteByte(byte value)
+ {
+ s.WriteByte(value);
+ }
+ protected readonly Stream s;
+ }
+}
diff --git a/crypto/src/util/io/Streams.cs b/crypto/src/util/io/Streams.cs
index ee95d3b01..70957acc7 100644
--- a/crypto/src/util/io/Streams.cs
+++ b/crypto/src/util/io/Streams.cs
@@ -83,10 +83,10 @@ namespace Org.BouncyCastle.Utilities.IO
int numRead;
while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0)
{
- total += numRead;
- if (total > limit)
+ if ((limit - total) < numRead)
throw new StreamOverflowException("Data Overflow");
- outStr.Write(bs, 0, numRead);
+ total += numRead;
+ outStr.Write(bs, 0, numRead);
}
return total;
}
diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs
index f156f3147..4487232f0 100644
--- a/crypto/src/x509/X509Certificate.cs
+++ b/crypto/src/x509/X509Certificate.cs
@@ -14,6 +14,7 @@ using Org.BouncyCastle.Security.Certificates;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.Crypto.Operators;
namespace Org.BouncyCastle.X509
{
@@ -546,30 +547,38 @@ namespace Org.BouncyCastle.X509
public virtual void Verify(
AsymmetricKeyParameter key)
{
- string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
- ISigner signature = SignerUtilities.GetSigner(sigName);
-
- CheckSignature(key, signature);
+ CheckSignature(new Asn1SignatureVerifier(c.SignatureAlgorithm, key));
}
- protected virtual void CheckSignature(
- AsymmetricKeyParameter publicKey,
- ISigner signature)
+ /// <summary>
+ /// Verify the certificate's signature using a verifier created using the passed in verifier provider.
+ /// </summary>
+ /// <param name="verifierProvider">An appropriate provider for verifying the certificate's signature.</param>
+ /// <returns>True if the signature is valid.</returns>
+ /// <exception cref="Exception">If verifier provider is not appropriate or the certificate algorithm is invalid.</exception>
+ public virtual void Verify(
+ ISignatureVerifierProvider verifierProvider)
+ {
+ CheckSignature(verifierProvider.CreateSignatureVerifier (c.SignatureAlgorithm));
+ }
+
+ protected virtual void CheckSignature(
+ ISignatureVerifier verifier)
{
if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature))
throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
- X509SignatureUtilities.SetSignatureParameters(signature, parameters);
-
- signature.Init(false, publicKey);
+ IStreamCalculator streamCalculator = verifier.CreateCalculator();
byte[] b = this.GetTbsCertificate();
- signature.BlockUpdate(b, 0, b.Length);
- byte[] sig = this.GetSignature();
- if (!signature.VerifySignature(sig))
+ streamCalculator.Stream.Write(b, 0, b.Length);
+
+ streamCalculator.Stream.Close();
+
+ if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
{
throw new InvalidKeyException("Public key presented not for certificate signature");
}
diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs
index 7d0e7aa72..1746960fb 100644
--- a/crypto/src/x509/X509Crl.cs
+++ b/crypto/src/x509/X509Crl.cs
@@ -14,6 +14,7 @@ using Org.BouncyCastle.Utilities.Collections;
using Org.BouncyCastle.Utilities.Date;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.Crypto.Operators;
namespace Org.BouncyCastle.X509
{
@@ -83,24 +84,46 @@ namespace Org.BouncyCastle.X509
public virtual void Verify(
AsymmetricKeyParameter publicKey)
{
- if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
- {
- throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
- }
+ Verify(new Asn1SignatureVerifierProvider(publicKey));
+ }
- ISigner sig = SignerUtilities.GetSigner(SigAlgName);
- sig.Init(false, publicKey);
+ /// <summary>
+ /// Verify the CRL's signature using a verifier created using the passed in verifier provider.
+ /// </summary>
+ /// <param name="verifierProvider">An appropriate provider for verifying the CRL's signature.</param>
+ /// <returns>True if the signature is valid.</returns>
+ /// <exception cref="Exception">If verifier provider is not appropriate or the CRL algorithm is invalid.</exception>
+ public virtual void Verify(
+ ISignatureVerifierProvider verifierProvider)
+ {
+ CheckSignature(verifierProvider.CreateSignatureVerifier(c.SignatureAlgorithm));
+ }
- byte[] encoded = this.GetTbsCertList();
- sig.BlockUpdate(encoded, 0, encoded.Length);
+ protected virtual void CheckSignature(
+ ISignatureVerifier verifier)
+ {
+ if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
+ {
+ throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
+ }
- if (!sig.VerifySignature(this.GetSignature()))
- {
- throw new SignatureException("CRL does not verify with supplied public key.");
- }
- }
+ Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
+
+ IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+ byte[] b = this.GetTbsCertList();
+
+ streamCalculator.Stream.Write(b, 0, b.Length);
+
+ streamCalculator.Stream.Close();
+
+ if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
+ {
+ throw new InvalidKeyException("CRL does not verify with supplied public key.");
+ }
+ }
- public virtual int Version
+ public virtual int Version
{
get { return c.Version; }
}
diff --git a/crypto/src/x509/X509V1CertificateGenerator.cs b/crypto/src/x509/X509V1CertificateGenerator.cs
index 02b58a198..a452df440 100644
--- a/crypto/src/x509/X509V1CertificateGenerator.cs
+++ b/crypto/src/x509/X509V1CertificateGenerator.cs
@@ -1,10 +1,12 @@
using System;
+using System.IO;
using System.Collections;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Security.Certificates;
@@ -119,6 +121,7 @@ namespace Org.BouncyCastle.X509
/// This can be either a name or an OID, names are treated as case insensitive.
/// </summary>
/// <param name="signatureAlgorithm">string representation of the algorithm name</param>
+ [Obsolete("Not needed if Generate used with an ISignatureCalculator")]
public void SetSignatureAlgorithm(
string signatureAlgorithm)
{
@@ -143,6 +146,7 @@ namespace Org.BouncyCastle.X509
/// </summary>
/// <param name="privateKey">The private key of the issuer used to sign this certificate.</param>
/// <returns>An X509Certificate.</returns>
+ [Obsolete("Use Generate with an ISignatureCalculator")]
public X509Certificate Generate(
AsymmetricKeyParameter privateKey)
{
@@ -155,43 +159,43 @@ namespace Org.BouncyCastle.X509
/// <param name="privateKey">The private key of the issuer used to sign this certificate.</param>
/// <param name="random">The Secure Random you want to use.</param>
/// <returns>An X509Certificate.</returns>
+ [Obsolete("Use Generate with an ISignatureCalculator")]
public X509Certificate Generate(
AsymmetricKeyParameter privateKey,
SecureRandom random)
{
+ return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random));
+ }
+
+ /// <summary>
+ /// Generate a new X509Certificate using the passed in SignatureCalculator.
+ /// </summary>
+ /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param>
+ /// <returns>An X509Certificate.</returns>
+ public X509Certificate Generate(ISignatureCalculator signatureCalculator)
+ {
+ tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails);
+
TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
- byte[] signature;
- try
- {
- signature = X509Utilities.GetSignatureForObject(
- sigOID, signatureAlgorithm, privateKey, random, tbsCert);
- }
- catch (Exception e)
- {
- // TODO
-// throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
- throw new CertificateEncodingException("exception encoding TBS cert", e);
- }
+ IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
- try
- {
- return GenerateJcaObject(tbsCert, signature);
- }
- catch (CertificateParsingException e)
- {
- // TODO
- // throw new ExtCertificateEncodingException("exception producing certificate object", e);
- throw new CertificateEncodingException("exception producing certificate object", e);
- }
+ byte[] encoded = tbsCert.GetDerEncoded();
+
+ streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+ streamCalculator.Stream.Close();
+
+ return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal());
}
private X509Certificate GenerateJcaObject(
TbsCertificateStructure tbsCert,
+ AlgorithmIdentifier sigAlg,
byte[] signature)
{
return new X509Certificate(
- new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+ new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature)));
}
/// <summary>
diff --git a/crypto/src/x509/X509V2AttributeCertificate.cs b/crypto/src/x509/X509V2AttributeCertificate.cs
index 117ac4cc2..cc72c23bb 100644
--- a/crypto/src/x509/X509V2AttributeCertificate.cs
+++ b/crypto/src/x509/X509V2AttributeCertificate.cs
@@ -9,6 +9,7 @@ using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Security.Certificates;
using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Crypto.Operators;
namespace Org.BouncyCastle.X509
{
@@ -151,29 +152,48 @@ namespace Org.BouncyCastle.X509
return cert.SignatureValue.GetBytes();
}
- public virtual void Verify(
- AsymmetricKeyParameter publicKey)
- {
- if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
+ public virtual void Verify(
+ AsymmetricKeyParameter key)
+ {
+ CheckSignature(new Asn1SignatureVerifier(cert.SignatureAlgorithm, key));
+ }
+
+ /// <summary>
+ /// Verify the certificate's signature using a verifier created using the passed in verifier provider.
+ /// </summary>
+ /// <param name="verifierProvider">An appropriate provider for verifying the certificate's signature.</param>
+ /// <returns>True if the signature is valid.</returns>
+ /// <exception cref="Exception">If verifier provider is not appropriate or the certificate algorithm is invalid.</exception>
+ public virtual void Verify(
+ ISignatureVerifierProvider verifierProvider)
+ {
+ CheckSignature(verifierProvider.CreateSignatureVerifier(cert.SignatureAlgorithm));
+ }
+
+ protected virtual void CheckSignature(
+ ISignatureVerifier verifier)
+ {
+ if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
{
throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
}
- ISigner signature = SignerUtilities.GetSigner(cert.SignatureAlgorithm.ObjectID.Id);
-
- signature.Init(false, publicKey);
+ IStreamCalculator streamCalculator = verifier.CreateCalculator();
try
{
- byte[] b = cert.ACInfo.GetEncoded();
- signature.BlockUpdate(b, 0, b.Length);
- }
+ byte[] b = this.cert.ACInfo.GetEncoded();
+
+ streamCalculator.Stream.Write(b, 0, b.Length);
+
+ streamCalculator.Stream.Close();
+ }
catch (IOException e)
{
throw new SignatureException("Exception encoding certificate info object", e);
}
- if (!signature.VerifySignature(this.GetSignature()))
+ if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
{
throw new InvalidKeyException("Public key presented not for certificate signature");
}
diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
index a683d5e20..138f2ec6f 100644
--- a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
+++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
@@ -8,6 +8,8 @@ using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Security.Certificates;
using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Crypto.Operators;
+using System.IO;
namespace Org.BouncyCastle.X509
{
@@ -66,12 +68,13 @@ namespace Org.BouncyCastle.X509
acInfoGen.SetEndDate(new DerGeneralizedTime(date));
}
- /// <summary>
- /// Set the signature algorithm. This can be either a name or an OID, names
- /// are treated as case insensitive.
- /// </summary>
- /// <param name="signatureAlgorithm">The algorithm name.</param>
- public void SetSignatureAlgorithm(
+ /// <summary>
+ /// Set the signature algorithm. This can be either a name or an OID, names
+ /// are treated as case insensitive.
+ /// </summary>
+ /// <param name="signatureAlgorithm">The algorithm name.</param>
+ [Obsolete("Not needed if Generate used with an ISignatureCalculator")]
+ public void SetSignatureAlgorithm(
string signatureAlgorithm)
{
this.signatureAlgorithm = signatureAlgorithm;
@@ -127,37 +130,57 @@ namespace Org.BouncyCastle.X509
extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
}
- /// <summary>
- /// Generate an X509 certificate, based on the current issuer and subject.
- /// </summary>
- public IX509AttributeCertificate Generate(
- AsymmetricKeyParameter publicKey)
+ /// <summary>
+ /// Generate an X509 certificate, based on the current issuer and subject.
+ /// </summary>
+ [Obsolete("Use Generate with an ISignatureCalculator")]
+ public IX509AttributeCertificate Generate(
+ AsymmetricKeyParameter privateKey)
{
- return Generate(publicKey, null);
+ return Generate(privateKey, null);
}
- /// <summary>
- /// Generate an X509 certificate, based on the current issuer and subject,
- /// using the supplied source of randomness, if required.
- /// </summary>
- public IX509AttributeCertificate Generate(
- AsymmetricKeyParameter publicKey,
+ /// <summary>
+ /// Generate an X509 certificate, based on the current issuer and subject,
+ /// using the supplied source of randomness, if required.
+ /// </summary>
+ [Obsolete("Use Generate with an ISignatureCalculator")]
+ public IX509AttributeCertificate Generate(
+ AsymmetricKeyParameter privateKey,
SecureRandom random)
- {
- if (!extGenerator.IsEmpty)
+ {
+ return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random));
+ }
+
+ /// <summary>
+ /// Generate a new X.509 Attribute Certificate using the passed in SignatureCalculator.
+ /// </summary>
+ /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param>
+ /// <returns>An IX509AttributeCertificate.</returns>
+ public IX509AttributeCertificate Generate(ISignatureCalculator signatureCalculator)
+ {
+ if (!extGenerator.IsEmpty)
{
acInfoGen.SetExtensions(extGenerator.Generate());
}
AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo();
- Asn1EncodableVector v = new Asn1EncodableVector();
+ byte[] encoded = acInfo.GetDerEncoded();
+
+ IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+ streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+ streamCalculator.Stream.Close();
+
+ Asn1EncodableVector v = new Asn1EncodableVector();
- v.Add(acInfo, sigAlgId);
+ v.Add(acInfo, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails);
try
{
- v.Add(new DerBitString(X509Utilities.GetSignatureForObject(sigOID, signatureAlgorithm, publicKey, random, acInfo)));
+ v.Add(new DerBitString(((IBlockResult)streamCalculator.GetResult()).DoFinal()));
return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v)));
}
diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs
index a2293b333..c1cc8e824 100644
--- a/crypto/src/x509/X509V2CRLGenerator.cs
+++ b/crypto/src/x509/X509V2CRLGenerator.cs
@@ -10,6 +10,7 @@ using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Security.Certificates;
using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Crypto.Operators;
namespace Org.BouncyCastle.X509
{
@@ -129,13 +130,12 @@ namespace Org.BouncyCastle.X509
}
}
- /**
- * Set the signature algorithm. This can be either a name or an oid, names
- * are treated as case insensitive.
- *
- * @param signatureAlgorithm string representation of the algorithm name.
- */
- public void SetSignatureAlgorithm(
+ /// <summary>
+ /// Set the signature algorithm that will be used to sign this CRL.
+ /// </summary>
+ /// <param name="signatureAlgorithm"/>
+ [Obsolete("Not needed if Generate used with an ISignatureCalculator")]
+ public void SetSignatureAlgorithm(
string signatureAlgorithm)
{
this.signatureAlgorithm = signatureAlgorithm;
@@ -198,40 +198,55 @@ namespace Org.BouncyCastle.X509
extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
}
- /// <summary>Generate an X509 CRL, based on the current issuer and subject.</summary>
- /// <param name="privateKey">The key used for signing.</param>
- public X509Crl Generate(
- AsymmetricKeyParameter privateKey)
- {
- return Generate(privateKey, null);
- }
+ /// <summary>
+ /// Generate an X.509 CRL, based on the current issuer and subject.
+ /// </summary>
+ /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+ /// <returns>An X509Crl.</returns>
+ [Obsolete("Use Generate with an ISignatureCalculator")]
+ public X509Crl Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
- /// <summary>Generate an X509 CRL, based on the current issuer and subject.</summary>
- /// <param name="privateKey">The key used for signing.</param>
- /// <param name="random">A user-defined source of randomness.</param>
- public X509Crl Generate(
- AsymmetricKeyParameter privateKey,
- SecureRandom random)
- {
- TbsCertificateList tbsCrl = GenerateCertList();
- byte[] signature;
+ /// <summary>
+ /// Generate an X.509 CRL, based on the current issuer and subject using the specified secure random.
+ /// </summary>
+ /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+ /// <param name="random">Your Secure Random instance.</param>
+ /// <returns>An X509Crl.</returns>
+ [Obsolete("Use Generate with an ISignatureCalculator")]
+ public X509Crl Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random));
+ }
- try
- {
- signature = X509Utilities.GetSignatureForObject(
- sigOID, signatureAlgorithm, privateKey, random, tbsCrl);
- }
- catch (IOException e)
- {
- // TODO
-// throw new ExtCrlException("cannot generate CRL encoding", e);
- throw new CrlException("cannot generate CRL encoding", e);
- }
+ /// <summary>
+ /// Generate a new X509Crl using the passed in SignatureCalculator.
+ /// </summary>
+ /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param>
+ /// <returns>An X509Crl.</returns>
+ public X509Crl Generate(ISignatureCalculator signatureCalculator)
+ {
+ tbsGen.SetSignature((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails);
- return GenerateJcaObject(tbsCrl, signature);
- }
+ TbsCertificateList tbsCertList = GenerateCertList();
+
+ IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+ byte[] encoded = tbsCertList.GetDerEncoded();
+
+ streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+ streamCalculator.Stream.Close();
+
+ return GenerateJcaObject(tbsCertList, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal());
+ }
- private TbsCertificateList GenerateCertList()
+ private TbsCertificateList GenerateCertList()
{
if (!extGenerator.IsEmpty)
{
@@ -243,11 +258,12 @@ namespace Org.BouncyCastle.X509
private X509Crl GenerateJcaObject(
TbsCertificateList tbsCrl,
+ AlgorithmIdentifier algId,
byte[] signature)
{
return new X509Crl(
CertificateList.GetInstance(
- new DerSequence(tbsCrl, sigAlgId, new DerBitString(signature))));
+ new DerSequence(tbsCrl, algId, new DerBitString(signature))));
}
/// <summary>
diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs
index bb0dd9cbc..a22cd9943 100644
--- a/crypto/src/x509/X509V3CertificateGenerator.cs
+++ b/crypto/src/x509/X509V3CertificateGenerator.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections;
+using System.IO;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
@@ -110,6 +112,7 @@ namespace Org.BouncyCastle.X509
/// Set the signature algorithm that will be used to sign this certificate.
/// </summary>
/// <param name="signatureAlgorithm"/>
+ [Obsolete("Not needed if Generate used with an ISignatureCalculator")]
public void SetSignatureAlgorithm(
string signatureAlgorithm)
{
@@ -274,7 +277,8 @@ namespace Org.BouncyCastle.X509
/// </summary>
/// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
/// <returns>An X509Certificate.</returns>
- public X509Certificate Generate(
+ [Obsolete("Use Generate with an ISignatureCalculator")]
+ public X509Certificate Generate(
AsymmetricKeyParameter privateKey)
{
return Generate(privateKey, null);
@@ -286,53 +290,48 @@ namespace Org.BouncyCastle.X509
/// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
/// <param name="random">You Secure Random instance.</param>
/// <returns>An X509Certificate.</returns>
+ [Obsolete("Use Generate with an ISignatureCalculator")]
public X509Certificate Generate(
AsymmetricKeyParameter privateKey,
SecureRandom random)
{
- TbsCertificateStructure tbsCert = GenerateTbsCert();
- byte[] signature;
-
- try
- {
- signature = X509Utilities.GetSignatureForObject(
- sigOid, signatureAlgorithm, privateKey, random, tbsCert);
- }
- catch (Exception e)
- {
- // TODO
-// throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
- throw new CertificateEncodingException("exception encoding TBS cert", e);
- }
-
- try
- {
- return GenerateJcaObject(tbsCert, signature);
- }
- catch (CertificateParsingException e)
- {
- // TODO
- // throw new ExtCertificateEncodingException("exception producing certificate object", e);
- throw new CertificateEncodingException("exception producing certificate object", e);
- }
+ return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random));
}
- private TbsCertificateStructure GenerateTbsCert()
+ /// <summary>
+ /// Generate a new X509Certificate using the passed in SignatureCalculator.
+ /// </summary>
+ /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param>
+ /// <returns>An X509Certificate.</returns>
+ public X509Certificate Generate(ISignatureCalculator signatureCalculator)
{
- if (!extGenerator.IsEmpty)
- {
- tbsGen.SetExtensions(extGenerator.Generate());
- }
+ tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails);
+
+ if (!extGenerator.IsEmpty)
+ {
+ tbsGen.SetExtensions(extGenerator.Generate());
+ }
+
+ TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
+
+ IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+ byte[] encoded = tbsCert.GetDerEncoded();
+
+ streamCalculator.Stream.Write (encoded, 0, encoded.Length);
+
+ streamCalculator.Stream.Close ();
- return tbsGen.GenerateTbsCertificate();
+ return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal());
}
private X509Certificate GenerateJcaObject(
TbsCertificateStructure tbsCert,
+ AlgorithmIdentifier sigAlg,
byte[] signature)
{
return new X509Certificate(
- new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+ new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature)));
}
/// <summary>
|