All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmMain.algorithms.JdkEcdsa.kt Maven / Gradle / Ivy

/*
 * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
 */

package dev.whyoleg.cryptography.providers.jdk.algorithms

import dev.whyoleg.cryptography.*
import dev.whyoleg.cryptography.algorithms.asymmetric.*
import dev.whyoleg.cryptography.algorithms.digest.*
import dev.whyoleg.cryptography.operations.signature.*
import dev.whyoleg.cryptography.providers.jdk.*
import dev.whyoleg.cryptography.providers.jdk.materials.*
import dev.whyoleg.cryptography.providers.jdk.operations.*
import dev.whyoleg.cryptography.serialization.pem.*
import java.security.interfaces.*

internal class JdkEcdsa(state: JdkCryptographyState) : JdkEc(state), ECDSA {
    override fun JPublicKey.convert(): ECDSA.PublicKey = EcdsaPublicKey(state, this)
    override fun JPrivateKey.convert(): ECDSA.PrivateKey = EcdsaPrivateKey(state, this)
    override fun JKeyPair.convert(): ECDSA.KeyPair = EcdsaKeyPair(public.convert(), private.convert())
}

private class EcdsaKeyPair(
    override val publicKey: ECDSA.PublicKey,
    override val privateKey: ECDSA.PrivateKey,
) : ECDSA.KeyPair

private class EcdsaPublicKey(
    private val state: JdkCryptographyState,
    private val key: JPublicKey,
) : ECDSA.PublicKey, JdkEncodableKey(key, "EC") {
    override fun signatureVerifier(digest: CryptographyAlgorithmId, format: ECDSA.SignatureFormat): SignatureVerifier {
        return JdkSignatureVerifier(state, key, digest.hashAlgorithmName() + "withECDSA" + format.algorithmSuffix(), null)
    }

    override fun encodeToBlocking(format: EC.PublicKey.Format): ByteArray = when (format) {
        EC.PublicKey.Format.JWK -> error("$format is not supported")
        EC.PublicKey.Format.RAW -> {
            key as ECPublicKey

            val point = key.w
            val fieldSize = (key.params.curve.field.fieldSize + 7) / 8
            val output = ByteArray(fieldSize * 2 + 1)
            output[0] = 4

            val x = point.affineX.toByteArray().trimLeadingZeros()
            val y = point.affineY.toByteArray().trimLeadingZeros()
            check(x.size <= fieldSize && y.size <= fieldSize)

            x.copyInto(output, fieldSize - x.size + 1)
            y.copyInto(output, fieldSize * 2 - y.size + 1)

            output
        }
        EC.PublicKey.Format.DER -> encodeToDer()
        EC.PublicKey.Format.PEM -> wrapPem(PemLabel.PublicKey, encodeToDer())
    }
}

private class EcdsaPrivateKey(
    private val state: JdkCryptographyState,
    private val key: JPrivateKey,
) : ECDSA.PrivateKey, JdkEncodableKey(key, "EC") {
    override fun signatureGenerator(digest: CryptographyAlgorithmId, format: ECDSA.SignatureFormat): SignatureGenerator {
        return JdkSignatureGenerator(state, key, digest.hashAlgorithmName() + "withECDSA" + format.algorithmSuffix(), null)
    }

    override fun encodeToBlocking(format: EC.PrivateKey.Format): ByteArray = when (format) {
        EC.PrivateKey.Format.JWK -> error("$format is not supported")
        EC.PrivateKey.Format.DER -> encodeToDer()
        EC.PrivateKey.Format.PEM -> wrapPem(PemLabel.PrivateKey, encodeToDer())
    }
}

private fun ECDSA.SignatureFormat.algorithmSuffix() = when (this) {
    ECDSA.SignatureFormat.RAW -> "inP1363Format"
    ECDSA.SignatureFormat.DER -> ""
}

private fun ByteArray.trimLeadingZeros(): ByteArray {
    val firstNonZeroIndex = indexOfFirst { it != 0.toByte() }
    if (firstNonZeroIndex == -1) return this
    return copyOfRange(firstNonZeroIndex, size)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy