繁体   English   中英

从证书的给定公钥生成 AsymmetricCipherKeyPair 椭圆曲线

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM