Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ internal class JdkCryptographyProvider(provider: Provider?) : CryptographyProvid
RSA.PKCS1 -> JdkRsaPkcs1(state)
RSA.RAW -> JdkRsaRaw(state)
ECDSA -> JdkEcdsa(state)
EdDSA -> JdkEdDSA(state)
ECDH -> JdkEcdh(state)
XDH -> JdkXDH(state)
PBKDF2 -> JdkPbkdf2(state)
HKDF -> JdkHkdf(state, this)
else -> null
Expand Down
109 changes: 109 additions & 0 deletions cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkEdDSA.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package dev.whyoleg.cryptography.providers.jdk.algorithms

import dev.whyoleg.cryptography.algorithms.*
import dev.whyoleg.cryptography.materials.key.*
import dev.whyoleg.cryptography.operations.*
import dev.whyoleg.cryptography.providers.jdk.*
import dev.whyoleg.cryptography.providers.jdk.materials.*
import dev.whyoleg.cryptography.providers.base.materials.*
import dev.whyoleg.cryptography.providers.jdk.operations.*
import dev.whyoleg.cryptography.serialization.pem.*
import dev.whyoleg.cryptography.serialization.asn1.*
import dev.whyoleg.cryptography.serialization.asn1.modules.*

internal class JdkEdDSA(private val state: JdkCryptographyState) : EdDSA {
private fun curveName(curve: EdDSA.Curve): String = when (curve) {
EdDSA.Curve.Ed25519 -> "Ed25519"
EdDSA.Curve.Ed448 -> "Ed448"
}
private fun oid(curve: EdDSA.Curve): ObjectIdentifier = when (curve) {
EdDSA.Curve.Ed25519 -> ObjectIdentifier.Ed25519
EdDSA.Curve.Ed448 -> ObjectIdentifier.Ed448
}

override fun publicKeyDecoder(curve: EdDSA.Curve): KeyDecoder<EdDSA.PublicKey.Format, EdDSA.PublicKey> =
object : JdkPublicKeyDecoder<EdDSA.PublicKey.Format, EdDSA.PublicKey>(state, curveName(curve)) {
override fun JPublicKey.convert(): EdDSA.PublicKey = EdDsaPublicKey(state, this)

override fun decodeFromByteArrayBlocking(format: EdDSA.PublicKey.Format, bytes: ByteArray): EdDSA.PublicKey = when (format) {
EdDSA.PublicKey.Format.JWK -> error("JWK is not supported")
EdDSA.PublicKey.Format.RAW -> decodeFromDer(
wrapSubjectPublicKeyInfo(UnknownKeyAlgorithmIdentifier(oid(curve)), bytes)
)
EdDSA.PublicKey.Format.DER -> decodeFromDer(bytes)
EdDSA.PublicKey.Format.PEM -> decodeFromDer(unwrapPem(PemLabel.PublicKey, bytes))
}
}

override fun privateKeyDecoder(curve: EdDSA.Curve): KeyDecoder<EdDSA.PrivateKey.Format, EdDSA.PrivateKey> =
object : JdkPrivateKeyDecoder<EdDSA.PrivateKey.Format, EdDSA.PrivateKey>(state, curveName(curve)) {
override fun JPrivateKey.convert(): EdDSA.PrivateKey = EdDsaPrivateKey(state, this)

override fun decodeFromByteArrayBlocking(format: EdDSA.PrivateKey.Format, bytes: ByteArray): EdDSA.PrivateKey = when (format) {
EdDSA.PrivateKey.Format.JWK -> error("JWK is not supported")
EdDSA.PrivateKey.Format.RAW -> decodeFromDer(
wrapPrivateKeyInfo(
0,
UnknownKeyAlgorithmIdentifier(oid(curve)),
bytes
)
)
EdDSA.PrivateKey.Format.DER -> decodeFromDer(bytes)
EdDSA.PrivateKey.Format.PEM -> decodeFromDer(unwrapPem(PemLabel.PrivateKey, bytes))
}
}

override fun keyPairGenerator(curve: EdDSA.Curve): KeyGenerator<EdDSA.KeyPair> = object : JdkKeyPairGenerator<EdDSA.KeyPair>(state, curveName(curve)) {
override fun JKeyPairGenerator.init() {
// no additional init required
}

override fun JKeyPair.convert(): EdDSA.KeyPair = EdDsaKeyPair(
EdDsaPublicKey(state, public),
EdDsaPrivateKey(state, private),
)
}

private class EdDsaKeyPair(
override val publicKey: EdDSA.PublicKey,
override val privateKey: EdDSA.PrivateKey,
) : EdDSA.KeyPair

private class EdDsaPublicKey(
private val state: JdkCryptographyState,
private val key: JPublicKey,
) : EdDSA.PublicKey, JdkEncodableKey<EdDSA.PublicKey.Format>(key) {
override fun signatureVerifier(): SignatureVerifier {
return JdkSignatureVerifier(state, key, "EdDSA", null)
}

override fun encodeToByteArrayBlocking(format: EdDSA.PublicKey.Format): ByteArray = when (format) {
EdDSA.PublicKey.Format.JWK -> error("JWK is not supported")
EdDSA.PublicKey.Format.RAW -> {
val der = encodeToDer()
unwrapSubjectPublicKeyInfo(setOf(ObjectIdentifier.Ed25519, ObjectIdentifier.Ed448), der)
}
EdDSA.PublicKey.Format.DER -> encodeToDer()
EdDSA.PublicKey.Format.PEM -> wrapPem(PemLabel.PublicKey, encodeToDer())
}
}

private class EdDsaPrivateKey(
private val state: JdkCryptographyState,
private val key: JPrivateKey,
) : EdDSA.PrivateKey, JdkEncodableKey<EdDSA.PrivateKey.Format>(key) {
override fun signatureGenerator(): SignatureGenerator {
return JdkSignatureGenerator(state, key, "EdDSA", null)
}

override fun encodeToByteArrayBlocking(format: EdDSA.PrivateKey.Format): ByteArray = when (format) {
EdDSA.PrivateKey.Format.JWK -> error("JWK is not supported")
EdDSA.PrivateKey.Format.RAW -> {
val der = encodeToDer()
KeyInfoUnwrap.unwrapPkcs8ForOids(der, listOf(ObjectIdentifier.Ed25519, ObjectIdentifier.Ed448))
}
EdDSA.PrivateKey.Format.DER -> encodeToDer()
EdDSA.PrivateKey.Format.PEM -> wrapPem(PemLabel.PrivateKey, encodeToDer())
}
}
}
117 changes: 117 additions & 0 deletions cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkXDH.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package dev.whyoleg.cryptography.providers.jdk.algorithms

