001package org.apache.commons.ssl.org.bouncycastle.asn1.x9; 002 003import java.math.BigInteger; 004 005import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector; 006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer; 007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object; 008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1OctetString; 009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive; 010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence; 011import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence; 012import org.bouncycastle.math.ec.ECAlgorithms; 013import org.bouncycastle.math.ec.ECCurve; 014import org.bouncycastle.math.ec.ECPoint; 015import org.bouncycastle.math.field.PolynomialExtensionField; 016 017/** 018 * ASN.1 def for Elliptic-Curve ECParameters structure. See 019 * X9.62, for further details. 020 */ 021public class X9ECParameters 022 extends ASN1Object 023 implements X9ObjectIdentifiers 024{ 025 private static final BigInteger ONE = BigInteger.valueOf(1); 026 027 private X9FieldID fieldID; 028 private ECCurve curve; 029 private ECPoint g; 030 private BigInteger n; 031 private BigInteger h; 032 private byte[] seed; 033 034 private X9ECParameters( 035 ASN1Sequence seq) 036 { 037 if (!(seq.getObjectAt(0) instanceof ASN1Integer) 038 || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE)) 039 { 040 throw new IllegalArgumentException("bad version in X9ECParameters"); 041 } 042 043 X9Curve x9c = new X9Curve( 044 X9FieldID.getInstance(seq.getObjectAt(1)), 045 ASN1Sequence.getInstance(seq.getObjectAt(2))); 046 047 this.curve = x9c.getCurve(); 048 Object p = seq.getObjectAt(3); 049 050 if (p instanceof X9ECPoint) 051 { 052 this.g = ((X9ECPoint)p).getPoint(); 053 } 054 else 055 { 056 this.g = new X9ECPoint(curve, (ASN1OctetString)p).getPoint(); 057 } 058 059 this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue(); 060 this.seed = x9c.getSeed(); 061 062 if (seq.size() == 6) 063 { 064 this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue(); 065 } 066 } 067 068 public static X9ECParameters getInstance(Object obj) 069 { 070 if (obj instanceof X9ECParameters) 071 { 072 return (X9ECParameters)obj; 073 } 074 075 if (obj != null) 076 { 077 return new X9ECParameters(ASN1Sequence.getInstance(obj)); 078 } 079 080 return null; 081 } 082 083 public X9ECParameters( 084 ECCurve curve, 085 ECPoint g, 086 BigInteger n) 087 { 088 this(curve, g, n, ONE, null); 089 } 090 091 public X9ECParameters( 092 ECCurve curve, 093 ECPoint g, 094 BigInteger n, 095 BigInteger h) 096 { 097 this(curve, g, n, h, null); 098 } 099 100 public X9ECParameters( 101 ECCurve curve, 102 ECPoint g, 103 BigInteger n, 104 BigInteger h, 105 byte[] seed) 106 { 107 this.curve = curve; 108 this.g = g.normalize(); 109 this.n = n; 110 this.h = h; 111 this.seed = seed; 112 113 if (ECAlgorithms.isFpCurve(curve)) 114 { 115 this.fieldID = new X9FieldID(curve.getField().getCharacteristic()); 116 } 117 else if (ECAlgorithms.isF2mCurve(curve)) 118 { 119 PolynomialExtensionField field = (PolynomialExtensionField)curve.getField(); 120 int[] exponents = field.getMinimalPolynomial().getExponentsPresent(); 121 if (exponents.length == 3) 122 { 123 this.fieldID = new X9FieldID(exponents[2], exponents[1]); 124 } 125 else if (exponents.length == 5) 126 { 127 this.fieldID = new X9FieldID(exponents[4], exponents[1], exponents[2], exponents[3]); 128 } 129 else 130 { 131 throw new IllegalArgumentException("Only trinomial and pentomial curves are supported"); 132 } 133 } 134 else 135 { 136 throw new IllegalArgumentException("'curve' is of an unsupported type"); 137 } 138 } 139 140 public ECCurve getCurve() 141 { 142 return curve; 143 } 144 145 public ECPoint getG() 146 { 147 return g; 148 } 149 150 public BigInteger getN() 151 { 152 return n; 153 } 154 155 public BigInteger getH() 156 { 157 if (h == null) 158 { 159 return ONE; // TODO - this should be calculated, it will cause issues with custom curves. 160 } 161 162 return h; 163 } 164 165 public byte[] getSeed() 166 { 167 return seed; 168 } 169 170 /** 171 * Produce an object suitable for an ASN1OutputStream. 172 * <pre> 173 * ECParameters ::= SEQUENCE { 174 * version INTEGER { ecpVer1(1) } (ecpVer1), 175 * fieldID FieldID {{FieldTypes}}, 176 * curve X9Curve, 177 * base X9ECPoint, 178 * order INTEGER, 179 * cofactor INTEGER OPTIONAL 180 * } 181 * </pre> 182 */ 183 public ASN1Primitive toASN1Primitive() 184 { 185 ASN1EncodableVector v = new ASN1EncodableVector(); 186 187 v.add(new ASN1Integer(1)); 188 v.add(fieldID); 189 v.add(new X9Curve(curve, seed)); 190 v.add(new X9ECPoint(g)); 191 v.add(new ASN1Integer(n)); 192 193 if (h != null) 194 { 195 v.add(new ASN1Integer(h)); 196 } 197 198 return new DERSequence(v); 199 } 200}