This discussion is archived
4 Replies Latest reply: Jun 27, 2007 12:32 AM by 807605 RSS

Confusing input / output of encrypted, serialized Obj

807605 Newbie
Currently Being Moderated
Hi.
I'm creating a class that serializes and saves itself to a file.
It can also deserialize and 'load' itself from a file.

However, I have a new option that allows for encryption of this file.
The way I have it set up is this:

If the encryption settings are met, during the 'deserializeFrom' method the file is read with a BufferedReader, and all the text in the file is gotten via readLine.

After I've gotten all the text in the file, I decrypt it using my Util class's decryptString method.

I then have a decrypted String, which should be what the ObjectOutputStream serialized my class as.

However, to "read" the object, I need to create an ObjectInputStream.
ObjectInputStream can only be passed an InputStream as an argument, and the only one that suits my needs appears to be FileInputStream.

So what I'm currently doing is saving the unencrypted, serialized text to ANOTHER file, and then creating a FileInputStream to that file and the ObjectInputStream off that stream.

Then I read the object and continue as normal.

In a sense,
If encryption settings are met,
I read a file, decrypt it, and save it to a temp file.
I then readObject off the temp file.
If encryption settings are not met,
I readObject off the supplied filename.

This seems way too complicated for what I'm trying to do, however.
Can anyone point out a better way to do it?
(I know, the code's hideous!)
private boolean IS_ENCRYPTED = false; // set to true during my testing
private String DESEDE_ENCRYPTION_KEY = null;

public final void deserializeFrom(String filename) throws LF.util.StringEncrypter.EncryptionException, ClassNotFoundException, IOException {
        if (filename != null && !filename.equals("")) {
            File file = new File(filename);
            File tFile = null;
            if (file.exists()) {
                System.out.println("Deserializing from "+filename);
                FileInputStream fis;
                // Check encryption
                // If encryption settings are correct,
                // the file will be decrypted and then fis will be instantiated to
                // the temp file, which contains the data of the unencrypted, serialized object.
                if (IS_ENCRYPTED && DESEDE_ENCRYPTION_KEY != null) {
                    System.out.println("File should be encrypted, trying to decrypt it...");
                    // Read the file and decrypt its text
                    BufferedReader br = new BufferedReader(new FileReader(filename));
                    String readText = "";
                    String readLine = null;
                    while ((readLine = br.readLine()) != null) {
                        readText = readText + readLine;
                    }
                    System.out.println("Encrypted, serialized text:\n"+readText);
                    br.close();
                    readText = LFStringUtils.decryptString(readText, DESEDE_ENCRYPTION_KEY);
                    System.out.println("Decrypted, serialized text:\n"+readText);
                    // Create a temporary file which will store the unencrypted text until JVM exit
                    tFile = file.createTempFile("un", filename);
                    tFile.deleteOnExit();
                    PrintStream ps = new PrintStream(tFile);
                    ps.print(readText);
                    ps.close();
                }                
                if (tFile != null) {
                    // There is a decrypted, serialized file
                    fis = new FileInputStream(tFile);
                }
                else {
                    // There was not a decrypted, serialized file
                    fis = new FileInputStream(file);
                }
                // Read the object
                ObjectInputStream ois = new ObjectInputStream(fis);
                preLoad((Configuration)ois.readObject());
            }
        }
    }
Note that my 'serializeTo' method performs the same functionality of the 'deserializeFrom' method, only it saves via ObjectOutputStream, loads via BufferedReader, encrypts via my Util class, and is saved AGAIN via PrintStream. This is way over the top.

Any suggestions would be great!
(My System.out calls are for debugging)
  • 1. Re: Confusing input / output of encrypted, serialized Obj
    807605 Newbie
    Currently Being Moderated
    Check out java.io.StringBufferInputString

    Or, for better OOP, override FilterInputStream so that it decrypts the input there.

    Message was edited by:
    myncknm
  • 2. Re: Confusing input / output of encrypted, serialized Obj
    807605 Newbie
    Currently Being Moderated
    I've been thinking about how to do this for a few hours now, and I'm reading

    http://java.sun.com/developer/technicalArticles/Streams/ProgIOStreams/

    To learn up on how Input / Ouput streams differ versus Input / Output readers, which seems to be the root of my problem.

    However, I'm having difficulty coming to a solution.
    I created a class called DecryptionInputStream...
    public class DecryptionInputStream extends FilterInputStream {
        // Fields
        
        // Constructors
        public DecryptionInputStream(InputStream in) {
            super(in);
        }
    }
    And I'm confused of where to go from here.
    I'm trying to understand how this thing works.
    In my program, this is what would ideally be used:
    FileInputStream fis = new FileInputStream(filename);
    DecryptionInputStream dis = new DecryptionInputStream(fis);
    ObjectInputStream ois = new ObjectInputStream(dis);
    preLoad((Configuration)ois.readObject());
    Correct? How would I implement "decryption" in my DecryptionInputStream class?

    My 'encryption' and 'decryption' methods, which are in my LFStringUtils class, use the StringEncrypter class located as a download from

    http //www devx com/Java/10MinuteSolution/21385/0/page/1

    They only accept Strings, but how would I use it with a stream of raw bytes? How would I convert them into a Stream? Can anyone help?

    Here is the code for it:
    package LF.util;
    
    import java.io.*;
    import java.security.*;
    import java.security.spec.*;
    
    import javax.crypto.*;
    import javax.crypto.spec.*;
    import sun.misc.*;
    
    /**
     * Courtesy of http://www.devx.com/Java/10MinuteSolution/21385/0/page/2
     */
    public class StringEncrypter {
    
        public static final String DESEDE_ENCRYPTION_SCHEME = "DESede";
        public static final String DES_ENCRYPTION_SCHEME = "DES";
        public static final String DEFAULT_ENCRYPTION_KEY = "This is a fairly long phrase used to encrypt";
    
        private KeySpec keySpec;
        private SecretKeyFactory keyFactory;
        private Cipher cipher;
    
        private static final String UNICODE_FORMAT = "UTF8";
    
        public StringEncrypter(String encryptionScheme) throws EncryptionException {
            this(encryptionScheme, DEFAULT_ENCRYPTION_KEY);
        }
    
        public StringEncrypter(String encryptionScheme, String encryptionKey) throws EncryptionException {
    
            if (encryptionKey == null) {
                throw new IllegalArgumentException("encryption key was null");
            }
            if (encryptionKey.trim().length() < 24) {
                throw new IllegalArgumentException("encryption key was less than 24 characters");
            }
    
            try {
                byte[] keyAsBytes = encryptionKey.getBytes(UNICODE_FORMAT);
    
                if (encryptionScheme.equals(DESEDE_ENCRYPTION_SCHEME)) {
                    keySpec = new DESedeKeySpec(keyAsBytes);
                }
                else if (encryptionScheme.equals(DES_ENCRYPTION_SCHEME)) {
                    keySpec = new DESKeySpec(keyAsBytes);
                }
                else {
                    throw new IllegalArgumentException("Encryption scheme not supported: " + encryptionScheme);
                }
    
                keyFactory = SecretKeyFactory.getInstance(encryptionScheme);
                cipher = Cipher.getInstance(encryptionScheme);
    
            }
            catch (InvalidKeyException e) {
                throw new EncryptionException(e);
            }
            catch (UnsupportedEncodingException e) {
                throw new EncryptionException(e);
            }
            catch (NoSuchAlgorithmException e) {
                throw new EncryptionException(e);
            }
            catch (NoSuchPaddingException e) {
                throw new EncryptionException(e);
            }
    
        }
    
        public String encrypt(String unencryptedString) throws EncryptionException {
            if (unencryptedString == null || unencryptedString.trim().length() == 0) {
                throw new IllegalArgumentException("unencrypted string was null or empty");
            }
    
            try {
                SecretKey key = keyFactory.generateSecret(keySpec);
                cipher.init(Cipher.ENCRYPT_MODE, key);
                byte[] cleartext = unencryptedString.getBytes(UNICODE_FORMAT);
                byte[] ciphertext = cipher.doFinal(cleartext);
    
                BASE64Encoder base64encoder = new BASE64Encoder();
                return base64encoder.encode(ciphertext);
            }
            catch (Exception e) {
                throw new EncryptionException(e);
            }
        }
    
        public String decrypt(String encryptedString) throws EncryptionException {
            if (encryptedString == null || encryptedString.trim().length() <= 0) {
                throw new IllegalArgumentException("encrypted string was null or empty");
            }
    
            try {
                SecretKey key = keyFactory.generateSecret(keySpec);
                cipher.init(Cipher.DECRYPT_MODE, key);
                BASE64Decoder base64decoder = new BASE64Decoder();
                byte[] cleartext = base64decoder.decodeBuffer(encryptedString);
                byte[] ciphertext = cipher.doFinal(cleartext);
    
                return bytes2String(ciphertext);
            }
            catch (Exception e) {
                throw new EncryptionException(e);
            }
        }
    
        private static String bytes2String(byte[] bytes) {
            StringBuffer stringBuffer = new StringBuffer();
            for (int i = 0; i < bytes.length; i++) {
                stringBuffer.append((char) bytes);
    }
    return stringBuffer.toString();
    }

    public static class EncryptionException extends Exception {
    public EncryptionException(Throwable t) {
    super(t);
    }
    }
    }


    Thanks :)
    I'm off to read some more the tutorials.
  • 3. Re: Confusing input / output of encrypted, serialized Obj
    EJP Guru
    Currently Being Moderated
    I created a class called DecryptionInputStream...
    Don't. See javax.crypto.CipherInputStream. See also javax.crypto.CipherOutputStream. Use both.

    And forget the StringEncrypter and the base64 encoding and all the other garbage.
  • 4. Re: Confusing input / output of encrypted, serialized Obj
    807605 Newbie
    Currently Being Moderated
    I tabbed back to this page with high hopes that someone responded.
    I had found that, and I'm reading up on how Ciphers work now, too.

    Thanks for the fast responses! :D
    Learning java is so fun. =)