Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/java/org/bouncycastle/asn1/ua')
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java119
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java144
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java94
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145Params.java121
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java162
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PublicKey.java46
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ua/UAObjectIdentifiers.java16
7 files changed, 702 insertions, 0 deletions
diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java
new file mode 100644
index 00000000..a0cca6b4
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java
@@ -0,0 +1,119 @@
+package org.bouncycastle.asn1.ua;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+
+public class DSTU4145BinaryField
+ extends ASN1Object
+{
+
+ private int m, k, j, l;
+
+ private DSTU4145BinaryField(ASN1Sequence seq)
+ {
+ m = ASN1Integer.getInstance(seq.getObjectAt(0)).getPositiveValue().intValue();
+
+ if (seq.getObjectAt(1) instanceof ASN1Integer)
+ {
+ k = ((ASN1Integer)seq.getObjectAt(1)).getPositiveValue().intValue();
+ }
+ else if (seq.getObjectAt(1) instanceof ASN1Sequence)
+ {
+ ASN1Sequence coefs = ASN1Sequence.getInstance(seq.getObjectAt(1));
+
+ k = ASN1Integer.getInstance(coefs.getObjectAt(0)).getPositiveValue().intValue();
+ j = ASN1Integer.getInstance(coefs.getObjectAt(1)).getPositiveValue().intValue();
+ l = ASN1Integer.getInstance(coefs.getObjectAt(2)).getPositiveValue().intValue();
+ }
+ else
+ {
+ throw new IllegalArgumentException("object parse error");
+ }
+ }
+
+ public static DSTU4145BinaryField getInstance(Object obj)
+ {
+ if (obj instanceof DSTU4145BinaryField)
+ {
+ return (DSTU4145BinaryField)obj;
+ }
+
+ if (obj != null)
+ {
+ return new DSTU4145BinaryField(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public DSTU4145BinaryField(int m, int k1, int k2, int k3)
+ {
+ this.m = m;
+ this.k = k1;
+ this.j = k2;
+ this.l = k3;
+ }
+
+ public int getM()
+ {
+ return m;
+ }
+
+ public int getK1()
+ {
+ return k;
+ }
+
+ public int getK2()
+ {
+ return j;
+ }
+
+ public int getK3()
+ {
+ return l;
+ }
+
+ public DSTU4145BinaryField(int m, int k)
+ {
+ this(m, k, 0, 0);
+ }
+
+ /**
+ * BinaryField ::= SEQUENCE {
+ * M INTEGER,
+ * CHOICE {Trinomial, Pentanomial}
+ * Trinomial::= INTEGER
+ * Pentanomial::= SEQUENCE {
+ * k INTEGER,
+ * j INTEGER,
+ * l INTEGER}
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(m));
+ if (j == 0) //Trinomial
+ {
+ v.add(new ASN1Integer(k));
+ }
+ else
+ {
+ ASN1EncodableVector coefs = new ASN1EncodableVector();
+ coefs.add(new ASN1Integer(k));
+ coefs.add(new ASN1Integer(j));
+ coefs.add(new ASN1Integer(l));
+
+ v.add(new DERSequence(coefs));
+ }
+
+ return new DERSequence(v);
+ }
+
+}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java
new file mode 100644
index 00000000..11c2af48
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java
@@ -0,0 +1,144 @@
+package org.bouncycastle.asn1.ua;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.util.Arrays;
+
+public class DSTU4145ECBinary
+ extends ASN1Object
+{
+
+ BigInteger version = BigInteger.valueOf(0);
+
+ DSTU4145BinaryField f;
+ ASN1Integer a;
+ ASN1OctetString b;
+ ASN1Integer n;
+ ASN1OctetString bp;
+
+ public DSTU4145ECBinary(ECDomainParameters params)
+ {
+ if (!(params.getCurve() instanceof ECCurve.F2m))
+ {
+ throw new IllegalArgumentException("only binary domain is possible");
+ }
+
+ // We always use big-endian in parameter encoding
+ ECCurve.F2m curve = (ECCurve.F2m)params.getCurve();
+ f = new DSTU4145BinaryField(curve.getM(), curve.getK1(), curve.getK2(), curve.getK3());
+ a = new ASN1Integer(curve.getA().toBigInteger());
+ X9IntegerConverter converter = new X9IntegerConverter();
+ b = new DEROctetString(converter.integerToBytes(curve.getB().toBigInteger(), converter.getByteLength(curve)));
+ n = new ASN1Integer(params.getN());
+ bp = new DEROctetString(DSTU4145PointEncoder.encodePoint(params.getG()));
+ }
+
+ private DSTU4145ECBinary(ASN1Sequence seq)
+ {
+ int index = 0;
+
+ if (seq.getObjectAt(index) instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject taggedVersion = (ASN1TaggedObject)seq.getObjectAt(index);
+ if (taggedVersion.isExplicit() && 0 == taggedVersion.getTagNo())
+ {
+ version = ASN1Integer.getInstance(taggedVersion.getLoadedObject()).getValue();
+ index++;
+ }
+ else
+ {
+ throw new IllegalArgumentException("object parse error");
+ }
+ }
+ f = DSTU4145BinaryField.getInstance(seq.getObjectAt(index));
+ index++;
+ a = ASN1Integer.getInstance(seq.getObjectAt(index));
+ index++;
+ b = ASN1OctetString.getInstance(seq.getObjectAt(index));
+ index++;
+ n = ASN1Integer.getInstance(seq.getObjectAt(index));
+ index++;
+ bp = ASN1OctetString.getInstance(seq.getObjectAt(index));
+ }
+
+ public static DSTU4145ECBinary getInstance(Object obj)
+ {
+ if (obj instanceof DSTU4145ECBinary)
+ {
+ return (DSTU4145ECBinary)obj;
+ }
+
+ if (obj != null)
+ {
+ return new DSTU4145ECBinary(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public DSTU4145BinaryField getField()
+ {
+ return f;
+ }
+
+ public BigInteger getA()
+ {
+ return a.getValue();
+ }
+
+ public byte[] getB()
+ {
+ return Arrays.clone(b.getOctets());
+ }
+
+ public BigInteger getN()
+ {
+ return n.getValue();
+ }
+
+ public byte[] getG()
+ {
+ return Arrays.clone(bp.getOctets());
+ }
+
+ /**
+ * ECBinary ::= SEQUENCE {
+ * version [0] EXPLICIT INTEGER DEFAULT 0,
+ * f BinaryField,
+ * a INTEGER (0..1),
+ * b OCTET STRING,
+ * n INTEGER,
+ * bp OCTET STRING}
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (0 != version.compareTo(BigInteger.valueOf(0)))
+ {
+ v.add(new DERTaggedObject(true, 0, new ASN1Integer(version)));
+ }
+ v.add(f);
+ v.add(a);
+ v.add(b);
+ v.add(n);
+ v.add(bp);
+
+ return new DERSequence(v);
+ }
+
+}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java
new file mode 100644
index 00000000..353c196d
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java
@@ -0,0 +1,94 @@
+package org.bouncycastle.asn1.ua;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class DSTU4145NamedCurves
+{
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ public static final ECDomainParameters[] params = new ECDomainParameters[10];
+ static final ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[10];
+
+ //All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X
+ //where X is the curve number 0-9
+ static final String oidBase = UAObjectIdentifiers.dstu4145le.getId() + ".2.";
+
+ static
+ {
+ ECCurve.F2m[] curves = new ECCurve.F2m[10];
+ curves[0] = new ECCurve.F2m(163, 3, 6, 7, ONE, new BigInteger("5FF6108462A2DC8210AB403925E638A19C1455D21", 16));
+ curves[1] = new ECCurve.F2m(167, 6, ONE, new BigInteger("6EE3CEEB230811759F20518A0930F1A4315A827DAC", 16));
+ curves[2] = new ECCurve.F2m(173, 1, 2, 10, ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16));
+ curves[3] = new ECCurve.F2m(179, 1, 2, 4, ONE, new BigInteger("4A6E0856526436F2F88DD07A341E32D04184572BEB710", 16));
+ curves[4] = new ECCurve.F2m(191, 9, ONE, new BigInteger("7BC86E2102902EC4D5890E8B6B4981ff27E0482750FEFC03", 16));
+ curves[5] = new ECCurve.F2m(233, 1, 4, 9, ONE, new BigInteger("06973B15095675534C7CF7E64A21BD54EF5DD3B8A0326AA936ECE454D2C", 16));
+ curves[6] = new ECCurve.F2m(257, 12, ZERO, new BigInteger("1CEF494720115657E18F938D7A7942394FF9425C1458C57861F9EEA6ADBE3BE10", 16));
+ curves[7] = new ECCurve.F2m(307, 2, 4, 8, ONE, new BigInteger("393C7F7D53666B5054B5E6C6D3DE94F4296C0C599E2E2E241050DF18B6090BDC90186904968BB", 16));
+ curves[8] = new ECCurve.F2m(367, 21, ONE, new BigInteger("43FC8AD242B0B7A6F3D1627AD5654447556B47BF6AA4A64B0C2AFE42CADAB8F93D92394C79A79755437B56995136", 16));
+ curves[9] = new ECCurve.F2m(431, 1, 3, 5, ONE, new BigInteger("03CE10490F6A708FC26DFE8C3D27C4F94E690134D5BFF988D8D28AAEAEDE975936C66BAC536B18AE2DC312CA493117DAA469C640CAF3", 16));
+
+ ECPoint[] points = new ECPoint[10];
+ points[0] = curves[0].createPoint(new BigInteger("2E2F85F5DD74CE983A5C4237229DAF8A3F35823BE", 16), new BigInteger("3826F008A8C51D7B95284D9D03FF0E00CE2CD723A", 16), false);
+ points[1] = curves[1].createPoint(new BigInteger("7A1F6653786A68192803910A3D30B2A2018B21CD54", 16), new BigInteger("5F49EB26781C0EC6B8909156D98ED435E45FD59918", 16), false);
+ points[2] = curves[2].createPoint(new BigInteger("4D41A619BCC6EADF0448FA22FAD567A9181D37389CA", 16), new BigInteger("10B51CC12849B234C75E6DD2028BF7FF5C1CE0D991A1", 16), false);
+ points[3] = curves[3].createPoint(new BigInteger("6BA06FE51464B2BD26DC57F48819BA9954667022C7D03", 16), new BigInteger("25FBC363582DCEC065080CA8287AAFF09788A66DC3A9E", 16), false);
+ points[4] = curves[4].createPoint(new BigInteger("714114B762F2FF4A7912A6D2AC58B9B5C2FCFE76DAEB7129", 16), new BigInteger("29C41E568B77C617EFE5902F11DB96FA9613CD8D03DB08DA", 16), false);
+ points[5] = curves[5].createPoint(new BigInteger("3FCDA526B6CDF83BA1118DF35B3C31761D3545F32728D003EEB25EFE96", 16), new BigInteger("9CA8B57A934C54DEEDA9E54A7BBAD95E3B2E91C54D32BE0B9DF96D8D35", 16), false);
+ points[6] = curves[6].createPoint(new BigInteger("02A29EF207D0E9B6C55CD260B306C7E007AC491CA1B10C62334A9E8DCD8D20FB7", 16), new BigInteger("10686D41FF744D4449FCCF6D8EEA03102E6812C93A9D60B978B702CF156D814EF", 16), false);
+ points[7] = curves[7].createPoint(new BigInteger("216EE8B189D291A0224984C1E92F1D16BF75CCD825A087A239B276D3167743C52C02D6E7232AA", 16), new BigInteger("5D9306BACD22B7FAEB09D2E049C6E2866C5D1677762A8F2F2DC9A11C7F7BE8340AB2237C7F2A0", 16), false);
+ points[8] = curves[8].createPoint(new BigInteger("324A6EDDD512F08C49A99AE0D3F961197A76413E7BE81A400CA681E09639B5FE12E59A109F78BF4A373541B3B9A1", 16), new BigInteger("1AB597A5B4477F59E39539007C7F977D1A567B92B043A49C6B61984C3FE3481AAF454CD41BA1F051626442B3C10", 16), false);
+ points[9] = curves[9].createPoint(new BigInteger("1A62BA79D98133A16BBAE7ED9A8E03C32E0824D57AEF72F88986874E5AAE49C27BED49A2A95058068426C2171E99FD3B43C5947C857D", 16), new BigInteger("70B5E1E14031C1F70BBEFE96BDDE66F451754B4CA5F48DA241F331AA396B8D1839A855C1769B1EA14BA53308B5E2723724E090E02DB9", 16), false);
+
+ BigInteger[] n_s = new BigInteger[10];
+ n_s[0] = new BigInteger("400000000000000000002BEC12BE2262D39BCF14D", 16);
+ n_s[1] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFB12EBCC7D7F29FF7701F", 16);
+ n_s[2] = new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16);
+ n_s[3] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFB981960435FE5AB64236EF", 16);
+ n_s[4] = new BigInteger("40000000000000000000000069A779CAC1DABC6788F7474F", 16);
+ n_s[5] = new BigInteger("1000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", 16);
+ n_s[6] = new BigInteger("800000000000000000000000000000006759213AF182E987D3E17714907D470D", 16);
+ n_s[7] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC079C2F3825DA70D390FBBA588D4604022B7B7", 16);
+ n_s[8] = new BigInteger("40000000000000000000000000000000000000000000009C300B75A3FA824F22428FD28CE8812245EF44049B2D49", 16);
+ n_s[9] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA3175458009A8C0A724F02F81AA8A1FCBAF80D90C7A95110504CF", 16);
+
+ for (int i = 0; i < params.length; i++)
+ {
+ params[i] = new ECDomainParameters(curves[i], points[i], n_s[i]);
+ }
+
+ for (int i = 0; i < oids.length; i++)
+ {
+ oids[i] = new ASN1ObjectIdentifier(oidBase + i);
+ }
+ }
+
+ /**
+ * All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X
+ * where X is the curve number 0-9
+ */
+ public static ASN1ObjectIdentifier[] getOIDs()
+ {
+ return oids;
+ }
+
+ /**
+ * All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X
+ * where X is the curve number 0-9
+ */
+ public static ECDomainParameters getByOID(ASN1ObjectIdentifier oid)
+ {
+ String oidStr = oid.getId();
+ if (oidStr.startsWith(oidBase))
+ {
+ int index = Integer.parseInt(oidStr.substring(oidStr.length() - 1));
+ return params[index];
+ }
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145Params.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145Params.java
new file mode 100644
index 00000000..c425d73b
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145Params.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.asn1.ua;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class DSTU4145Params
+ extends ASN1Object
+{
+ private static final byte DEFAULT_DKE[] = {
+ (byte)0xa9, (byte)0xd6, (byte)0xeb, 0x45, (byte)0xf1, 0x3c, 0x70, (byte)0x82,
+ (byte)0x80, (byte)0xc4, (byte)0x96, 0x7b, 0x23, 0x1f, 0x5e, (byte)0xad,
+ (byte)0xf6, 0x58, (byte)0xeb, (byte)0xa4, (byte)0xc0, 0x37, 0x29, 0x1d,
+ 0x38, (byte)0xd9, 0x6b, (byte)0xf0, 0x25, (byte)0xca, 0x4e, 0x17,
+ (byte)0xf8, (byte)0xe9, 0x72, 0x0d, (byte)0xc6, 0x15, (byte)0xb4, 0x3a,
+ 0x28, (byte)0x97, 0x5f, 0x0b, (byte)0xc1, (byte)0xde, (byte)0xa3, 0x64,
+ 0x38, (byte)0xb5, 0x64, (byte)0xea, 0x2c, 0x17, (byte)0x9f, (byte)0xd0,
+ 0x12, 0x3e, 0x6d, (byte)0xb8, (byte)0xfa, (byte)0xc5, 0x79, 0x04};
+
+
+ private ASN1ObjectIdentifier namedCurve;
+ private DSTU4145ECBinary ecbinary;
+ private byte[] dke = DEFAULT_DKE;
+
+ public DSTU4145Params(ASN1ObjectIdentifier namedCurve)
+ {
+ this.namedCurve = namedCurve;
+ }
+
+ public DSTU4145Params(DSTU4145ECBinary ecbinary)
+ {
+ this.ecbinary = ecbinary;
+ }
+
+ public boolean isNamedCurve()
+ {
+ return namedCurve != null;
+ }
+
+ public DSTU4145ECBinary getECBinary()
+ {
+ return ecbinary;
+ }
+
+ public byte[] getDKE()
+ {
+ return dke;
+ }
+
+ public static byte[] getDefaultDKE()
+ {
+ return DEFAULT_DKE;
+ }
+
+ public ASN1ObjectIdentifier getNamedCurve()
+ {
+ return namedCurve;
+ }
+
+ public static DSTU4145Params getInstance(Object obj)
+ {
+ if (obj instanceof DSTU4145Params)
+ {
+ return (DSTU4145Params)obj;
+ }
+
+ if (obj != null)
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(obj);
+ DSTU4145Params params;
+
+ if (seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ params = new DSTU4145Params(ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)));
+ }
+ else
+ {
+ params = new DSTU4145Params(DSTU4145ECBinary.getInstance(seq.getObjectAt(0)));
+ }
+
+ if (seq.size() == 2)
+ {
+ params.dke = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets();
+ if (params.dke.length != DSTU4145Params.DEFAULT_DKE.length)
+ {
+ throw new IllegalArgumentException("object parse error");
+ }
+ }
+
+ return params;
+ }
+
+ throw new IllegalArgumentException("object parse error");
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (namedCurve != null)
+ {
+ v.add(namedCurve);
+ }
+ else
+ {
+ v.add(ecbinary);
+ }
+
+ if (!org.bouncycastle.util.Arrays.areEqual(dke, DEFAULT_DKE))
+ {
+ v.add(new DEROctetString(dke));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java
new file mode 100644
index 00000000..0227d2ad
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java
@@ -0,0 +1,162 @@
+package org.bouncycastle.asn1.ua;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * DSTU4145 encodes points somewhat differently than X9.62
+ * It compresses the point to the size of the field element
+ */
+
+public abstract class DSTU4145PointEncoder
+{
+
+ private static X9IntegerConverter converter = new X9IntegerConverter();
+
+ private static BigInteger trace(ECFieldElement fe)
+ {
+ ECFieldElement t = fe;
+ for (int i = 0; i < fe.getFieldSize() - 1; i++)
+ {
+ t = t.square().add(fe);
+ }
+ return t.toBigInteger();
+ }
+
+ /**
+ * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+ * D.1.6) The other solution is <code>z + 1</code>.
+ *
+ * @param beta The value to solve the qradratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private static ECFieldElement solveQuadradicEquation(ECFieldElement beta)
+ {
+ ECFieldElement.F2m b = (ECFieldElement.F2m)beta;
+ ECFieldElement zeroElement = new ECFieldElement.F2m(
+ b.getM(), b.getK1(), b.getK2(), b.getK3(), ECConstants.ZERO);
+
+ if (beta.toBigInteger().equals(ECConstants.ZERO))
+ {
+ return zeroElement;
+ }
+
+ ECFieldElement z = null;
+ ECFieldElement gamma = zeroElement;
+
+ Random rand = new Random();
+ int m = b.getM();
+ do
+ {
+ ECFieldElement t = new ECFieldElement.F2m(b.getM(), b.getK1(),
+ b.getK2(), b.getK3(), new BigInteger(m, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i <= m - 1; i++)
+ {
+ ECFieldElement w2 = w.square();
+ z = z.square().add(w2.multiply(t));
+ w = w2.add(beta);
+ }
+ if (!w.toBigInteger().equals(ECConstants.ZERO))
+ {
+ return null;
+ }
+ gamma = z.square().add(z);
+ }
+ while (gamma.toBigInteger().equals(ECConstants.ZERO));
+
+ return z;
+ }
+
+ public static byte[] encodePoint(ECPoint Q)
+ {
+ /*if (!Q.isCompressed())
+ Q=new ECPoint.F2m(Q.getCurve(),Q.getX(),Q.getY(),true);
+
+ byte[] bytes=Q.getEncoded();
+
+ if (bytes[0]==0x02)
+ bytes[bytes.length-1]&=0xFE;
+ else if (bytes[0]==0x02)
+ bytes[bytes.length-1]|=0x01;
+
+ return Arrays.copyOfRange(bytes, 1, bytes.length);*/
+
+ int byteCount = converter.getByteLength(Q.getX());
+ byte[] bytes = converter.integerToBytes(Q.getX().toBigInteger(), byteCount);
+
+ if (!(Q.getX().toBigInteger().equals(ECConstants.ZERO)))
+ {
+ ECFieldElement y = Q.getY().multiply(Q.getX().invert());
+ if (trace(y).equals(ECConstants.ONE))
+ {
+ bytes[bytes.length - 1] |= 0x01;
+ }
+ else
+ {
+ bytes[bytes.length - 1] &= 0xFE;
+ }
+ }
+
+ return bytes;
+ }
+
+ public static ECPoint decodePoint(ECCurve curve, byte[] bytes)
+ {
+ /*byte[] bp_enc=new byte[bytes.length+1];
+ if (0==(bytes[bytes.length-1]&0x1))
+ bp_enc[0]=0x02;
+ else
+ bp_enc[0]=0x03;
+ System.arraycopy(bytes, 0, bp_enc, 1, bytes.length);
+ if (!trace(curve.fromBigInteger(new BigInteger(1, bytes))).equals(curve.getA().toBigInteger()))
+ bp_enc[bp_enc.length-1]^=0x01;
+
+ return curve.decodePoint(bp_enc);*/
+
+ BigInteger k = BigInteger.valueOf(bytes[bytes.length - 1] & 0x1);
+ if (!trace(curve.fromBigInteger(new BigInteger(1, bytes))).equals(curve.getA().toBigInteger()))
+ {
+ bytes = Arrays.clone(bytes);
+ bytes[bytes.length - 1] ^= 0x01;
+ }
+ ECCurve.F2m c = (ECCurve.F2m)curve;
+ ECFieldElement xp = curve.fromBigInteger(new BigInteger(1, bytes));
+ ECFieldElement yp = null;
+ if (xp.toBigInteger().equals(ECConstants.ZERO))
+ {
+ yp = (ECFieldElement.F2m)curve.getB();
+ for (int i = 0; i < c.getM() - 1; i++)
+ {
+ yp = yp.square();
+ }
+ }
+ else
+ {
+ ECFieldElement beta = xp.add(curve.getA()).add(
+ curve.getB().multiply(xp.square().invert()));
+ ECFieldElement z = solveQuadradicEquation(beta);
+ if (z == null)
+ {
+ throw new RuntimeException("Invalid point compression");
+ }
+ if (!trace(z).equals(k))
+ {
+ z = z.add(curve.fromBigInteger(ECConstants.ONE));
+ }
+ yp = xp.multiply(z);
+ }
+
+ return new ECPoint.F2m(curve, xp, yp);
+ }
+
+}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PublicKey.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PublicKey.java
new file mode 100644
index 00000000..769eff66
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PublicKey.java
@@ -0,0 +1,46 @@
+package org.bouncycastle.asn1.ua;
+
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class DSTU4145PublicKey
+ extends ASN1Object
+{
+
+ private ASN1OctetString pubKey;
+
+ public DSTU4145PublicKey(ECPoint pubKey)
+ {
+ // We always use big-endian in parameter encoding
+ this.pubKey = new DEROctetString(DSTU4145PointEncoder.encodePoint(pubKey));
+ }
+
+ private DSTU4145PublicKey(ASN1OctetString ocStr)
+ {
+ pubKey = ocStr;
+ }
+
+ public static DSTU4145PublicKey getInstance(Object obj)
+ {
+ if (obj instanceof DSTU4145PublicKey)
+ {
+ return (DSTU4145PublicKey)obj;
+ }
+
+ if (obj != null)
+ {
+ return new DSTU4145PublicKey(ASN1OctetString.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return pubKey;
+ }
+
+}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/UAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/ua/UAObjectIdentifiers.java
new file mode 100644
index 00000000..046bc6f7
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/ua/UAObjectIdentifiers.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.asn1.ua;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface UAObjectIdentifiers
+{
+ // Ukrainian object identifiers
+ // {iso(1) member-body(2) Ukraine(804 ) root(2) security(1) cryptography(1) pki(1)}
+
+ static final ASN1ObjectIdentifier UaOid = new ASN1ObjectIdentifier("1.2.804.2.1.1.1");
+
+ // {pki-alg(1) pki-alg-�sym(3) Dstu4145WithGost34311(1) PB(1)}
+ // DSTU4145 in polynomial basis has 2 oids, one for little-endian representation and one for big-endian
+ static final ASN1ObjectIdentifier dstu4145le = UaOid.branch("1.3.1.1");
+ static final ASN1ObjectIdentifier dstu4145be = UaOid.branch("1.3.1.1.1.1");
+}