Search code examples
javaencryptionrsaencryption-asymmetric

How to read public/private key files for encryption when they are Base64?


I'm trying to learn RSA public/private key-pair encryption in Java.

I have the code below working. It generates a private & public key pair, writes the keys to disk, encrypts the string with the public key from disk, the decrypts with the private key from disk, and then it outputs the decrypted string.

All works great.

The next thing is, I want the key files to be the readable "-----BEGIN RSA PRIVATE KEY-----" type of key files ... so I wrote the method saveKeysToDiskBase64.

The problem is, when I write the files using saveKeysToDiskBase64, the methods that read the key files fail. That is loadPrivateKey and loadPublicKey can't read the Base64 files.

What am I missing?

public class EncryptionTest1 {


    public void execute() throws Exception {
        
        String filename = "test1";
        
        KeyPair keyPair = EncryptionUtil.generateKeyPair();
        EncryptionUtil.saveKeysToDisk(filename, keyPair);
        // EncryptionUtil.saveKeysToDiskBase64(filename, keyPair);

        String pvtKeyFilename = filename+".key";
        String pubKeyFilename = filename+".pub";
        
        PrivateKey privateKey = EncryptionUtil.loadPrivateKey(pvtKeyFilename);
        byte[] bPrivateKey = privateKey.getEncoded();

        PublicKey publicKey = EncryptionUtil.loadPublicKey(pubKeyFilename);
        byte[] bPublicKey = publicKey.getEncoded();

        String sOriginal = "hi this is plain text";

        byte[] encryptedData = EncryptionUtil.encrypt(bPublicKey, sOriginal.getBytes());
        byte[] decryptedData = EncryptionUtil.decrypt(bPrivateKey, encryptedData);
        
        String sEncrypted = new String(encryptedData);
        String sDecrypted = new String(decryptedData);
        
        System.out.println("sOriginal = "+sOriginal);
        System.out.println("sEncrypted = "+sEncrypted);
        System.out.println("sDecryptedData = "+sDecrypted);

    }
    
    
    public static void main(String[] args) {
        try {
            new EncryptionTest1().execute();
        } catch (Exception x) {
            x.printStackTrace();
        }
    }
    
}

...

public class EncryptionUtil {

    
    private static final String ALGORITHM = "RSA";

    
    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {

        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);

        SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");

        // 2048 is keysize
        keyGen.initialize(2048, random);

        KeyPair generateKeyPair = keyGen.generateKeyPair();
        
        return generateKeyPair;
    }
    
    public static void saveKeysToDisk(String name, KeyPair keyPair) {
        try {
            String privateFileName = name+".key";
            FileOutputStream out1 = new FileOutputStream(privateFileName);
            out1.write(keyPair.getPrivate().getEncoded());
            out1.close();
             
            String publicFileName = name+".pub";
            FileOutputStream out2 = new FileOutputStream(publicFileName);
            out2.write(keyPair.getPublic().getEncoded());
            out2.close();
        } catch (Exception x) {
            x.printStackTrace();
        }
    }


    public static void saveKeysToDiskBase64(String name, KeyPair keyPair) {
        try {

            Base64.Encoder encoder = Base64.getEncoder();
             
            String privateFileName = name+".key";
            Writer out = new FileWriter(privateFileName);
            out.write("-----BEGIN RSA PRIVATE KEY-----\n");
            out.write(encoder.encodeToString(keyPair.getPrivate().getEncoded()));
            out.write("\n-----END RSA PRIVATE KEY-----\n");
            out.close();            

            String publicFileName = name+".pub";
            Writer out2 = new FileWriter(publicFileName);
            out2.write("-----BEGIN RSA PUBLIC KEY-----\n");
            out2.write(encoder.encodeToString(keyPair.getPublic().getEncoded()));
            out2.write("\n-----END RSA PUBLIC KEY-----\n");
            out2.close();           

        } catch (Exception x) {
            x.printStackTrace();
        }
    }

    
    public static PrivateKey loadPrivateKey(String keyFile) {
        PrivateKey pvt = null;
        try {
            /* Read all bytes from the private key file */
            Path path = Paths.get(keyFile);
            byte[] bytes = Files.readAllBytes(path);

            /* Generate private key. */
            PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            pvt = kf.generatePrivate(ks);
        } catch (Exception x) {
            x.printStackTrace();
        }
        
        return pvt;
    }
    
    public static PublicKey loadPublicKey(String keyFile) {
        PublicKey pub = null;
        try {
            /* Read all the public key bytes */
            Path path = Paths.get(keyFile);
            byte[] bytes = Files.readAllBytes(path);
            
            /* Generate public key. */
            X509EncodedKeySpec ks = new X509EncodedKeySpec(bytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            pub = kf.generatePublic(ks);
        } catch (Exception x) {
            x.printStackTrace();
        }
        return pub;
    }
    
    
    
    


    public static byte[] encrypt(byte[] publicKey, byte[] inputData) throws Exception {

        PublicKey key = KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(publicKey));

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] encryptedBytes = cipher.doFinal(inputData);

        return encryptedBytes;
    }

    public static byte[] decrypt(byte[] privateKey, byte[] inputData) throws Exception {

        PrivateKey key = KeyFactory.getInstance(ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(privateKey));

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);

        byte[] decryptedBytes = cipher.doFinal(inputData);

        return decryptedBytes;
    }
    
}

