Looking for Signing algorithm that creates 32 or 1

2019-09-08 05:32发布

问题:

Cannot match up the size of key generated using public/private keys for licensing application. Ive written a self contained example that creates public/private key, create a license by signing user emailaddress with public key, and then check using public key, license and email address that the license indeed was encoded using private key (Obviously this wouldn't all be in one class usually).

This all works but the hex version of the license key is 96 characters (i.e representing 48 bytes/384 bits) which is a little longer than I wanted (In contrast the length of public/private keys is not a problem and the longer the better). What could I use to generate a 32 (64 hex chars) byte or maybe 16 byte (32 hex chars), and would the security of this be reasonable ?

Picking another algorithm is somewhat hard as I do not understand the the interaction between the algorithm picked for generating the keys

KeyPairGenerator.getInstance("DSA");

and the algorithm for signing

Signature.getInstance("SHA/DSA");

and I cant find a list for either.

One other point when I generate a public/private key pairs I specify key size of

keyGen.initialize(1024, new SecureRandom());

yet neither the public key (443 bytes) or the private key (335 bytes) or the sum of both (778 bytes) match this number.

import org.apache.commons.codec.binary.Hex;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 *
 */
public class CreateLicense
{

    private String PUBLIC_KEY;
    private String PRIVATE_KEY;

    public static void main(final String[] args)
    {
        try
        {
            String email = args[0];
            System.out.println("Creating license for:"+email);
            CreateLicense cl = new CreateLicense();
            cl.generatePublicPrivateKeyPair();
            String license = cl.createLicense(email);
            cl.checkLicense(email, license);

        }
        catch(Throwable t)
        {
            t.printStackTrace();
        }
    }

    //Would only be done once on server
    private void generatePublicPrivateKeyPair() throws Exception
    {
        final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
        keyGen.initialize(1024, new SecureRandom());
        final KeyPair pair = keyGen.generateKeyPair();
        PrivateKey privateKey = pair.getPrivate();
        PRIVATE_KEY=Hex.encodeHexString(privateKey.getEncoded());
        PublicKey  publicKey = pair.getPublic();
        PUBLIC_KEY=Hex.encodeHexString(publicKey.getEncoded());
        System.out.println("PrivateKeyHexLength:"+privateKey.getEncoded().length);
        System.out.println("PublicKeyHexLength:"+publicKey.getEncoded().length);

    }

    private PrivateKey reinflatePrivateKey(String keyAsHexString) throws Exception
    {
        byte[] keyBytes = Hex.decodeHex(keyAsHexString.toCharArray());
        final  PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        final  KeyFactory keyFactory = KeyFactory.getInstance("DSA");
        final  PrivateKey privateKey = keyFactory.generatePrivate(privKeySpec);
        return privateKey;
    }

    private PublicKey reinflatePublicKey(String keyAsHexString) throws Exception
    {
        byte[] keyBytes = Hex.decodeHex(keyAsHexString.toCharArray());
        final  X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyBytes);
        final  KeyFactory keyFactory = KeyFactory.getInstance("DSA");
        final  PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
        return publicKey;
    }

    //License Create on server based on email address
    private String createLicense(String emailAddress) throws Exception
    {
        String message=emailAddress;
        PrivateKey privateKey =  reinflatePrivateKey(PRIVATE_KEY);
        final Signature dsa = Signature.getInstance("SHA/DSA");
        dsa.initSign(privateKey);
        dsa.update(message.getBytes());
        final byte[] m1 = dsa.sign();
        String license =  Hex.encodeHexString(m1);
        System.out.println("CreateLicense:"+license+":Size:"+license.length());
        return license;
    }

    //Client checks that given known emailaddress and public key that a if a license was derived from
    //that and corresponding privatekey it would match license.
    private boolean checkLicense(String  emailAddress, String license) throws Exception
    {
        String message=emailAddress;
        PublicKey publicKey =  reinflatePublicKey(PUBLIC_KEY);
        final Signature dsa = Signature.getInstance("SHA/DSA");
        dsa.initVerify(publicKey);
        dsa.update(message.getBytes());

        boolean result = dsa.verify(Hex.decodeHex(license.toCharArray()));
        System.out.println("Result"+result);
        return result;
    }
}

gives output like

Creating license for:testuser@nowhere.com
PrivateKeyHexLength:335
PublicKeyHexLength:443
CreateLicense:302c021425f7ad7289b073f82a1d808838f43e0134c5591402140d2a7a4e3967706d4659dc73ace6455040a5fc6b:Size:92
Resulttrue

回答1:

@Paul - I think your solution here would be to use ECDSA. Change your line of code

final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");

to

final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDSA");

The keys are much shorter than DSA - and I'm sure hex version signature would be shorter. I suggest you use a prime ECC curve of say 256 or 128 bits.

Please let us know if this solves the problem.