2
votes

I'm working on a project to Encrypt/Decrypt files. as this is my first time, I'm wondering if I'm doing it right or not. till now, my idea about encrypting is this :

Select a file -> Read all its bytes and add it to byte array -> Encrypt the byte array -> write encrypted bytes to same file.

note that in this project output file is same file as input. So I decided to clear file before writing encrypted bytes to it.

This might be stupid (and thats why I'm asking for help), so here is my way

public class Encryptor {
  File file;
  SecretKeySpec secretKeySpec;
  public void setFile(String filePath) throws Exception {
    this.file = new File(filePath);
    if(!file.isFile()){
      throw new Exception("The file you choosed is not valid");
    }
  }
  public void setKey(String keyword){
    try {
      MessageDigest sha = MessageDigest.getInstance("SHA-256");
      sha.update(keyword.getBytes("UTF-8"));
      byte[] key = sha.digest();
      secretKeySpec = new SecretKeySpec(key, "AES");
    } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
  }
  public void encrypt(){
    byte[] bFile = new byte[(int) file.length()];
    try {
      //adding portocol bytes to the file bytes
      //String portcol = "encryptor portocol";
      //byte[] decPortocol = portcol.getBytes();

      //convert file into array of bytes
      BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
      bufferedInputStream.read(bFile);
      bufferedInputStream.close();

      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      //outputStream.write(decPortocol);
      outputStream.write(bFile);

      byte[] cryptedFileBytes = outputStream.toByteArray();
      //Cipher and encrypting
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
      cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
      byte[] encryptedBytes = cipher.doFinal(cryptedFileBytes);

      //Write Encrypted File
      BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file,false));
      bufferedOutputStream.write(encryptedBytes);
      bufferedOutputStream.flush();
      bufferedOutputStream.close();
    }catch (Exception e){
      e.printStackTrace();
    }
  }

}

main question

are there other ways to read-encrypt-write on same file together at same time? like reading bytes part by part and at same time encrypting that part and overwrite it with encrypted bytes.

Can You Help me more ?

And also Any information about how to make my encrypted files more safe can also be helpful.

and does my program kill RAM ?!

(NOTE) I'm writing encrypted data on same file for some reasons. I'm not much familiar with how hard drive works. One of my reasons is to prevent file from being recovered later. is there anything I have to know about that ? does what I'm doing prevent unEncrypted file to be recovered later ?


EDIT @erickson has pointed out something important in his answer. I got to know that this way of encrypting a file is not safe. What I was considering to prevent too, was preventing file from being recovered later. I mean there is no point to encrypt a file and keep it in your hard drive if you once had it unEncrypted there ! in my experience, everytime I recovered a file, I reached last edits of it and I could never get history of changes. I thought this must be the same if I was not wrong in first place. How can I help preventing data recovery then ?!

2
The standard way to handle the operation you're describing is to create a new file, write the processed bytes to it, then remove the input file. See, for example, gzip. And on any modern (journaled) filesystem, you're not going to be overwriting the data in-place anyhow; you simply have no control over that.chrylis -cautiouslyoptimistic-
@chrylis I know this is not standard way. I can deal with writing an output file in other directory. as I already noted, I have some reasons to do this in nonstandard ways (and I have doubts about them for sure). like preventing file recovery to access plain(unEncrypted) file later and other ...Sep GH
Understood, but overwriting the file in-place won't accomplish that, so it's a lot of complication for no benefit.chrylis -cautiouslyoptimistic-

2 Answers

3
votes

Writing to a file while reading can work, but it would be easy to introduce a bug that would corrupt the file. For safety's sake, it might be better to write to a temporary file, then delete the original file and replace it with the temporary file. That way, all of the file content is always safely in at least one file.

One caveat about this is that if you encrypt an existing file, there's no guarantee that the original file isn't still recorded on disk. Even if you write to the same file as you read, whether the same storage is overwritten with encrypted data will depend on the underlying file system.

It would be better if the original file was written in its encrypted form. Even if the writing application doesn't support encryption, most operating systems support the creation of an encrypted file system so that any application can keep files secret.

1
votes

You need to close your reader after you have finished reading the file. You are currently doing it in this line:

bufferedInputStream.close();

So it's ok. Then, instead of clearing file, you can just simply overwrite it using:

BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filename, false);

Hope that helps :)