Search code examples
javanetworkingencryptioninputstreamobjectinputstream

Having A problem with reading my public and private key files


I have a method in an encryption class that is responsible for reading my RSA key files and there respective components. To do this is use an InputStream object with an ObjectInputStream object. These are called inand input respectively. My issue is I think I might have the wrong Idea of how to use these. My error appears when I try and call this class from my encryption method to encrypt some binary data. I will link below the ReadKey and Encrypt Methods.

Both Methods:

PublicKey  ReadKey(String File) throws IOException{
        PublicKey publicKey = null;
        InputStream in = Encryption.class.getResourceAsStream(File);
        
        ObjectInputStream input = new ObjectInputStream(new BufferedInputStream(in));
        try {
            BigInteger m = (BigInteger) input.readObject();
            BigInteger e = (BigInteger) input.readObject(); 
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
            KeyFactory fact = KeyFactory.getInstance("RSA");
            publicKey = fact.generatePublic(keySpec);
            return publicKey;
        }catch (Exception e){
        
        }finally{
            // input.close();
        }
    return null;
        
}



public byte[] Encrypt(byte[] data) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IOException, BadPaddingException, IllegalBlockSizeException{
        PublicKey publicKey = ReadKey("/public.key");
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        
        byte[] cipherData = cipher.doFinal(data);
        return cipherData;
}




To add to the context of my issue, I will explain how I use these. I have Other methods that creat a public and private RSA keys. Now This program I use with the encryption is a simple messaging program which sends messages from a server to a client via a socket. I want to incorperate end-to-end encryption using RSA so thats where this all comes in. I grab the entered text when the user clicks send (Saved as the variable message) and then run this line sendMessage(Encryption.Encrypt(Converter(message))); It first hands the string to my converter method which converts my message from a string to a byte array[]. This is then handed to my encryption methods above. The error then occurs when my encryption method calls PublicKey publicKey = ReadKey("/public.key"); and appears to be an issue surrounding this ObjectInputStream input = new ObjectInputStream(new BufferedInputStream(in)); in the ReadKey method. I am a bit confused with this one as I am relatively new to these tools. Ill leave a link to a snippet of the error below:

java.io.IOException: Stream closed
    at java.base/java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:157)
    at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:244)
    at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:284)
    at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:343)
    at java.base/java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2914)
    at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2930)
    at java.base/java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3427)
    at java.base/java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:962)
    at java.base/java.io.ObjectInputStream.<init>(ObjectInputStream.java:405)
    at oserver.Encryption.ReadKey(Encryption.java:114)
    at oserver.Encryption.Encrypt(Encryption.java:133)
    at oserver.Server.jButton1ActionPerformed(Server.java:172)
    at oserver.Server$1.actionPerformed(Server.java:105)

I know its a long one to read so sorry about that. Any help would be much appreaciated and if you need more info I have no problem with that. Many thanks :)

How I store my keys:

 public void KeyStorage() throws NoSuchAlgorithmException, InvalidKeySpecException{
        
        KeyFactory factory = KeyFactory.getInstance("RSA"); // creating a key factory object
        RSAPublicKeySpec publ = factory.getKeySpec(Pairs.getPublic(),RSAPublicKeySpec.class); // Creat a RSAPublicKeySpec object that allows us to translate between keys and there specification
        RSAPrivateKeySpec priv = factory.getKeySpec(Pairs.getPrivate(),RSAPrivateKeySpec.class); // Creat a RSAPublicKeySpec object that allows us to translate between keys and there specification
        try{
            FileSave("public.key", publ.getModulus(),publ.getPublicExponent()); // Saving the Exponent and Modulus to file public.key
            FileSave("private.key", priv.getModulus(),priv.getPrivateExponent()); // Saving the Exponent and Modulus to file private.key
        }catch(IOException e){
            // need to handle this error at some point
        }
    }
    
    public void FileSave(String fileName, BigInteger mod, BigInteger exp) throws IOException{
        
        ObjectOutputStream out = null;
            
        try{
            out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));  
            out.writeObject(mod);
            out.writeObject(exp);
        }catch(IOException e){
            // need to handle this error at some point
        }
    }    



Solution

  • The direct problem is that you are writing to a file and reading from a resource. A resource is a read only file that is included with your Java source files (think e.g. icons in a GUI application).

    You should definitely write public and private keys using key.getEncoded() instead. Then you can use the same key factory but with X509EncodedKeySpec to read back the public key and PKCS8EncodedKeySpec for the private key.

    Note that you are currently just writing the modulus and private exponent for the private key. In practice the Chinese Remainder Theorem (CRT) parameters are written as well, and those can be used to speed up RSA private key operations.