Home | History | Annotate | Download | only in provider
      1 package org.bouncycastle.jce.provider;
      2 
      3 import java.io.IOException;
      4 import java.io.ObjectInputStream;
      5 import java.io.ObjectOutputStream;
      6 import java.math.BigInteger;
      7 import java.security.interfaces.ECPublicKey;
      8 import java.security.spec.ECParameterSpec;
      9 import java.security.spec.ECPoint;
     10 import java.security.spec.ECPublicKeySpec;
     11 import java.security.spec.EllipticCurve;
     12 
     13 import org.bouncycastle.asn1.ASN1Encodable;
     14 import org.bouncycastle.asn1.ASN1Object;
     15 import org.bouncycastle.asn1.ASN1OctetString;
     16 import org.bouncycastle.asn1.ASN1Sequence;
     17 import org.bouncycastle.asn1.DERBitString;
     18 import org.bouncycastle.asn1.DERNull;
     19 import org.bouncycastle.asn1.DERObject;
     20 import org.bouncycastle.asn1.DERObjectIdentifier;
     21 import org.bouncycastle.asn1.DEROctetString;
     22 import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
     23 // BEGIN android-removed
     24 // import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
     25 // import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
     26 // END android-removed
     27 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     28 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
     29 import org.bouncycastle.asn1.x9.X962Parameters;
     30 import org.bouncycastle.asn1.x9.X9ECParameters;
     31 import org.bouncycastle.asn1.x9.X9ECPoint;
     32 import org.bouncycastle.asn1.x9.X9IntegerConverter;
     33 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
     34 import org.bouncycastle.crypto.params.ECDomainParameters;
     35 import org.bouncycastle.crypto.params.ECPublicKeyParameters;
     36 // BEGIN android-removed
     37 // import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
     38 // END android-removed
     39 import org.bouncycastle.jce.interfaces.ECPointEncoder;
     40 import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
     41 import org.bouncycastle.jce.provider.asymmetric.ec.ECUtil;
     42 // BEGIN android-removed
     43 // import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
     44 // END android-removed
     45 import org.bouncycastle.jce.spec.ECNamedCurveSpec;
     46 import org.bouncycastle.math.ec.ECCurve;
     47 
     48 public class JCEECPublicKey
     49     implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder
     50 {
     51     private String                  algorithm = "EC";
     52     private org.bouncycastle.math.ec.ECPoint q;
     53     private ECParameterSpec         ecSpec;
     54     private boolean                 withCompression;
     55     // BEGIN android-removed
     56     // private GOST3410PublicKeyAlgParameters       gostParams;
     57     // END android-removed
     58 
     59     public JCEECPublicKey(
     60         String              algorithm,
     61         JCEECPublicKey      key)
     62     {
     63         this.algorithm = algorithm;
     64         this.q = key.q;
     65         this.ecSpec = key.ecSpec;
     66         this.withCompression = key.withCompression;
     67         // BEGIN android-removed
     68         // this.gostParams = key.gostParams;
     69         // END android-removed
     70     }
     71 
     72     public JCEECPublicKey(
     73         String              algorithm,
     74         ECPublicKeySpec     spec)
     75     {
     76         this.algorithm = algorithm;
     77         this.ecSpec = spec.getParams();
     78         this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
     79     }
     80 
     81     public JCEECPublicKey(
     82         String              algorithm,
     83         org.bouncycastle.jce.spec.ECPublicKeySpec     spec)
     84     {
     85         this.algorithm = algorithm;
     86         this.q = spec.getQ();
     87 
     88         if (spec.getParams() != null) // can be null if implictlyCa
     89         {
     90             ECCurve curve = spec.getParams().getCurve();
     91             EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
     92 
     93             this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
     94         }
     95         else
     96         {
     97             if (q.getCurve() == null)
     98             {
     99                 org.bouncycastle.jce.spec.ECParameterSpec s = ProviderUtil.getEcImplicitlyCa();
    100 
    101                 q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
    102             }
    103             this.ecSpec = null;
    104         }
    105     }
    106 
    107     public JCEECPublicKey(
    108         String                  algorithm,
    109         ECPublicKeyParameters   params,
    110         ECParameterSpec         spec)
    111     {
    112         ECDomainParameters      dp = params.getParameters();
    113 
    114         this.algorithm = algorithm;
    115         this.q = params.getQ();
    116 
    117         if (spec == null)
    118         {
    119             EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
    120 
    121             this.ecSpec = createSpec(ellipticCurve, dp);
    122         }
    123         else
    124         {
    125             this.ecSpec = spec;
    126         }
    127     }
    128 
    129     public JCEECPublicKey(
    130         String                  algorithm,
    131         ECPublicKeyParameters   params,
    132         org.bouncycastle.jce.spec.ECParameterSpec         spec)
    133     {
    134         ECDomainParameters      dp = params.getParameters();
    135 
    136         this.algorithm = algorithm;
    137         this.q = params.getQ();
    138 
    139         if (spec == null)
    140         {
    141             EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
    142 
    143             this.ecSpec = createSpec(ellipticCurve, dp);
    144         }
    145         else
    146         {
    147             EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
    148 
    149             this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
    150         }
    151     }
    152 
    153     /*
    154      * called for implicitCA
    155      */
    156     public JCEECPublicKey(
    157         String                  algorithm,
    158         ECPublicKeyParameters   params)
    159     {
    160         this.algorithm = algorithm;
    161         this.q = params.getQ();
    162         this.ecSpec = null;
    163     }
    164 
    165     private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
    166     {
    167         return new ECParameterSpec(
    168                 ellipticCurve,
    169                 new ECPoint(
    170                         dp.getG().getX().toBigInteger(),
    171                         dp.getG().getY().toBigInteger()),
    172                         dp.getN(),
    173                         dp.getH().intValue());
    174     }
    175 
    176     public JCEECPublicKey(
    177         ECPublicKey     key)
    178     {
    179         this.algorithm = key.getAlgorithm();
    180         this.ecSpec = key.getParams();
    181         this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
    182     }
    183 
    184     JCEECPublicKey(
    185         SubjectPublicKeyInfo    info)
    186     {
    187         populateFromPubKeyInfo(info);
    188     }
    189 
    190     private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
    191     {
    192         // BEGIN android-removed
    193         // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
    194         // {
    195         //     DERBitString bits = info.getPublicKeyData();
    196         //     ASN1OctetString key;
    197         //     this.algorithm = "ECGOST3410";
    198         //
    199         //     try
    200         //     {
    201         //         key = (ASN1OctetString) ASN1Object.fromByteArray(bits.getBytes());
    202         //     }
    203         //     catch (IOException ex)
    204         //     {
    205         //         throw new IllegalArgumentException("error recovering public key");
    206         //     }
    207         //
    208         //     byte[]          keyEnc = key.getOctets();
    209         //     byte[]          x = new byte[32];
    210         //     byte[]          y = new byte[32];
    211         //
    212         //     for (int i = 0; i != x.length; i++)
    213         //     {
    214         //         x[i] = keyEnc[32 - 1 - i];
    215         //     }
    216         //
    217         //     for (int i = 0; i != y.length; i++)
    218         //     {
    219         //         y[i] = keyEnc[64 - 1 - i];
    220         //     }
    221         //
    222         //     gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
    223         //
    224         //     ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
    225         //
    226         //     ECCurve curve = spec.getCurve();
    227         //     EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
    228         //
    229         //     this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
    230         //
    231         //     ecSpec = new ECNamedCurveSpec(
    232         //             ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
    233         //             ellipticCurve,
    234         //             new ECPoint(
    235         //                     spec.getG().getX().toBigInteger(),
    236         //                     spec.getG().getY().toBigInteger()),
    237         //                     spec.getN(), spec.getH());
    238         //
    239         // }
    240         // else
    241         // END android-removed
    242         {
    243             X962Parameters params = new X962Parameters((DERObject)info.getAlgorithmId().getParameters());
    244             ECCurve                 curve;
    245             EllipticCurve           ellipticCurve;
    246 
    247             if (params.isNamedCurve())
    248             {
    249                 DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
    250                 X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
    251 
    252                 curve = ecP.getCurve();
    253                 ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
    254 
    255                 ecSpec = new ECNamedCurveSpec(
    256                         ECUtil.getCurveName(oid),
    257                         ellipticCurve,
    258                         new ECPoint(
    259                                 ecP.getG().getX().toBigInteger(),
    260                                 ecP.getG().getY().toBigInteger()),
    261                         ecP.getN(),
    262                         ecP.getH());
    263             }
    264             else if (params.isImplicitlyCA())
    265             {
    266                 ecSpec = null;
    267                 curve = ProviderUtil.getEcImplicitlyCa().getCurve();
    268             }
    269             else
    270             {
    271                 X9ECParameters          ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
    272 
    273                 curve = ecP.getCurve();
    274                 ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
    275 
    276                 this.ecSpec = new ECParameterSpec(
    277                         ellipticCurve,
    278                         new ECPoint(
    279                                 ecP.getG().getX().toBigInteger(),
    280                                 ecP.getG().getY().toBigInteger()),
    281                         ecP.getN(),
    282                         ecP.getH().intValue());
    283             }
    284 
    285             DERBitString    bits = info.getPublicKeyData();
    286             byte[]          data = bits.getBytes();
    287             ASN1OctetString key = new DEROctetString(data);
    288 
    289             //
    290             // extra octet string - one of our old certs...
    291             //
    292             if (data[0] == 0x04 && data[1] == data.length - 2
    293                 && (data[2] == 0x02 || data[2] == 0x03))
    294             {
    295                 int qLength = new X9IntegerConverter().getByteLength(curve);
    296 
    297                 if (qLength >= data.length - 3)
    298                 {
    299                     try
    300                     {
    301                         key = (ASN1OctetString) ASN1Object.fromByteArray(data);
    302                     }
    303                     catch (IOException ex)
    304                     {
    305                         throw new IllegalArgumentException("error recovering public key");
    306                     }
    307                 }
    308             }
    309             X9ECPoint derQ = new X9ECPoint(curve, key);
    310 
    311             this.q = derQ.getPoint();
    312         }
    313     }
    314 
    315     public String getAlgorithm()
    316     {
    317         return algorithm;
    318     }
    319 
    320     public String getFormat()
    321     {
    322         return "X.509";
    323     }
    324 
    325     public byte[] getEncoded()
    326     {
    327         ASN1Encodable        params;
    328         SubjectPublicKeyInfo info;
    329 
    330         // BEGIN android-removed
    331         // if (algorithm.equals("ECGOST3410"))
    332         // {
    333         //     if (gostParams != null)
    334         //     {
    335         //         params = gostParams;
    336         //     }
    337         //     else
    338         //     {
    339         //         if (ecSpec instanceof ECNamedCurveSpec)
    340         //         {
    341         //             params = new GOST3410PublicKeyAlgParameters(
    342         //                            ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
    343         //                            CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
    344         //         }
    345         //         else
    346         //         {   // strictly speaking this may not be applicable...
    347         //             ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
    348         //
    349         //             X9ECParameters ecP = new X9ECParameters(
    350         //                 curve,
    351         //                 EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
    352         //                 ecSpec.getOrder(),
    353         //                 BigInteger.valueOf(ecSpec.getCofactor()),
    354         //                 ecSpec.getCurve().getSeed());
    355         //
    356         //             params = new X962Parameters(ecP);
    357         //         }
    358         //     }
    359         //
    360         //     BigInteger      bX = this.q.getX().toBigInteger();
    361         //     BigInteger      bY = this.q.getY().toBigInteger();
    362         //     byte[]          encKey = new byte[64];
    363         //
    364         //     extractBytes(encKey, 0, bX);
    365         //     extractBytes(encKey, 32, bY);
    366         //
    367         //     info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), new DEROctetString(encKey));
    368         // }
    369         // else
    370         // END android-removed
    371         {
    372             if (ecSpec instanceof ECNamedCurveSpec)
    373             {
    374                 DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
    375                 if (curveOid == null)
    376                 {
    377                     curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
    378                 }
    379                 params = new X962Parameters(curveOid);
    380             }
    381             else if (ecSpec == null)
    382             {
    383                 params = new X962Parameters(DERNull.INSTANCE);
    384             }
    385             else
    386             {
    387                 ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
    388 
    389                 X9ECParameters ecP = new X9ECParameters(
    390                     curve,
    391                     EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
    392                     ecSpec.getOrder(),
    393                     BigInteger.valueOf(ecSpec.getCofactor()),
    394                     ecSpec.getCurve().getSeed());
    395 
    396                 params = new X962Parameters(ecP);
    397             }
    398 
    399             ECCurve curve = this.engineGetQ().getCurve();
    400             ASN1OctetString p = (ASN1OctetString)
    401                 new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).getDERObject();
    402 
    403             info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.getDERObject()), p.getOctets());
    404         }
    405 
    406         return info.getDEREncoded();
    407     }
    408 
    409     private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
    410     {
    411         byte[] val = bI.toByteArray();
    412         if (val.length < 32)
    413         {
    414             byte[] tmp = new byte[32];
    415             System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
    416             val = tmp;
    417         }
    418 
    419         for (int i = 0; i != 32; i++)
    420         {
    421             encKey[offSet + i] = val[val.length - 1 - i];
    422         }
    423     }
    424 
    425     public ECParameterSpec getParams()
    426     {
    427         return ecSpec;
    428     }
    429 
    430     public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
    431     {
    432         if (ecSpec == null)     // implictlyCA
    433         {
    434             return null;
    435         }
    436 
    437         return EC5Util.convertSpec(ecSpec, withCompression);
    438     }
    439 
    440     public ECPoint getW()
    441     {
    442         return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger());
    443     }
    444 
    445     public org.bouncycastle.math.ec.ECPoint getQ()
    446     {
    447         if (ecSpec == null)
    448         {
    449             if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp)
    450             {
    451                 return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
    452             }
    453             else
    454             {
    455                 return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
    456             }
    457         }
    458 
    459         return q;
    460     }
    461 
    462     public org.bouncycastle.math.ec.ECPoint engineGetQ()
    463     {
    464         return q;
    465     }
    466 
    467     org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
    468     {
    469         if (ecSpec != null)
    470         {
    471             return EC5Util.convertSpec(ecSpec, withCompression);
    472         }
    473 
    474         return ProviderUtil.getEcImplicitlyCa();
    475     }
    476 
    477     public String toString()
    478     {
    479         StringBuffer    buf = new StringBuffer();
    480         String          nl = System.getProperty("line.separator");
    481 
    482         buf.append("EC Public Key").append(nl);
    483         buf.append("            X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl);
    484         buf.append("            Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl);
    485 
    486         return buf.toString();
    487 
    488     }
    489 
    490     public void setPointFormat(String style)
    491     {
    492        withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
    493     }
    494 
    495     public boolean equals(Object o)
    496     {
    497         if (!(o instanceof JCEECPublicKey))
    498         {
    499             return false;
    500         }
    501 
    502         JCEECPublicKey other = (JCEECPublicKey)o;
    503 
    504         return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
    505     }
    506 
    507     public int hashCode()
    508     {
    509         return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
    510     }
    511 
    512     private void readObject(
    513         ObjectInputStream in)
    514         throws IOException, ClassNotFoundException
    515     {
    516         byte[] enc = (byte[])in.readObject();
    517 
    518         populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Object.fromByteArray(enc)));
    519 
    520         this.algorithm = (String)in.readObject();
    521         this.withCompression = in.readBoolean();
    522     }
    523 
    524     private void writeObject(
    525         ObjectOutputStream out)
    526         throws IOException
    527     {
    528         out.writeObject(this.getEncoded());
    529         out.writeObject(algorithm);
    530         out.writeBoolean(withCompression);
    531     }
    532 }
    533