- Add hashCode() and equals() everywhere it was missing,
  so we can test keys for equality: Curve, EdDSAParameterSpec, EdDSAPrivateKey, and EdDSAPublicKey
- Speedup for GroupElement.equals()
- Fix public key decode()
- Put unknown class name in exceptions
- indent fixes
Provider:
- Add KeyFactory aliases required for cert.verify()
- Fix EdDSA signature OID
SelfSigned:
- Add simple tests after generation using cert.verify() and key equality
This commit is contained in:
zzz
2016-01-29 16:01:23 +00:00
parent 8badb609e4
commit da3086bbef
9 changed files with 123 additions and 10 deletions

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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")

View File

@ -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());
}
}

View File

@ -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()
}

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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");