Java >> Java tutorial >  >> Tag >> public

Sådan laver du en hoppeborg ECPublicKey

Generering af ECPublicKey ved hjælp af Bouncy Castle

Dette genererer den offentlige EC-nøgle som brugt i JCE/JCA. Bouncy Castle-udbyderen kan bruge disse softwarenøgler direkte. Ellers bruges Bouncy bare til at generere de parametre, der kræves for at generere den offentlige nøgle.

package nl.owlstead.stackoverflow;

import static java.nio.charset.StandardCharsets.US_ASCII;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;

import javax.crypto.Cipher;

import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.util.encoders.Hex;

public class ECPublicKeyFactory {

    public static void main(String[] args) throws Exception {

        String name = "secp256r1";

        Security.addProvider(new BouncyCastleProvider());

        // === NOT PART OF THE CODE, JUST GETTING TEST VECTOR ===
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
        ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(name);
        kpg.initialize(ecGenParameterSpec);
        ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic();
        byte[] x = key.getW().getAffineX().toByteArray();
        byte[] y = key.getW().getAffineY().toByteArray();

        // === here the magic happens ===
        KeyFactory eckf = KeyFactory.getInstance("EC");
        ECPoint point = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));
        ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(name);
        ECParameterSpec spec = new ECNamedCurveSpec(name, parameterSpec.getCurve(), parameterSpec.getG(), parameterSpec.getN(), parameterSpec.getH(), parameterSpec.getSeed());
        ECPublicKey ecPublicKey = (ECPublicKey) eckf.generatePublic(new ECPublicKeySpec(point, spec));
        System.out.println(ecPublicKey.getClass().getName());

        // === test 123 ===
        Cipher ecies = Cipher.getInstance("ECIESwithAES", "BC");
        ecies.init(Cipher.ENCRYPT_MODE, ecPublicKey);
        byte[] ct = ecies.doFinal("owlstead".getBytes(US_ASCII));
        System.out.println(Hex.toHexString(ct));
    }
}

Generering af Bouncy Castle ECPublicKeyParameters

Til at begynde med troede jeg, at en Bouncy Castle-specifik nøgle var påkrævet, så følgende kode genererer den offentlige EC-nøgle, som bruges i Bouncy Castle letvægts-API.

package nl.owlstead.stackoverflow;

import java.math.BigInteger;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

public class BC_EC_KeyCreator {

    public static void main(String[] args) throws Exception {

        String name = "secp256r1";

        // === NOT PART OF THE CODE, JUST GETTING TEST VECTOR ===
        Security.addProvider(new BouncyCastleProvider());
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
        kpg.initialize(new ECGenParameterSpec(name));
        ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic();
        byte[] x = key.getW().getAffineX().toByteArray();
        byte[] y = key.getW().getAffineY().toByteArray();

        // assumes that x and y are (unsigned) big endian encoded
        BigInteger xbi = new BigInteger(1, x);
        BigInteger ybi = new BigInteger(1, y);
        X9ECParameters x9 = ECNamedCurveTable.getByName(name);
        ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name);
        ECCurve curve = x9.getCurve();
        ECPoint point = curve.createPoint(xbi, ybi);
        ECNamedDomainParameters dParams = new ECNamedDomainParameters(oid,
                x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
        ECPublicKeyParameters pubKey = new ECPublicKeyParameters(point, dParams);
        System.out.println(pubKey);

        // some additional encoding tricks
        byte[] compressed = point.getEncoded(true);
        System.out.println(Hex.toHexString(compressed));
        byte[] uncompressed = point.getEncoded(false);
        System.out.println(Hex.toHexString(uncompressed));
    }
}

Dette var for det meste vanskeligt, fordi jeg ikke ønskede at inkludere nogen JCE-specifik kode og X9ECParameters er ikke en underklasse af ECDomainParameters . Så jeg brugte en konvertering til ECNamedDomainParameters kopieret fra et andet sted i kodebasen på Bouncy Castle.


I koden, der følger, encoded indeholder 0x04 efterfulgt af 32 bytes X, derefter 32 bytes Y.

Alternativt kan den indeholde 0x02 eller 0x03 (afhængig af tegnet for Y) efterfulgt af 32 bytes X.

public static ECPublicKey decodeKey(byte[] encoded) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException{
    ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec("secp256k1");
    KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC");
    ECCurve curve = params.getCurve();
    java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, params.getSeed());
    java.security.spec.ECPoint point = ECPointUtil.decodePoint(ellipticCurve, encoded);
    java.security.spec.ECParameterSpec params2 =EC5Util.convertSpec(ellipticCurve, params);
    java.security.spec.ECPublicKeySpec keySpec = new java.security.spec.ECPublicKeySpec(point,params2);
    return (ECPublicKey) fact.generatePublic(keySpec);
}

Java tag