whyoleg / cryptography-kotlin

Kotlin Multiplatform cryptography / crypto library
https://whyoleg.github.io/cryptography-kotlin/
Apache License 2.0
330 stars 20 forks source link

RAW decoding/encoding of ECDSA private keys #37

Closed morki closed 3 weeks ago

morki commented 3 months ago

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.

whyoleg commented 3 months ago

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:

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 3 months ago

Thank you for considering, just for reference, this is the original issue why I want to implement this: https://github.com/interaso/webpush/issues/22

whyoleg commented 3 weeks ago

It was fixed in https://github.com/whyoleg/cryptography-kotlin/commit/2dad24caaf84807f04c20e66557cc8994bd97ea7 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.