import dev.whyoleg.cryptography.algorithms.*
import dev.whyoleg.cryptography.materials.key.*
import dev.whyoleg.cryptography.operations.*
import dev.whyoleg.cryptography.providers.jdk.*
import dev.whyoleg.cryptography.providers.jdk.materials.*
import dev.whyoleg.cryptography.providers.base.materials.*
import dev.whyoleg.cryptography.providers.jdk.operations.*
import dev.whyoleg.cryptography.serialization.pem.*
import dev.whyoleg.cryptography.serialization.asn1.*
import dev.whyoleg.cryptography.serialization.asn1.modules.*

internal class JdkXDH(private val state: JdkCryptographyState) : XDH {
private fun curveName(curve: XDH.Curve): String = when (curve) {
XDH.Curve.X25519 -> "X25519"
XDH.Curve.X448 -> "X448"
}
private fun oid(curve: XDH.Curve): ObjectIdentifier = when (curve) {
XDH.Curve.X25519 -> ObjectIdentifier.X25519
XDH.Curve.X448 -> ObjectIdentifier.X448
}

override fun publicKeyDecoder(curve: XDH.Curve): KeyDecoder<XDH.PublicKey.Format, XDH.PublicKey> =
object : JdkPublicKeyDecoder<XDH.PublicKey.Format, XDH.PublicKey>(state, curveName(curve)) {
override fun JPublicKey.convert(): XDH.PublicKey = XdhPublicKey(state, this)

override fun decodeFromByteArrayBlocking(format: XDH.PublicKey.Format, bytes: ByteArray): XDH.PublicKey = when (format) {
XDH.PublicKey.Format.JWK -> error("JWK is not supported")
XDH.PublicKey.Format.RAW -> decodeFromDer(
wrapSubjectPublicKeyInfo(UnknownKeyAlgorithmIdentifier(oid(curve)), bytes)
)
XDH.PublicKey.Format.DER -> decodeFromDer(bytes)
XDH.PublicKey.Format.PEM -> decodeFromDer(unwrapPem(PemLabel.PublicKey, bytes))
}
}

override fun privateKeyDecoder(curve: XDH.Curve): KeyDecoder<XDH.PrivateKey.Format, XDH.PrivateKey> =
object : JdkPrivateKeyDecoder<XDH.PrivateKey.Format, XDH.PrivateKey>(state, curveName(curve)) {
override fun JPrivateKey.convert(): XDH.PrivateKey = XdhPrivateKey(state, this)

override fun decodeFromByteArrayBlocking(format: XDH.PrivateKey.Format, bytes: ByteArray): XDH.PrivateKey = when (format) {
XDH.PrivateKey.Format.JWK -> error("JWK is not supported")
XDH.PrivateKey.Format.RAW -> decodeFromDer(
wrapPrivateKeyInfo(
0,
UnknownKeyAlgorithmIdentifier(oid(curve)),
bytes
)
)
XDH.PrivateKey.Format.DER -> decodeFromDer(bytes)
XDH.PrivateKey.Format.PEM -> decodeFromDer(unwrapPem(PemLabel.PrivateKey, bytes))
}
}

override fun keyPairGenerator(curve: XDH.Curve): KeyGenerator<XDH.KeyPair> = object : JdkKeyPairGenerator<XDH.KeyPair>(state, curveName(curve)) {
override fun JKeyPairGenerator.init() {
// no additional init required
}

override fun JKeyPair.convert(): XDH.KeyPair = XdhKeyPair(
XdhPublicKey(state, public),
XdhPrivateKey(state, private),
)
}

private class XdhKeyPair(
override val publicKey: XDH.PublicKey,
override val privateKey: XDH.PrivateKey,
) : XDH.KeyPair

private class XdhPublicKey(
private val state: JdkCryptographyState,
val key: JPublicKey,
) : XDH.PublicKey, JdkEncodableKey<XDH.PublicKey.Format>(key), SharedSecretGenerator<XDH.PrivateKey> {
private val keyAgreement = state.keyAgreement("XDH")
override fun sharedSecretGenerator(): SharedSecretGenerator<XDH.PrivateKey> = this
override fun generateSharedSecretToByteArrayBlocking(other: XDH.PrivateKey): ByteArray {
check(other is XdhPrivateKey) { "Only key produced by JDK provider is supported" }
return keyAgreement.doAgreement(state, other.key, key)
}

override fun encodeToByteArrayBlocking(format: XDH.PublicKey.Format): ByteArray = when (format) {
XDH.PublicKey.Format.JWK -> error("JWK is not supported")
XDH.PublicKey.Format.RAW -> {
val der = encodeToDer()
unwrapSubjectPublicKeyInfo(setOf(ObjectIdentifier.X25519, ObjectIdentifier.X448), der)
}
XDH.PublicKey.Format.DER -> encodeToDer()
XDH.PublicKey.Format.PEM -> wrapPem(PemLabel.PublicKey, encodeToDer())
}
}

private class XdhPrivateKey(
private val state: JdkCryptographyState,
val key: JPrivateKey,
) : XDH.PrivateKey, JdkEncodableKey<XDH.PrivateKey.Format>(key), SharedSecretGenerator<XDH.PublicKey> {
private val keyAgreement = state.keyAgreement("XDH")
override fun sharedSecretGenerator(): SharedSecretGenerator<XDH.PublicKey> = this
override fun generateSharedSecretToByteArrayBlocking(other: XDH.PublicKey): ByteArray {
check(other is XdhPublicKey) { "Only key produced by JDK provider is supported" }
return keyAgreement.doAgreement(state, key, other.key)
}

override fun encodeToByteArrayBlocking(format: XDH.PrivateKey.Format): ByteArray = when (format) {
XDH.PrivateKey.Format.JWK -> error("JWK is not supported")
XDH.PrivateKey.Format.RAW -> {
val der = encodeToDer()
KeyInfoUnwrap.unwrapPkcs8ForOids(der, listOf(ObjectIdentifier.X25519, ObjectIdentifier.X448))
}
XDH.PrivateKey.Format.DER -> encodeToDer()
XDH.PrivateKey.Format.PEM -> wrapPem(PemLabel.PrivateKey, encodeToDer())
}
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dev.whyoleg.cryptography.providers.jdk.algorithms

import dev.whyoleg.cryptography.serialization.asn1.*
import dev.whyoleg.cryptography.serialization.asn1.modules.*
import dev.whyoleg.cryptography.providers.base.materials.*

internal object KeyInfoUnwrap {
fun unwrapPkcs8ForOids(der: ByteArray, oids: List<ObjectIdentifier>): ByteArray {
var lastError: Throwable? = null
for (oid in oids) {
try {
return unwrapPrivateKeyInfo(oid, der)
} catch (t: Throwable) {
lastError = t
}
}
throw lastError ?: IllegalArgumentException("No OID matched for PKCS#8 unwrap")
}
}