С теоретической точки зрения открытый ключ может быть пересчитан из закрытого ключа (вычислительные затраты для этого немного ниже, чем стоимость создания одной сигнатуры ECDSA или создания половины ECDH, поэтому это происходит быстро).Следовательно, концептуально вам нужно хранить только закрытый ключ, и стандартный формат для него - PKCS # 8 , который поддерживается Java с java.security.spec.PKCS8EncodedKeySpec
.Более того, формат PKCS # 8 включает в себя положения для необязательного кодирования открытого ключа вдоль закрытого ключа в том же самом двоичном объекте, так что это действительно похоже на то, что вы ищете.
Однако сложно убедитьпоставщик криптографии (например, BouncyCastle) для извлечения открытого ключа как такового и / или его повторного вычисления.Очевидно, что если вы создадите PKCS8EncodedKeySpec
из закрытого ключа EC с кодировкой PKCS # 8, который также содержит открытый ключ, BouncyCastle будет достаточно любезен, чтобы внутренне сохранить копию закодированного открытого ключа и записать ее обратно, если вы решите перекодироватьзакрытый ключ в формате PKCS # 8.Тем не менее, он ничего не делает с этим;он обрабатывает его как непрозрачный BLOB-объект.
Следовательно, вы должны пересчитать открытый ключ.Проходя через JCE и BouncyCastle API и нереализованные биты, я нашел следующее, которое работает (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();
Концептуально, я должен использовать kf.getkeySpec()
с org.bouncycastle.jce.spec.ECPrivateKeySpec
вместо того, чтобы безжалостно приводить закрытый ключ к классу JCEECPrivateKey
, но метод clean, похоже, еще не реализован в BouncyCastle.