TransWikia.com

Given a DSAPrivateKey, how to compute corresponding DSAPublicKey?

Stack Overflow Asked by Simon Kissane on December 17, 2020

In Java, I have a DSAPrivateKey, which has an X parameter, and also a DSAParams with P, Q and G parameters. I want to compute the corresponding DSAPublicKey. I know I can construct a DSAPublicKeySpec if I know Y, P, Q, and G, and then I can use the KeyFactory.generatePublic(KeySpec) method to turn that into a DSAPublicKey.

The thing I’m not sure about, is how to compute Y given knowledge of X, P, Q and G. I guessed the answer was:

BigInteger y = g.multiply(x).mod(p);

But that produces exception:

Caused by: java.lang.IllegalArgumentException: Y value does not appear to be in correct group
    at org.bouncycastle.crypto.asymmetric.KeyUtils.validated(Unknown Source)
    at org.bouncycastle.crypto.asymmetric.AsymmetricDSAPublicKey.<init>(Unknown Source)
    at org.bouncycastle.jcajce.provider.ProvDSAPublicKey.<init>(Unknown Source)

So obviously that guess isn’t right. I also tried:

BigInteger y = g.modPow(x, p);

which gives the same exception.

I’m using BouncyCastle FIPS version 1.0.2, so I’d be happy with an answer that uses BouncyCastle classes, but I’d also be happy with one that doesn’t use BouncyC

One Answer

You were right with the multiplication to get the value y. I found a very handy solution that does work with native Java.

Security warning: the sample program has no exception handling and is for educational purposes only.

Have a nice weekend!

Here is the (short) result of my example program:

Derive DSA PublicKey from PrivateKey
publicKey equals publicKeyDerived: true

full code:

import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.spec.DSAPublicKeySpec;
import java.util.Arrays;

public class DSA_RetrievePublicKeyFromPrivateKey {
    public static void main(String[] args) throws NoSuchProviderException, NoSuchAlgorithmException {
        System.out.println("Derive DSA PublicKey from PrivateKey");

        KeyPair keyPair = generateDsaKeyPair(2048);
        PublicKey publicKeyOriginal =  keyPair.getPublic(); // original for comparison
        PublicKey publicKeyDerived = deriveDsaPublicKeyFromPrivatekey(keyPair.getPrivate());
        System.out.println("publicKey equals publicKeyDerived: " + Arrays.equals(publicKeyOriginal.getEncoded(), publicKeyDerived.getEncoded()));
    }

    public static KeyPair generateDsaKeyPair(int keylengthInt)
            throws NoSuchAlgorithmException, NoSuchProviderException {
        KeyPairGenerator keypairGenerator = KeyPairGenerator.getInstance("DSA", "SUN");
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
        keypairGenerator.initialize(keylengthInt, random);
        return keypairGenerator.generateKeyPair();
    }

    public static PublicKey deriveDsaPublicKeyFromPrivatekey (PrivateKey privateKey) throws NoSuchAlgorithmException {
        DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) privateKey;
        DSAParams params = dsaPrivateKey.getParams();
        BigInteger y = params.getG().modPow(dsaPrivateKey.getX(), params.getP());
        DSAPublicKeySpec keySpec = new DSAPublicKeySpec(y, params.getP(), params.getQ(), params.getG());
        PublicKey publicKey;
        KeyFactory keyFactory = KeyFactory.getInstance("DSA");
        try {
            publicKey = keyFactory.generatePublic(keySpec);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return publicKey;
    }
}

Correct answer by Michael Fehr on December 17, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP