diff --git a/core/java/src/net/i2p/crypto/SelfSignedGenerator.java b/core/java/src/net/i2p/crypto/SelfSignedGenerator.java index c60b9a09fd0aa6d624041647f4cba1dd007a256e..bf18a0f1c62a34a24c0564c99b94f4fe6b6a5ff7 100644 --- a/core/java/src/net/i2p/crypto/SelfSignedGenerator.java +++ b/core/java/src/net/i2p/crypto/SelfSignedGenerator.java @@ -153,6 +153,12 @@ public final class SelfSignedGenerator { throw new GeneralSecurityException("cert error", iae); } + // some simple tests + PublicKey cpub = cert.getPublicKey(); + cert.verify(cpub); + if (!cpub.equals(jpub)) + throw new GeneralSecurityException("pubkey mismatch"); + Object[] rv = { jpub, jpriv, cert }; return rv; } diff --git a/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java b/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java index 5a79c61bf554de20d732db21d1e0ae1d642b9bff..ce8bb5783205a89aed9f01b3e396acb132372527 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 java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Arrays; import net.i2p.crypto.eddsa.math.GroupElement; import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; @@ -152,8 +153,9 @@ public class EdDSAPrivateKey implements EdDSAKey, PrivateKey { d[idx++] != 1 || d[idx++] != 1 || d[idx++] != 0x04 || - d[idx++] != 32) - throw new InvalidKeySpecException("unsupported key spec"); + d[idx++] != 32) { + throw new InvalidKeySpecException("unsupported key spec"); + } byte[] rv = new byte[32]; System.arraycopy(d, idx, rv, 0, 32); return rv; @@ -185,4 +187,26 @@ public class EdDSAPrivateKey implements EdDSAKey, PrivateKey { public byte[] getAbyte() { return Abyte; } + + /** + * @since 0.9.25 + */ + @Override + public int hashCode() { + return Arrays.hashCode(seed); + } + + /** + * @since 0.9.25 + */ + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof EdDSAPrivateKey)) + return false; + EdDSAPrivateKey pk = (EdDSAPrivateKey) o; + return Arrays.equals(seed, pk.getSeed()) && + edDsaSpec.equals(pk.getParams()); + } } diff --git a/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java b/core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java index 5b7036547fcac40d4e39dbe5556417c3e2af735d..83817f8238c0f5317c74e4222a1162d9d0889ccf 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 java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; import net.i2p.crypto.eddsa.math.GroupElement; import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; @@ -126,9 +127,10 @@ public class EdDSAPublicKey implements EdDSAKey, PublicKey { d[idx++] != 1 || d[idx++] != 1 || d[idx++] != 0x03 || - d[idx++] != 32 || - d[idx++] != 0) - throw new InvalidKeySpecException("unsupported key spec"); + d[idx++] != 33 || + d[idx++] != 0) { + throw new InvalidKeySpecException("unsupported key spec"); + } byte[] rv = new byte[32]; System.arraycopy(d, idx, rv, 0, 32); return rv; @@ -152,4 +154,26 @@ public class EdDSAPublicKey implements EdDSAKey, PublicKey { public byte[] getAbyte() { return Abyte; } + + /** + * @since 0.9.25 + */ + @Override + public int hashCode() { + return Arrays.hashCode(Abyte); + } + + /** + * @since 0.9.25 + */ + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof EdDSAPublicKey)) + return false; + EdDSAPublicKey pk = (EdDSAPublicKey) o; + return Arrays.equals(Abyte, pk.getAbyte()) && + edDsaSpec.equals(pk.getParams()); + } } diff --git a/core/java/src/net/i2p/crypto/eddsa/KeyFactory.java b/core/java/src/net/i2p/crypto/eddsa/KeyFactory.java index 47f8542498f21562bea98ede18216185e2aaef3e..72fd03152ec098058722cfc2f88c9d73abb00eef 100644 --- a/core/java/src/net/i2p/crypto/eddsa/KeyFactory.java +++ b/core/java/src/net/i2p/crypto/eddsa/KeyFactory.java @@ -31,7 +31,7 @@ public final class KeyFactory extends KeyFactorySpi { if (keySpec instanceof PKCS8EncodedKeySpec) { return new EdDSAPrivateKey((PKCS8EncodedKeySpec) keySpec); } - throw new InvalidKeySpecException("key spec not recognised"); + throw new InvalidKeySpecException("key spec not recognised: " + keySpec.getClass()); } /** @@ -45,7 +45,7 @@ public final class KeyFactory extends KeyFactorySpi { if (keySpec instanceof X509EncodedKeySpec) { return new EdDSAPublicKey((X509EncodedKeySpec) keySpec); } - throw new InvalidKeySpecException("key spec not recognised"); + throw new InvalidKeySpecException("key spec not recognised: " + keySpec.getClass()); } @SuppressWarnings("unchecked") diff --git a/core/java/src/net/i2p/crypto/eddsa/math/Curve.java b/core/java/src/net/i2p/crypto/eddsa/math/Curve.java index 2c6ade4ea17c3e67efce84a356fbd67435b77f44..fba8f29aa8e0c1fa81fba86ac5a17093d5cca30d 100644 --- a/core/java/src/net/i2p/crypto/eddsa/math/Curve.java +++ b/core/java/src/net/i2p/crypto/eddsa/math/Curve.java @@ -69,4 +69,29 @@ public class Curve implements Serializable { ge.precompute(true); return ge; } + + /** + * @since 0.9.25 + */ + @Override + public int hashCode() { + return f.hashCode() ^ + d.hashCode() ^ + I.hashCode(); + } + + /** + * @since 0.9.25 + */ + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Curve)) + return false; + Curve c = (Curve) o; + return f.equals(c.getField()) && + d.equals(c.getD()) && + I.equals(c.getI()); + } } diff --git a/core/java/src/net/i2p/crypto/eddsa/math/FieldElement.java b/core/java/src/net/i2p/crypto/eddsa/math/FieldElement.java index 4bea7c39e955f5e1f5c1c103be5420831775bbb3..3f111f4449ef009ebbebe7292f5e7723e7cbec85 100644 --- a/core/java/src/net/i2p/crypto/eddsa/math/FieldElement.java +++ b/core/java/src/net/i2p/crypto/eddsa/math/FieldElement.java @@ -60,4 +60,6 @@ public abstract class FieldElement implements Serializable { public abstract FieldElement invert(); public abstract FieldElement pow22523(); + + // Note: concrete subclasses must implement hashCode() and equals() } diff --git a/core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java b/core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java index ec81b5d408449da9ef91de337f422fb1f234ef3f..3a6c57b8249ffaa324b58a90cf612e024ace075b 100644 --- a/core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java +++ b/core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java @@ -716,6 +716,8 @@ public class GroupElement implements Serializable { @Override public boolean equals(Object obj) { + if (obj == this) + return true; if (!(obj instanceof GroupElement)) return false; GroupElement ge = (GroupElement) obj; diff --git a/core/java/src/net/i2p/crypto/eddsa/spec/EdDSAParameterSpec.java b/core/java/src/net/i2p/crypto/eddsa/spec/EdDSAParameterSpec.java index 4ace0fb62c699355c1d2712c3e0cabb39648c9b6..75b0140c6ac461a154f58113e5eeda8b29a75746 100644 --- a/core/java/src/net/i2p/crypto/eddsa/spec/EdDSAParameterSpec.java +++ b/core/java/src/net/i2p/crypto/eddsa/spec/EdDSAParameterSpec.java @@ -59,4 +59,29 @@ public class EdDSAParameterSpec implements AlgorithmParameterSpec, Serializable public GroupElement getB() { return B; } + + /** + * @since 0.9.25 + */ + @Override + public int hashCode() { + return hashAlgo.hashCode() ^ + curve.hashCode() ^ + B.hashCode(); + } + + /** + * @since 0.9.25 + */ + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof EdDSAParameterSpec)) + return false; + EdDSAParameterSpec s = (EdDSAParameterSpec) o; + return hashAlgo.equals(s.getHashAlgorithm()) && + curve.equals(s.getCurve()) && + B.equals(s.getB()); + } } diff --git a/core/java/src/net/i2p/crypto/provider/I2PProvider.java b/core/java/src/net/i2p/crypto/provider/I2PProvider.java index f60284a3e0b89da04bddd4172278380f9ab0829d..958f307c4406f893acc90658761d485d93d33604 100644 --- a/core/java/src/net/i2p/crypto/provider/I2PProvider.java +++ b/core/java/src/net/i2p/crypto/provider/I2PProvider.java @@ -50,19 +50,22 @@ public final class I2PProvider extends Provider { //put("Signature.SHA1withDSA", "net.i2p.crypto.provider.SignatureSpi"); // EdDSA - // OID: 1.3.101.100 + // Key OID: 1.3.101.100; Sig OID: 1.3.101.101 put("KeyFactory.EdDSA", "net.i2p.crypto.eddsa.KeyFactory"); put("KeyPairGenerator.EdDSA", "net.i2p.crypto.eddsa.KeyPairGenerator"); put("Signature.SHA512withEdDSA", "net.i2p.crypto.eddsa.EdDSAEngine"); // Didn't find much documentation on these at all, // see http://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/HowToImplAProvider.html // section "Mapping from OID to name" + // without these, Certificate.verify() fails + put("Alg.Alias.KeyFactory.1.3.101.100", "EdDSA"); + put("Alg.Alias.KeyFactory.OID.1.3.101.100", "EdDSA"); // Without these, keytool fails with: // keytool error: java.security.NoSuchAlgorithmException: unrecognized algorithm name: SHA512withEdDSA put("Alg.Alias.KeyPairGenerator.1.3.101.100", "EdDSA"); put("Alg.Alias.KeyPairGenerator.OID.1.3.101.100", "EdDSA"); - put("Alg.Alias.Signature.1.3.101.100", "SHA512withEdDSA"); - put("Alg.Alias.Signature.OID.1.3.101.100", "SHA512withEdDSA"); + put("Alg.Alias.Signature.1.3.101.101", "SHA512withEdDSA"); + put("Alg.Alias.Signature.OID.1.3.101.101", "SHA512withEdDSA"); // TODO Ed25519ph // OID: 1.3.101.101 @@ -75,6 +78,8 @@ public final class I2PProvider extends Provider { put("KeyPairGenerator.DiffieHellman", "net.i2p.crypto.elgamal.KeyPairGenerator"); put("KeyPairGenerator.ElGamal", "net.i2p.crypto.elgamal.KeyPairGenerator"); put("Signature.SHA256withElGamal", "net.i2p.crypto.elgamal.ElGamalSigEngine"); + put("Alg.Alias.KeyFactory.1.3.14.7.2.1.1", "ElGamal"); + put("Alg.Alias.KeyFactory.OID.1.3.14.7.2.1.1", "ElGamal"); put("Alg.Alias.KeyPairGenerator.1.3.14.7.2.1.1", "ElGamal"); put("Alg.Alias.KeyPairGenerator.OID.1.3.14.7.2.1.1", "ElGamal"); put("Alg.Alias.Signature.1.3.14.7.2.1.1", "SHA256withElGamal");