存储 Diffie-Hellman 密钥对以便在 Java 的 KeyStore 中重复使用
Storing a Diffie-Hellman key pair for reuse in a KeyStore in Java
我目前正在编写一个加密 Java 程序,我为其实现了密钥交换,这样两个用户就可以使用该程序的 运行ning 实例(不必 运行 同时)可以就 AES 加密的共享密钥达成一致。我计划为此使用 Diffie Hellman 密钥交换协议。
因此,我通常遵循 this example by Oracle,并在程序的不同方法中添加了实现 Alice 和 Bob 的部分。在这个例子中,Alice 和 Bob 交换的是他们编码的 public keys
byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
分别。为了传输这些编码的 public 密钥,我将这些字节数组保存为文件,供每个用户将其传输给其他用户。
现在我想处理以下情况:启动密钥交换的用户,比如 Alice,在等待其他用户的响应时关闭了程序,将他们编码的 public 密钥作为文件发回。在重新启动程序时,Alice 想根据从 Bob 收到的 public 密钥和她自己的私钥计算共享密钥,在她关闭程序时,私钥必须存储在某个地方。因为我的程序已经使用了 PKCS12-KeyStore,所以我想我可以将 Diffie-Hellman 密钥对保存到那个 KeyStore。
因此,我遵循的方法,使用自签名X509证书来存储RSA密钥对。但是,对于 RSA 签名算法,这显然会引发错误 org.bouncycastle.operator.OperatorCreationException: cannot create signer: Supplied key (com.sun.crypto.provider.DHPrivateKey) is not a RSAPrivateKey instance
:
String signatureAlgorithm = "SHA256WithRSA";
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm)
.setProvider(bcProvider).build(keyPair.getPrivate());
在我用
初始化密钥对之后
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DH");
keyPairGen.initialize(bitLength);
KeyPair keyPair = keyPairGen.generateKeyPair();
现在要解决这个问题,有没有办法:
- 以不同方式签署 X509 证书,以便可以存储 Diffie-Hellman 密钥对?
- 使用不同的方法在 KeyStore 中存储 Diffie-Hellman 密钥对?
- 将 Diffie-Hellman 密钥对安全地存储在 KeyStore 之外的其他地方?
- 或者使用另一种密钥交换协议方式,同时要求将中间值存储在 KeyStore 中?
我在我的项目中使用了这个完整的示例解决方案,因此它可能对其他人有用。它使用 EC 密钥对(曲线 "secp256r1")和 ECDH 进行密钥交换。您需要 BouncyCastle 并注意没有适当的异常处理,并且 现有密钥库将被覆盖,恕不另行通知.
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import javax.crypto.KeyAgreement;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
public class StoreEcdhKeyInPKCS12KeystoreSO {
public static void main(String[] args) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, OperatorCreationException, CertificateException, KeyStoreException, IOException, UnrecoverableKeyException, InvalidKeySpecException, InvalidKeyException {
System.out.println("Storing a ECDH Keypair in a PKCS12 Keystore");
// you need BouncyCastle, get it from https://www.bouncycastle.org/latest_releases.html
Security.addProvider(new BouncyCastleProvider());
System.out.println("\nJava version: " + Runtime.version() + " BouncyCastle Version: " + Security.getProvider("BC"));
// ### WARNING: no exception handling, existing keystores will be overwritten without notice ###
String ecCurvename = "secp256r1";
// alice's credentials
String aliceKeystoreFilename = "alicekeystore.p12";
char[] aliceKeystoreEntryPassword = "aliceEntryPassword".toCharArray();
String aliceKeypairAlias = "aliceKeypairAlias";
char[] aliceKeypairPassword = "aliceKeypairPassword".toCharArray();
KeyPair aliceKeyPairGenerated;
PrivateKey alicePrivateKeyLoaded;
byte[] aliceReceivedPublicKeyFromBob;
byte[] aliceSharedSecret;
// bob's credentials
String bobKeystoreFilename = "bobkeystore.p12";
char[] bobKeystoreEntryPassword = "bobEntryPassword".toCharArray();
String bobKeypairAlias = "bobKeypairAlias";
char[] bobKeypairPassword = "bobKeypairPassword".toCharArray();
KeyPair bobKeyPairGenerated;
PrivateKey bobPrivateKeyLoaded;
byte[] bobReceivedPublicKeyFromAlice;
byte[] bobSharedSecret;
// alice start keypair generation, comment out if you still have a keystore with the keys
aliceKeyPairGenerated = generateEcdhKeyPair(ecCurvename);
// save keypair
storeEcdhKeypairInPKCS12Keystore(aliceKeystoreFilename, aliceKeystoreEntryPassword, aliceKeypairAlias, aliceKeypairPassword, aliceKeyPairGenerated);
System.out.println("alice has a new keystore: " + aliceKeystoreFilename);
// bob start keypair generation, comment out if you still have a keystore with the keys
bobKeyPairGenerated = generateEcdhKeyPair(ecCurvename);
storeEcdhKeypairInPKCS12Keystore(bobKeystoreFilename, bobKeystoreEntryPassword, bobKeypairAlias, bobKeypairPassword, bobKeyPairGenerated);
System.out.println("bob has a new keystore: " + bobKeystoreFilename);
// alice sends her public key to bob -e.g. you could code it with base64, here we're just cloning the key
bobReceivedPublicKeyFromAlice = aliceKeyPairGenerated.getPublic().getEncoded().clone();
// later on - bob received the the public key from alice and loads his key from keystore
bobPrivateKeyLoaded = loadEcdhPrivateKeyFromPKCS12Keystore(bobKeystoreFilename, bobKeystoreEntryPassword, bobKeypairAlias, bobKeypairPassword);
// bob creates the shared secret with public key from alice
bobSharedSecret = createEcdhSharedSecret(bobPrivateKeyLoaded, bobReceivedPublicKeyFromAlice);
System.out.println("SharedSecret Bob: " + bytesToHex(bobSharedSecret));
// bob sends his public key to alice -e.g. you could code it with base64, here we're just cloning the key
aliceReceivedPublicKeyFromBob = loadEcdhPublicKeyFromPKCS12Keystore(bobKeystoreFilename, bobKeystoreEntryPassword, bobKeypairAlias, bobKeypairPassword).getEncoded().clone();
// alice loads her private key from keystore and generates the SecretShare
alicePrivateKeyLoaded = loadEcdhPrivateKeyFromPKCS12Keystore(aliceKeystoreFilename, aliceKeystoreEntryPassword, aliceKeypairAlias, aliceKeypairPassword);
aliceSharedSecret = createEcdhSharedSecret(alicePrivateKeyLoaded, aliceReceivedPublicKeyFromBob);
System.out.println("SharedSecret Alice: " + bytesToHex(aliceSharedSecret));
// check that both SecretShare's are equal
System.out.println("Compare aliceSharedSecret and bobSharedSecret: " + Arrays.equals(aliceSharedSecret, bobSharedSecret));
// do what ever you want with your SharedSecret, e.g. shorten it using SHA256 for a AES encryption key
}
public static KeyPair generateEcdhKeyPair(String curvenameString) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "SunEC");
ECGenParameterSpec ecParameterSpec = new ECGenParameterSpec(curvenameString);
keyPairGenerator.initialize(ecParameterSpec);
return keyPairGenerator.genKeyPair();
}
public static void storeEcdhKeypairInPKCS12Keystore(String filename, char[] entryPassword, String keypairAlias, char[] keypairPassword, KeyPair keypair) throws CertificateException, OperatorCreationException, KeyStoreException, IOException, NoSuchAlgorithmException {
// --- create the self signed cert
java.security.cert.Certificate cert = createSelfSigned(keypair);
// --- create a new pkcs12 key store in memory
KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
pkcs12.load(null, null);
// --- create entry in PKCS12
pkcs12.setKeyEntry(keypairAlias, keypair.getPrivate(), keypairPassword, new Certificate[]{cert});
// --- store PKCS#12 as file
try (FileOutputStream p12 = new FileOutputStream(filename)) {
pkcs12.store(p12, entryPassword);
} catch (NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
}
public static PrivateKey loadEcdhPrivateKeyFromPKCS12Keystore(String filename, char[] entryPassword, String keypairAlias, char[] keypairPassword) throws CertificateException, OperatorCreationException, KeyStoreException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
// --- read PKCS#12 as file
KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
try (FileInputStream p12 = new FileInputStream(filename)) {
pkcs12.load(p12, entryPassword);
}
// --- retrieve private key
return (PrivateKey) pkcs12.getKey(keypairAlias, keypairPassword);
}
public static PublicKey loadEcdhPublicKeyFromPKCS12Keystore(String filename, char[] entryPassword, String keypairAlias, char[] keypairPassword) throws CertificateException, OperatorCreationException, KeyStoreException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
// --- read PKCS#12 as file
KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
try (FileInputStream p12 = new FileInputStream(filename)) {
pkcs12.load(p12, entryPassword);
}
// --- retrieve public key
Certificate cert = pkcs12.getCertificate(keypairAlias);
return cert.getPublicKey();
}
public static byte[] createEcdhSharedSecret(PrivateKey privateKey, byte[] publicKeyByte) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
KeyAgreement keyAgree = KeyAgreement.getInstance("ECDH");
keyAgree.init(privateKey);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyByte);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
keyAgree.doPhase(publicKey, true);
return keyAgree.generateSecret();
}
private static X509Certificate createSelfSigned(KeyPair pair) throws OperatorCreationException, CertificateException {
// source: author Maarten Bodewes
X500Name dnName = new X500Name("CN=publickeystorageonly");
BigInteger certSerialNumber = BigInteger.ONE;
Date startDate = new Date(); // now
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.add(Calendar.YEAR, 100); // 100 years validity
Date endDate = calendar.getTime();
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithECDSA").build(pair.getPrivate());
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, pair.getPublic());
return new JcaX509CertificateConverter().getCertificate(certBuilder.build(contentSigner));
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}
这是小输出:
Storing a ECDH Keypair in a PKCS12 Keystore
Java version: 11.0.6+8-b520.43 BouncyCastle Version: BC version 1.65
alice has a new keystore: alicekeystore.p12
bob has a new keystore: bobkeystore.p12
SharedSecret Bob: ab457b66687fcaefca6d648d428a66b1642355be6c8fb5190624043a7de2215c
SharedSecret Alice: ab457b66687fcaefca6d648d428a66b1642355be6c8fb5190624043a7de2215c
Compare aliceSharedSecret and bobSharedSecret: true
我目前正在编写一个加密 Java 程序,我为其实现了密钥交换,这样两个用户就可以使用该程序的 运行ning 实例(不必 运行 同时)可以就 AES 加密的共享密钥达成一致。我计划为此使用 Diffie Hellman 密钥交换协议。
因此,我通常遵循 this example by Oracle,并在程序的不同方法中添加了实现 Alice 和 Bob 的部分。在这个例子中,Alice 和 Bob 交换的是他们编码的 public keys
byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
分别。为了传输这些编码的 public 密钥,我将这些字节数组保存为文件,供每个用户将其传输给其他用户。
现在我想处理以下情况:启动密钥交换的用户,比如 Alice,在等待其他用户的响应时关闭了程序,将他们编码的 public 密钥作为文件发回。在重新启动程序时,Alice 想根据从 Bob 收到的 public 密钥和她自己的私钥计算共享密钥,在她关闭程序时,私钥必须存储在某个地方。因为我的程序已经使用了 PKCS12-KeyStore,所以我想我可以将 Diffie-Hellman 密钥对保存到那个 KeyStore。
因此,我遵循org.bouncycastle.operator.OperatorCreationException: cannot create signer: Supplied key (com.sun.crypto.provider.DHPrivateKey) is not a RSAPrivateKey instance
:
String signatureAlgorithm = "SHA256WithRSA";
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm)
.setProvider(bcProvider).build(keyPair.getPrivate());
在我用
初始化密钥对之后KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DH");
keyPairGen.initialize(bitLength);
KeyPair keyPair = keyPairGen.generateKeyPair();
现在要解决这个问题,有没有办法:
- 以不同方式签署 X509 证书,以便可以存储 Diffie-Hellman 密钥对?
- 使用不同的方法在 KeyStore 中存储 Diffie-Hellman 密钥对?
- 将 Diffie-Hellman 密钥对安全地存储在 KeyStore 之外的其他地方?
- 或者使用另一种密钥交换协议方式,同时要求将中间值存储在 KeyStore 中?
我在我的项目中使用了这个完整的示例解决方案,因此它可能对其他人有用。它使用 EC 密钥对(曲线 "secp256r1")和 ECDH 进行密钥交换。您需要 BouncyCastle 并注意没有适当的异常处理,并且 现有密钥库将被覆盖,恕不另行通知.
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import javax.crypto.KeyAgreement;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
public class StoreEcdhKeyInPKCS12KeystoreSO {
public static void main(String[] args) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, OperatorCreationException, CertificateException, KeyStoreException, IOException, UnrecoverableKeyException, InvalidKeySpecException, InvalidKeyException {
System.out.println("Storing a ECDH Keypair in a PKCS12 Keystore");
// you need BouncyCastle, get it from https://www.bouncycastle.org/latest_releases.html
Security.addProvider(new BouncyCastleProvider());
System.out.println("\nJava version: " + Runtime.version() + " BouncyCastle Version: " + Security.getProvider("BC"));
// ### WARNING: no exception handling, existing keystores will be overwritten without notice ###
String ecCurvename = "secp256r1";
// alice's credentials
String aliceKeystoreFilename = "alicekeystore.p12";
char[] aliceKeystoreEntryPassword = "aliceEntryPassword".toCharArray();
String aliceKeypairAlias = "aliceKeypairAlias";
char[] aliceKeypairPassword = "aliceKeypairPassword".toCharArray();
KeyPair aliceKeyPairGenerated;
PrivateKey alicePrivateKeyLoaded;
byte[] aliceReceivedPublicKeyFromBob;
byte[] aliceSharedSecret;
// bob's credentials
String bobKeystoreFilename = "bobkeystore.p12";
char[] bobKeystoreEntryPassword = "bobEntryPassword".toCharArray();
String bobKeypairAlias = "bobKeypairAlias";
char[] bobKeypairPassword = "bobKeypairPassword".toCharArray();
KeyPair bobKeyPairGenerated;
PrivateKey bobPrivateKeyLoaded;
byte[] bobReceivedPublicKeyFromAlice;
byte[] bobSharedSecret;
// alice start keypair generation, comment out if you still have a keystore with the keys
aliceKeyPairGenerated = generateEcdhKeyPair(ecCurvename);
// save keypair
storeEcdhKeypairInPKCS12Keystore(aliceKeystoreFilename, aliceKeystoreEntryPassword, aliceKeypairAlias, aliceKeypairPassword, aliceKeyPairGenerated);
System.out.println("alice has a new keystore: " + aliceKeystoreFilename);
// bob start keypair generation, comment out if you still have a keystore with the keys
bobKeyPairGenerated = generateEcdhKeyPair(ecCurvename);
storeEcdhKeypairInPKCS12Keystore(bobKeystoreFilename, bobKeystoreEntryPassword, bobKeypairAlias, bobKeypairPassword, bobKeyPairGenerated);
System.out.println("bob has a new keystore: " + bobKeystoreFilename);
// alice sends her public key to bob -e.g. you could code it with base64, here we're just cloning the key
bobReceivedPublicKeyFromAlice = aliceKeyPairGenerated.getPublic().getEncoded().clone();
// later on - bob received the the public key from alice and loads his key from keystore
bobPrivateKeyLoaded = loadEcdhPrivateKeyFromPKCS12Keystore(bobKeystoreFilename, bobKeystoreEntryPassword, bobKeypairAlias, bobKeypairPassword);
// bob creates the shared secret with public key from alice
bobSharedSecret = createEcdhSharedSecret(bobPrivateKeyLoaded, bobReceivedPublicKeyFromAlice);
System.out.println("SharedSecret Bob: " + bytesToHex(bobSharedSecret));
// bob sends his public key to alice -e.g. you could code it with base64, here we're just cloning the key
aliceReceivedPublicKeyFromBob = loadEcdhPublicKeyFromPKCS12Keystore(bobKeystoreFilename, bobKeystoreEntryPassword, bobKeypairAlias, bobKeypairPassword).getEncoded().clone();
// alice loads her private key from keystore and generates the SecretShare
alicePrivateKeyLoaded = loadEcdhPrivateKeyFromPKCS12Keystore(aliceKeystoreFilename, aliceKeystoreEntryPassword, aliceKeypairAlias, aliceKeypairPassword);
aliceSharedSecret = createEcdhSharedSecret(alicePrivateKeyLoaded, aliceReceivedPublicKeyFromBob);
System.out.println("SharedSecret Alice: " + bytesToHex(aliceSharedSecret));
// check that both SecretShare's are equal
System.out.println("Compare aliceSharedSecret and bobSharedSecret: " + Arrays.equals(aliceSharedSecret, bobSharedSecret));
// do what ever you want with your SharedSecret, e.g. shorten it using SHA256 for a AES encryption key
}
public static KeyPair generateEcdhKeyPair(String curvenameString) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "SunEC");
ECGenParameterSpec ecParameterSpec = new ECGenParameterSpec(curvenameString);
keyPairGenerator.initialize(ecParameterSpec);
return keyPairGenerator.genKeyPair();
}
public static void storeEcdhKeypairInPKCS12Keystore(String filename, char[] entryPassword, String keypairAlias, char[] keypairPassword, KeyPair keypair) throws CertificateException, OperatorCreationException, KeyStoreException, IOException, NoSuchAlgorithmException {
// --- create the self signed cert
java.security.cert.Certificate cert = createSelfSigned(keypair);
// --- create a new pkcs12 key store in memory
KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
pkcs12.load(null, null);
// --- create entry in PKCS12
pkcs12.setKeyEntry(keypairAlias, keypair.getPrivate(), keypairPassword, new Certificate[]{cert});
// --- store PKCS#12 as file
try (FileOutputStream p12 = new FileOutputStream(filename)) {
pkcs12.store(p12, entryPassword);
} catch (NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
}
public static PrivateKey loadEcdhPrivateKeyFromPKCS12Keystore(String filename, char[] entryPassword, String keypairAlias, char[] keypairPassword) throws CertificateException, OperatorCreationException, KeyStoreException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
// --- read PKCS#12 as file
KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
try (FileInputStream p12 = new FileInputStream(filename)) {
pkcs12.load(p12, entryPassword);
}
// --- retrieve private key
return (PrivateKey) pkcs12.getKey(keypairAlias, keypairPassword);
}
public static PublicKey loadEcdhPublicKeyFromPKCS12Keystore(String filename, char[] entryPassword, String keypairAlias, char[] keypairPassword) throws CertificateException, OperatorCreationException, KeyStoreException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
// --- read PKCS#12 as file
KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
try (FileInputStream p12 = new FileInputStream(filename)) {
pkcs12.load(p12, entryPassword);
}
// --- retrieve public key
Certificate cert = pkcs12.getCertificate(keypairAlias);
return cert.getPublicKey();
}
public static byte[] createEcdhSharedSecret(PrivateKey privateKey, byte[] publicKeyByte) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
KeyAgreement keyAgree = KeyAgreement.getInstance("ECDH");
keyAgree.init(privateKey);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyByte);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
keyAgree.doPhase(publicKey, true);
return keyAgree.generateSecret();
}
private static X509Certificate createSelfSigned(KeyPair pair) throws OperatorCreationException, CertificateException {
// source: author Maarten Bodewes
X500Name dnName = new X500Name("CN=publickeystorageonly");
BigInteger certSerialNumber = BigInteger.ONE;
Date startDate = new Date(); // now
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.add(Calendar.YEAR, 100); // 100 years validity
Date endDate = calendar.getTime();
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithECDSA").build(pair.getPrivate());
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, pair.getPublic());
return new JcaX509CertificateConverter().getCertificate(certBuilder.build(contentSigner));
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}
这是小输出:
Storing a ECDH Keypair in a PKCS12 Keystore
Java version: 11.0.6+8-b520.43 BouncyCastle Version: BC version 1.65
alice has a new keystore: alicekeystore.p12
bob has a new keystore: bobkeystore.p12
SharedSecret Bob: ab457b66687fcaefca6d648d428a66b1642355be6c8fb5190624043a7de2215c
SharedSecret Alice: ab457b66687fcaefca6d648d428a66b1642355be6c8fb5190624043a7de2215c
Compare aliceSharedSecret and bobSharedSecret: true