mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-23 04:42:06 +01:00
Add ElGamal validation ported from openpgpjs
This commit is contained in:
parent
a34cd77920
commit
af1d4f3e5b
1 changed files with 89 additions and 12 deletions
|
@ -16,6 +16,8 @@ import org.bouncycastle.bcpg.DSAPublicBCPGKey;
|
|||
import org.bouncycastle.bcpg.DSASecretBCPGKey;
|
||||
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
|
||||
import org.bouncycastle.bcpg.EdSecretBCPGKey;
|
||||
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
|
||||
import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
|
||||
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
|
||||
import org.bouncycastle.bcpg.RSASecretBCPGKey;
|
||||
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
|
||||
|
@ -39,7 +41,7 @@ import org.pgpainless.implementation.ImplementationFactory;
|
|||
public class PublicKeyParameterValidationUtil {
|
||||
|
||||
public static void verifyPublicKeyParameterIntegrity(PGPPrivateKey privateKey, PGPPublicKey publicKey)
|
||||
throws KeyIntegrityException, PGPException {
|
||||
throws KeyIntegrityException {
|
||||
PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.fromId(publicKey.getAlgorithm());
|
||||
boolean valid = true;
|
||||
|
||||
|
@ -60,10 +62,13 @@ public class PublicKeyParameterValidationUtil {
|
|||
(DSASecretBCPGKey) key,
|
||||
(DSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey())
|
||||
&& valid;
|
||||
} else if (key instanceof ElGamalSecretBCPGKey) {
|
||||
valid = verifyElGamalKeyIntegrity(
|
||||
(ElGamalSecretBCPGKey) key,
|
||||
(ElGamalPublicBCPGKey) publicKey.getPublicKeyPacket().getKey())
|
||||
&& valid;
|
||||
}
|
||||
|
||||
// TODO: ElGamal
|
||||
|
||||
if (!valid) {
|
||||
throw new KeyIntegrityException();
|
||||
}
|
||||
|
@ -84,13 +89,20 @@ public class PublicKeyParameterValidationUtil {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean verifyCanSign(PGPPrivateKey privateKey, PGPPublicKey publicKey) throws PGPException {
|
||||
/**
|
||||
* Verify that the public key can be used to successfully verify a signature made by the private key.
|
||||
* @param privateKey private key
|
||||
* @param publicKey public key
|
||||
* @return false if signature verification fails
|
||||
*/
|
||||
private static boolean verifyCanSign(PGPPrivateKey privateKey, PGPPublicKey publicKey) {
|
||||
SecureRandom random = new SecureRandom();
|
||||
PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.fromId(publicKey.getAlgorithm());
|
||||
PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
|
||||
ImplementationFactory.getInstance().getPGPContentSignerBuilder(publicKeyAlgorithm, HashAlgorithm.SHA256)
|
||||
);
|
||||
|
||||
try {
|
||||
signatureGenerator.init(SignatureType.TIMESTAMP.getCode(), privateKey);
|
||||
|
||||
byte[] data = new byte[512];
|
||||
|
@ -102,8 +114,18 @@ public class PublicKeyParameterValidationUtil {
|
|||
sig.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), publicKey);
|
||||
sig.update(data);
|
||||
return sig.verify();
|
||||
} catch (PGPException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the public key can be used to encrypt a message which can successfully be
|
||||
* decrypted using the private key.
|
||||
* @param privateKey private key
|
||||
* @param publicKey public key
|
||||
* @return false if decryption of a message encrypted with the public key fails
|
||||
*/
|
||||
private static boolean verifyCanDecrypt(PGPPrivateKey privateKey, PGPPublicKey publicKey) {
|
||||
SecureRandom random = new SecureRandom();
|
||||
PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(
|
||||
|
@ -201,4 +223,59 @@ public class PublicKeyParameterValidationUtil {
|
|||
// Verify that the public keys N is equal to private keys p*q
|
||||
return publicKey.getModulus().equals(secretKey.getPrimeP().multiply(secretKey.getPrimeQ()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate ElGamal public key parameters.
|
||||
*
|
||||
* Original implementation by the openpgpjs authors:
|
||||
* https://github.com/openpgpjs/openpgpjs/blob/main/src/crypto/public_key/elgamal.js#L76-L143
|
||||
* @param secretKey secret key
|
||||
* @param publicKey public key
|
||||
* @return true if supposedly valid, false if invalid
|
||||
*/
|
||||
private static boolean verifyElGamalKeyIntegrity(ElGamalSecretBCPGKey secretKey, ElGamalPublicBCPGKey publicKey) {
|
||||
BigInteger p = publicKey.getP();
|
||||
BigInteger g = publicKey.getG();
|
||||
BigInteger y = publicKey.getY();
|
||||
BigInteger one = BigInteger.ONE;
|
||||
|
||||
// 1 < g < p
|
||||
if (g.min(one).equals(g) || g.max(p).equals(g)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// p-1 is large
|
||||
if (p.bitLength() < 1023) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// g^(p-1) mod p = 1
|
||||
if (!g.modPow(p.subtract(one), p).equals(one)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check g^i mod p != 1 for i < threshold
|
||||
BigInteger res = g;
|
||||
BigInteger i = BigInteger.valueOf(1);
|
||||
BigInteger threshold = BigInteger.valueOf(2).shiftLeft(17);
|
||||
while (i.compareTo(threshold) < 0) {
|
||||
res = res.multiply(g).mod(p);
|
||||
if (res.equals(one)) {
|
||||
return false;
|
||||
}
|
||||
i = i.add(one);
|
||||
}
|
||||
|
||||
// blinded exponentiation to check y = g^(r*(p-1)+x) mod p
|
||||
SecureRandom random = new SecureRandom();
|
||||
BigInteger x = secretKey.getX();
|
||||
BigInteger r = new BigInteger(p.bitLength(), random);
|
||||
BigInteger rqx = p.subtract(one).multiply(r).add(x);
|
||||
if (!y.equals(g.modPow(rqx, p))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue