我想要生成一次密钥对并重用它.
public static KeyPair generateKeyPair() throws Exception { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(2048,new SecureRandom()); KeyPair pair = generator.generateKeyPair(); return pair; }
我该怎么做?
解决方法
这里有一个问题:Java的重点几乎完全在于TLS和实现TLS所需的加密.对于TLS,需要私钥和证书.所以你会遇到这样的情况:
>必须生成(伪造)自签名证书以使用您的公钥或;
>必须找到另一种存储没有证书的私钥的方法.
但是,使用(2.),您很快就会得到一种不兼容的方法.如果你想这样做,你可以创建一个使用PBE / CBC加密的PKCS#8加密私钥.
所以这里有一些代码来创建自签名证书并使用它来存储密钥.注意到期日期,您可以将其设置为100年以保证安全(或者您实际上可以进行一些密钥管理).
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.KeyStore.Entry; import java.security.KeyStore.PrivateKeyEntry; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Provider; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.UnrecoverableEntryException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.Calendar; import java.util.Date; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; public class StoreKeyPair { public static KeyPair generateKeyPair() throws Exception { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(2048,new SecureRandom()); KeyPair pair = generator.generateKeyPair(); return pair; } public static Certificate selfSign(KeyPair keyPair,String subjectDN) throws OperatorCreationException,CertificateException,IOException { Provider bcProvider = new BouncyCastleProvider(); Security.addProvider(bcProvider); long now = System.currentTimeMillis(); Date startDate = new Date(now); X500Name dnName = new X500Name(subjectDN); // Using the current timestamp as the certificate serial number BigInteger certSerialNumber = new BigInteger(Long.toString(now)); Calendar calendar = Calendar.getInstance(); calendar.setTime(startDate); // 1 Yr validity calendar.add(Calendar.YEAR,1); Date endDate = calendar.getTime(); // Use appropriate signature algorithm based on your keyPair algorithm. String signatureAlgorithm = "SHA256WithRSA"; SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair .getPublic().getEncoded()); X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(dnName,certSerialNumber,startDate,endDate,dnName,subjectPublicKeyInfo); ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider( bcProvider).build(keyPair.getPrivate()); X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner); Certificate selfSignedCert = new JcaX509CertificateConverter() .getCertificate(certificateHolder); return selfSignedCert; } public static void main(String[] args) throws Exception { KeyPair generatedKeyPair = generateKeyPair(); String filename = "test_gen_self_signed.pkcs12"; char[] password = "test".tocharArray(); storeToPKCS12(filename,password,generatedKeyPair); KeyPair retrievedKeyPair = loadFromPKCS12(filename,password); // you can validate by generating a signature and verifying it or by // comparing the moduli by first casting to RSAPublicKey,e.g.: RSAPublicKey pubKey = (RSAPublicKey) generatedKeyPair.getPublic(); RSAPrivateKey privKey = (RSAPrivateKey) retrievedKeyPair.getPrivate(); System.out.println(pubKey.getModulus().equals(privKey.getModulus())); } private static KeyPair loadFromPKCS12(String filename,char[] password) throws KeyStoreException,NoSuchAlgorithmException,FileNotFoundException,IOException,UnrecoverableEntryException { KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12"); try (FileInputStream fis = new FileInputStream(filename);) { pkcs12KeyStore.load(fis,password); } KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(password); Entry entry = pkcs12KeyStore.getEntry("owlstead",param); if (!(entry instanceof PrivateKeyEntry)) { throw new KeyStoreException("That's not a private key!"); } PrivateKeyEntry privKeyEntry = (PrivateKeyEntry) entry; PublicKey publicKey = privKeyEntry.getCertificate().getPublicKey(); PrivateKey privateKey = privKeyEntry.getPrivateKey(); return new KeyPair(publicKey,privateKey); } private static void storeToPKCS12( String filename,char[] password,KeyPair generatedKeyPair) throws KeyStoreException,OperatorCreationException { Certificate selfSignedCertificate = selfSign(generatedKeyPair,"CN=owlstead"); KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12"); pkcs12KeyStore.load(null,null); KeyStore.Entry entry = new PrivateKeyEntry(generatedKeyPair.getPrivate(),new Certificate[] { selfSignedCertificate }); KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(password); pkcs12KeyStore.setEntry("owlstead",entry,param); try (FileOutputStream fos = new FileOutputStream(filename)) { pkcs12KeyStore.store(fos,password); } } }
请注意,我太懒了,无法正确处理异常.
此代码使用稍微修改过的this answer版本,请参阅我的注释,了解我更改代码的原因.