[英]Codes to generate a public key in an elliptic curve algorithm using a given private key
[英]Generate AsymmetricCipherKeyPair elliptic curve from a given public key of a ceritificate
我正在尝试从证书的给定公钥生成椭圆曲线算法的私钥/公钥对。
我试图像这样实现它:
ECPublicKeyParameters pubKey = (ECPublicKeyParameters)cert.getPublicKey();
ECKeyPairGenerator gen = new ECKeyPairGenerator();
gen.init(new ECKeyGenerationParameters(pubKey.getParameters(), new SecureRandom()));
AsymmetricCipherKeyPair ks = gen.generateKeyPair();
但由于第一行,我得到了运行时转换错误:
Exception in thread "main" java.lang.ClassCastException: class sun.security.ec.ECPublicKeyImpl cannot be cast to class org.bouncycastle.crypto.params.ECPublicKeyParameters (sun.security.ec.ECPublicKeyImpl is in module jdk.crypto.ec of loader 'platform'; org.bouncycastle.crypto.params.ECPublicKeyParameters is in unnamed module of loader 'app')
cert
是 X509 类型的X509Certificate
证书我正在使用 bouncycastle 的bouncycastle
编辑:这是我尝试过的一个实现:
public CryptoContext(X509Certificate serverCertificate) {
ECPublicKeyParameters serverPubKey = getServerPublicKey(serverCertificate);
AsymmetricCipherKeyPair keyPair = generateKeyPair(serverPubKey);
byte[] sharedSecret = generateSharedSecret(serverPubKey, keyPair.getPrivate());
}
private ECPublicKeyParameters getServerPublicKey(X509Certificate cert) {
byte[] public_key_bytes = cert.getPublicKey().getEncoded();
ECPublicKeyParameters serverPubKey = null;
try {
serverPubKey = (ECPublicKeyParameters) PublicKeyFactory.createKey(public_key_bytes);
} catch (IOException e) {
e.printStackTrace();
}
return serverPubKey;
}
private AsymmetricCipherKeyPair generateKeyPair(ECPublicKeyParameters serverPubKey) {
ECKeyPairGenerator gen = new ECKeyPairGenerator();
gen.init(new ECKeyGenerationParameters(serverPubKey.getParameters(), new SecureRandom()));
AsymmetricCipherKeyPair keyPair = gen.generateKeyPair();
return keyPair;
}
private byte[] generateSharedSecret(ECPublicKeyParameters serverPubKey, AsymmetricKeyParameter clientPrivate) {
BasicAgreement agree = new ECDHBasicAgreement();
agree.init(clientPrivate);
BigInteger agreementValue = agree.calculateAgreement(serverPubKey);
byte[] sharedSecret = BigIntegers.asUnsignedByteArray(agree.getFieldSize(), agreementValue);
return sharedSecret;
}
但是当我尝试发回sharedSecret
时,我没有得到服务器的任何响应,因此我认为我在路上出了点问题。
sharedSecret 的生成是通过(您自己的)privateKey 和(第三方)公钥这两个组成部分完成的——这里的公钥取自(第三方)证书。 要获得 sharedSecret,您无需重建 keyPair(因为它们不是一对),而是使用带有实例“ECDH”的 KeyAgreement。
下面是一个完整的工作示例程序,它为双方(通常命名为“alice”和“bob”)获取 PEM 格式的私钥和证书。 双方都重建了 PrivateKey 和 PublicKey,最后使用“混合”密钥生成 sharedSecret(第一个共享密钥:来自 alice 的私钥和来自 bob 的公钥,第二个共享密钥:来自 bob 的私钥和来自爱丽丝)。 两个 sharedSecrets 是相同的,适用于密钥长度为 32 字节/256 位的 AES 加密。
另一个注意事项:此示例在没有 Bouncy Castle 依赖项的情况下运行。
没有适当的异常处理,使用固定(内置)私钥是不安全的。
密钥是使用 Java 密钥工具生成的,并使用 openssl 导出为 PEM 格式:
keytool -genkeypair -keysize 256 -sigalg SHA256withECDSA -keyalg EC -dname "cn=Alice" -alias alice -keypass apassword -keystore alice_keystore.pkcs12 -storetype pkcs12 -storepass apassword -validity 3650
openssl pkcs12 -in alice_keystore.pkcs12 -nokeys -out alice_crt.pem
openssl pkcs12 -in alice_keystore.pkcs12 -nodes -nocerts -out alice_privatekey.pem
[password: apassword]
结果:
Example Key Exchange EC Curves without BC
alice crt: [
Version: V3
Subject: CN=Alice
Signature Algorithm: SHA256withECDSA, OID = 1.2.840.10045.4.3.2
Key: Sun EC public key, 256 bits
public x coord: 53193002007562396012681859968974283073474881849394375511693405764629717680344
public y coord: 67114127612689688829965470157066506514867660192432128210506355717815080266028
parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)
Validity: [From: Sat Aug 08 18:16:47 CEST 2020,
To: Tue Aug 06 18:16:47 CEST 2030]
Issuer: CN=Alice
SerialNumber: [ 57c8f4ae]
...
bob crt: [
Version: V3
Subject: CN=Bob
Signature Algorithm: SHA256withECDSA, OID = 1.2.840.10045.4.3.2
Key: Sun EC public key, 256 bits
public x coord: 53218839282383347527983259020322984395517469483615530947798768625444790545484
public y coord: 50373539334339208285989254642248018747424962690612261530706567696443441910381
parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)
Validity: [From: Sat Aug 08 20:22:39 CEST 2020,
To: Tue Aug 06 20:22:39 CEST 2030]
Issuer: CN=Bob
SerialNumber: [ 5c814597]
...
alice & bob sharedSecret equals: true
sharedSecret length: 32 data: c4adaea9b1f3cdf8bede4f3f51546c8bb5a33158f8299e6692c20c2de6109c16
代码:
import javax.crypto.KeyAgreement;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.regex.Pattern;
public class EllipticCurveKeyExchange {
public static void main(String[] args) throws GeneralSecurityException, IOException {
System.out.println("Example Key Exchange EC Curves without BC");
// all keys are sample keys
// certificate and private key for alice
String alice_cert_pem = "-----BEGIN CERTIFICATE-----\n" +
"MIIBNjCB26ADAgECAgRXyPSuMAwGCCqGSM49BAMCBQAwEDEOMAwGA1UEAxMFQWxp\n" +
"Y2UwHhcNMjAwODA4MTYxNjQ3WhcNMzAwODA2MTYxNjQ3WjAQMQ4wDAYDVQQDEwVB\n" +
"bGljZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHWaLBYzJU0/WTsIWOXhQrNG\n" +
"NFypOpTI1UOO3k+S0YDYlGFABWPdALUfjk00SAsW5xpgEW2WRsnKgjO6IVMLKSyj\n" +
"ITAfMB0GA1UdDgQWBBQN9LQY8o7xlOWtJVmtAg84SZdz7jAMBggqhkjOPQQDAgUA\n" +
"A0gAMEUCIGwjEeUFk9Qv0dRvUsnJgmokpAfQ9ISfofkskanz8L9CAiEAvh7SbBd5\n" +
"A/50QbKp+73M+Sy1jmXqD+IEfkI0YDWtDac=\n" +
"-----END CERTIFICATE-----";
String alice_privateKey_pem = "-----BEGIN PRIVATE KEY-----\n" +
"MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCB+NAwfARVZ6KymEgd4\n" +
"D4DQjX0WomJDKZ7fUTDrNJtOqQ==\n" +
"-----END PRIVATE KEY-----";
CertificateFactory cf = CertificateFactory.getInstance("X.509");
ByteArrayInputStream bis_alice = new ByteArrayInputStream(loadPEM(alice_cert_pem));
X509Certificate alice_cert = (X509Certificate) cf.generateCertificate(bis_alice);
System.out.println("alice crt: " + alice_cert);
PublicKey alice_publicKey = alice_cert.getPublicKey();
KeyFactory kf = KeyFactory.getInstance("EC");
PrivateKey alice_privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(loadPEM(alice_privateKey_pem)));
System.out.println("alice publicKey: " + alice_publicKey);
System.out.println("alice privateKey: " + alice_privateKey);
// certificate and private key for bob
String bob_cert_pem = "-----BEGIN CERTIFICATE-----\n" +
"MIIBMzCB16ADAgECAgRcgUWXMAwGCCqGSM49BAMCBQAwDjEMMAoGA1UEAxMDQm9i\n" +
"MB4XDTIwMDgwODE4MjIzOVoXDTMwMDgwNjE4MjIzOVowDjEMMAoGA1UEAxMDQm9i\n" +
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdajLq/yS6RMr+Pj745/mZ3gEDin8\n" +
"Idea+8VfIMepLExvXmmzTun18700D8tFJAhRk7PgkoRhztGgbzrXIaOSbaMhMB8w\n" +
"HQYDVR0OBBYEFDJqdrcRZD7noaNlKcYncfO+YdDIMAwGCCqGSM49BAMCBQADSQAw\n" +
"RgIhAOW7Asmky4fHL4/luoc0F1IuDUhXtS8iASKAaYHL72m8AiEA5reQE+JK93l9\n" +
"5+oPb2wxhD7QINZxShleE7qjBngT6io=\n" +
"-----END CERTIFICATE-----";
String bob_privateKey_pem = "-----BEGIN PRIVATE KEY-----\n" +
"MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDv9KwdBlhxGukLkXp5\n" +
"UfMTddh+h00pEpMcvR3qsZYVyA==\n" +
"-----END PRIVATE KEY-----";
ByteArrayInputStream bis_bob = new ByteArrayInputStream(loadPEM(bob_cert_pem));
X509Certificate bob_cert = (X509Certificate) cf.generateCertificate(bis_bob);
System.out.println("bob crt: " + bob_cert);
PublicKey bob_publicKey = bob_cert.getPublicKey();
PrivateKey bob_privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(loadPEM(bob_privateKey_pem)));
System.out.println("bob publicKey: " + bob_publicKey);
System.out.println("bob privateKey: " + bob_privateKey);
// generate sharedSecret for alice & bob
byte[] alice_sharedSecret = createEcdhSharedSecret(alice_privateKey, bob_publicKey);
byte[] bob_sharedSecret = createEcdhSharedSecret(bob_privateKey, alice_publicKey);
System.out.println("\nalice & bob sharedSecret equals: " + Arrays.equals(alice_sharedSecret, bob_sharedSecret));
System.out.println("sharedSecret length: " + alice_sharedSecret.length + " data: " + bytesToHex(alice_sharedSecret));
}
// https://stackoverflow.com/a/49753179/8166854
private static byte[] loadPEM (String resource) throws IOException {
byte[] input = resource.getBytes(StandardCharsets.ISO_8859_1);
// URL url = getClass().getResource(resource);
// InputStream in = url.openStream();
ByteArrayInputStream in = new ByteArrayInputStream(input);
String pem = new String(in.readAllBytes(), StandardCharsets.ISO_8859_1);
Pattern parse = Pattern.compile("(?m)(?s)^---*BEGIN.*---*$(.*)^---*END.*---*$.*");
String encoded = parse.matcher(pem).replaceFirst("$1");
return Base64.getMimeDecoder().decode(encoded);
}
public static byte[] createEcdhSharedSecret(PrivateKey privateKey, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException {
KeyAgreement keyAgree = KeyAgreement.getInstance("ECDH");
keyAgree.init(privateKey);
keyAgree.doPhase(publicKey, true);
return keyAgree.generateSecret();
}
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();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.