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/anssi/ANSSINamedCurves.cs b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
new file mode 100644
index 000000000..04e30bb07
--- /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));
+ ECPoint G = curve.DecodePoint(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/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/sec/SECNamedCurves.cs b/crypto/src/asn1/sec/SECNamedCurves.cs
index 60d456ef0..0bd60b0b8 100644
--- a/crypto/src/asn1/sec/SECNamedCurves.cs
+++ b/crypto/src/asn1/sec/SECNamedCurves.cs
@@ -1154,7 +1154,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 +1200,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 +1213,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 +1235,7 @@ namespace Org.BouncyCastle.Asn1.Sec
public static string GetName(
DerObjectIdentifier oid)
{
- return (string) names[oid];
+ return (string)names[oid];
}
/**
@@ -1247,7 +1244,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..f476619a7 100644
--- a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
+++ b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -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/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs
index 0030d376b..d8315c16f 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,12 +33,17 @@ 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;
@@ -60,12 +66,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 +98,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 +127,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..a9ea0240c 100644
--- a/crypto/src/asn1/x9/X962NamedCurves.cs
+++ b/crypto/src/asn1/x9/X962NamedCurves.cs
@@ -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/bcpg/S2k.cs b/crypto/src/bcpg/S2k.cs
index de08c016c..f6d306890 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;
diff --git a/crypto/src/cms/CMSSignedDataGenerator.cs b/crypto/src/cms/CMSSignedDataGenerator.cs
index f31105c41..114b9631d 100644
--- a/crypto/src/cms/CMSSignedDataGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataGenerator.cs
@@ -93,19 +93,25 @@ 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));
- }
-
- byte[] hash = DigestUtilities.DoFinal(dig);
- outer._digests.Add(digestOID, hash.Clone());
+ 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());
+ }
sig.Init(true, new ParametersWithRandom(key, random));
#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
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/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/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/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
index 8ff1d24c7..9b7935523 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;
@@ -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());
+ ECPoint G = curve.DecodePoint(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);
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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()
{
@@ -104,12 +200,12 @@ 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()
{
@@ -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()
{
@@ -158,12 +254,12 @@ 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()
{
@@ -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()
{
@@ -212,12 +308,12 @@ 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()
{
@@ -233,12 +329,12 @@ 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()
{
@@ -254,12 +350,12 @@ 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()
{
@@ -272,43 +368,425 @@ namespace Org.BouncyCastle.Crypto.EC
}
}
+ /*
+ * 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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(Hex.Decode("04"
+ + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+ + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+ 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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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());
+ ECPoint G = curve.DecodePoint(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("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 +838,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/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 0cdd868fa..9d7f76c05 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -363,7 +363,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)
{
@@ -377,41 +377,32 @@ namespace Org.BouncyCastle.Crypto.Engines
this.forEncryption = forEncryption;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "AES"; }
}
- 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("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);
@@ -429,7 +420,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public void Reset()
+ public virtual void Reset()
{
}
diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs
index 38d3a5841..a1b544568 100644
--- a/crypto/src/crypto/engines/AesFastEngine.cs
+++ b/crypto/src/crypto/engines/AesFastEngine.cs
@@ -695,7 +695,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,41 +709,32 @@ namespace Org.BouncyCastle.Crypto.Engines
this.forEncryption = forEncryption;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "AES"; }
}
- 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("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);
@@ -761,7 +752,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public void Reset()
+ public virtual void Reset()
{
}
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index 54f2d2e88..a6b9e3bd4 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -258,7 +258,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)
{
@@ -272,41 +272,32 @@ namespace Org.BouncyCastle.Crypto.Engines
this.forEncryption = forEncryption;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "AES"; }
}
- 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("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);
@@ -324,7 +315,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public void Reset()
+ public virtual void Reset()
{
}
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 70df3077c..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,
@@ -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..037abf7e9 100644
--- a/crypto/src/crypto/engines/RSABlindedEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindedEngine.cs
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Crypto.Engines
private RsaKeyParameters key;
private SecureRandom random;
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "RSA"; }
}
@@ -28,7 +28,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 param)
{
@@ -55,7 +55,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an input block.
*/
- public int GetInputBlockSize()
+ public virtual int GetInputBlockSize()
{
return core.GetInputBlockSize();
}
@@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @return maximum size for an output block.
*/
- public int GetOutputBlockSize()
+ public virtual int GetOutputBlockSize()
{
return core.GetOutputBlockSize();
}
@@ -81,7 +81,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/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/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/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/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index 653d75cb9..e0b1e6b54 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,45 @@ 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);
ctrCipher.ProcessBlock(macBlock, 0, macBlock, 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(macBlock, 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,30 +306,30 @@ 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)
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 2e2ac2eca..8e6120eef 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -284,6 +284,9 @@ namespace Org.BouncyCastle.Crypto.Modes
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)
@@ -301,6 +304,7 @@ namespace Org.BouncyCastle.Crypto.Modes
private void OutputBlock(byte[] output, int offset)
{
+ Check.OutputLength(output, offset, BlockSize, "Output buffer too short");
if (totalLength == 0)
{
InitCipher();
@@ -325,12 +329,19 @@ namespace Org.BouncyCastle.Crypto.Modes
}
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)
diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
index 54359dfe8..e7dc466e6 100644
--- a/crypto/src/crypto/modes/OCBBlockCipher.cs
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -355,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)
@@ -382,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;
@@ -431,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
*/
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index 0f241035f..de41d88f4 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -106,6 +106,29 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
x[3] = r13;
}
+ internal static void Multiply(ulong[] x, ulong[] y)
+ {
+ ulong r00 = x[0], r01 = x[1], r10 = 0, r11 = 0;
+
+ for (int i = 0; i < 2; ++i)
+ {
+ 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 = (r01 << 63) >> 8;
+ r01 = (r01 >> 1) | (r00 << 63);
+ r00 = (r00 >> 1) ^ (m2 & E1L);
+ }
+ }
+
+ x[0] = r10;
+ x[1] = r11;
+ }
+
// P is the value with only bit i=1 set
internal static void MultiplyP(uint[] x)
{
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/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/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/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 5035b454d..a5512176f 100644
--- a/crypto/src/crypto/signers/GenericSigner.cs
+++ b/crypto/src/crypto/signers/GenericSigner.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Signers
this.digest = digest;
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return "Generic(" + engine.AlgorithmName + "/" + digest.AlgorithmName + ")"; }
}
@@ -34,7 +34,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* @param parameters
* necessary parameters.
*/
- public void Init(bool forSigning, ICipherParameters parameters)
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
{
this.forSigning = forSigning;
@@ -62,7 +62,7 @@ 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);
}
@@ -70,7 +70,7 @@ 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);
}
@@ -79,7 +79,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("GenericSigner not initialised for signature generation.");
@@ -94,7 +94,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* 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("GenericSigner not initialised for verification");
@@ -122,7 +122,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
}
- public void Reset()
+ public virtual void Reset()
{
digest.Reset();
}
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index d4f6c5522..1486656bd 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -120,7 +120,7 @@ namespace Org.BouncyCastle.Crypto.Signers
{
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "with" + "ISO9796-2S2"; }
}
@@ -365,7 +365,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];
diff --git a/crypto/src/crypto/signers/Iso9796d2Signer.cs b/crypto/src/crypto/signers/Iso9796d2Signer.cs
index cfb8942e6..4bb4d17a6 100644
--- a/crypto/src/crypto/signers/Iso9796d2Signer.cs
+++ b/crypto/src/crypto/signers/Iso9796d2Signer.cs
@@ -105,7 +105,7 @@ namespace Org.BouncyCastle.Crypto.Signers
{
}
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "with" + "ISO9796-2S1"; }
}
@@ -252,7 +252,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 +266,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)
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/RsaDigestSigner.cs b/crypto/src/crypto/signers/RsaDigestSigner.cs
index 9af4e7145..d9b19cf6b 100644
--- a/crypto/src/crypto/signers/RsaDigestSigner.cs
+++ b/crypto/src/crypto/signers/RsaDigestSigner.cs
@@ -64,8 +64,7 @@ namespace Org.BouncyCastle.Crypto.Signers
this.algId = algId;
}
- [Obsolete]
- public string AlgorithmName
+ public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "withRSA"; }
}
@@ -76,7 +75,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* @param forSigning true if for signing, false otherwise
* @param param necessary parameters.
*/
- public void Init(
+ public virtual void Init(
bool forSigning,
ICipherParameters parameters)
{
@@ -106,7 +105,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);
@@ -115,7 +114,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)
@@ -127,7 +126,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("RsaDigestSigner not initialised for signature generation.");
@@ -143,7 +142,7 @@ namespace Org.BouncyCastle.Crypto.Signers
* return true if the internal state represents the signature described
* in the passed in array.
*/
- public bool VerifySignature(
+ public virtual bool VerifySignature(
byte[] signature)
{
if (forSigning)
@@ -197,7 +196,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
}
- public void Reset()
+ public virtual void Reset()
{
digest.Reset();
}
diff --git a/crypto/src/crypto/signers/X931Signer.cs b/crypto/src/crypto/signers/X931Signer.cs
new file mode 100644
index 000000000..89f512b78
--- /dev/null
+++ b/crypto/src/crypto/signers/X931Signer.cs
@@ -0,0 +1,234 @@
+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
+ {
+ 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;
+
+ private static readonly IDictionary trailerMap = Platform.CreateHashtable();
+
+ static X931Signer()
+ {
+ trailerMap.Add("RIPEMD128", TRAILER_RIPEMD128);
+ trailerMap.Add("RIPEMD160", TRAILER_RIPEMD160);
+
+ trailerMap.Add("SHA-1", TRAILER_SHA1);
+ trailerMap.Add("SHA-224", TRAILER_SHA224);
+ trailerMap.Add("SHA-256", TRAILER_SHA256);
+ trailerMap.Add("SHA-384", TRAILER_SHA384);
+ trailerMap.Add("SHA-512", TRAILER_SHA512);
+
+ trailerMap.Add("Whirlpool", TRAILER_WHIRLPOOL);
+ }
+
+ private IDigest digest;
+ private IAsymmetricBlockCipher cipher;
+ private RsaKeyParameters kParam;
+
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+
+ /**
+ * Generate a signer for the with either implicit or explicit trailers
+ * for ISO9796-2.
+ *
+ * @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 = TRAILER_IMPLICIT;
+ }
+ else
+ {
+ string name = digest.AlgorithmName;
+ if (!trailerMap.Contains(name))
+ throw new ArgumentException("no valid trailer", "digest");
+
+ trailer = (int)trailerMap[name];
+ }
+ }
+
+ 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 == TRAILER_IMPLICIT)
+ {
+ delta = block.Length - digSize - 1;
+ digest.DoFinal(block, delta);
+ block[block.Length - 1] = (byte)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/AbstractTlsClient.cs b/crypto/src/crypto/tls/AbstractTlsClient.cs
index 771bc004b..046feb78c 100644
--- a/crypto/src/crypto/tls/AbstractTlsClient.cs
+++ b/crypto/src/crypto/tls/AbstractTlsClient.cs
@@ -117,27 +117,7 @@ namespace Org.BouncyCastle.Crypto.Tls
{
// TODO Provide a way for the user to specify the acceptable hash/signature algorithms.
- byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha512, HashAlgorithm.sha384, HashAlgorithm.sha256,
- HashAlgorithm.sha224, HashAlgorithm.sha1 };
-
- // TODO Sort out ECDSA signatures and add them as the preferred option here
- byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa };
-
- this.mSupportedSignatureAlgorithms = Platform.CreateArrayList();
- for (int i = 0; i < hashAlgorithms.Length; ++i)
- {
- for (int j = 0; j < signatureAlgorithms.Length; ++j)
- {
- this.mSupportedSignatureAlgorithms.Add(new SignatureAndHashAlgorithm(hashAlgorithms[i],
- signatureAlgorithms[j]));
- }
- }
-
- /*
- * RFC 5264 7.4.3. Currently, DSA [DSS] may only be used with SHA-1.
- */
- this.mSupportedSignatureAlgorithms.Add(new SignatureAndHashAlgorithm(HashAlgorithm.sha1,
- SignatureAlgorithm.dsa));
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);
@@ -263,6 +243,14 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
+ 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
index 83150d37e..e283ee58c 100644
--- a/crypto/src/crypto/tls/AbstractTlsContext.cs
+++ b/crypto/src/crypto/tls/AbstractTlsContext.cs
@@ -96,6 +96,15 @@ namespace Org.BouncyCastle.Crypto.Tls
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");
diff --git a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
index 155ac94d8..c9ec06107 100644
--- a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
+++ b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Tls
protected readonly int mKeyExchange;
protected IList mSupportedSignatureAlgorithms;
- protected TlsContext context;
+ protected TlsContext mContext;
protected AbstractTlsKeyExchange(int keyExchange, IList supportedSignatureAlgorithms)
{
@@ -20,7 +20,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public virtual void Init(TlsContext context)
{
- this.context = context;
+ this.mContext = context;
ProtocolVersion clientVersion = context.ClientVersion;
diff --git a/crypto/src/crypto/tls/AbstractTlsServer.cs b/crypto/src/crypto/tls/AbstractTlsServer.cs
index b0a5f0d52..c3e250fd8 100644
--- a/crypto/src/crypto/tls/AbstractTlsServer.cs
+++ b/crypto/src/crypto/tls/AbstractTlsServer.cs
@@ -140,7 +140,11 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
@@ -320,6 +324,14 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
+ public override TlsCipher GetCipher()
+ {
+ int encryptionAlgorithm = TlsUtilities.GetEncryptionAlgorithm(mSelectedCipherSuite);
+ int macAlgorithm = TlsUtilities.GetMacAlgorithm(mSelectedCipherSuite);
+
+ return mCipherFactory.CreateCipher(mContext, encryptionAlgorithm, macAlgorithm);
+ }
+
public virtual NewSessionTicket GetNewSessionTicket()
{
/*
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/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs
index ec98413b7..ff7e6da85 100644
--- a/crypto/src/crypto/tls/DefaultTlsClient.cs
+++ b/crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -28,9 +28,18 @@ namespace Org.BouncyCastle.Crypto.Tls
{
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_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,
@@ -39,395 +48,28 @@ namespace Org.BouncyCastle.Crypto.Tls
public override TlsKeyExchange GetKeyExchange()
{
- switch (mSelectedCipherSuite)
- {
- 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 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_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 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_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 CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
-
- 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 CreateDheKeyExchange(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 CreateECDHKeyExchange(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 CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_RSA);
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
- 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 CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_ECDSA);
-
- 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 CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA);
-
- 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 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);
- }
- }
-
- public override TlsCipher GetCipher()
- {
- switch (mSelectedCipherSuite)
+ switch (keyExchangeAlgorithm)
{
- 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_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AEAD_CHACHA20_POLY1305, MacAlgorithm.cls_null);
-
- 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_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_RSA_WITH_AES_128_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1);
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DH_RSA:
+ return CreateDHKeyExchange(keyExchangeAlgorithm);
- 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_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_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha256);
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ return CreateDheKeyExchange(keyExchangeAlgorithm);
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
- case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM, MacAlgorithm.cls_null);
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ return CreateECDHKeyExchange(keyExchangeAlgorithm);
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM_8, MacAlgorithm.cls_null);
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return CreateECDheKeyExchange(keyExchangeAlgorithm);
- 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_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_RSA_WITH_AES_128_GCM_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_GCM, MacAlgorithm.cls_null);
-
- 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_ECDH_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha256);
-
- 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_RSA_WITH_AES_256_CBC_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha384);
-
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
- case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
- case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM_8, MacAlgorithm.cls_null);
-
- 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_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_RSA_WITH_AES_256_GCM_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_GCM, MacAlgorithm.cls_null);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha1);
-
- 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_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_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha256);
-
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_DHE_RSA_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_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_GCM, MacAlgorithm.cls_null);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha256);
-
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_RSA_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_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_GCM, MacAlgorithm.cls_null);
-
- 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_RSA_WITH_CAMELLIA_256_CBC_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha384);
-
- case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.ESTREAM_SALSA20, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_RSA_WITH_NULL_MD5:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_md5);
-
- 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_RSA_WITH_NULL_SHA:
- case CipherSuite.TLS_RSA_WITH_NULL_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha256);
-
- case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_md5);
-
- 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_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SALSA20, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SEED_CBC, MacAlgorithm.hmac_sha1);
+ case KeyExchangeAlgorithm.RSA:
+ return CreateRsaKeyExchange();
default:
/*
diff --git a/crypto/src/crypto/tls/DefaultTlsServer.cs b/crypto/src/crypto/tls/DefaultTlsServer.cs
index 75f6d8d88..b12c43e1c 100644
--- a/crypto/src/crypto/tls/DefaultTlsServer.cs
+++ b/crypto/src/crypto/tls/DefaultTlsServer.cs
@@ -20,6 +20,16 @@ namespace Org.BouncyCastle.Crypto.Tls
{
}
+ 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);
@@ -45,6 +55,12 @@ namespace Org.BouncyCastle.Crypto.Tls
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,
@@ -56,472 +72,62 @@ namespace Org.BouncyCastle.Crypto.Tls
public override TlsCredentials GetCredentials()
{
- switch (mSelectedCipherSuite)
- {
- 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_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_SEED_CBC_SHA:
- return GetRsaEncryptionCredentials();
-
- 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_SEED_CBC_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_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 GetRsaSignerCredentials();
-
- default:
- /*
- * Note: internal error here; selected a key exchange we don't implement!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- }
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
- public override TlsKeyExchange GetKeyExchange()
- {
- switch (mSelectedCipherSuite)
+ switch (keyExchangeAlgorithm)
{
- 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 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_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 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_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 CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DHE_DSS:
+ return GetDsaSignerCredentials();
- 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 CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA);
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ return GetECDsaSignerCredentials();
- 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 CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_ECDSA);
+ case KeyExchangeAlgorithm.DHE_RSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return GetRsaSignerCredentials();
- 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 CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_RSA);
+ case KeyExchangeAlgorithm.RSA:
+ return GetRsaEncryptionCredentials();
- 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 CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_ECDSA);
-
- 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 CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA);
-
- 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 createRSAKeyExchange();
-
- default:
- /*
- * Note: internal error here; selected a key exchange we don't implement!
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ default:
+ /* Note: internal error here; selected a key exchange we don't implement! */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
- public override TlsCipher GetCipher()
+ public override TlsKeyExchange GetKeyExchange()
{
- switch (mSelectedCipherSuite)
- {
- 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_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AEAD_CHACHA20_POLY1305, MacAlgorithm.cls_null);
-
- 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_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_RSA_WITH_AES_128_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1);
-
- 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_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_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha256);
-
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
- case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM_8, MacAlgorithm.cls_null);
-
- 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_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_RSA_WITH_AES_128_GCM_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_GCM, MacAlgorithm.cls_null);
-
- 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_ECDH_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha256);
-
- 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_RSA_WITH_AES_256_CBC_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha384);
-
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
- case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
- case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM_8, MacAlgorithm.cls_null);
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
- 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_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_RSA_WITH_AES_256_GCM_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_GCM, MacAlgorithm.cls_null);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha1);
-
- 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_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_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha256);
-
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_DHE_RSA_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_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_GCM, MacAlgorithm.cls_null);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha256);
-
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_RSA_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_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_GCM, MacAlgorithm.cls_null);
-
- 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_RSA_WITH_CAMELLIA_256_CBC_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha384);
-
- case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.ESTREAM_SALSA20, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_RSA_WITH_NULL_MD5:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_md5);
-
- 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_RSA_WITH_NULL_SHA:
- case CipherSuite.TLS_RSA_WITH_NULL_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha256);
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DH_RSA:
+ return CreateDHKeyExchange(keyExchangeAlgorithm);
- case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_md5);
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ return CreateDheKeyExchange(keyExchangeAlgorithm);
- 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_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_sha1);
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ return CreateECDHKeyExchange(keyExchangeAlgorithm);
- case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SALSA20, MacAlgorithm.hmac_sha1);
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return CreateECDheKeyExchange(keyExchangeAlgorithm);
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SEED_CBC, MacAlgorithm.hmac_sha1);
+ case KeyExchangeAlgorithm.RSA:
+ return CreateRsaKeyExchange();
default:
/*
- * Note: internal error here; selected a cipher suite we don't implement!
- */
+ * 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);
}
}
@@ -548,7 +154,7 @@ namespace Org.BouncyCastle.Crypto.Tls
mServerECPointFormats);
}
- protected virtual TlsKeyExchange createRSAKeyExchange()
+ protected virtual TlsKeyExchange CreateRsaKeyExchange()
{
return new TlsRsaKeyExchange(mSupportedSignatureAlgorithms);
}
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/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs
index 67c49f890..411e7cca2 100644
--- a/crypto/src/crypto/tls/DtlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Crypto.Tls
DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.clientContext, client, ContentType.handshake);
TlsSession sessionToResume = state.client.GetSessionToResume();
- if (sessionToResume != null)
+ if (sessionToResume != null && sessionToResume.IsResumable)
{
SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
if (sessionParameters != null)
@@ -112,39 +112,12 @@ namespace Org.BouncyCastle.Crypto.Tls
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
- if (state.maxFragmentLength >= 0)
- {
- int plainTextLimit = 1 << (8 + state.maxFragmentLength);
- recordLayer.SetPlaintextLimit(plainTextLimit);
- }
-
- securityParameters.cipherSuite = state.selectedCipherSuite;
- securityParameters.compressionAlgorithm = (byte)state.selectedCompressionMethod;
- securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext, state.selectedCipherSuite);
-
- /*
- * 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;
-
handshake.NotifyHelloComplete();
- bool resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null
- && Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);
+ ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
- if (resumedSession)
+ if (state.resumedSession)
{
- if (securityParameters.CipherSuite != state.sessionParameters.CipherSuite
- || securityParameters.CompressionAlgorithm != state.sessionParameters.CompressionAlgorithm)
- {
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
-
- IDictionary sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
-
- securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
-
securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret);
recordLayer.InitPendingEpoch(state.client.GetCipher());
@@ -317,23 +290,17 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
*/
- SignatureAndHashAlgorithm signatureAndHashAlgorithm;
- byte[] hash;
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ state.clientContext, signerCredentials);
- if (TlsUtilities.IsTlsV12(state.clientContext))
+ byte[] hash;
+ if (signatureAndHashAlgorithm == null)
{
- signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm;
- if (signatureAndHashAlgorithm == null)
- {
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
-
- hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
+ hash = securityParameters.SessionHash;
}
else
{
- signatureAndHashAlgorithm = null;
- hash = securityParameters.SessionHash;
+ hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
}
byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
@@ -370,10 +337,14 @@ namespace Org.BouncyCastle.Crypto.Tls
if (state.tlsSession != null)
{
state.sessionParameters = new SessionParameters.Builder()
- .SetCipherSuite(securityParameters.cipherSuite)
- .SetCompressionAlgorithm(securityParameters.compressionAlgorithm)
- .SetMasterSecret(securityParameters.masterSecret)
+ .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);
@@ -434,8 +405,6 @@ namespace Org.BouncyCastle.Crypto.Tls
// Integer -> byte[]
state.clientExtensions = client.GetClientExtensions();
- securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions);
-
// Cipher Suites (and SCSV)
{
/*
@@ -603,8 +572,10 @@ namespace Org.BouncyCastle.Crypto.Tls
MemoryStream buf = new MemoryStream(body, false);
- ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
- ReportServerVersion(state, server_version);
+ {
+ ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+ ReportServerVersion(state, server_version);
+ }
securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
@@ -612,24 +583,24 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
- state.selectedCipherSuite = TlsUtilities.ReadUint16(buf);
- if (!Arrays.Contains(state.offeredCipherSuites, state.selectedCipherSuite)
- || state.selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
- || CipherSuite.IsScsv(state.selectedCipherSuite)
- || !TlsUtilities.IsValidCipherSuiteForVersion(state.selectedCipherSuite, server_version))
+ 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);
- ValidateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.illegal_parameter);
-
- state.client.NotifySelectedCipherSuite(state.selectedCipherSuite);
-
- state.selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
- if (!Arrays.Contains(state.offeredCompressionMethods, (byte)state.selectedCompressionMethod))
+ byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
+ if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- state.client.NotifySelectedCompressionMethod((byte)state.selectedCompressionMethod);
+ state.client.NotifySelectedCompressionMethod(selectedCompressionMethod);
/*
* RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
@@ -647,25 +618,16 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
// Integer -> byte[]
- IDictionary serverExtensions = TlsProtocol.ReadExtensions(buf);
-
- /*
- * draft-ietf-tls-session-hash-01 5.2. If a server receives the "extended_master_secret"
- * extension, it MUST include the "extended_master_secret" extension in its ServerHello
- * message.
- */
- bool serverSentExtendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(serverExtensions);
- if (serverSentExtendedMasterSecret != securityParameters.extendedMasterSecret)
- throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ 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 (serverExtensions != null)
+ if (state.serverExtensions != null)
{
- foreach (int extType in serverExtensions.Keys)
+ foreach (int extType in state.serverExtensions.Keys)
{
/*
* RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
@@ -688,83 +650,118 @@ namespace Org.BouncyCastle.Crypto.Tls
throw new TlsFatalAlert(AlertDescription.unsupported_extension);
/*
- * draft-ietf-tls-session-hash-01 5.2. Implementation note: if the server decides to
- * proceed with resumption, the extension does not have any effect. Requiring the
- * extension to be included anyway makes the extension negotiation logic easier,
- * because it does not depend on whether resumption is accepted or not.
- */
- if (extType == ExtensionType.extended_master_secret)
- continue;
-
- /*
* 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[.]
*/
- // TODO[sessions]
- // 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);
- // }
+ 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
+ */
+ {
/*
- * 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)
{
/*
- * When a ServerHello is received, the client MUST check if it includes the
- * "renegotiation_info" extension:
- */
- byte[] renegExtData = (byte[])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);
- }
+ * 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);
}
+ }
- /*
- * 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(serverExtensions);
- if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(state.selectedCipherSuite))
+ // 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);
+ }
- securityParameters.encryptThenMac = serverSentEncryptThenMAC;
+ sessionClientExtensions = null;
+ sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
+ }
- state.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.clientExtensions, serverExtensions,
- AlertDescription.illegal_parameter);
+ securityParameters.cipherSuite = selectedCipherSuite;
+ securityParameters.compressionAlgorithm = selectedCompressionMethod;
- securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(serverExtensions);
+ 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);
- state.allowCertificateStatus = TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions,
- ExtensionType.status_request, AlertDescription.illegal_parameter);
+ securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
+ sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
- state.expectSessionTicket = TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions,
- ExtensionType.session_ticket, 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);
}
- state.client.NotifySecureRenegotiation(state.secure_renegotiation);
+ /*
+ * 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 (state.clientExtensions != null)
+ if (sessionClientExtensions != null)
{
- state.client.ProcessServerExtensions(serverExtensions);
+ 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)
@@ -826,11 +823,10 @@ namespace Org.BouncyCastle.Crypto.Tls
internal int[] offeredCipherSuites = null;
internal byte[] offeredCompressionMethods = null;
internal IDictionary clientExtensions = null;
+ internal IDictionary serverExtensions = null;
internal byte[] selectedSessionID = null;
- internal int selectedCipherSuite = -1;
- internal short selectedCompressionMethod = -1;
+ internal bool resumedSession = false;
internal bool secure_renegotiation = false;
- internal short maxFragmentLength = -1;
internal bool allowCertificateStatus = false;
internal bool expectSessionTicket = false;
internal TlsKeyExchange keyExchange = null;
diff --git a/crypto/src/crypto/tls/DtlsProtocol.cs b/crypto/src/crypto/tls/DtlsProtocol.cs
index 6d62c5a90..e4ebd436c 100644
--- a/crypto/src/crypto/tls/DtlsProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsProtocol.cs
@@ -33,12 +33,32 @@ namespace Org.BouncyCastle.Crypto.Tls
}
/// <exception cref="IOException"/>
- protected static short EvaluateMaxFragmentLengthExtension(IDictionary clientExtensions, IDictionary serverExtensions,
- byte alertDescription)
+ 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 && maxFragmentLength != TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions))
- throw new TlsFatalAlert(alertDescription);
+ if (maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)maxFragmentLength)
+ || (!resumedSession && maxFragmentLength != TlsExtensionsUtilities
+ .GetMaxFragmentLengthExtension(clientExtensions)))
+ {
+ throw new TlsFatalAlert(alertDescription);
+ }
+ }
return maxFragmentLength;
}
diff --git a/crypto/src/crypto/tls/DtlsReliableHandshake.cs b/crypto/src/crypto/tls/DtlsReliableHandshake.cs
index bf9e61d03..8e4439e67 100644
--- a/crypto/src/crypto/tls/DtlsReliableHandshake.cs
+++ b/crypto/src/crypto/tls/DtlsReliableHandshake.cs
@@ -114,17 +114,17 @@ namespace Org.BouncyCastle.Crypto.Tls
{
for (; ; )
{
- int Received = mRecordLayer.Receive(buf, 0, receiveLimit, readTimeoutMillis);
- if (Received < 0)
+ int received = mRecordLayer.Receive(buf, 0, receiveLimit, readTimeoutMillis);
+ if (received < 0)
{
break;
}
- if (Received < 12)
+ if (received < 12)
{
continue;
}
int fragment_length = TlsUtilities.ReadUint24(buf, 9);
- if (Received != (fragment_length + 12))
+ if (received != (fragment_length + 12))
{
continue;
}
diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs
index 3335a9f36..9c7caf290 100644
--- a/crypto/src/crypto/tls/DtlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs
@@ -94,24 +94,9 @@ namespace Org.BouncyCastle.Crypto.Tls
{
byte[] serverHelloBody = GenerateServerHello(state);
-
- if (state.maxFragmentLength >= 0)
- {
- int plainTextLimit = 1 << (8 + state.maxFragmentLength);
- recordLayer.SetPlaintextLimit(plainTextLimit);
- }
-
- securityParameters.cipherSuite = state.selectedCipherSuite;
- securityParameters.compressionAlgorithm = (byte)state.selectedCompressionMethod;
- securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.serverContext,
- state.selectedCipherSuite);
- /*
- * 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;
-
+ ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
+
handshake.SendMessage(HandshakeType.server_hello, serverHelloBody);
}
@@ -302,17 +287,19 @@ namespace Org.BouncyCastle.Crypto.Tls
MemoryStream buf = new MemoryStream();
- ProtocolVersion server_version = state.server.GetServerVersion();
- if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ {
+ 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);
+ // 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);
+ TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);
+ }
buf.Write(securityParameters.ServerRandom, 0, securityParameters.ServerRandom.Length);
@@ -322,23 +309,24 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);
- state.selectedCipherSuite = state.server.GetSelectedCipherSuite();
- if (!Arrays.Contains(state.offeredCipherSuites, state.selectedCipherSuite)
- || state.selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
- || CipherSuite.IsScsv(state.selectedCipherSuite)
- || !TlsUtilities.IsValidCipherSuiteForVersion(state.selectedCipherSuite, server_version))
+ 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;
- ValidateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.internal_error);
-
- state.selectedCompressionMethod = state.server.GetSelectedCompressionMethod();
- if (!Arrays.Contains(state.offeredCompressionMethods, (byte)state.selectedCompressionMethod))
+ byte selectedCompressionMethod = state.server.GetSelectedCompressionMethod();
+ if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
throw new TlsFatalAlert(AlertDescription.internal_error);
+ securityParameters.compressionAlgorithm = selectedCompressionMethod;
- TlsUtilities.WriteUint16(state.selectedCipherSuite, buf);
- TlsUtilities.WriteUint8((byte)state.selectedCompressionMethod, buf);
+ TlsUtilities.WriteUint16(selectedCipherSuite, buf);
+ TlsUtilities.WriteUint8(selectedCompressionMethod, buf);
state.serverExtensions = state.server.GetServerExtensions();
@@ -375,24 +363,45 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
- state.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.clientExtensions, state.serverExtensions,
- AlertDescription.internal_error);
+ securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
+ state.clientExtensions, state.serverExtensions, AlertDescription.internal_error);
securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions);
- state.allowCertificateStatus = TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions,
- ExtensionType.status_request, AlertDescription.internal_error);
+ /*
+ * 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 = TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions,
- ExtensionType.session_ticket, 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();
}
@@ -538,6 +547,12 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
@@ -622,16 +637,14 @@ namespace Org.BouncyCastle.Crypto.Tls
{
internal TlsServer server = null;
internal TlsServerContextImpl serverContext = null;
- internal int[] offeredCipherSuites;
- internal byte[] offeredCompressionMethods;
- internal IDictionary clientExtensions;
- internal int selectedCipherSuite = -1;
- internal short selectedCompressionMethod = -1;
+ 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 short maxFragmentLength = -1;
internal bool allowCertificateStatus = false;
internal bool expectSessionTicket = false;
- internal IDictionary serverExtensions = null;
internal TlsKeyExchange keyExchange = null;
internal TlsCredentials serverCredentials = null;
internal CertificateRequest certificateRequest = null;
diff --git a/crypto/src/crypto/tls/ExporterLabel.cs b/crypto/src/crypto/tls/ExporterLabel.cs
index 280321e2a..5970769d7 100644
--- a/crypto/src/crypto/tls/ExporterLabel.cs
+++ b/crypto/src/crypto/tls/ExporterLabel.cs
@@ -30,7 +30,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public const string dtls_srtp = "EXTRACTOR-dtls_srtp";
/*
- * draft-ietf-tls-session-hash-01
+ * 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 acee380b6..b4b24f7c3 100644
--- a/crypto/src/crypto/tls/ExtensionType.cs
+++ b/crypto/src/crypto/tls/ExtensionType.cs
@@ -49,7 +49,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int encrypt_then_mac = 22;
/*
- * draft-ietf-tls-session-hash-01
+ * draft-ietf-tls-session-hash-04
*
* NOTE: Early code-point assignment
*/
diff --git a/crypto/src/crypto/tls/PskTlsClient.cs b/crypto/src/crypto/tls/PskTlsClient.cs
index 6063572a0..2ef80dcfd 100644
--- a/crypto/src/crypto/tls/PskTlsClient.cs
+++ b/crypto/src/crypto/tls/PskTlsClient.cs
@@ -3,7 +3,7 @@ using System.Collections;
namespace Org.BouncyCastle.Crypto.Tls
{
- public abstract class PskTlsClient
+ public class PskTlsClient
: AbstractTlsClient
{
protected TlsPskIdentity mPskIdentity;
@@ -25,94 +25,22 @@ namespace Org.BouncyCastle.Crypto.Tls
{
CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
- CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
- CipherSuite.TLS_RSA_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 TlsKeyExchange GetKeyExchange()
{
- switch (mSelectedCipherSuite)
- {
- 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 CreatePskKeyExchange(KeyExchangeAlgorithm.DHE_PSK);
-
- 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 CreatePskKeyExchange(KeyExchangeAlgorithm.ECDHE_PSK);
-
- 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 CreatePskKeyExchange(KeyExchangeAlgorithm.PSK);
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
- 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 CreatePskKeyExchange(KeyExchangeAlgorithm.RSA_PSK);
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ return CreatePskKeyExchange(keyExchangeAlgorithm);
default:
/*
@@ -124,137 +52,18 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
- public override TlsCipher GetCipher()
+ public override TlsAuthentication GetAuthentication()
{
- switch (mSelectedCipherSuite)
- {
- case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha256);
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
- case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM_8, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_GCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha384);
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
- case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
- case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM_8, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_GCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha256);
-
- case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_GCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha384);
-
- case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_GCM, MacAlgorithm.cls_null);
-
- case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.ESTREAM_SALSA20, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
- case CipherSuite.TLS_PSK_WITH_NULL_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha1);
-
- 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:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha256);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha384);
-
- case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_sha1);
-
- case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
- return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SALSA20, MacAlgorithm.hmac_sha1);
-
- 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);
- }
+ /*
+ * 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(keyExchange, mSupportedSignatureAlgorithms, mPskIdentity, null, mNamedCurves,
+ 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..27d2b8119
--- /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_1024_160;
+ }
+
+ 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/SecurityParameters.cs b/crypto/src/crypto/tls/SecurityParameters.cs
index 12bb59f22..3b851587d 100644
--- a/crypto/src/crypto/tls/SecurityParameters.cs
+++ b/crypto/src/crypto/tls/SecurityParameters.cs
@@ -15,6 +15,8 @@ namespace Org.BouncyCastle.Crypto.Tls
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;
@@ -87,5 +89,15 @@ namespace Org.BouncyCastle.Crypto.Tls
{
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
index 381858854..b09262771 100644
--- a/crypto/src/crypto/tls/ServerDHParams.cs
+++ b/crypto/src/crypto/tls/ServerDHParams.cs
@@ -54,7 +54,8 @@ namespace Org.BouncyCastle.Crypto.Tls
BigInteger g = TlsDHUtilities.ReadDHParameter(input);
BigInteger Ys = TlsDHUtilities.ReadDHParameter(input);
- return new ServerDHParams(new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
+ return new ServerDHParams(
+ TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Ys, new DHParameters(p, g))));
}
}
}
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
index c4616ac71..a1eb5f27c 100644
--- a/crypto/src/crypto/tls/SessionParameters.cs
+++ b/crypto/src/crypto/tls/SessionParameters.cs
@@ -14,6 +14,8 @@ namespace Org.BouncyCastle.Crypto.Tls
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()
@@ -26,7 +28,7 @@ namespace Org.BouncyCastle.Crypto.Tls
Validate(this.mCompressionAlgorithm >= 0, "compressionAlgorithm");
Validate(this.mMasterSecret != null, "masterSecret");
return new SessionParameters(mCipherSuite, (byte)mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
- mEncodedServerExtensions);
+ mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
}
public Builder SetCipherSuite(int cipherSuite)
@@ -53,6 +55,18 @@ namespace Org.BouncyCastle.Crypto.Tls
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)
@@ -79,15 +93,19 @@ namespace Org.BouncyCastle.Crypto.Tls
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[] encodedServerExtensions)
+ 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;
}
@@ -102,7 +120,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public SessionParameters Copy()
{
return new SessionParameters(mCipherSuite, mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
- mEncodedServerExtensions);
+ mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
}
public int CipherSuite
@@ -125,6 +143,16 @@ namespace Org.BouncyCastle.Crypto.Tls
get { return mPeerCertificate; }
}
+ public byte[] PskIdentity
+ {
+ get { return mPskIdentity; }
+ }
+
+ public byte[] SrpIdentity
+ {
+ get { return mSrpIdentity; }
+ }
+
public IDictionary ReadServerExtensions()
{
if (mEncodedServerExtensions == null)
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 5d82ed470..df1607751 100644
--- a/crypto/src/crypto/tls/SrpTlsClient.cs
+++ b/crypto/src/crypto/tls/SrpTlsClient.cs
@@ -6,20 +6,29 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Tls
{
- public abstract class SrpTlsClient
+ public class SrpTlsClient
: AbstractTlsClient
{
+ protected TlsSrpGroupVerifier mGroupVerifier;
+
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)
+ {
+ }
+
+ public SrpTlsClient(TlsCipherFactory cipherFactory, TlsSrpGroupVerifier groupVerifier,
+ byte[] identity, byte[] password)
: base(cipherFactory)
{
+ this.mGroupVerifier = groupVerifier;
this.mIdentity = Arrays.Clone(identity);
this.mPassword = Arrays.Clone(password);
}
@@ -59,22 +68,14 @@ namespace Org.BouncyCastle.Crypto.Tls
public override TlsKeyExchange GetKeyExchange()
{
- switch (mSelectedCipherSuite)
- {
- 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);
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
- 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);
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ case KeyExchangeAlgorithm.SRP_DSS:
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return CreateSrpKeyExchange(keyExchangeAlgorithm);
default:
/*
@@ -86,38 +87,18 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
- public override TlsCipher GetCipher()
+ public override TlsAuthentication GetAuthentication()
{
- switch (mSelectedCipherSuite)
- {
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1);
-
- 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1);
-
- 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);
- }
+ /*
+ * 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(keyExchange, mSupportedSignatureAlgorithms, mIdentity, mPassword);
+ 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/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs
index 19e7d71aa..7b8439acc 100644
--- a/crypto/src/crypto/tls/TlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -58,7 +58,7 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mRecordStream.Init(mTlsClientContext);
TlsSession sessionToResume = tlsClient.GetSessionToResume();
- if (sessionToResume != null)
+ if (sessionToResume != null && sessionToResume.IsResumable)
{
SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
if (sessionParameters != null)
@@ -224,24 +224,10 @@ namespace Org.BouncyCastle.Crypto.Tls
ReceiveServerHelloMessage(buf);
this.mConnectionState = CS_SERVER_HELLO;
- if (this.mSecurityParameters.maxFragmentLength >= 0)
- {
- int plainTextLimit = 1 << (8 + this.mSecurityParameters.maxFragmentLength);
- mRecordStream.SetPlaintextLimit(plainTextLimit);
- }
-
- 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;
-
this.mRecordStream.NotifyHelloComplete();
+ ApplyMaxFragmentLengthExtension();
+
if (this.mResumedSession)
{
this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
@@ -373,21 +359,17 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
*/
- SignatureAndHashAlgorithm signatureAndHashAlgorithm;
- byte[] hash;
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ Context, signerCredentials);
- if (TlsUtilities.IsTlsV12(Context))
+ byte[] hash;
+ if (signatureAndHashAlgorithm == null)
{
- signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm;
- if (signatureAndHashAlgorithm == null)
- throw new TlsFatalAlert(AlertDescription.internal_error);
-
- hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
+ hash = mSecurityParameters.SessionHash;
}
else
{
- signatureAndHashAlgorithm = null;
- hash = mSecurityParameters.SessionHash;
+ hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
}
byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
@@ -529,15 +511,7 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
if (this.mConnectionState == CS_END)
{
- /*
- * 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);
-
- string message = "Renegotiation not supported";
- RaiseWarning(AlertDescription.no_renegotiation, message);
+ RefuseRenegotiation();
}
break;
}
@@ -570,21 +544,23 @@ namespace Org.BouncyCastle.Crypto.Tls
protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
{
- ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
- if (server_version.IsDtls)
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ {
+ 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);
+ // 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);
+ 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);
+ this.mRecordStream.SetWriteVersion(server_version);
+ ContextAdmin.SetServerVersion(server_version);
+ this.mTlsClient.NotifyServerVersion(server_version);
+ }
/*
* Read the server random
@@ -594,9 +570,7 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
@@ -608,11 +582,10 @@ namespace Org.BouncyCastle.Crypto.Tls
if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite)
|| selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
|| CipherSuite.IsScsv(selectedCipherSuite)
- || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, server_version))
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
{
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
-
this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
/*
@@ -622,7 +595,6 @@ namespace Org.BouncyCastle.Crypto.Tls
byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-
this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
/*
@@ -636,15 +608,6 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mServerExtensions = ReadExtensions(buf);
/*
- * draft-ietf-tls-session-hash-01 5.2. If a server receives the "extended_master_secret"
- * extension, it MUST include the "extended_master_secret" extension in its ServerHello
- * message.
- */
- bool serverSentExtendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mServerExtensions);
- if (serverSentExtendedMasterSecret != mSecurityParameters.extendedMasterSecret)
- throw new TlsFatalAlert(AlertDescription.handshake_failure);
-
- /*
* RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
* extended client hello message.
*
@@ -676,15 +639,6 @@ namespace Org.BouncyCastle.Crypto.Tls
throw new TlsFatalAlert(AlertDescription.unsupported_extension);
/*
- * draft-ietf-tls-session-hash-01 5.2. Implementation note: if the server decides to
- * proceed with resumption, the extension does not have any effect. Requiring the
- * extension to be included anyway makes the extension negotiation logic easier,
- * because it does not depend on whether resumption is accepted or not.
- */
- if (extType == ExtensionType.extended_master_secret)
- continue;
-
- /*
* 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[.]
@@ -737,8 +691,6 @@ namespace Org.BouncyCastle.Crypto.Tls
sessionClientExtensions = null;
sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
-
- this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
}
this.mSecurityParameters.cipherSuite = selectedCipherSuite;
@@ -746,17 +698,21 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
+ {
+ /*
+ * 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.encryptThenMac = serverSentEncryptThenMAC;
+ }
+
+ this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
sessionServerExtensions, AlertDescription.illegal_parameter);
@@ -776,10 +732,26 @@ namespace Org.BouncyCastle.Crypto.Tls
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)
@@ -832,8 +804,6 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mClientExtensions = this.mTlsClient.GetClientExtensions();
- this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mClientExtensions);
-
HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
TlsUtilities.WriteVersion(client_version, message);
diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
index b831249a6..211249fcc 100644
--- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -4,6 +4,7 @@ using System.IO;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Tls
@@ -16,12 +17,10 @@ namespace Org.BouncyCastle.Crypto.Tls
protected DHParameters mDHParameters;
protected AsymmetricKeyParameter mServerPublicKey;
- protected DHPublicKeyParameters mDHAgreeServerPublicKey;
protected TlsAgreementCredentials mAgreementCredentials;
- protected DHPrivateKeyParameters mDHAgreeClientPrivateKey;
- protected DHPrivateKeyParameters mDHAgreeServerPrivateKey;
- protected DHPublicKeyParameters mDHAgreeClientPublicKey;
+ protected DHPrivateKeyParameters mDHAgreePrivateKey;
+ protected DHPublicKeyParameters mDHAgreePublicKey;
public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
: base(keyExchange, supportedSignatureAlgorithms)
@@ -81,7 +80,7 @@ namespace Org.BouncyCastle.Crypto.Tls
{
try
{
- this.mDHAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey((DHPublicKeyParameters)this.mServerPublicKey);
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey((DHPublicKeyParameters)this.mServerPublicKey);
}
catch (InvalidCastException e)
{
@@ -165,26 +164,40 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
if (mAgreementCredentials == null)
{
- this.mDHAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom,
- mDHAgreeServerPublicKey.Parameters, output);
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mDHParameters, output);
}
}
- public override byte[] GeneratePremasterSecret()
+ public override void ProcessClientCertificate(Certificate clientCertificate)
{
- if (mAgreementCredentials != null)
+ // TODO Extract the public key
+ // TODO If the certificate is 'fixed', take the public key as dhAgreeClientPublicKey
+ }
+
+ public override void ProcessClientKeyExchange(Stream input)
+ {
+ if (mDHAgreePublicKey != null)
{
- return mAgreementCredentials.GenerateAgreement(mDHAgreeServerPublicKey);
+ // For dss_fixed_dh and rsa_fixed_dh, the key arrived in the client certificate
+ return;
}
- if (mDHAgreeServerPrivateKey != null)
+ BigInteger Yc = TlsDHUtilities.ReadDHParameter(input);
+
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters));
+ }
+
+ public override byte[] GeneratePremasterSecret()
+ {
+ if (mAgreementCredentials != null)
{
- return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreeClientPublicKey, mDHAgreeServerPrivateKey);
+ return mAgreementCredentials.GenerateAgreement(mDHAgreePublicKey);
}
- if (mDHAgreeClientPrivateKey != null)
+ if (mDHAgreePrivateKey != null)
{
- return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreeServerPublicKey, mDHAgreeClientPrivateKey);
+ return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey);
}
throw new TlsFatalAlert(AlertDescription.internal_error);
diff --git a/crypto/src/crypto/tls/TlsDheKeyExchange.cs b/crypto/src/crypto/tls/TlsDheKeyExchange.cs
index 3c05bb6f0..419d4e442 100644
--- a/crypto/src/crypto/tls/TlsDheKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDheKeyExchange.cs
@@ -36,30 +36,18 @@ namespace Org.BouncyCastle.Crypto.Tls
DigestInputBuffer buf = new DigestInputBuffer();
- this.mDHAgreeServerPrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom,
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
this.mDHParameters, buf);
/*
* RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
*/
- SignatureAndHashAlgorithm signatureAndHashAlgorithm;
- IDigest d;
-
- if (TlsUtilities.IsTlsV12(context))
- {
- signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm;
- if (signatureAndHashAlgorithm == null)
- throw new TlsFatalAlert(AlertDescription.internal_error);
-
- d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash);
- }
- else
- {
- signatureAndHashAlgorithm = null;
- d = new CombinedHash();
- }
-
- SecurityParameters securityParameters = context.SecurityParameters;
+ 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);
@@ -76,21 +64,22 @@ namespace Org.BouncyCastle.Crypto.Tls
public override void ProcessServerKeyExchange(Stream input)
{
- SecurityParameters securityParameters = context.SecurityParameters;
+ SecurityParameters securityParameters = mContext.SecurityParameters;
SignerInputBuffer buf = new SignerInputBuffer();
Stream teeIn = new TeeInputStream(input, buf);
ServerDHParams dhParams = ServerDHParams.Parse(teeIn);
- DigitallySigned signed_params = DigitallySigned.Parse(context, input);
+ 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.mDHAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey);
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey);
+ this.mDHParameters = mDHAgreePublicKey.Parameters;
}
protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
diff --git a/crypto/src/crypto/tls/TlsDsaSigner.cs b/crypto/src/crypto/tls/TlsDsaSigner.cs
index a5ac55974..f0c1e9451 100644
--- a/crypto/src/crypto/tls/TlsDsaSigner.cs
+++ b/crypto/src/crypto/tls/TlsDsaSigner.cs
@@ -64,8 +64,7 @@ namespace Org.BouncyCastle.Crypto.Tls
if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
throw new InvalidOperationException();
- // TODO For TLS 1.2+, lift the SHA-1 restriction here
- if (algorithm != null && (algorithm.Hash != HashAlgorithm.sha1 || algorithm.Signature != SignatureAlgorithm))
+ if (algorithm != null && algorithm.Signature != SignatureAlgorithm)
throw new InvalidOperationException();
byte hashAlgorithm = algorithm == null ? HashAlgorithm.sha1 : algorithm.Hash;
diff --git a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
index 42dc2f2ef..992be4aca 100644
--- a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
@@ -166,7 +166,7 @@ namespace Org.BouncyCastle.Crypto.Tls
{
if (mAgreementCredentials == null)
{
- this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom,
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
mServerECPointFormats, mECAgreePublicKey.Parameters, output);
}
}
diff --git a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
index 0644bd44d..b681aada3 100644
--- a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
@@ -34,95 +34,20 @@ namespace Org.BouncyCastle.Crypto.Tls
public override byte[] GenerateServerKeyExchange()
{
- /*
- * First we try to find a supported named curve from the client's list.
- */
- int namedCurve = -1;
- if (mNamedCurves == null)
- {
- // TODO Let the peer choose the default named curve
- namedCurve = NamedCurve.secp256r1;
- }
- else
- {
- for (int i = 0; i < mNamedCurves.Length; ++i)
- {
- int entry = mNamedCurves[i];
- if (NamedCurve.IsValid(entry) && TlsEccUtilities.IsSupportedNamedCurve(entry))
- {
- namedCurve = entry;
- break;
- }
- }
- }
-
- ECDomainParameters curve_params = null;
- if (namedCurve >= 0)
- {
- curve_params = TlsEccUtilities.GetParametersForNamedCurve(namedCurve);
- }
- else
- {
- /*
- * If no named curves are suitable, check if the client supports explicit curves.
- */
- if (Arrays.Contains(mNamedCurves, NamedCurve.arbitrary_explicit_prime_curves))
- {
- curve_params = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.secp256r1);
- }
- else if (Arrays.Contains(mNamedCurves, NamedCurve.arbitrary_explicit_char2_curves))
- {
- curve_params = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.sect283r1);
- }
- }
-
- if (curve_params == 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);
- }
-
- AsymmetricCipherKeyPair kp = TlsEccUtilities.GenerateECKeyPair(context.SecureRandom, curve_params);
- this.mECAgreePrivateKey = (ECPrivateKeyParameters)kp.Private;
-
DigestInputBuffer buf = new DigestInputBuffer();
- if (namedCurve < 0)
- {
- TlsEccUtilities.WriteExplicitECParameters(mClientECPointFormats, curve_params, buf);
- }
- else
- {
- TlsEccUtilities.WriteNamedECParameters(namedCurve, buf);
- }
-
- ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
- TlsEccUtilities.WriteECPoint(mClientECPointFormats, ecPublicKey.Q, buf);
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves,
+ mClientECPointFormats, buf);
/*
* RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
*/
- SignatureAndHashAlgorithm signatureAndHashAlgorithm;
- IDigest d;
-
- if (TlsUtilities.IsTlsV12(context))
- {
- signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm;
- if (signatureAndHashAlgorithm == null)
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ mContext, mServerCredentials);
- d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash);
- }
- else
- {
- signatureAndHashAlgorithm = null;
- d = new CombinedHash();
- }
+ IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm);
- SecurityParameters securityParameters = context.SecurityParameters;
+ SecurityParameters securityParameters = mContext.SecurityParameters;
d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
buf.UpdateDigest(d);
@@ -139,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public override void ProcessServerKeyExchange(Stream input)
{
- SecurityParameters securityParameters = context.SecurityParameters;
+ SecurityParameters securityParameters = mContext.SecurityParameters;
SignerInputBuffer buf = new SignerInputBuffer();
Stream teeIn = new TeeInputStream(input, buf);
@@ -148,7 +73,7 @@ namespace Org.BouncyCastle.Crypto.Tls
byte[] point = TlsUtilities.ReadOpaque8(teeIn);
- DigitallySigned signed_params = DigitallySigned.Parse(context, input);
+ DigitallySigned signed_params = DigitallySigned.Parse(mContext, input);
ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
buf.UpdateSigner(signer);
diff --git a/crypto/src/crypto/tls/TlsEccUtilities.cs b/crypto/src/crypto/tls/TlsEccUtilities.cs
index 34f0f57ba..d0d794d0e 100644
--- a/crypto/src/crypto/tls/TlsEccUtilities.cs
+++ b/crypto/src/crypto/tls/TlsEccUtilities.cs
@@ -427,7 +427,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public static ECPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random, byte[] ecPointFormats,
ECDomainParameters ecParams, Stream output)
{
- AsymmetricCipherKeyPair kp = TlsEccUtilities.GenerateECKeyPair(random, ecParams);
+ AsymmetricCipherKeyPair kp = GenerateECKeyPair(random, ecParams);
ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
WriteECPoint(ecPointFormats, ecPublicKey.Q, output);
@@ -435,6 +435,69 @@ namespace Org.BouncyCastle.Crypto.Tls
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
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index 09838a717..8eb7beb3f 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -99,6 +99,24 @@ namespace Org.BouncyCastle.Crypto.Tls
{
}
+ 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)
@@ -158,10 +176,12 @@ namespace Org.BouncyCastle.Crypto.Tls
if (this.mSessionParameters == null)
{
this.mSessionParameters = new SessionParameters.Builder()
- .SetCipherSuite(this.mSecurityParameters.cipherSuite)
- .SetCompressionAlgorithm(this.mSecurityParameters.compressionAlgorithm)
- .SetMasterSecret(this.mSecurityParameters.masterSecret)
+ .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();
@@ -259,6 +279,8 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
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.
@@ -270,15 +292,20 @@ namespace Org.BouncyCastle.Crypto.Tls
break;
case HandshakeType.finished:
default:
- if (type == HandshakeType.finished && this.mExpectedVerifyData == null)
+ {
+ TlsContext ctx = Context;
+ if (type == HandshakeType.finished
+ && this.mExpectedVerifyData == null
+ && ctx.SecurityParameters.MasterSecret != null)
{
- this.mExpectedVerifyData = CreateVerifyData(!Context.IsServer);
+ this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
}
mRecordStream.UpdateHandshakeData(beginning, 0, 4);
mRecordStream.UpdateHandshakeData(buf, 0, len);
break;
}
+ }
/*
* Now, parse the message.
@@ -612,6 +639,9 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
@@ -743,14 +773,30 @@ namespace Org.BouncyCastle.Crypto.Tls
byte alertDescription)
{
short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
- if (maxFragmentLength >= 0 && !this.mResumedSession)
+ if (maxFragmentLength >= 0)
{
- if (maxFragmentLength != TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions))
+ 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.
*
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 cd13e3438..0af7f7a69 100644
--- a/crypto/src/crypto/tls/TlsPskKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
@@ -4,7 +4,10 @@ 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
{
@@ -13,22 +16,29 @@ namespace Org.BouncyCastle.Crypto.Tls
: AbstractTlsKeyExchange
{
protected TlsPskIdentity mPskIdentity;
+ protected TlsPskIdentityManager mPskIdentityManager;
+
protected DHParameters mDHParameters;
protected int[] mNamedCurves;
protected byte[] mClientECPointFormats, mServerECPointFormats;
protected byte[] mPskIdentityHint = null;
+ protected byte[] mPsk = null;
protected DHPrivateKeyParameters mDHAgreePrivateKey = null;
protected DHPublicKeyParameters mDHAgreePublicKey = null;
+ 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,
- DHParameters dhParameters, int[] namedCurves, byte[] clientECPointFormats, byte[] serverECPointFormats)
+ TlsPskIdentityManager pskIdentityManager, DHParameters dhParameters, int[] namedCurves,
+ byte[] clientECPointFormats, byte[] serverECPointFormats)
: base(keyExchange, supportedSignatureAlgorithms)
{
switch (keyExchange)
@@ -43,6 +53,7 @@ namespace Org.BouncyCastle.Crypto.Tls
}
this.mPskIdentity = pskIdentity;
+ this.mPskIdentityManager = pskIdentityManager;
this.mDHParameters = dhParameters;
this.mNamedCurves = namedCurves;
this.mClientECPointFormats = clientECPointFormats;
@@ -67,8 +78,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public override byte[] GenerateServerKeyExchange()
{
- // TODO[RFC 4279] Need a server-side PSK API to determine hint and resolve identities to keys
- this.mPskIdentityHint = null;
+ this.mPskIdentityHint = mPskIdentityManager.GetHint();
if (this.mPskIdentityHint == null && !RequiresServerKeyExchange)
return null;
@@ -89,12 +99,13 @@ namespace Org.BouncyCastle.Crypto.Tls
if (this.mDHParameters == null)
throw new TlsFatalAlert(AlertDescription.internal_error);
- this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom,
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
this.mDHParameters, buf);
}
else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
{
- // TODO[RFC 5489]
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+ mNamedCurves, mClientECPointFormats, buf);
}
return buf.ToArray();
@@ -154,10 +165,16 @@ namespace Org.BouncyCastle.Crypto.Tls
ServerDHParams serverDHParams = ServerDHParams.Parse(input);
this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(serverDHParams.PublicKey);
+ this.mDHParameters = mDHAgreePublicKey.Parameters;
}
else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
{
- // TODO[RFC 5489]
+ ECDomainParameters ecParams = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, input);
+
+ byte[] point = TlsUtilities.ReadOpaque8(input);
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mClientECPointFormats, ecParams, point));
}
}
@@ -183,34 +200,87 @@ namespace Org.BouncyCastle.Crypto.Tls
}
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);
+ mContext.SecurityParameters.pskIdentity = psk_identity;
+
if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
{
- this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom,
- mDHAgreePublicKey.Parameters, output);
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mDHParameters, output);
}
else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
{
- // TODO[RFC 5489]
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mServerECPointFormats, mECAgreePublicKey.Parameters, output);
}
else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
{
- this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(context,
+ 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)
+ {
+ byte[] point = TlsUtilities.ReadOpaque8(input);
+
+ ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mServerECPointFormats, curve_params, point));
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ 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 override byte[] GeneratePremasterSecret()
{
- byte[] psk = mPskIdentity.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();
}
@@ -228,7 +298,11 @@ namespace Org.BouncyCastle.Crypto.Tls
if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
{
- // TODO[RFC 5489]
+ if (mECAgreePrivateKey != null)
+ {
+ return TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey);
+ }
+
throw new TlsFatalAlert(AlertDescription.internal_error);
}
diff --git a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
index 3a0a49154..b02d56486 100644
--- a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
@@ -16,13 +16,13 @@ namespace Org.BouncyCastle.Crypto.Tls
public class TlsRsaKeyExchange
: AbstractTlsKeyExchange
{
- protected AsymmetricKeyParameter serverPublicKey = null;
+ protected AsymmetricKeyParameter mServerPublicKey = null;
- protected RsaKeyParameters rsaServerPublicKey = null;
+ protected RsaKeyParameters mRsaServerPublicKey = null;
- protected TlsEncryptionCredentials serverCredentials = null;
+ protected TlsEncryptionCredentials mServerCredentials = null;
- protected byte[] premasterSecret;
+ protected byte[] mPremasterSecret;
public TlsRsaKeyExchange(IList supportedSignatureAlgorithms)
: base(KeyExchangeAlgorithm.RSA, supportedSignatureAlgorithms)
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Crypto.Tls
ProcessServerCertificate(serverCredentials.Certificate);
- this.serverCredentials = (TlsEncryptionCredentials)serverCredentials;
+ this.mServerCredentials = (TlsEncryptionCredentials)serverCredentials;
}
public override void ProcessServerCertificate(Certificate serverCertificate)
@@ -54,7 +54,7 @@ namespace Org.BouncyCastle.Crypto.Tls
SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
try
{
- this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
}
catch (Exception e)
{
@@ -62,10 +62,10 @@ namespace Org.BouncyCastle.Crypto.Tls
}
// 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);
@@ -97,13 +97,13 @@ namespace Org.BouncyCastle.Crypto.Tls
public override void GenerateClientKeyExchange(Stream output)
{
- this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(context, rsaServerPublicKey, output);
+ this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(mContext, mRsaServerPublicKey, output);
}
public override void ProcessClientKeyExchange(Stream input)
{
byte[] encryptedPreMasterSecret;
- if (TlsUtilities.IsSsl(context))
+ if (TlsUtilities.IsSsl(mContext))
{
// TODO Do any SSLv3 clients actually include the length?
encryptedPreMasterSecret = Streams.ReadAll(input);
@@ -113,16 +113,16 @@ namespace Org.BouncyCastle.Crypto.Tls
encryptedPreMasterSecret = TlsUtilities.ReadOpaque16(input);
}
- this.premasterSecret = serverCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret);
+ this.mPremasterSecret = mServerCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret);
}
public override byte[] GeneratePremasterSecret()
{
- if (this.premasterSecret == null)
+ if (this.mPremasterSecret == null)
throw new TlsFatalAlert(AlertDescription.internal_error);
- byte[] tmp = this.premasterSecret;
- this.premasterSecret = null;
+ byte[] tmp = this.mPremasterSecret;
+ this.mPremasterSecret = null;
return tmp;
}
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
index b1fb830b6..b73cb5a30 100644
--- a/crypto/src/crypto/tls/TlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -106,6 +106,8 @@ namespace Org.BouncyCastle.Crypto.Tls
SendServerHelloMessage();
this.mConnectionState = CS_SERVER_HELLO;
+ mRecordStream.NotifyHelloComplete();
+
IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
if (serverSupplementalData != null)
{
@@ -179,6 +181,11 @@ namespace Org.BouncyCastle.Crypto.Tls
break;
}
+ case CS_END:
+ {
+ RefuseRenegotiation();
+ break;
+ }
default:
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
@@ -496,6 +503,12 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
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);
@@ -607,16 +620,18 @@ namespace Org.BouncyCastle.Crypto.Tls
{
HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);
- ProtocolVersion server_version = mTlsServer.GetServerVersion();
- if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ {
+ 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);
+ mRecordStream.ReadVersion = server_version;
+ mRecordStream.SetWriteVersion(server_version);
+ mRecordStream.SetRestrictReadVersion(true);
+ ContextAdmin.SetServerVersion(server_version);
- TlsUtilities.WriteVersion(server_version, message);
+ TlsUtilities.WriteVersion(server_version, message);
+ }
message.Write(this.mSecurityParameters.serverRandom);
@@ -630,7 +645,7 @@ namespace Org.BouncyCastle.Crypto.Tls
if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite)
|| selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
|| CipherSuite.IsScsv(selectedCipherSuite)
- || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, server_version))
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
@@ -711,12 +726,6 @@ namespace Org.BouncyCastle.Crypto.Tls
WriteExtensions(message, this.mServerExtensions);
}
- if (mSecurityParameters.maxFragmentLength >= 0)
- {
- int plainTextLimit = 1 << (8 + mSecurityParameters.maxFragmentLength);
- mRecordStream.SetPlaintextLimit(plainTextLimit);
- }
-
mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
/*
@@ -725,9 +734,9 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
mSecurityParameters.verifyDataLength = 12;
- message.WriteToRecordStream(this);
+ ApplyMaxFragmentLengthExtension();
- this.mRecordStream.NotifyHelloComplete();
+ message.WriteToRecordStream(this);
}
protected virtual void SendServerHelloDoneMessage()
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 f42f7456d..ce8e4834a 100644
--- a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
@@ -16,36 +16,64 @@ namespace Org.BouncyCastle.Crypto.Tls
public class TlsSrpKeyExchange
: AbstractTlsKeyExchange
{
+ protected static TlsSigner CreateSigner(int keyExchange)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ return null;
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return new TlsRsaSigner();
+ case KeyExchangeAlgorithm.SRP_DSS:
+ return new TlsDssSigner();
+ default:
+ throw new ArgumentException("unsupported key exchange algorithm");
+ }
+ }
+
protected TlsSigner mTlsSigner;
+ protected TlsSrpGroupVerifier mGroupVerifier;
protected byte[] mIdentity;
protected byte[] mPassword;
protected AsymmetricKeyParameter mServerPublicKey = null;
- protected byte[] mS = null;
- protected BigInteger mB = null;
- protected Srp6Client mSrpClient = new Srp6Client();
+ 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)
- : base(keyExchange, supportedSignatureAlgorithms)
+ : this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsSrpGroupVerifier(), identity, password)
{
- switch (keyExchange)
- {
- case KeyExchangeAlgorithm.SRP:
- this.mTlsSigner = null;
- break;
- case KeyExchangeAlgorithm.SRP_RSA:
- this.mTlsSigner = new TlsRsaSigner();
- break;
- case KeyExchangeAlgorithm.SRP_DSS:
- this.mTlsSigner = new TlsDssSigner();
- break;
- default:
- throw new InvalidOperationException("unsupported key exchange algorithm");
- }
+ }
+ 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();
+ }
+
+ 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 override void Init(TlsContext context)
@@ -91,14 +119,62 @@ namespace Org.BouncyCastle.Crypto.Tls
base.ProcessServerCertificate(serverCertificate);
}
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+ {
+ 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 override byte[] GenerateServerKeyExchange()
+ {
+ mSrpServer.Init(mSrpGroup, mSrpVerifier, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom);
+ BigInteger B = mSrpServer.GenerateServerCredentials();
+
+ ServerSrpParams srpParams = new ServerSrpParams(mSrpGroup.N, mSrpGroup.G, mSrpSalt, B);
+
+ DigestInputBuffer buf = new DigestInputBuffer();
+
+ srpParams.Encode(buf);
+
+ if (mServerCredentials != 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);
+ }
+
+ return buf.ToArray();
+ }
+
public override void ProcessServerKeyExchange(Stream input)
{
- SecurityParameters securityParameters = context.SecurityParameters;
+ SecurityParameters securityParameters = mContext.SecurityParameters;
SignerInputBuffer buf = null;
Stream teeIn = input;
@@ -109,14 +185,11 @@ namespace Org.BouncyCastle.Crypto.Tls
teeIn = new TeeInputStream(input, buf);
}
- byte[] NBytes = TlsUtilities.ReadOpaque16(teeIn);
- byte[] gBytes = TlsUtilities.ReadOpaque16(teeIn);
- byte[] sBytes = TlsUtilities.ReadOpaque8(teeIn);
- byte[] BBytes = TlsUtilities.ReadOpaque16(teeIn);
+ ServerSrpParams srpParams = ServerSrpParams.Parse(teeIn);
if (buf != null)
{
- DigitallySigned signed_params = DigitallySigned.Parse(context, input);
+ DigitallySigned signed_params = DigitallySigned.Parse(mContext, input);
ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
buf.UpdateSigner(signer);
@@ -124,13 +197,12 @@ namespace Org.BouncyCastle.Crypto.Tls
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.mS = sBytes;
+ this.mSrpSalt = srpParams.S;
/*
* RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter" alert if
@@ -138,14 +210,14 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
try
{
- this.mB = Srp6Utilities.ValidatePublicValue(N, new BigInteger(1, BBytes));
+ this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, srpParams.B);
}
catch (CryptoException e)
{
throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
}
- this.mSrpClient.Init(N, g, TlsUtilities.CreateHash(HashAlgorithm.sha1), context.SecureRandom);
+ this.mSrpClient.Init(mSrpGroup, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom);
}
public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
@@ -160,16 +232,40 @@ namespace Org.BouncyCastle.Crypto.Tls
public override void GenerateClientKeyExchange(Stream output)
{
- BigInteger A = mSrpClient.GenerateClientCredentials(mS, this.mIdentity, this.mPassword);
- TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(A), output);
+ BigInteger A = mSrpClient.GenerateClientCredentials(mSrpSalt, mIdentity, mPassword);
+ TlsSrpUtilities.WriteSrpParameter(A, output);
+
+ mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity);
+ }
+
+ public override void ProcessClientKeyExchange(Stream input)
+ {
+ /*
+ * 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 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(mSrpClient.CalculateSecret(mB));
+ return BigIntegers.AsUnsignedByteArray(S);
}
catch (CryptoException e)
{
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
index bbb6ac280..873189dc6 100644
--- a/crypto/src/crypto/tls/TlsSrpUtilities.cs
+++ b/crypto/src/crypto/tls/TlsSrpUtilities.cs
@@ -2,6 +2,9 @@
using System.Collections;
using System.IO;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
namespace Org.BouncyCastle.Crypto.Tls
{
public abstract class TlsSrpUtilities
@@ -37,5 +40,35 @@ namespace Org.BouncyCastle.Crypto.Tls
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/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 485ecb760..a8c8a2b28 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -21,6 +21,9 @@ namespace Org.BouncyCastle.Crypto.Tls
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)
{
@@ -589,6 +592,37 @@ namespace Org.BouncyCastle.Crypto.Tls
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)
{
@@ -941,6 +975,13 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
+ public static IDigest CreateHash(SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+ {
+ return signatureAndHashAlgorithm == null
+ ? new CombinedHash()
+ : CreateHash(signatureAndHashAlgorithm.Hash);
+ }
+
public static IDigest CloneHash(byte hashAlgorithm, IDigest hash)
{
switch (hashAlgorithm)
@@ -1490,6 +1531,528 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
+ 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)
diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs
index 3c911b173..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)
@@ -61,10 +70,9 @@ 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 ValidatePoint(P.Multiply(a).Add(Q.Multiply(b)));
}
@@ -117,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:
@@ -133,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)
{
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index eaa3e0c3d..9fe9e32fd 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -221,26 +221,56 @@ namespace Org.BouncyCastle.Math.EC
*/
public virtual void NormalizeAll(ECPoint[] points)
{
- CheckPoints(points);
+ NormalizeAll(points, 0, points.Length, null);
+ }
- if (this.CoordinateSystem == ECCurve.COORD_AFFINE)
+ /**
+ * 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);
+
+ 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;
}
}
@@ -249,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)
{
@@ -298,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");
}
@@ -586,6 +623,18 @@ namespace Org.BouncyCastle.Math.EC
public abstract class AbstractF2mCurve
: ECCurve
{
+ public static BigInteger Inverse(int m, int[] ks, BigInteger x)
+ {
+ return new LongArray(x).ModInverse(m, ks).ToBigInteger();
+ }
+
+ /**
+ * 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)
{
if (k1 == 0)
@@ -620,6 +669,69 @@ namespace Org.BouncyCastle.Math.EC
: 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);
+ }
+
+ /**
+ * @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);
+ }
+ }
}
/**
@@ -668,19 +780,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>.
@@ -880,37 +979,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);
@@ -926,60 +994,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 = null;
@@ -1049,7 +1063,7 @@ namespace Org.BouncyCastle.Math.EC
ECFieldElement t = FromBigInteger(new BigInteger(m, rand));
z = zeroElement;
ECFieldElement w = beta;
- for (int i = 1; i <= m - 1; i++)
+ for (int i = 1; i < m; i++)
{
ECFieldElement w2 = w.Square();
z = z.Square().Add(w2.Multiply(t));
diff --git a/crypto/src/math/ec/ECFieldElement.cs b/crypto/src/math/ec/ECFieldElement.cs
index e589fc737..844bed649 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);
@@ -812,6 +823,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 +835,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 3e206e65f..a5ba515c5 100644
--- a/crypto/src/math/ec/ECPoint.cs
+++ b/crypto/src/math/ec/ECPoint.cs
@@ -1383,6 +1383,139 @@ namespace Org.BouncyCastle.Math.EC
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");
+ }
+ }
+ }
}
/**
@@ -1491,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
@@ -1579,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)
@@ -1640,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);
@@ -1681,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();
@@ -1705,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];
@@ -1736,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;
@@ -1801,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 712b68f29..6ed7c0648 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519.cs
@@ -1,6 +1,6 @@
using System;
-using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Math.EC.Custom.Djb
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 bfec1d11d..eb8fc12f2 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519Point.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519Point.cs
@@ -1,6 +1,6 @@
using System;
-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/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/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 648aca502..58eb09102 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP192K1Point
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 797a8de35..3b53e341e 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP192R1Point
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 8cbd29699..98cb29274 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP224K1Point
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 c3f4efb59..73c4f1948 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP224R1Point
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 3165682fa..072a0b969 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP256K1Point
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 1de4a0b4a..83320824d 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP256R1Point
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 68c601611..83159ce61 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP384R1Point
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 fb1996cfd..7ad97f76f 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Math.Raw;
+
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal class SecP521R1Point
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..dbb645e6f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113Field.cs
@@ -0,0 +1,180 @@
+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 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..7e9d53e44
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
@@ -0,0 +1,213 @@
+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)
+ 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()
+ {
+ return new SecT113FieldElement(
+ AbstractF2mCurve.Inverse(113, new int[]{ 9 }, ToBigInteger()));
+ }
+
+ 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..04e69e2a8
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
@@ -0,0 +1,188 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(113, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 113; 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 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..a02db6b25
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
@@ -0,0 +1,190 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(113, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 113; 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 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..df75dfcd7
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131Field.cs
@@ -0,0 +1,274 @@
+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 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..d60c7ed7d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
@@ -0,0 +1,213 @@
+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)
+ 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()
+ {
+ return new SecT131FieldElement(
+ AbstractF2mCurve.Inverse(131, new int[] { 2, 3, 8 }, ToBigInteger()));
+ }
+
+ 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..789e3c0c3
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
@@ -0,0 +1,188 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(131, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 131; 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 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..2004f84ca
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
@@ -0,0 +1,190 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(131, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 131; 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 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..2a775e20d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163Field.cs
@@ -0,0 +1,272 @@
+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 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..0ef421c71
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
@@ -0,0 +1,213 @@
+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)
+ 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()
+ {
+ return new SecT163FieldElement(
+ AbstractF2mCurve.Inverse(163, new int[] { 3, 6, 7 }, ToBigInteger()));
+ }
+
+ 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..1cfd09e1c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
@@ -0,0 +1,194 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(163, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 163; 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 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..fc18e1094
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
@@ -0,0 +1,190 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(163, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 163; 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 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..9efe11c3e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
@@ -0,0 +1,188 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(163, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 163; 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 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/SecT233Field.cs b/crypto/src/math/ec/custom/sec/SecT233Field.cs
new file mode 100644
index 000000000..165fadbf3
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233Field.cs
@@ -0,0 +1,243 @@
+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 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..439c41d37
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
@@ -0,0 +1,213 @@
+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)
+ 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()
+ {
+ return new SecT233FieldElement(
+ AbstractF2mCurve.Inverse(233, new int[] { 74 }, ToBigInteger()));
+ }
+
+ 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..8768eaa81
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
@@ -0,0 +1,196 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(233, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 233; 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 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..92795b8a7
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
@@ -0,0 +1,188 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(233, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 233; 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 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..1e0824af9
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239Field.cs
@@ -0,0 +1,249 @@
+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 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..c89b484b1
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
@@ -0,0 +1,213 @@
+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)
+ 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()
+ {
+ return new SecT239FieldElement(
+ AbstractF2mCurve.Inverse(239, new int[] { 158 }, ToBigInteger()));
+ }
+
+ 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..2c73d941f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
@@ -0,0 +1,194 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(239, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 239; 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 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..9afb27461
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283Field.cs
@@ -0,0 +1,335 @@
+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 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..09243e859
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
@@ -0,0 +1,213 @@
+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)
+ 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()
+ {
+ return new SecT283FieldElement(
+ AbstractF2mCurve.Inverse(283, new int[] { 5, 7, 12 }, ToBigInteger()));
+ }
+
+ 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..42414401f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
@@ -0,0 +1,194 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(283, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 283; 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 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..d8c462eeb
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
@@ -0,0 +1,188 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(283, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 283; 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 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..d71f5b5f9
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409Field.cs
@@ -0,0 +1,244 @@
+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 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..6dabf6a7a
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
@@ -0,0 +1,213 @@
+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)
+ 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()
+ {
+ return new SecT409FieldElement(
+ AbstractF2mCurve.Inverse(409, new int[] { 87 }, ToBigInteger()));
+ }
+
+ 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..edfe1a293
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
@@ -0,0 +1,194 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(409, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 409; 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 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..e679094ad
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
@@ -0,0 +1,188 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(409, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 409; 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 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..0711ee4aa
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571Field.cs
@@ -0,0 +1,251 @@
+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 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..8474c912e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
@@ -0,0 +1,213 @@
+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)
+ 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()
+ {
+ return new SecT571FieldElement(
+ AbstractF2mCurve.Inverse(571, new int[] { 2, 5, 10 }, ToBigInteger()));
+ }
+
+ 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..fb136c967
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
@@ -0,0 +1,196 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ y = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(571, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 571; 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 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..05d58863e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
@@ -0,0 +1,193 @@
+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; }
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param yTilde
+ * ~yp, an indication bit for the decompression of yp.
+ * @param X1
+ * The field element xp.
+ * @return the decompressed point.
+ */
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1), y = null;
+ if (x.IsZero)
+ {
+ // y = B.Sqrt();
+ y = SecT571R1_B_SQRT;
+ }
+ else
+ {
+ ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+ ECFieldElement z = SolveQuadraticEquation(beta);
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ y = z.Add(x);
+ break;
+ }
+ default:
+ {
+ y = z.Multiply(x);
+ break;
+ }
+ }
+ }
+ }
+
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return this.CreateRawPoint(x, y, 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 quadratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement SolveQuadraticEquation(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(571, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < 571; 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 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/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..9755c9d6f
--- /dev/null
+++ b/crypto/src/math/raw/Interleave.cs
@@ -0,0 +1,70 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Interleave
+ {
+ /*
+ * 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)
+ {
+ return INTERLEAVE2_TABLE[x & 0xFF];
+ }
+
+ internal static uint Expand16to32(uint x)
+ {
+ return (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16);
+ }
+
+ internal static ulong Expand32to64(uint x)
+ {
+ uint r00 = (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16);
+ uint r32 = (uint)(INTERLEAVE2_TABLE[(x >> 16) & 0xFF] | INTERLEAVE2_TABLE[x >> 24] << 16);
+ return (ulong)r32 << 32 | (ulong)r00;
+ }
+
+ internal static void Expand64To128(ulong x, ulong[] z, int zOff)
+ {
+ z[zOff ] = Expand32to64((uint)x);
+ z[zOff + 1] = Expand32to64((uint)(x >> 32));
+ }
+ }
+}
diff --git a/crypto/src/math/ec/Mod.cs b/crypto/src/math/raw/Mod.cs
index 80534ca9f..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
{
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/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs
index c6b2e9e0e..249b94ea6 100644
--- a/crypto/src/openpgp/PgpPublicKey.cs
+++ b/crypto/src/openpgp/PgpPublicKey.cs
@@ -266,16 +266,23 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
/// <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)
+ if (publicPk.Version <= 3)
{
- return (int)(GetValidSeconds() / (24 * 60 * 60));
+ return publicPk.ValidDays;
}
- return publicPk.ValidDays;
+ long expSecs = GetValidSeconds();
+ if (expSecs <= 0)
+ return 0;
+
+ int days = (int)(expSecs / (24 * 60 * 60));
+ return System.Math.Max(1, days);
}
}
@@ -294,34 +301,32 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
/// <summary>The number of valid seconds from creation time - zero means no expiry.</summary>
public long GetValidSeconds()
{
- if (publicPk.Version > 3)
+ if (publicPk.Version <= 3)
{
- if (IsMasterKey)
- {
- for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
- {
- long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]);
+ return (long)publicPk.ValidDays * (24 * 60 * 60);
+ }
- if (seconds >= 0)
- {
- return seconds;
- }
- }
- }
- else
+ if (IsMasterKey)
+ {
+ for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
{
- long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding);
-
+ long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]);
if (seconds >= 0)
{
return seconds;
}
}
-
- return 0;
+ }
+ else
+ {
+ long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding);
+ if (seconds >= 0)
+ {
+ return seconds;
+ }
}
- return (long) publicPk.ValidDays * 24 * 60 * 60;
+ return 0;
}
private long GetExpirationTimeFromSig(
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/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/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs
index 0cf113f65..bd1515147 100644
--- a/crypto/src/security/SignerUtilities.cs
+++ b/crypto/src/security/SignerUtilities.cs
@@ -261,10 +261,10 @@ namespace Org.BouncyCastle.Security
}
/// <summary>
- /// Returns a ObjectIdentifier for a give encoding.
+ /// 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>
+ /// <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)
@@ -534,6 +534,26 @@ namespace Org.BouncyCastle.Security
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.");
}
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 8614baead..1f9711555 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -311,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)
{
@@ -613,5 +655,21 @@ namespace Org.BouncyCastle.Utilities
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;
+ }
}
}
|