-3

is it possible to generate ecdsa 32-byte private key in java using KeyPairGenerator? I mean that keys.getPublic.getEncoded.length will return 32 I've tried to generate private key, but size is 144 bytes

//keys.getPrivate.getEncoded.length - 144 bytes
val ecSpec: ECNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("secp256k1")
val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "BC")
val secRandom = new SecureRandom()
keyPairGenerator.initialize(ecSpec, secRandom)
val keys = keyPairGenerator.generateKeyPair

//keys.getPrivate.getEncoded.length - 67 bytes
val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance("EC")
keyPairGenerator.initialize(256)
val keys = keyPairGenerator.generateKeyPair
  • 1
    Welcome to stackoverflow. Please take the [tour] of the site to understand how stackoverflow works and how to ask good questions. Then come back and [edit] your question. Include the code of what you've tried as a [mcve], plus any error messages. Ask specific questions. Most people are happy to help, but don't want to do your work for you. Questions like "how do I do x?" that don't show any research effort on your end are likely to get ignored. – Robert Sep 12 '18 at 16:32
  • You mean `.getPrivate` not `.getPublic`; a secp256k1 raw publickey (an uncompressed point) is 65 bytes not 32. – dave_thompson_085 Sep 12 '18 at 18:34

1 Answers1

1

The value returned from Java PrivateKey.getEncoded() is an encoded privatekey, as the name says. Specifically as documented in the superclass Key it is an ASN.1 (DER) encoding of PKCS#8 = Public-Key Cryptography Standard #8, Private Key Information Syntax. PKCS#8 handles privatekeys for a wide variety of different public-key algorithms and contains metadata in addition to the actual key, namely an 'AlgorithmIdentifier' which identifies the algorithm and any parameters of the algorithm; for the ECC algorithm(s) (ECDSA, ECDH, ECMQV and more share one key format) these parameters specify the elliptic curve group used, and although there are several options for this specification, in practice everyone, including here Java, uses the 'namedCurve' option which defines the curve group by an ASN.1 OID aka Object Identifier.

The PKCS#8 structure then contains the actual privatekey data, 'wrapped' in an OCTET STRING, in a format that varies depending on the algorithm. For ECC, this format is defined (AFAICT) in SEC1 by SECG/Certicom and contains the actual privatekey value (a number, expressed as an OCTET STRING) plus optionally the curve spec and the public key.

Your first code uses BouncyCastle, and Bouncy generates the encoding with the wrapped value including the optional curve spec and public key, making it longer.

Your second code uses by default the Oracle/Sun provider (SunEC), which generates the encoding without those options, but still including the required AlgorithmIdentifier making it longer than the actual privatekey value. It also uses a different curve: initializing a SunEC generator with the integer 256 chooses secp256r1 (aka P-256, prime256v1) NOT secp256k1. If you change this to use new ECGenParameterSpec("secp256k1") as the parameter then SunEC will also generate secp256k1, but without the options, giving a 64-byte encoding.

In both cases, if you want only the privatekey number, cast to java.security.interfaces.ECPrivateKey and use getS(). If you want the result in a byte/octet array, as is conventional, note BigInteger.toByteArray() returns a variable-length result and you often need to left zero trim or pad it.

And if you did want the publickey, it has a similar scheme using 'X.509' encoding which contains both an AlgorithmIdentifier and a BIT STRING wrapping the actual publickey value, and thus is longer than the raw publickey value. However in this case interfaces.ECPublicKey and spec.ECPoint won't construct the encoding for you; using the Bouncy-only types can be more convenient.

dave_thompson_085
  • 24,048
  • 4
  • 34
  • 52