How to create Java Key Store (.jks) file with AES encryption

后端 未结 4 1339
栀梦
栀梦 2021-02-03 16:12

Reading Oracle documentation, I see that by default JKS files are encrypted using PBEWithMD5AndTripleDES. While DES alone makes me feel uneasy, MD5 lights a big red

相关标签:
4条回答
  • 2021-02-03 16:39

    Triple DES is pretty strong, and Oracle likely uses keys with 168 bit of entropy (giving a full 112 bits of security at the time of writing).

    Furthermore, although MD5 may not be secure for e.g. signatures, it is certainly valid for use in a key derivation scheme as such as PBE.

    Of course it would be a good idea for Oracle to migrate away from these schemes in time, but Triple DES and MD5 should not worry you needlessly. Writing your own is probably a worse idea, there are too many pitfalls.

    Choose a good password, it's probably the best thing you can do. Or put your keystore in a correctly configured HSM or smartcard if you want high end security.

    0 讨论(0)
  • 2021-02-03 16:52

    In the end I went with PKCS#8 files encrypted using PBEWithSHA256And256BitAES-CBC-BC

    Encryption:

    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.security.AlgorithmParameters;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.InvalidKeyException;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.InvalidParameterSpecException;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.EncryptedPrivateKeyInfo;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.PBEParameterSpec;
    
    import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
    
    public class EncodePKCS8 {
    
    /**
     * @param args
     * @throws NoSuchAlgorithmException 
     * @throws InvalidKeySpecException 
     * @throws NoSuchPaddingException 
     * @throws InvalidAlgorithmParameterException 
     * @throws InvalidKeyException 
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException 
     * @throws InvalidParameterSpecException 
     * @throws IOException 
     * @throws NoSuchProviderException 
     */
    public static void main(String[] args) throws NoSuchAlgorithmException,
    InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException,
    InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
    InvalidParameterSpecException, IOException, NoSuchProviderException
    {
        // before we can do anything with BouncyCastle we have to register its provider
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    
        String password = "Very long and complex password";
    
        // generate RSA key pair
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
    
        byte[] encryptedPkcs8 = encryptPrivateKey(password, keyPair);
    
        FileOutputStream fos = new FileOutputStream("privkey.p8");
        fos.write(encryptedPkcs8);
        fos.close();
    
        return;
    }
    
    private static byte[] encryptPrivateKey(String password, KeyPair keyPair)
        throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
        InvalidKeySpecException, NoSuchPaddingException,
        InvalidAlgorithmParameterException, IllegalBlockSizeException,
        BadPaddingException, InvalidParameterSpecException, IOException
    {
        int count = 100000; // hash iteration count, best to leave at default or increase
        return encryptPrivateKey(password, keyPair, count);
    }
    
    /**
     * 
     * @param password
     * @param keyPair
     * @param count
     * @return PKCS#8 encoded, encrypted keyPair
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws InvalidAlgorithmParameterException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws InvalidParameterSpecException
     * @throws IOException
     */
    private static byte[] encryptPrivateKey(String password, 
            KeyPair keyPair, int count) throws NoSuchAlgorithmException,
            NoSuchProviderException, InvalidKeySpecException,
            NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException,
            BadPaddingException, InvalidParameterSpecException, IOException
    {
        // extract the encoded private key, this is an unencrypted PKCS#8 private key
            byte[] encodedprivkey = keyPair.getPrivate().getEncoded();
    
            // Use a PasswordBasedEncryption (PBE) algorithm, OID of this algorithm will be saved
            // in the PKCS#8 file, so changing it (when more standard algorithm or safer
            // algorithm is available) doesn't break backwards compatibility.
            // In other words, decryptor doesn't need to know the algorithm before it will be
            // able to decrypt the PKCS#8 object.
            String encAlg = BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId();
    
            SecureRandom random = new SecureRandom();
            byte[] salt = new byte[16];
            random.nextBytes(salt);
    
            // Create PBE parameter set
            PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, count);
            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
            SecretKeyFactory keyFac = SecretKeyFactory.getInstance(encAlg, "BC");
            SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
    
            Cipher pbeCipher = Cipher.getInstance(encAlg, "BC");
    
            // Initialize PBE Cipher with key and parameters
            pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
    
            // Encrypt the encoded Private Key with the PBE key
            byte[] ciphertext = pbeCipher.doFinal(encodedprivkey);
    
            // Now construct  PKCS #8 EncryptedPrivateKeyInfo object
            AlgorithmParameters algparms = AlgorithmParameters.getInstance(encAlg, "BC");
            algparms.init(pbeParamSpec);
            EncryptedPrivateKeyInfo encinfo = new EncryptedPrivateKeyInfo(algparms, ciphertext);
    
            // DER encoded PKCS#8 encrypted key
            byte[] encryptedPkcs8 = encinfo.getEncoded();
    
            return encryptedPkcs8;
        }
    }
    

    Decryption:

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.security.AlgorithmParameters;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.InvalidKeyException;
    import java.security.Key;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.Security;
    import java.security.interfaces.RSAKey;
    import java.security.interfaces.RSAPrivateCrtKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.KeySpec;
    import java.security.spec.RSAPublicKeySpec;
    
    import javax.crypto.Cipher;
    import javax.crypto.EncryptedPrivateKeyInfo;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.PBEKeySpec;
    
    public class DecodePKCS8 {
    
        /**
         * @param args
         * @throws IOException 
         * @throws NoSuchPaddingException When file is corrupted
         * @throws NoSuchAlgorithmException When no BC provider has been loaded 
         * @throws InvalidKeySpecException When decryption of file failed
         * @throws InvalidAlgorithmParameterException When file is corrupted
         * @throws InvalidKeyException When Unlimited cryptography extensions are not installed
         */
        public static void main(String[] args) throws
        IOException, NoSuchAlgorithmException, NoSuchPaddingException,
        InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException
        {
            // before we can do anything with BouncyCastle we have to register its provider
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    
            String password = "Very long and complex password";
    
            // read DER encoded key from files
            byte[] encodedprivkey = getFileBytes("privkey.p8");
    
            // this is a encoded PKCS#8 encrypted private key
            EncryptedPrivateKeyInfo ePKInfo = new EncryptedPrivateKeyInfo(encodedprivkey);
    
            // first we have to read algorithm name and parameters (salt, iterations) used
            // to encrypt the file
            Cipher cipher = Cipher.getInstance(ePKInfo.getAlgName());
            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
    
            SecretKeyFactory skFac = SecretKeyFactory.getInstance(ePKInfo
                    .getAlgName());
            Key pbeKey = skFac.generateSecret(pbeKeySpec);
    
            // Extract the iteration count and the salt
            AlgorithmParameters algParams = ePKInfo.getAlgParameters();
            cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);
    
            // Decrypt the encryped private key into a PKCS8EncodedKeySpec
            KeySpec pkcs8KeySpec = ePKInfo.getKeySpec(cipher);
    
            // Now retrieve the RSA Public and private keys by using an
            // RSA key factory.
            KeyFactory rsaKeyFac = KeyFactory.getInstance("RSA");
            // First get the private key
            PrivateKey rsaPriv = rsaKeyFac.generatePrivate(pkcs8KeySpec);
            // Now derive the RSA public key from the private key
            RSAPublicKeySpec rsaPubKeySpec = new RSAPublicKeySpec(((RSAKey) rsaPriv).getModulus(),
                    ((RSAPrivateCrtKey) rsaPriv).getPublicExponent());
            PublicKey rsaPubKey = (RSAPublicKey) rsaKeyFac.generatePublic(rsaPubKeySpec);
    
        System.out.println("Key extracted, public part: " + rsaPubKey);
        }
    
        private static byte[] getFileBytes(String path)
        {
            File f = new File(path);
            int sizecontent = ((int) f.length()); // no key file will ever be bigger than 4GiB...
            byte[] data = new byte[sizecontent];
            try 
                {
                FileInputStream freader = new FileInputStream(f);
                freader.read(data, 0, sizecontent) ;
                freader.close();
                return data;
                }
            catch(IOException ioe)
            {
                System.out.println(ioe.toString());
                return null;
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-03 17:02

    Since Java 8, you can create a PKCS#12 keystore and pass an explicit PasswordProtection parameter when storing a key to specify the encryption algorithm to use:

    import java.io.FileOutputStream;
    import java.security.KeyStore;
    import java.security.KeyStore.PasswordProtection;
    import java.security.KeyStore.PrivateKeyEntry;
    import java.security.PrivateKey;
    import java.security.SecureRandom;
    import java.security.cert.Certificate;
    
    import javax.crypto.spec.PBEParameterSpec;
    
    public class scratch {
        public static void main(String... args) throws Exception {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(null, null); // Initialize a blank keystore
    
            // Your key to store
            PrivateKey key = ...;
            Certificate[] chain = new Certificate[] { ... };
    
            char[] password = "changeit".toCharArray();
            byte[] salt = new byte[20];
            new SecureRandom().nextBytes(salt);
            keyStore.setEntry("test", new PrivateKeyEntry(key, chain),
                              new PasswordProtection(password,
                                                     "PBEWithHmacSHA512AndAES_256",
                                                     new PBEParameterSpec(salt, 100_000)));
    
            keyStore.store(new FileOutputStream("/tmp/keystore.p12"), password);
        }
    }
    

    You can read a bit more on the details in this article (dislaimer: I wrote that article).

    0 讨论(0)
  • 2021-02-03 17:03

    Main Class

    `public class a {
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        // TODO code application logic here
        String b = "MSISDN=559915129&productID=5859";
    
        AEScryptography enj = new AEScryptography();
        String[] argts = {b, "EN"};
        System.out.println("ENCY -> "+enj.encryptionDecryption(argts));
        System.out.println(checksum.encode(b));
    } }`
    

    AEScryptography Class

    `public class AEScryptography {
    public String encryptionDecryption(String[] args) throws UnsupportedEncodingException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
        String returnVariable = "";
        if (args.length == 2) {
            try {
                String keystorePass = "201774";  // KeyStroe Password
                String keyPass = "mc7129";       // KeyPassword 
                String alias = "raVi";           // Alias
    
            InputStream keystoreStream = new FileInputStream("D:/keyFile.jks");
                KeyStore keystore = KeyStore.getInstance("JCEKS");
                keystore.load(keystoreStream, keystorePass.toCharArray());
                Key key = keystore.getKey(alias, keyPass.toCharArray());
                byte[] bt = key.getEncoded();
                String s = new String(bt);
                String originalString = args[0];
                switch (args[1]) {
                    case "EN":
                        String encryptedString = AES.encrypt(originalString, s, bt);
                        returnVariable = encryptedString;
                        break;
                    case "DE":
                        String decryptedString = AES.decrypt(originalString, s, bt);
                        returnVariable = decryptedString;
                        break;
                    default:
                        System.out.println("java -jar /home/jocg/AES-256Encryption.jar StringToEncrypt/Decrypt EN/DE");
                        break;
                }
    
            } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException ex) {
                System.out.println(ex);
    
            }
        } else {
            System.out.println("java -jar /home/jocg/AES-256Encryption.jar StringToEncrypt/Decrypt EN/DE");
        }
        return returnVariable;
    } }`
    

    AES Class

     public class AES {
    private static SecretKeySpec secretKey;
    private static byte[] key;
    public static void setKey(String myKey, byte[] ActualKey) throws 
    NoSuchAlgorithmException {
        try {
            key = myKey.getBytes("UTF-8");
            key = ActualKey;
            secretKey = new SecretKeySpec(key, "AES");
        } catch (UnsupportedEncodingException e) {
        }
    }
    
    public static String encrypt(String strToEncrypt, String secret, byte[] bt) throws UnsupportedEncodingException, NoSuchProviderException, InvalidAlgorithmParameterException {
        try {
            setKey(secret, bt);
            byte[] iv = new byte[16];
            IvParameterSpec ivspec = new IvParameterSpec(iv);
            SecretKey secKey = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secKey, ivspec);
            byte[] newData = cipher.doFinal(strToEncrypt.getBytes("UTF-8"));
            return Base64.getEncoder().encodeToString(newData);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            System.out.println("Error while encrypting: " + e.toString());
        }
        return null;
    }
     }`
    
    0 讨论(0)
提交回复
热议问题