diff --git a/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java b/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java index 7fc3dbe85..c1dcd8032 100644 --- a/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java +++ b/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java @@ -1,6 +1,8 @@ package net.i2p.crypto.eddsa; import java.security.PrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import net.i2p.crypto.eddsa.math.GroupElement; import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; @@ -32,6 +34,14 @@ public class EdDSAPrivateKey implements EdDSAKey, PrivateKey { this.edDsaSpec = spec.getParams(); } + /** + * @since 0.9.25 + */ + public EdDSAPrivateKey(PKCS8EncodedKeySpec spec) throws InvalidKeySpecException { + this(new EdDSAPrivateKeySpec(decode(spec.getEncoded()), + EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512))); + } + public String getAlgorithm() { return "EdDSA"; } @@ -111,6 +121,32 @@ public class EdDSAPrivateKey implements EdDSAKey, PrivateKey { return rv; } + /** + * This is really dumb for now. + * See getEncoded(). + * + * @return 32 bytes for Ed25519, throws for other curves + * @since 0.9.25 + */ + private static byte[] decode(byte[] d) throws InvalidKeySpecException { + try { + int idx = 0; + if (d[idx++] != 0x30 || + d[idx++] != 37 || + d[idx++] != 0x0a || + d[idx++] != 1 || + d[idx++] != 1 || + d[idx++] != 0x04 || + d[idx++] != 32) + throw new InvalidKeySpecException("unsupported key spec"); + byte[] rv = new byte[32]; + System.arraycopy(d, idx, rv, 0, 32); + return rv; + } catch (IndexOutOfBoundsException ioobe) { + throw new InvalidKeySpecException(ioobe); + } + } + public EdDSAParameterSpec getParams() { return edDsaSpec; } diff --git a/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java b/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java index 4e71f128f..0e91f087b 100644 --- a/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java +++ b/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java @@ -1,6 +1,8 @@ package net.i2p.crypto.eddsa; import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; import net.i2p.crypto.eddsa.math.GroupElement; import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; @@ -28,6 +30,14 @@ public class EdDSAPublicKey implements EdDSAKey, PublicKey { this.edDsaSpec = spec.getParams(); } + /** + * @since 0.9.25 + */ + public EdDSAPublicKey(X509EncodedKeySpec spec) throws InvalidKeySpecException { + this(new EdDSAPublicKeySpec(decode(spec.getEncoded()), + EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512))); + } + public String getAlgorithm() { return "EdDSA"; } @@ -93,6 +103,40 @@ public class EdDSAPublicKey implements EdDSAKey, PublicKey { return rv; } + /** + * This is really dumb for now. + * See getEncoded(). + * + * @return 32 bytes for Ed25519, throws for other curves + * @since 0.9.25 + */ + private static byte[] decode(byte[] d) throws InvalidKeySpecException { + try { + int idx = 0; + if (d[idx++] != 0x30 || + d[idx++] != 45 || + d[idx++] != 0x30 || + d[idx++] != 8 || + d[idx++] != 0x06 || + d[idx++] != 1 || + d[idx++] != (1 * 40) + 3 || + d[idx++] != 101 || + d[idx++] != 100 || + d[idx++] != 0x0a || + d[idx++] != 1 || + d[idx++] != 1 || + d[idx++] != 0x03 || + d[idx++] != 32 || + d[idx++] != 0) + throw new InvalidKeySpecException("unsupported key spec"); + byte[] rv = new byte[32]; + System.arraycopy(d, idx, rv, 0, 32); + return rv; + } catch (IndexOutOfBoundsException ioobe) { + throw new InvalidKeySpecException(ioobe); + } + } + public EdDSAParameterSpec getParams() { return edDsaSpec; } diff --git a/core/java/src/net/i2p/crypto/eddsa/KeyFactory.java b/core/java/src/net/i2p/crypto/eddsa/KeyFactory.java index 950130ac9..642ca2daf 100644 --- a/core/java/src/net/i2p/crypto/eddsa/KeyFactory.java +++ b/core/java/src/net/i2p/crypto/eddsa/KeyFactory.java @@ -7,6 +7,8 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; @@ -18,19 +20,31 @@ import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; */ public class KeyFactory extends KeyFactorySpi { + /** + * As of 0.9.25, supports PKCS8EncodedKeySpec + */ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { if (keySpec instanceof EdDSAPrivateKeySpec) { return new EdDSAPrivateKey((EdDSAPrivateKeySpec) keySpec); } + if (keySpec instanceof PKCS8EncodedKeySpec) { + return new EdDSAPrivateKey((PKCS8EncodedKeySpec) keySpec); + } throw new InvalidKeySpecException("key spec not recognised"); } + /** + * As of 0.9.25, supports X509EncodedKeySpec + */ protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { if (keySpec instanceof EdDSAPublicKeySpec) { return new EdDSAPublicKey((EdDSAPublicKeySpec) keySpec); } + if (keySpec instanceof X509EncodedKeySpec) { + return new EdDSAPublicKey((X509EncodedKeySpec) keySpec); + } throw new InvalidKeySpecException("key spec not recognised"); }