Solution

  • Great thanks to @President James K. Polk who gave me the correct answer in a comment.

    Here is the Base64 related code that that worked for me ...

    private static String PRIVATE_HEADER = "-----BEGIN PRIVATE KEY-----\n";
    private static String PRIVATE_FOOTER = "\n-----END PRIVATE KEY-----\n";
    private static String PUBLIC_HEADER = "-----BEGIN PUBLIC KEY-----\n";
    private static String PUBLIC_FOOTER = "\n-----END PUBLIC KEY-----\n";
    
    
    public static void saveKeysToDiskBase64(String name, KeyPair keyPair) {
        try {
    
            Base64.Encoder encoder = Base64.getEncoder();
             
            String privateFileName = name+".key";
            Writer out = new FileWriter(privateFileName);
            out.write(PRIVATE_HEADER);
            out.write(encoder.encodeToString(keyPair.getPrivate().getEncoded()));
            out.write(PRIVATE_FOOTER);
            out.close();            
    
            String publicFileName = name+".pub";
            Writer out2 = new FileWriter(publicFileName);
            out2.write(PUBLIC_HEADER);
            out2.write(encoder.encodeToString(keyPair.getPublic().getEncoded()));
            out2.write(PUBLIC_FOOTER);
            out2.close();           
    
        } catch (Exception x) {
            x.printStackTrace();
        }
    }
    
    public static PrivateKey loadPrivateKeyBase64(String keyFile) {
        PrivateKey pvt = null;
        try {
            /* Read all bytes from the private key file */
            Path path = Paths.get(keyFile);
            byte[] bytes = Files.readAllBytes(path);
    
            String s = new String(bytes);
            s = s.replace(PRIVATE_HEADER, "");
            s = s.replace(PRIVATE_FOOTER, "");
            
            bytes = Base64.getDecoder().decode(s.getBytes());
    
            /* Generate private key. */
            PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            pvt = kf.generatePrivate(ks);
        } catch (Exception x) {
            x.printStackTrace();
        }
        
        return pvt;
    }
    
    public static PublicKey loadPublicKeyBase64(String keyFile) {
        PublicKey pub = null;
        try {
            /* Read all the public key bytes */
            Path path = Paths.get(keyFile);
            byte[] bytes = Files.readAllBytes(path);
            
            String s = new String(bytes);
            s = s.replace(PUBLIC_HEADER, "");
            s = s.replace(PUBLIC_FOOTER, "");
            
            bytes = Base64.getDecoder().decode(s.getBytes());
            
            /* Generate public key. */
            X509EncodedKeySpec ks = new X509EncodedKeySpec(bytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            pub = kf.generatePublic(ks);
        } catch (Exception x) {
            x.printStackTrace();
        }
        return pub;
    }