From a theoretical point of view, the public key can be recalculated from the private key (the computational cost for this is slightly lower than the cost to create one ECDSA signature, or makes half ECDH, so it is fast). Therefore, conceptually, you just have to save the private key, and the standard format for it is PKCS # 8 , which is supported by Java with java.security.spec.PKCS8EncodedKeySpec . Moreover, PKCS # 8 includes provisions for optionally encrypting a public key with a private key in the same blob, so it really looks like what you are looking for.
However, the hardest thing is to convince the cryptographic provider (for example, BouncyCastle) to extract the public key as such and / or double-check it. Apparently, if you create PKCS8EncodedKeySpec from an EC private key encoded in PKCS # 8, which also contains a public key, BouncyCastle will be kind enough to internally save a copy of the encoded public key and write it back if you decide to reinstall the private key in the format PKCS # 8. However, it does nothing with this; he treats it like an opaque blob.
Therefore, you must recount the public key. Making my way through the JCE and BouncyCastle APIs and unrealized bits, I found the following that seems to work (JDK 1.6.0_24, BouncyCastle 1.46):
import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Provider; import java.security.spec.PKCS8EncodedKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.JCEECPrivateKey; import org.bouncycastle.jce.provider.JCEECPublicKey; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.jce.spec.ECPublicKeySpec; // Create the provider and an appropriate key factory. Provider pp = new BouncyCastleProvider(); KeyFactory kf = KeyFactory.getInstance("EC", pp); // Decode the private key (read as a byte[] called 'buf'). PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(buf); PrivateKey sk = kf.generatePrivate(ks); // Recompute public key. JCEECPrivateKey priv = (JCEECPrivateKey)sk; ECParameterSpec params = priv.getParameters(); ECPublicKeySpec pubKS = new ECPublicKeySpec( params.getG().multiply(priv.getD()), params); PublicKey pk = kf.generatePublic(pubKS); // To reencode the private key. buf = kf.getKeySpec(sk, PKCS8EncodedKeySpec.class).getEncoded();
Conceptually, I should use kf.getkeySpec() with org.bouncycastle.jce.spec.ECPrivateKeySpec instead of ruthlessly pouring the private key into the JCEECPrivateKey class, but the clean method does not seem to be implemented in BouncyCastle yet.
source share