whyoleg/cryptography-kotlin

RAW decoding/encoding of ECDSA private keys

morki opened this issue · 3 comments

morki commented

Please, could be the "RAW" encoding of private keys added?

In Java I am now using this in my webpush library to allow decoding private keys in format compatible with other libraries:

/**
 * Standard name for the secp256r1 elliptic curve.
 */
private const val CURVE = "secp256r1"

/**
 * The ECParameterSpec for the secp256r1 elliptic curve.
 *
 * This variable represents the parameters for the secp256r1 elliptic curve,
 * which is also known as the P-256 curve. It is commonly used in cryptographic
 * algorithms such as the Elliptic Curve Digital Signature Algorithm (ECDSA).
 */
private val secp256r1parameterSpec: ECParameterSpec = AlgorithmParameters.getInstance("EC").run {
    init(ECGenParameterSpec(CURVE))
    getParameterSpec(ECParameterSpec::class.java)
}

/**
 * Generate an EC private key from uncompressed bytes.
 *
 * @param bytes The uncompressed bytes representing the private key.
 * @return The generated EC private key.
 */
internal fun generatePrivateKeyFromUncompressedBytes(bytes: ByteArray): ECPrivateKey {
    return KeyFactory.getInstance("EC").run {
        generatePrivate(ECPrivateKeySpec(BigInteger(bytes), secp256r1parameterSpec)) as ECPrivateKey
    }
}

I am trying to convert the library to multiplaform, so I am finding how to do it with your library but I could not see RAW encoding in ECDSA.PrivateKey.

Thank you very much for considering this.

Hey!
AFAIK EC private key encoding via just secret value is not that popular comparing to RAW public key encoding. Also, there are different formats for raw encoding of EC private keys.
F.e Apple Security framework cryptography specifies:

  • For an elliptic curve public key, the format follows the ANSI X9.63 standard using a byte string of 04 || X || Y.
  • For an elliptic curve private key, the output is formatted as the public key concatenated with the big endian encoding of the secret scalar, or 04 || X || Y || K.

Still, looks like CryptoKit do support RAW encoding. So looks like it would be nice to add it.
ANSI X9.63 private key encoding will not be supported for now, as it's not possible to support it in JDK (only with BouncyCastle) because there is no possibility to get public key from private key via public APIs, I tried.

Until it will be implemented, it's possible to use EcPrivateKey and ASN.1 module to create PrivateKey.Format.DER.SEC1 (or even PKCS8), like this:

DER.encodeToByteArray(EcPrivateKey(1, PRIVATE_KEY_BYTE_ARRAY, EcParameters(ObjectIdentifier.secp256r1)))
morki commented

Thank you for considering, just for reference, this is the original issue why I want to implement this: interaso/webpush#22

It was fixed in 2dad24c and will be available in 0.4.0.
Note: RAW decoding of ECDSA private key will not be supported with Apple provider because of the underlying API limitations.