views:

304

answers:

2

How do you decrypt a file in java and export it to a file without having to end up in an infinite loop if you have more than one user and password. Here is my code and at the end is my test file:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
public class Checker {
    private ArrayList<String> usersList = new ArrayList<String>();
    private ArrayList<String> passwordList = new ArrayList<String>();
    private Cipher cipher = null;
    private KeyGenerator keyGen = null;
    private Key key = null;
    private PrintStream output = System.out;
    private FileOutputStream fos = null;
    Checker(){
        try {
      cipher = Cipher.getInstance("AES");
      keyGen = KeyGenerator.getInstance("AES");
      key = keyGen.generateKey();
      output = new PrintStream(new FileOutputStream("data.txt"), true);
      fos =  new FileOutputStream(new File("data.txt"));
     } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
     } catch (NoSuchPaddingException e) {
      e.printStackTrace();
     } catch (FileNotFoundException e) {
      e.printStackTrace();
     }
    }

    public void check(){
     try {
      CipherInputStream cipherIn = new CipherInputStream(new FileInputStream(new File("data.txt")), cipher);
      cipher.init(Cipher.DECRYPT_MODE, key);



      int i; 
      while((i = cipherIn.read())!=-1){
       fos.write(i);
      }
      output.close();
     } catch (FileNotFoundException e) {
      System.err.println("filepath not found!");
     } catch (IOException e) {
      System.err.println("IOException: " + e);
     } catch (InvalidKeyException e) {
      e.printStackTrace();
     }


    }

    public void add(String user, String password){
     if(!(usersList.contains(user)||passwordList.contains(password))){
      if(usersList.isEmpty()||passwordList.isEmpty()){
       usersList.clear();
       passwordList.clear();
       usersList.add(user);
       passwordList.add(password);
      }else{
       usersList.add(usersList.size(), user);
       passwordList.add(usersList.size()-1, password);
      }
     }
    }

    public void display(){
     System.out.println(usersList);
     System.out.println(passwordList);
    }

    public void save(){
     try {
      for (int x = 0; x<usersList.size(); x++){
       output.print(usersList.get(x));
       output.print("|");
       output.println(passwordList.get(x));
      }
      CipherInputStream cipherIn = new CipherInputStream(new FileInputStream(new File("data.txt")), cipher);
      cipher.init(Cipher.ENCRYPT_MODE, key);
      int i; 
      while((i = cipherIn.read())!=-1){
       fos.write(i);
      }

      output.close();
     } catch (FileNotFoundException e) {
      e.printStackTrace();
     } catch (IOException e) {
      e.printStackTrace();
     } catch (InvalidKeyException e) {
      e.printStackTrace();
     }
    }}

    public class CheckerTest {
    public static void main(String[] args) {
     Checker checker = new Checker();
     checker.add("peter", "12345");
     checker.add("mike", "67890");
     checker.display();
     checker.save();
     checker.check();
    }}

PS I know that my check() method does not work fully (it doesn't actually check if they are in the list) but I just need to decrypt the file as well as not have the encrypted with the decrypted data all mixed up.

A: 

Some remarks on your code:

  1. Don't store plaintext passwords... it's just bad.
  2. Why are you doing this:

    usersList.add(usersList.size(), user); passwordList.add(usersList.size()-1, password);

    Honestly, I don't get it. Why don't you just .add() to the according list?

  3. Why do you .clear() the lists when you have checked before that they are already empty?

  4. Why won't you let two users have the same password?

For your exporting problem (I think it won't be too hard to adapt it):

 KeyGenerator kg = KeyGenerator.getInstance("DES");
 kg.init(new SecureRandom());
 SecretKey key = kg.generateKey();
 SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
 Class spec = Class.forName("javax.crypto.spec.DESKeySpec");
 DESKeySpec ks = (DESKeySpec) skf.getKeySpec(key, spec);
 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("keyfile"));
 oos.writeObject(ks.getKey());

 Cipher c = Cipher.getInstance("DES/CFB8/NoPadding");
 c.init(Cipher.ENCRYPT_MODE, key);
 CipherOutputStream cos = new CipherOutputStream(new FileOutputStream("ciphertext"), c);
 PrintWriter pw = new PrintWriter(new OutputStreamWriter(cos));
 pw.println("Stand and unfold yourself");
 pw.close();
 oos.writeObject(c.getIV());
 oos.close();

From here: http://www.java2s.com/Tutorial/Java/0490%5F%5FSecurity/UsingCipherOutputStream.htm

Chris
@3, he checked one of them is empty and clears both
rsp
yes i noticed that. but isn't that a strange thing to do? I mean if you have more passwords than users or vice versa is it then really clever to delete everything? And in the code as posted above, if I'm not mistaken, is no possibility to ever run into such a situation
Chris
+1  A: 

A few hints towards your code:

  • insert comments that describe why you do things (to help you maintain / understand it later)
  • define private final constants for the magic strings like "AES" and "data.txt" that are copied all over now (less chance of typoes and easier to change if need be)
  • use base types hiding implementation details where possible, i.e. List<String> usersList
  • instead of trying to keep the usersList and passwordsList in synch, you could also create a Map<<String>,<String>> for storing passwords for usernames.
rsp