forked from I2P_Developers/i2p.i2p
Add ElGamal signature implementation
Add ElGamal to provider doesn't work yet, needs key encoding/decoding and SigUtil support for longer signatures
This commit is contained in:
164
core/java/src/net/i2p/crypto/elgamal/ElGamalSigEngine.java
Normal file
164
core/java/src/net/i2p/crypto/elgamal/ElGamalSigEngine.java
Normal file
@ -0,0 +1,164 @@
|
||||
package net.i2p.crypto.elgamal;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Signature;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.i2p.crypto.SHA256Generator;
|
||||
import net.i2p.crypto.SigUtil;
|
||||
import net.i2p.util.NativeBigInteger;
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
/**
|
||||
* ElG signatures with SHA-256
|
||||
*
|
||||
* ref: https://en.wikipedia.org/wiki/ElGamal_signature_scheme
|
||||
*
|
||||
* @since 0.9.25
|
||||
*/
|
||||
public final class ElGamalSigEngine extends Signature {
|
||||
private final MessageDigest digest;
|
||||
private ElGamalKey key;
|
||||
|
||||
/**
|
||||
* No specific hash requested, allows any ElGamal key.
|
||||
*/
|
||||
public ElGamalSigEngine() {
|
||||
this(SHA256Generator.getDigestInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific hash requested, only matching keys will be allowed.
|
||||
* @param digest the hash algorithm that keys must have to sign or verify.
|
||||
*/
|
||||
public ElGamalSigEngine(MessageDigest digest) {
|
||||
super("ElGamal");
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
|
||||
digest.reset();
|
||||
if (privateKey instanceof ElGamalPrivateKey) {
|
||||
ElGamalPrivateKey privKey = (ElGamalPrivateKey) privateKey;
|
||||
key = privKey;
|
||||
} else {
|
||||
throw new InvalidKeyException("cannot identify ElGamal private key: " + privateKey.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
|
||||
digest.reset();
|
||||
if (publicKey instanceof ElGamalPublicKey) {
|
||||
key = (ElGamalPublicKey) publicKey;
|
||||
} else {
|
||||
throw new InvalidKeyException("cannot identify ElGamal public key: " + publicKey.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
digest.update(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len)
|
||||
throws SignatureException {
|
||||
digest.update(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ASN.1 R,S
|
||||
*/
|
||||
@Override
|
||||
protected byte[] engineSign() throws SignatureException {
|
||||
BigInteger elgp = key.getParams().getP();
|
||||
BigInteger pm1 = elgp.subtract(BigInteger.ONE);
|
||||
BigInteger elgg = key.getParams().getG();
|
||||
BigInteger x = ((ElGamalPrivateKey) key).getX();
|
||||
if (!(x instanceof NativeBigInteger))
|
||||
x = new NativeBigInteger(x);
|
||||
byte[] data = digest.digest();
|
||||
|
||||
BigInteger k;
|
||||
boolean ok;
|
||||
do {
|
||||
k = new BigInteger(2048, RandomSource.getInstance());
|
||||
ok = k.compareTo(pm1) == -1;
|
||||
ok = ok && k.compareTo(BigInteger.ONE) == 1;
|
||||
ok = ok && k.gcd(pm1).equals(BigInteger.ONE);
|
||||
} while (!ok);
|
||||
|
||||
BigInteger r = elgg.modPow(k, elgp);
|
||||
BigInteger kinv = k.modInverse(pm1);
|
||||
BigInteger h = new NativeBigInteger(1, data);
|
||||
BigInteger s = (kinv.multiply(h.subtract(x.multiply(r)))).mod(pm1);
|
||||
// todo if s == 0 go around again
|
||||
|
||||
byte[] rv;
|
||||
try {
|
||||
rv = SigUtil.sigBytesToASN1(r, s);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new SignatureException("ASN1", iae);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sigBytes ASN.1 R,S
|
||||
*/
|
||||
@Override
|
||||
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
|
||||
BigInteger elgp = key.getParams().getP();
|
||||
BigInteger pm1 = elgp.subtract(BigInteger.ONE);
|
||||
BigInteger elgg = key.getParams().getG();
|
||||
BigInteger y = ((ElGamalPublicKey) key).getY();
|
||||
if (!(y instanceof NativeBigInteger))
|
||||
y = new NativeBigInteger(y);
|
||||
byte[] data = digest.digest();
|
||||
|
||||
try {
|
||||
BigInteger[] rs = SigUtil.aSN1ToBigInteger(sigBytes, 256);
|
||||
BigInteger r = rs[0];
|
||||
BigInteger s = rs[1];
|
||||
if (r.signum() != 1 || s.signum() != 1 ||
|
||||
r.compareTo(elgp) != -1 || s.compareTo(pm1) != -1)
|
||||
return false;
|
||||
NativeBigInteger h = new NativeBigInteger(1, data);
|
||||
BigInteger modvalr = r.modPow(s, elgp);
|
||||
BigInteger modvaly = y.modPow(r, elgp);
|
||||
BigInteger modmulval = modvalr.multiply(modvaly).mod(elgp);
|
||||
BigInteger v = elgg.modPow(h, elgp);
|
||||
|
||||
boolean ok = v.compareTo(modmulval) == 0;
|
||||
return ok;
|
||||
} catch (RuntimeException e) {
|
||||
throw new SignatureException("verify", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated replaced with <a href="#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
|
||||
*/
|
||||
@Override
|
||||
protected void engineSetParameter(String param, Object value) {
|
||||
throw new UnsupportedOperationException("engineSetParameter unsupported");
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Override
|
||||
protected Object engineGetParameter(String param) {
|
||||
throw new UnsupportedOperationException("engineSetParameter unsupported");
|
||||
}
|
||||
}
|
@ -31,13 +31,24 @@ public final class I2PProvider extends Provider {
|
||||
|
||||
private void setup() {
|
||||
// TODO: Implement SPIs for existing code
|
||||
// However -
|
||||
// quote
|
||||
// http://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/HowToImplAProvider.html
|
||||
//
|
||||
// If your provider is supplying encryption algorithms through the
|
||||
// Cipher, KeyAgreement, KeyGenerator, Mac, or SecretKeyFactory classes,
|
||||
// you will need to sign your JAR file so that the JCA can authenticate the code at runtime.
|
||||
// If you are NOT providing an implementation of this type you can skip this step.
|
||||
//
|
||||
//put("Cipher.AES", "net.i2p.crypto.provider.CipherSpi$aesCBC");
|
||||
//put("Cipher.ElGamal", "net.i2p.crypto.provider.CipherSpi$elGamal");
|
||||
//put("Mac.HmacMD5-I2P", "net.i2p.crypto.provider.MacSpi");
|
||||
|
||||
put("MessageDigest.SHA-1", "net.i2p.crypto.SHA1");
|
||||
//put("Signature.SHA1withDSA", "net.i2p.crypto.provider.SignatureSpi");
|
||||
|
||||
// EdDSA
|
||||
// OID: 1.3.101.100
|
||||
put("KeyFactory.EdDSA", "net.i2p.crypto.eddsa.KeyFactory");
|
||||
put("KeyPairGenerator.EdDSA", "net.i2p.crypto.eddsa.KeyPairGenerator");
|
||||
put("Signature.SHA512withEdDSA", "net.i2p.crypto.eddsa.EdDSAEngine");
|
||||
@ -50,5 +61,21 @@ public final class I2PProvider extends Provider {
|
||||
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");
|
||||
// TODO Ed25519ph
|
||||
// OID: 1.3.101.101
|
||||
|
||||
// ElGamal
|
||||
// OID: 1.3.14.7.2.1.1
|
||||
put("KeyFactory.DH", "net.i2p.crypto.elgamal.KeyFactory");
|
||||
put("KeyFactory.DiffieHellman", "net.i2p.crypto.elgamal.KeyFactory");
|
||||
put("KeyFactory.ElGamal", "net.i2p.crypto.elgamal.KeyFactory");
|
||||
put("KeyPairGenerator.DH", "net.i2p.crypto.elgamal.KeyPairGenerator");
|
||||
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.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");
|
||||
put("Alg.Alias.Signature.OID.1.3.14.7.2.1.1", "SHA256withElGamal");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user