Skip to content

Commit 1be8ed6

Browse files
committed
Add JDK implementation for Ed (edwards curve), EdDSA (Ed25519/Ed448) and XDH (X25519/X448) interfaces
1 parent 6f26356 commit 1be8ed6

File tree

3 files changed

+189
-0
lines changed

3 files changed

+189
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package algorithms
2+
3+
import dev.whyoleg.cryptography.materials.key.KeyDecoder
4+
import dev.whyoleg.cryptography.materials.key.KeyGenerator
5+
import dev.whyoleg.cryptography.providers.jdk.JKeyPair
6+
import dev.whyoleg.cryptography.providers.jdk.JKeyPairGenerator
7+
import dev.whyoleg.cryptography.providers.jdk.JPrivateKey
8+
import dev.whyoleg.cryptography.providers.jdk.JPublicKey
9+
import dev.whyoleg.cryptography.providers.jdk.JdkCryptographyState
10+
import dev.whyoleg.cryptography.providers.jdk.materials.JdkEncodableKey
11+
import dev.whyoleg.cryptography.providers.jdk.materials.JdkKeyPairGenerator
12+
import dev.whyoleg.cryptography.providers.jdk.materials.JdkPrivateKeyDecoder
13+
import dev.whyoleg.cryptography.providers.jdk.materials.JdkPublicKeyDecoder
14+
import dev.whyoleg.cryptography.providers.jdk.materials.unwrapPem
15+
import dev.whyoleg.cryptography.providers.jdk.materials.wrapPem
16+
import dev.whyoleg.cryptography.serialization.pem.PemLabel
17+
//import java.security.spec.XECPublicKeySpec // TODO: for raw encoding
18+
19+
internal sealed class JdkEd<PublicK : Ed.PublicKey, PrivateK : Ed.PrivateKey, KP : Ed.KeyPair<PublicK, PrivateK>>(
20+
protected val state: JdkCryptographyState,
21+
) : Ed<PublicK, PrivateK, KP> {
22+
protected abstract fun JPublicKey.convert(): PublicK
23+
protected abstract fun JPrivateKey.convert(): PrivateK
24+
protected abstract fun JKeyPair.convert(): KP
25+
26+
final override fun publicKeyDecoder(curve: Ed.Curve): KeyDecoder<Ed.PublicKey.Format, PublicK> {
27+
return EdPublicKeyDecoder(curve.jdkName)
28+
}
29+
30+
final override fun privateKeyDecoder(curve: Ed.Curve): KeyDecoder<Ed.PrivateKey.Format, PrivateK> {
31+
return EdPrivateKeyDecoder(curve.jdkName)
32+
}
33+
34+
final override fun keyPairGenerator(curve: Ed.Curve): KeyGenerator<KP> {
35+
return EdKeyPairGenerator(curve.jdkName)
36+
}
37+
38+
private val Ed.Curve.jdkName: String get() = name
39+
40+
private inner class EdKeyPairGenerator(
41+
private val algorithm: String,
42+
) : JdkKeyPairGenerator<KP>(state, algorithm) {
43+
override fun JKeyPairGenerator.init() {
44+
//initialize(null, state.secureRandom) // TODO
45+
}
46+
47+
override fun JKeyPair.convert(): KP = with(this@JdkEd) { convert() }
48+
}
49+
50+
private inner class EdPublicKeyDecoder(
51+
private val algorithm: String,
52+
) : JdkPublicKeyDecoder<Ed.PublicKey.Format, PublicK>(state, algorithm) {
53+
override fun JPublicKey.convert(): PublicK = with(this@JdkEd) { convert() }
54+
55+
override fun decodeFromByteArrayBlocking(format: Ed.PublicKey.Format, bytes: ByteArray): PublicK = when (format) {
56+
Ed.PublicKey.Format.JWK -> error("$format is not supported")
57+
/* Ed.PublicKey.Format.RAW -> keyFactory.use {
58+
it.generatePublic(XECPublicKeySpec(NamedParameterSpec(algorithm), bytes))
59+
}.convert()*/ // TODO: for raw encoding
60+
Ed.PublicKey.Format.RAW -> TODO("Todo: raw encoding")
61+
Ed.PublicKey.Format.DER -> decodeFromDer(bytes)
62+
Ed.PublicKey.Format.PEM -> decodeFromDer(unwrapPem(PemLabel.PublicKey, bytes))
63+
}
64+
}
65+
66+
private inner class EdPrivateKeyDecoder(
67+
private val algorithm: String,
68+
) : JdkPrivateKeyDecoder<Ed.PrivateKey.Format, PrivateK>(state, algorithm) {
69+
override fun JPrivateKey.convert(): PrivateK = with(this@JdkEd) { convert() }
70+
71+
override fun decodeFromByteArrayBlocking(format: Ed.PrivateKey.Format, bytes: ByteArray): PrivateK = when (format) {
72+
Ed.PrivateKey.Format.JWK -> error("$format is not supported")
73+
Ed.PrivateKey.Format.RAW -> TODO("Todo: raw encoding")
74+
/*Ed.PrivateKey.Format.RAW -> keyFactory.use {
75+
it.generatePrivate(XECPrivateKeySpec(NamedParameterSpec(algorithm), bytes))
76+
}.convert()*/ // TODO: for raw encoding
77+
Ed.PrivateKey.Format.DER -> decodeFromDer(bytes)
78+
Ed.PrivateKey.Format.PEM -> decodeFromDer(unwrapPem(PemLabel.PrivateKey, bytes))
79+
}
80+
}
81+
82+
protected abstract class BaseEdPublicKey(
83+
private val key: JPublicKey,
84+
) : Ed.PublicKey, JdkEncodableKey<Ed.PublicKey.Format>(key) {
85+
final override fun encodeToByteArrayBlocking(format: Ed.PublicKey.Format): ByteArray = when (format) {
86+
Ed.PublicKey.Format.JWK -> error("$format is not supported")
87+
Ed.PublicKey.Format.RAW -> TODO("Todo: raw encoding")
88+
// Ed.PublicKey.Format.RAW -> (key as XECPublicKey).encoded
89+
Ed.PublicKey.Format.DER -> encodeToDer()
90+
Ed.PublicKey.Format.PEM -> wrapPem(PemLabel.PublicKey, encodeToDer())
91+
else -> TODO()
92+
}
93+
}
94+
95+
protected abstract class BaseEdPrivateKey(
96+
private val key: JPrivateKey,
97+
) : Ed.PrivateKey, JdkEncodableKey<Ed.PrivateKey.Format>(key) {
98+
final override fun encodeToByteArrayBlocking(format: Ed.PrivateKey.Format): ByteArray = when (format) {
99+
Ed.PrivateKey.Format.JWK -> error("$format is not supported")
100+
Ed.PrivateKey.Format.RAW -> TODO("Todo: raw encoding")
101+
// Ed.PrivateKey.Format.RAW -> (key as XECPrivateKey).encoded
102+
Ed.PrivateKey.Format.DER -> encodeToDer()
103+
Ed.PrivateKey.Format.PEM -> wrapPem(PemLabel.PrivateKey, encodeToDer())
104+
else -> TODO()
105+
}
106+
}
107+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package algorithms
2+
3+
import dev.whyoleg.cryptography.operations.SignatureGenerator
4+
import dev.whyoleg.cryptography.operations.SignatureVerifier
5+
import dev.whyoleg.cryptography.providers.jdk.JKeyPair
6+
import dev.whyoleg.cryptography.providers.jdk.JPrivateKey
7+
import dev.whyoleg.cryptography.providers.jdk.JPublicKey
8+
import dev.whyoleg.cryptography.providers.jdk.JdkCryptographyState
9+
import dev.whyoleg.cryptography.providers.jdk.operations.JdkSignatureGenerator
10+
import dev.whyoleg.cryptography.providers.jdk.operations.JdkSignatureVerifier
11+
12+
internal class JdkEdDSA(state: JdkCryptographyState) : JdkEd<EdDSA.PublicKey, EdDSA.PrivateKey, EdDSA.KeyPair>(state), EdDSA {
13+
override fun JPublicKey.convert(): EdDSA.PublicKey = EdDsaPublicKey(state, this)
14+
override fun JPrivateKey.convert(): EdDSA.PrivateKey = EdDsaPrivateKey(state, this)
15+
override fun JKeyPair.convert(): EdDSA.KeyPair = EdDsaKeyPair(public.convert(), private.convert())
16+
17+
private class EdDsaKeyPair(
18+
override val publicKey: EdDSA.PublicKey,
19+
override val privateKey: EdDSA.PrivateKey,
20+
) : EdDSA.KeyPair
21+
22+
private class EdDsaPublicKey(
23+
private val state: JdkCryptographyState,
24+
private val key: JPublicKey,
25+
) : EdDSA.PublicKey, BaseEdPublicKey(key) {
26+
override fun signatureVerifier(): SignatureVerifier {
27+
return JdkSignatureVerifier(state, key, "EdDSA", null)
28+
}
29+
}
30+
31+
private class EdDsaPrivateKey(
32+
private val state: JdkCryptographyState,
33+
private val key: JPrivateKey,
34+
) : EdDSA.PrivateKey, BaseEdPrivateKey(key) {
35+
override fun signatureGenerator(): SignatureGenerator {
36+
return JdkSignatureGenerator(state, key, "EdDSA", null)
37+
}
38+
}
39+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package algorithms
2+
3+
import dev.whyoleg.cryptography.operations.SharedSecretGenerator
4+
import dev.whyoleg.cryptography.providers.jdk.JKeyPair
5+
import dev.whyoleg.cryptography.providers.jdk.JPrivateKey
6+
import dev.whyoleg.cryptography.providers.jdk.JPublicKey
7+
import dev.whyoleg.cryptography.providers.jdk.JdkCryptographyState
8+
import dev.whyoleg.cryptography.providers.jdk.operations.doAgreement
9+
10+
internal class JdkXDH(state: JdkCryptographyState) : JdkEd<XDH.PublicKey, XDH.PrivateKey, XDH.KeyPair>(state), XDH {
11+
override fun JPublicKey.convert(): XDH.PublicKey = XdhPublicKey(state, this)
12+
override fun JPrivateKey.convert(): XDH.PrivateKey = XdhPrivateKey(state, this)
13+
override fun JKeyPair.convert(): XDH.KeyPair = XdhKeyPair(public.convert(), private.convert())
14+
15+
private class XdhKeyPair(
16+
override val publicKey: XDH.PublicKey,
17+
override val privateKey: XDH.PrivateKey,
18+
) : XDH.KeyPair
19+
20+
private class XdhPublicKey(
21+
private val state: JdkCryptographyState,
22+
val key: JPublicKey,
23+
) : XDH.PublicKey, BaseEdPublicKey(key), SharedSecretGenerator<XDH.PrivateKey> {
24+
private val keyAgreement = state.keyAgreement("XDH")
25+
override fun sharedSecretGenerator(): SharedSecretGenerator<XDH.PrivateKey> = this
26+
override fun generateSharedSecretToByteArrayBlocking(other: XDH.PrivateKey): ByteArray {
27+
check(other is XdhPrivateKey) { "Only key produced by JDK provider is supported" }
28+
return keyAgreement.doAgreement(state, other.key, key)
29+
}
30+
}
31+
32+
private class XdhPrivateKey(
33+
private val state: JdkCryptographyState,
34+
val key: JPrivateKey,
35+
) : XDH.PrivateKey, BaseEdPrivateKey(key), SharedSecretGenerator<XDH.PublicKey> {
36+
private val keyAgreement = state.keyAgreement("XDH")
37+
override fun sharedSecretGenerator(): SharedSecretGenerator<XDH.PublicKey> = this
38+
override fun generateSharedSecretToByteArrayBlocking(other: XDH.PublicKey): ByteArray {
39+
check(other is XdhPublicKey) { "Only key produced by JDK provider is supported" }
40+
return keyAgreement.doAgreement(state, key, other.key)
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)