001/**
002 * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
003 *
004 * This file is part of Dicoogle/dicoogle.
005 *
006 * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * Dicoogle/dicoogle is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package pt.ua.dicoogle.server.users;
020
021import java.io.ByteArrayInputStream;
022import java.io.ByteArrayOutputStream;
023import java.io.FileInputStream;
024import java.io.FileNotFoundException;
025import java.io.FileOutputStream;
026import java.io.IOException;
027import java.io.InputStream;
028import java.io.ObjectInputStream;
029import java.io.ObjectOutputStream;
030import java.security.InvalidKeyException;
031import java.security.Key;
032import java.security.NoSuchAlgorithmException;
033import java.security.SecureRandom;
034
035import javax.crypto.BadPaddingException;
036import javax.crypto.Cipher;
037import javax.crypto.IllegalBlockSizeException;
038import javax.crypto.KeyGenerator;
039import javax.crypto.NoSuchPaddingException;
040import org.slf4j.LoggerFactory;
041
042import pt.ua.dicoogle.core.ServerSettings;
043import pt.ua.dicoogle.sdk.Utils.Platform;
044
045/**
046 * This class provides encryptation to the file that saves users information
047 * Uses the AES algorithim with 128 bit key
048 *
049 * @author Samuel Campos <samuelcampos@ua.pt>
050 */
051public class UserFileHandle {
052
053    private String filename;
054    private String keyFile;
055
056    private Cipher cipher;
057    private Key key;
058    private boolean encrypt;
059
060    public UserFileHandle() throws IOException {
061        filename = Platform.homePath() + "users.xml";
062        encrypt = ServerSettings.getInstance().isEncryptUsersFile();
063        try {
064
065            if(encrypt){
066                keyFile = "users.key";
067
068                try {
069                    ObjectInputStream in = new ObjectInputStream(new FileInputStream(keyFile));
070                    key = (Key) in.readObject();
071                    in.close();
072
073                } catch (FileNotFoundException ex) {
074                    KeyGenerator gen = KeyGenerator.getInstance("AES");
075
076                    gen.init(128, new SecureRandom());
077                    key = gen.generateKey();
078
079                    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(keyFile))) {
080                        out.writeObject(key);
081                    }
082                }
083
084                cipher = Cipher.getInstance("AES");
085            }
086
087        } catch (NoSuchAlgorithmException | ClassNotFoundException | NoSuchPaddingException ex) {
088            LoggerFactory.getLogger(UserFileHandle.class).error(ex.getMessage(), ex);
089        }
090    }
091
092    /**
093     * Print one byte array in File
094     * Encrypt that file with the key
095     * @param bytes
096     */
097    public void printFile(byte[] bytes) throws Exception {
098        InputStream in;
099
100        if(encrypt){
101            cipher.init(Cipher.ENCRYPT_MODE, key);
102
103            byte[] encryptedBytes = cipher.doFinal(bytes);
104            in = new ByteArrayInputStream(encryptedBytes);
105        }
106        else
107            in = new ByteArrayInputStream(bytes);
108
109        FileOutputStream out = new FileOutputStream(filename);
110        
111
112        byte[] input = new byte[1024];
113        int bytesRead;
114        while ((bytesRead = in.read(input)) != -1) {
115            out.write(input, 0, bytesRead);
116            out.flush();
117        }
118
119        out.close();
120        in.close();
121    }
122
123    /** Retrieve the contents of the users configuration file.
124     * @return a byte array, or null if the configuration file is not available or corrupted
125     * @throws IOException on a failed attempt to read the file
126     */
127    public byte[] getFileContent() throws IOException {
128        try {
129            try (FileInputStream fin = new FileInputStream(filename);
130                    ByteArrayOutputStream out = new ByteArrayOutputStream()) {
131                byte[] data = new byte[1024];
132                int bytesRead;
133
134                while ((bytesRead = fin.read(data)) != -1) {
135                    out.write(data, 0, bytesRead);
136                    out.flush();
137                }
138
139                if(encrypt){
140                    cipher.init(Cipher.DECRYPT_MODE, key);
141                    byte[] Bytes = cipher.doFinal(out.toByteArray());
142                    return Bytes;
143                }
144                
145                return out.toByteArray();
146            }
147        } catch (FileNotFoundException ex) {
148            LoggerFactory.getLogger(UserFileHandle.class).info("No such users file \"{}\", will create one with default settings.", filename);
149        } catch (IllegalBlockSizeException ex) {
150            LoggerFactory.getLogger(UserFileHandle.class).error("Users file \"{}\" is corrupted, will override it with default settings.", filename, ex);
151        } catch (InvalidKeyException ex) {
152            LoggerFactory.getLogger(UserFileHandle.class).error("Invalid Key to decrypt users file! Please contact your system administator.");
153            System.exit(1); // FIXME this is too dangerous
154        }
155        catch(BadPaddingException ex){
156            LoggerFactory.getLogger(UserFileHandle.class).error("Invalid Key to decrypt users file! Please contact your system administator.");
157            System.exit(2); // FIXME this is too dangerous
158        }
159        return null;
160    }
161}