diff --git a/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java b/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java index 4136b321a..7fc3dbe85 100644 --- a/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java +++ b/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java @@ -3,6 +3,7 @@ package net.i2p.crypto.eddsa; import java.security.PrivateKey; import net.i2p.crypto.eddsa.math.GroupElement; +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; @@ -39,9 +40,75 @@ public class EdDSAPrivateKey implements EdDSAKey, PrivateKey { return "PKCS#8"; } + /** + * This follows the spec at + * https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04 + * NOT the docs from + * java.security.spec.PKCS8EncodedKeySpec + * quote: + *
+     *  The PrivateKeyInfo syntax is defined in the PKCS#8 standard as follows:
+     *  PrivateKeyInfo ::= SEQUENCE {
+     *    version Version,
+     *    privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+     *    privateKey PrivateKey,
+     *    attributes [0] IMPLICIT Attributes OPTIONAL }
+     *  Version ::= INTEGER
+     *  PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+     *  PrivateKey ::= OCTET STRING
+     *  Attributes ::= SET OF Attribute
+     *
+ * + *
+     *  AlgorithmIdentifier ::= SEQUENCE
+     *  {
+     *    algorithm           OBJECT IDENTIFIER,
+     *    parameters          ANY OPTIONAL
+     *  }
+     *
+ * + * @return 39 bytes for Ed25519, null for other curves + * @since implemented in 0.9.25 + */ public byte[] getEncoded() { - // TODO Auto-generated method stub - return null; + // TODO no equals() implemented in spec, but it's essentially a singleton + if (!edDsaSpec.equals(EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512))) + return null; + int totlen = 7 + seed.length; + byte[] rv = new byte[totlen]; + int idx = 0; + // sequence + rv[idx++] = 0x30; + rv[idx++] = (byte) (5 + seed.length); + + // version + // not in the Josefsson example + //rv[idx++] = 0x02; + //rv[idx++] = 1; + //rv[idx++] = 0; + + // Algorithm Identifier + // sequence + // not in the Josefsson example + //rv[idx++] = 0x30; + //rv[idx++] = (byte) (10 + seed.length); + // OID 1.3.101.100 + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb540809%28v=vs.85%29.aspx + // not in the Josefsson example + //rv[idx++] = 0x06; + //rv[idx++] = 3; + //rv[idx++] = (1 * 40) + 3; + //rv[idx++] = 101; + //rv[idx++] = 100; + // params + rv[idx++] = 0x0a; + rv[idx++] = 1; + rv[idx++] = 1; // Ed25519 + // the key + rv[idx++] = 0x04; // octet string + rv[idx++] = (byte) seed.length; + System.arraycopy(seed, 0, rv, idx, seed.length); + return rv; } public EdDSAParameterSpec getParams() { diff --git a/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java b/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java index 8e436bd1d..4e71f128f 100644 --- a/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java +++ b/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java @@ -3,6 +3,7 @@ package net.i2p.crypto.eddsa; import java.security.PublicKey; import net.i2p.crypto.eddsa.math.GroupElement; +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; @@ -35,9 +36,61 @@ public class EdDSAPublicKey implements EdDSAKey, PublicKey { return "X.509"; } + /** + * This follows the spec at + * ref: https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04 + * which matches the docs from + * java.security.spec.X509EncodedKeySpec + * quote: + *
+     * The SubjectPublicKeyInfo syntax is defined in the X.509 standard as follows:
+     *  SubjectPublicKeyInfo ::= SEQUENCE {
+     *    algorithm AlgorithmIdentifier,
+     *    subjectPublicKey BIT STRING }
+     *
+ * + *
+     *  AlgorithmIdentifier ::= SEQUENCE
+     *  {
+     *    algorithm           OBJECT IDENTIFIER,
+     *    parameters          ANY OPTIONAL
+     *  }
+     *
+ * + * @return 47 bytes for Ed25519, null for other curves + * @since implemented in 0.9.25 + */ public byte[] getEncoded() { - // TODO Auto-generated method stub - return null; + // TODO no equals() implemented in spec, but it's essentially a singleton + if (!edDsaSpec.equals(EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512))) + return null; + int totlen = 15 + Abyte.length; + byte[] rv = new byte[totlen]; + int idx = 0; + // sequence + rv[idx++] = 0x30; + rv[idx++] = (byte) (13 + Abyte.length); + // Algorithm Identifier + // sequence + rv[idx++] = 0x30; + rv[idx++] = 8; + // OID 1.3.101.100 + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb540809%28v=vs.85%29.aspx + rv[idx++] = 0x06; + rv[idx++] = 3; + rv[idx++] = (1 * 40) + 3; + rv[idx++] = 101; + rv[idx++] = 100; + // params + rv[idx++] = 0x0a; + rv[idx++] = 1; + rv[idx++] = 1; // Ed25519 + // the key + rv[idx++] = 0x03; // bit string + rv[idx++] = (byte) (1 + Abyte.length); + rv[idx++] = 0; // number of trailing unused bits + System.arraycopy(Abyte, 0, rv, idx, Abyte.length); + return rv; } public EdDSAParameterSpec getParams() {