1

I am trying to generate ECDSA key pair using SpongyCastle in Android. This is the code:

static {
    Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}

public static KeyPair generate() {
        ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("prime256v1");
        KeyPairGenerator generator = KeyPairGenerator.getInstance("ECDSA", "SC");
        generator.initialize(ecSpec, new SecureRandom());
        KeyPair keyPair = g.generateKeyPair();
        Log.i(TAG, "EC Pub Key generated: " + utils.bytesToHex(keyPair.getPublic().getEncoded()));
        Log.i(TAG, "EC Private Key generated: " + utils.bytesToHex(keyPair.getPrivate().getEncoded()));            
       return generator.generateKeyPair();
}

Something is wrong since I always get something like that example of Public Key:

3059301306072A8648CE3D020106082A8648CE3D03010703420004483ABA9F322240010ECF00E818C041A60FE71A2BD64C64CD5A60519985F110AEDE6308027D2730303F5E2478F083C7F5BB683DCAC22BFEB62F3A48BD01009F40

and Private Key:

308193020100301306072A8648CE3D020106082A8648CE3D030107047930770201010420219AB4B3701630973A4B2917D53F69A4BE6DAD61F48016BFEF147B2999575CB2A00A06082A8648CE3D030107A14403420004483ABA9F322240010ECF00E818C041A60FE71A2BD64C64CD5A60519985F110AEDE6308027D2730303F5E2478F083C7F5BB683DCAC22BFEB62F3A48BD01009F40

The site ECDSA sample give Invalid ECDSA signature, and them seems really very different from that smaller Private Key and always starting with "04" Public Key generated in the same site.

Also, my backend verification gives me the error "Invalid point encoding 0x30"

The backend Java method check is:

public ECPublicKey getPublicKeyFromHex(String publicKeyHex)
        throws NoSuchAlgorithmException, DecoderException, ApplicationGenericException {
    byte[] rawPublicKey = Hex.decodeHex(publicKeyHex.toCharArray());
    ECPublicKey ecPublicKey = null;
    KeyFactory kf = null;

    ECNamedCurveParameterSpec ecNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("prime256v1");
    ECCurve curve = ecNamedCurveParameterSpec.getCurve();
    EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, ecNamedCurveParameterSpec.getSeed());
    java.security.spec.ECPoint ecPoint = ECPointUtil.decodePoint(ellipticCurve, rawPublicKey);
    java.security.spec.ECParameterSpec ecParameterSpec = EC5Util.convertSpec(ellipticCurve,
            ecNamedCurveParameterSpec);
    java.security.spec.ECPublicKeySpec publicKeySpec = new java.security.spec.ECPublicKeySpec(ecPoint,
            ecParameterSpec);

    kf = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());

    try {
        ecPublicKey = (ECPublicKey) kf.generatePublic(publicKeySpec);
    } catch (Exception e) {
        throw new ApplicationGenericException(e.getMessage(), e.getCause());
    }

    return ecPublicKey;
}
Justinas Jakavonis
  • 8,220
  • 10
  • 69
  • 114
snewtMs
  • 61
  • 1
  • 2
  • 6
  • Possible duplicate of [How can I generate a valid ECDSA EC key pair?](http://stackoverflow.com/questions/40155888/how-can-i-generate-a-valid-ecdsa-ec-key-pair) – mikeazo Oct 20 '16 at 13:30
  • If anyone interested to use [Bouncy Castle Provider](https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15to18) to generate the keypair on Android, refer the [stackoverflow post](https://stackoverflow.com/a/66267459/3049065). – Mahendran Sakkarai Feb 18 '21 at 20:27

1 Answers1

0

Convert generated public key to decoded bytes array or hex string:

public String getPublicKeyAsHex(PublicKey publicKey){

    ECPublicKey ecPublicKey = (ECPublicKey)publicKey;
    ECPoint ecPoint = ecPublicKey.getW();

    byte[] publicKeyBytes = new byte[PUBLIC_KEY_LENGTH];
    writeToStream(publicKeyBytes, 0, ecPoint.getAffineX(), PRIVATE_KEY_LENGTH);
    writeToStream(publicKeyBytes, PRIVATE_KEY_LENGTH, ecPoint.getAffineY(), PRIVATE_KEY_LENGTH);

    String hex = Hex.toHexString(publicKeyBytes);

    logger.debug("Public key bytes: " + Arrays.toString(publicKeyBytes));
    logger.debug("Public key hex: " + hex);

    return hex;
}

private void writeToStream(byte[] stream, int start, BigInteger value, int size) {
    byte[] data = value.toByteArray();
    int length = Math.min(size, data.length);
    int writeStart = start + size - length;
    int readStart = data.length - length;
    System.arraycopy(data, readStart, stream, writeStart, length);
}

Convert decoded bytes array back to PublicKey:

KeyFactory factory = KeyFactory.getInstance(ALGORITHM, ALGORITHM_PROVIDER);

ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(CURVE);

ECNamedCurveSpec params = new ECNamedCurveSpec(CURVE, spec.getCurve(), spec.getG(), spec.getN());

BigInteger xCoordinate = new BigInteger(1, Arrays.copyOfRange(decodedPublicKey, 0, PRIVATE_KEY_LENGTH));
BigInteger yCoordinate = new BigInteger(1, Arrays.copyOfRange(decodedPublicKey, PRIVATE_KEY_LENGTH, PUBLIC_KEY_LENGTH));
java.security.spec.ECPoint w = new java.security.spec.ECPoint(xCoordinate, yCoordinate);

PublicKey encodedPublicKey = factory.generatePublic(new java.security.spec.ECPublicKeySpec(w, params));
Justinas Jakavonis
  • 8,220
  • 10
  • 69
  • 114