diff options
Diffstat (limited to 'core/src/main/java/org/bouncycastle/asn1/ua')
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"); +} |