0

I am implementing an Hybrid Encryption project and I have generated 2 key pairs for sender and receiver keys (private and public). I have these keys in a file.

KeyPair Generation Code

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;

import Decoder.BASE64Encoder;

public class GenerateRSAKeys{

    public static void main(String[] args)
    {



        String publicKeyFilename = null;
        String privateKeyFilename = null;

        publicKeyFilename = "C:\\Users\\imjme1\\Desktop\\Work_backup\\FMS\\EPM_FILE_ENCRYPTION\\NIFT_SOLUTION\\sender_keys\\receiver_publicKey";
        privateKeyFilename = "C:\\Users\\imjme1\\Desktop\\Work_backup\\FMS\\EPM_FILE_ENCRYPTION\\NIFT_SOLUTION\\sender_keys\\receiver_privateKey";

        GenerateRSAKeys generateRSAKeys = new GenerateRSAKeys();

        generateRSAKeys.generate(publicKeyFilename, privateKeyFilename);

    }

    private void generate (String publicKeyFilename, String privateFilename){

        try {

            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

            // Create the public and private keys
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
            BASE64Encoder b64 = new BASE64Encoder();

            SecureRandom random = createFixedRandom();
            generator.initialize(1024, random);

            KeyPair pair = generator.generateKeyPair();
            Key pubKey = pair.getPublic();
            Key privKey = pair.getPrivate();

            System.out.println("publicKey : " + b64.encode(pubKey.getEncoded()));
            System.out.println("privateKey : " + b64.encode(privKey.getEncoded()));

            BufferedWriter out = new BufferedWriter(new FileWriter(publicKeyFilename));
            out.write(b64.encode(pubKey.getEncoded()));
            out.close();

            out = new BufferedWriter(new FileWriter(privateFilename));
            out.write(b64.encode(privKey.getEncoded()));
            out.close();


        }
        catch (Exception e) {
            System.out.println(e);
        }
    }

    public static SecureRandom createFixedRandom()
    {
        return new FixedRand();
    }

    private static class FixedRand extends SecureRandom {

        MessageDigest sha;
        byte[] state;

        FixedRand() {
            try
            {
                this.sha = MessageDigest.getInstance("SHA-1");
                this.state = sha.digest();
            }
            catch (NoSuchAlgorithmException e)
            {
                throw new RuntimeException("can't find SHA-1!");
            }
        }

        public void nextBytes(byte[] bytes){

            int    off = 0;

            sha.update(state);

            while (off < bytes.length)
            {                
                state = sha.digest();

                if (bytes.length - off > state.length)
                {
                    System.arraycopy(state, 0, bytes, off, state.length);
                }
                else
                {
                    System.arraycopy(state, 0, bytes, off, bytes.length - off);
                }

                off += state.length;

                sha.update(state);
            }
        }
    }

}

Now, I need to secure these keys (probably not on any disk directly).

I have searched for this case on the internet; saving keys into key stores is the way to secure keys and use the same keystore when reading keys for the use in encryption and decryption.

Can someone suggest me how to save public and private key in key store and how to read it in java?

Jawad-Dev
  • 274
  • 10
  • 31

1 Answers1

2

The Java KeyStore API (and underlying providers) does not support storing a keypair -- that is, a privatekey and publickey (which can then be used for publickey operations like encrypt and verify). It does support storing a privatekey and a certificate chain for the publickey. The certificate chain can consist of only one certificate, especially if that certificate is a self-signed certificate (which by definition is a chain by itself). That is exactly what commandline keytool -genkeypair does: it generates a keypair and stores the privatekey plus a self-signed certificate for the publickey in the (specified or defaulted) keystore file.

If you were using only 'standard' JRE, creating a self-signed (or other) certificate in code is not very easy.

However, if you have BouncyCastle added, as you obviously do or the code you posted wouldn't work, that has numerous applicable capabilities. For a simple example of generating a cert with only bcprov (the old, deprecated X509V3CertificateGenerator) see my JAVA API to create a keystore and attaching a csr and keypair to it -- but do as I recommended there but didn't show: don't create the unneeded CSR first, instead create the cert using the desired name and publickey.

Better, if you also have or can get bcpkix, use X509v3CertificateBuilder. See examples at Self signed X509 Certificate with Bouncy Castle in Java and Generating X509 Certificate using Bouncy Castle Java .

For writing out, and reading back in, a keystore file containing this data, just see the Javadoc linked above. Note Java traditionally defaulted to JKS-format files, and you will find many older answers here and elsewhere on the web which assume that, but since Java 9 in 2017 it defaults to PKCS12-format, which is not only standard and thus (mostly) interoperable but also more secure (uses a much better PBKDF algorithm).

However, your code uses a completely bogus random generator, and as a result generates the same keypair every time. Given this, there is no real need to store it, since you can always re-generate it any time you want. In fact, there is no benefit to even having this keypairs since it provides no security at all.

dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70