Home | History | Annotate | Download | only in ec
      1 package org.bouncycastle.jcajce.provider.asymmetric.ec;
      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.ECPrivateKey;
      8 import java.security.spec.ECParameterSpec;
      9 import java.security.spec.ECPoint;
     10 import java.security.spec.ECPrivateKeySpec;
     11 import java.security.spec.EllipticCurve;
     12 import java.util.Enumeration;
     13 
     14 import org.bouncycastle.asn1.ASN1Encodable;
     15 import org.bouncycastle.asn1.ASN1Encoding;
     16 import org.bouncycastle.asn1.ASN1Integer;
     17 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     18 import org.bouncycastle.asn1.ASN1Primitive;
     19 import org.bouncycastle.asn1.DERBitString;
     20 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
     21 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     22 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
     23 import org.bouncycastle.asn1.x9.X962Parameters;
     24 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
     25 import org.bouncycastle.crypto.params.ECDomainParameters;
     26 import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
     27 import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
     28 import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
     29 import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
     30 import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
     31 import org.bouncycastle.jce.interfaces.ECPointEncoder;
     32 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
     33 import org.bouncycastle.jce.provider.BouncyCastleProvider;
     34 import org.bouncycastle.math.ec.ECCurve;
     35 import org.bouncycastle.util.Strings;
     36 
     37 public class BCECPrivateKey
     38     implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
     39 {
     40     static final long serialVersionUID = 994553197664784084L;
     41 
     42     private String          algorithm = "EC";
     43     private boolean         withCompression;
     44 
     45     private transient BigInteger              d;
     46     private transient ECParameterSpec         ecSpec;
     47     private transient ProviderConfiguration   configuration;
     48     private transient DERBitString            publicKey;
     49 
     50     private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
     51 
     52     protected BCECPrivateKey()
     53     {
     54     }
     55 
     56     public BCECPrivateKey(
     57         ECPrivateKey key,
     58         ProviderConfiguration configuration)
     59     {
     60         this.d = key.getS();
     61         this.algorithm = key.getAlgorithm();
     62         this.ecSpec = key.getParams();
     63         this.configuration = configuration;
     64     }
     65 
     66     public BCECPrivateKey(
     67         String algorithm,
     68         org.bouncycastle.jce.spec.ECPrivateKeySpec spec,
     69         ProviderConfiguration configuration)
     70     {
     71         this.algorithm = algorithm;
     72         this.d = spec.getD();
     73 
     74         if (spec.getParams() != null) // can be null if implicitlyCA
     75         {
     76             ECCurve curve = spec.getParams().getCurve();
     77             EllipticCurve ellipticCurve;
     78 
     79             ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
     80 
     81             this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
     82         }
     83         else
     84         {
     85             this.ecSpec = null;
     86         }
     87 
     88         this.configuration = configuration;
     89     }
     90 
     91 
     92     public BCECPrivateKey(
     93         String algorithm,
     94         ECPrivateKeySpec spec,
     95         ProviderConfiguration configuration)
     96     {
     97         this.algorithm = algorithm;
     98         this.d = spec.getS();
     99         this.ecSpec = spec.getParams();
    100         this.configuration = configuration;
    101     }
    102 
    103     public BCECPrivateKey(
    104         String algorithm,
    105         BCECPrivateKey key)
    106     {
    107         this.algorithm = algorithm;
    108         this.d = key.d;
    109         this.ecSpec = key.ecSpec;
    110         this.withCompression = key.withCompression;
    111         this.attrCarrier = key.attrCarrier;
    112         this.publicKey = key.publicKey;
    113         this.configuration = key.configuration;
    114     }
    115 
    116     public BCECPrivateKey(
    117         String algorithm,
    118         ECPrivateKeyParameters params,
    119         BCECPublicKey pubKey,
    120         ECParameterSpec spec,
    121         ProviderConfiguration configuration)
    122     {
    123         ECDomainParameters      dp = params.getParameters();
    124 
    125         this.algorithm = algorithm;
    126         this.d = params.getD();
    127         this.configuration = configuration;
    128 
    129         if (spec == null)
    130         {
    131             EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
    132 
    133             this.ecSpec = new ECParameterSpec(
    134                             ellipticCurve,
    135                             new ECPoint(
    136                                     dp.getG().getAffineXCoord().toBigInteger(),
    137                                     dp.getG().getAffineYCoord().toBigInteger()),
    138                             dp.getN(),
    139                             dp.getH().intValue());
    140         }
    141         else
    142         {
    143             this.ecSpec = spec;
    144         }
    145 
    146         publicKey = getPublicKeyDetails(pubKey);
    147     }
    148 
    149     public BCECPrivateKey(
    150         String algorithm,
    151         ECPrivateKeyParameters params,
    152         BCECPublicKey pubKey,
    153         org.bouncycastle.jce.spec.ECParameterSpec spec,
    154         ProviderConfiguration configuration)
    155     {
    156         ECDomainParameters      dp = params.getParameters();
    157 
    158         this.algorithm = algorithm;
    159         this.d = params.getD();
    160         this.configuration = configuration;
    161 
    162         if (spec == null)
    163         {
    164             EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
    165 
    166             this.ecSpec = new ECParameterSpec(
    167                             ellipticCurve,
    168                             new ECPoint(
    169                                     dp.getG().getAffineXCoord().toBigInteger(),
    170                                     dp.getG().getAffineYCoord().toBigInteger()),
    171                             dp.getN(),
    172                             dp.getH().intValue());
    173         }
    174         else
    175         {
    176             EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
    177 
    178             this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
    179         }
    180 
    181         try
    182         {
    183             publicKey = getPublicKeyDetails(pubKey);
    184         }
    185         catch (Exception e)
    186         {
    187             publicKey = null; // not all curves are encodable
    188         }
    189     }
    190 
    191     public BCECPrivateKey(
    192         String algorithm,
    193         ECPrivateKeyParameters params,
    194         ProviderConfiguration configuration)
    195     {
    196         this.algorithm = algorithm;
    197         this.d = params.getD();
    198         this.ecSpec = null;
    199         this.configuration = configuration;
    200     }
    201 
    202     BCECPrivateKey(
    203         String         algorithm,
    204         PrivateKeyInfo info,
    205         ProviderConfiguration configuration)
    206         throws IOException
    207     {
    208         this.algorithm = algorithm;
    209         this.configuration = configuration;
    210         populateFromPrivKeyInfo(info);
    211     }
    212 
    213     private void populateFromPrivKeyInfo(PrivateKeyInfo info)
    214         throws IOException
    215     {
    216         X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
    217 
    218         ECCurve curve = EC5Util.getCurve(configuration, params);
    219         ecSpec = EC5Util.convertToSpec(params, curve);
    220 
    221         ASN1Encodable privKey = info.parsePrivateKey();
    222         if (privKey instanceof ASN1Integer)
    223         {
    224             ASN1Integer          derD = ASN1Integer.getInstance(privKey);
    225 
    226             this.d = derD.getValue();
    227         }
    228         else
    229         {
    230             org.bouncycastle.asn1.sec.ECPrivateKey ec = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(privKey);
    231 
    232             this.d = ec.getKey();
    233             this.publicKey = ec.getPublicKey();
    234         }
    235     }
    236 
    237     public String getAlgorithm()
    238     {
    239         return algorithm;
    240     }
    241 
    242     /**
    243      * return the encoding format we produce in getEncoded().
    244      *
    245      * @return the string "PKCS#8"
    246      */
    247     public String getFormat()
    248     {
    249         return "PKCS#8";
    250     }
    251 
    252     /**
    253      * Return a PKCS8 representation of the key. The sequence returned
    254      * represents a full PrivateKeyInfo object.
    255      *
    256      * @return a PKCS8 representation of the key.
    257      */
    258     public byte[] getEncoded()
    259     {
    260         X962Parameters  params = ECUtils.getDomainParametersFromName(ecSpec, withCompression);
    261 
    262         int orderBitLength;
    263         if (ecSpec == null)
    264         {
    265             orderBitLength = ECUtil.getOrderBitLength(configuration, null, this.getS());
    266         }
    267         else
    268         {
    269             orderBitLength = ECUtil.getOrderBitLength(configuration, ecSpec.getOrder(), this.getS());
    270         }
    271 
    272         PrivateKeyInfo          info;
    273         org.bouncycastle.asn1.sec.ECPrivateKey            keyStructure;
    274 
    275         if (publicKey != null)
    276         {
    277             keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), publicKey, params);
    278         }
    279         else
    280         {
    281             keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), params);
    282         }
    283 
    284         try
    285         {
    286             info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure);
    287 
    288             return info.getEncoded(ASN1Encoding.DER);
    289         }
    290         catch (IOException e)
    291         {
    292             return null;
    293         }
    294     }
    295 
    296     public ECParameterSpec getParams()
    297     {
    298         return ecSpec;
    299     }
    300 
    301     public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
    302     {
    303         if (ecSpec == null)
    304         {
    305             return null;
    306         }
    307 
    308         return EC5Util.convertSpec(ecSpec, withCompression);
    309     }
    310 
    311     org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
    312     {
    313         if (ecSpec != null)
    314         {
    315             return EC5Util.convertSpec(ecSpec, withCompression);
    316         }
    317 
    318         return configuration.getEcImplicitlyCa();
    319     }
    320 
    321     public BigInteger getS()
    322     {
    323         return d;
    324     }
    325 
    326     public BigInteger getD()
    327     {
    328         return d;
    329     }
    330 
    331     public void setBagAttribute(
    332         ASN1ObjectIdentifier oid,
    333         ASN1Encodable        attribute)
    334     {
    335         attrCarrier.setBagAttribute(oid, attribute);
    336     }
    337 
    338     public ASN1Encodable getBagAttribute(
    339         ASN1ObjectIdentifier oid)
    340     {
    341         return attrCarrier.getBagAttribute(oid);
    342     }
    343 
    344     public Enumeration getBagAttributeKeys()
    345     {
    346         return attrCarrier.getBagAttributeKeys();
    347     }
    348 
    349     public void setPointFormat(String style)
    350     {
    351        withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
    352     }
    353 
    354     public boolean equals(Object o)
    355     {
    356         if (!(o instanceof BCECPrivateKey))
    357         {
    358             return false;
    359         }
    360 
    361         BCECPrivateKey other = (BCECPrivateKey)o;
    362 
    363         return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
    364     }
    365 
    366     public int hashCode()
    367     {
    368         return getD().hashCode() ^ engineGetSpec().hashCode();
    369     }
    370 
    371     public String toString()
    372     {
    373         StringBuffer    buf = new StringBuffer();
    374         String          nl = Strings.lineSeparator();
    375 
    376         buf.append("EC Private Key").append(nl);
    377         buf.append("             S: ").append(this.d.toString(16)).append(nl);
    378 
    379         return buf.toString();
    380 
    381     }
    382 
    383     private DERBitString getPublicKeyDetails(BCECPublicKey pub)
    384     {
    385         try
    386         {
    387             SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
    388 
    389             return info.getPublicKeyData();
    390         }
    391         catch (IOException e)
    392         {   // should never happen
    393             return null;
    394         }
    395     }
    396 
    397     private void readObject(
    398         ObjectInputStream in)
    399         throws IOException, ClassNotFoundException
    400     {
    401         in.defaultReadObject();
    402 
    403         byte[] enc = (byte[])in.readObject();
    404 
    405         this.configuration = BouncyCastleProvider.CONFIGURATION;
    406 
    407         populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
    408 
    409         this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
    410     }
    411 
    412     private void writeObject(
    413         ObjectOutputStream out)
    414         throws IOException
    415     {
    416         out.defaultWriteObject();
    417 
    418         out.writeObject(this.getEncoded());
    419     }
    420 }
    421