View Javadoc

1   /********************************************************************************
2    *InternetCafe is a software solution that helps the management of Cybercafes 
3    * according with the ITALIAN DECREE LAW ON ANTI-TERROR MEASURES, 27 JULY 2005.
4    * Copyright (C) 2006  Guido Angelo Ingenito
5   
6    * This program is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU General Public License
8    * as published by the Free Software Foundation; either version 2
9    * of the License, or (at your option) any later version.
10  
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   * 
16   * You should have received a copy of the GNU General Public License
17   * along with this program; if not, write to the Free Software
18   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19   *******************************************************************************/
20  package base.jdbs;
21  
22  import java.io.File;
23  import java.io.FileWriter;
24  import java.io.IOException;
25  import java.io.PrintStream;
26  
27  import javax.xml.parsers.DocumentBuilderFactory;
28  import javax.xml.transform.Transformer;
29  import javax.xml.transform.TransformerFactory;
30  import javax.xml.transform.dom.DOMSource;
31  import javax.xml.transform.stream.StreamResult;
32  
33  import org.apache.log4j.Logger;
34  import org.w3c.dom.Document;
35  
36  import base.jdbs.cryptography.asymmetric.KeyPair;
37  import base.jdbs.cryptography.asymmetric.RSAAsymmetricCipher;
38  import base.jdbs.cryptography.symmetric.DESSymmetricCipher;
39  import base.jdbs.cryptography.symmetric.SymmetricKey;
40  import base.util.FileUtil;
41  import base.util.ZipUtil;
42  
43  /***
44   * This class provided methods and utils to assembly a backup.
45   * @author Guido Angelo Ingenito
46   */
47  public class BackupArtifactAssembler {
48  	
49  	public static final String ENCRYPTION_DIRECTORY_NAME = "enc";
50  	public static final String DECRYPTION_DIRECTORY_NAME = "dec";
51  
52  	private static final transient Logger logger = Logger.getLogger(BackupArtifactAssembler.class.getName());
53  	
54  	/***
55  	 * This method builds a new signed backup artifact placing it into a temp directory. 
56  	 * The backup building process is fully described in the JDBS analysis and it consists of some phases:
57  	 * Phase 1: backup files encryption (only in the case of PRIVATE content).
58  	 * Phase 2: backup info file creation.
59  	 * Phase 3: backup compression.
60  	 * Phase 4: backup CRC32 Checksum, MD5 Digest and X509 certificate file creation.
61  	 * Phase 5: backup asymmetric signature ( the signature is placed on the MD5 Digest file and a new signed file is created ).
62  	 * @param symmetricKey The symmetric key to use in the encryption process.
63  	 * @param keyPair The asymmetric key pair to be used during the signing phase.
64  	 * @param backup The input backup from which the backup artifact must be created.
65  	 * @return The directory where the backup has been created and that contains the Compressed and Encrypted Backup Artifact and 
66  	 * some info files. This outputted directory reference should be moved to the local JDBS users'repository.
67  	 * @throws IOException If something wrong happens with the filesystem.
68  	 */
69  	public static File buildNewBackupArtifact(File repositoryDirectory, SymmetricKey symmetricKey, KeyPair keyPair, Backup backup) throws IOException{
70  		
71  		final String backupArtifactName = backup.getGuId()+"-"+backup.getName();
72  		//This is the backup directory under the local Repository
73  		final File backupDirectory = new File(repositoryDirectory,backupArtifactName);
74  		backupDirectory.mkdir();
75  		logger.debug("Backup Directory on local Repository: "+ backupDirectory);
76  		
77  		final File encryptionDir = new File(backupDirectory,ENCRYPTION_DIRECTORY_NAME);
78  		final File decryptionDir = new File(backupDirectory,DECRYPTION_DIRECTORY_NAME);
79  		
80  		logger.debug("Backup Encryption Directory: "+ encryptionDir);
81  		encryptionDir.mkdir();
82  		logger.debug("Backup Decryption Directory: "+ decryptionDir);
83  		decryptionDir.mkdir();
84  		
85  		//Each backups' file must be encrypted preserving the directory structure on the filesystem...
86  		logger.debug("Backup's security level: "+backup.getSecurityLevel());
87  		if(backup.getSecurityLevel().equals(SecurityLevel.PRIVATE)){
88  			logger.debug("Symmetric encryption with key: "+symmetricKey.getValue()+"...");
89  			
90  			DESSymmetricCipher symmetricCipher = new DESSymmetricCipher(symmetricKey);
91  			
92  			//Here starts the file encryption
93  			for(int i=0;i<backup.getFileDescriptor().length;i++){
94  				File encFile = new File(encryptionDir, backup.getFileDescriptor()[i].getFile().getAbsolutePath());
95  				encFile.getParentFile().mkdirs();
96  				encFile.createNewFile();
97  				symmetricCipher.encrypt(backup.getFileDescriptor()[i].getFile(),encFile);
98  			}
99  			
100 			
101 		}else{
102 			logger.debug("Moving backup's files under the decryption folder, backup has PUBLIC content...");
103 			//Here starts the file copy
104 			for(int i=0;i<backup.getFileDescriptor().length;i++){
105 				File decFile = new File(decryptionDir, backup.getFileDescriptor()[i].getFile().getAbsolutePath());
106 				decFile.getParentFile().mkdirs();
107 				decFile.createNewFile();
108 				FileUtil.copyFile(backup.getFileDescriptor()[i].getFile(),decFile);
109 			}
110 			
111 		}
112 		
113 		final File compressedFile;
114 		if(backup.getSecurityLevel().equals(SecurityLevel.PRIVATE)){
115 			logger.debug("Backup has PRIVATE content, compressing the encryption directory...");
116 			compressedFile = new File(backupDirectory,backupArtifactName+JDBSConstant.DOTTED_ZIP_EXTENSION);
117 			compressedFile.createNewFile();
118 			ZipUtil.zipDirectory(encryptionDir,compressedFile);
119 		}
120 		else{
121 			logger.debug("Backup has PUBLIC content, compressing the decryption directory...");
122 			compressedFile = new File(backupDirectory,backupArtifactName+JDBSConstant.DOTTED_ZIP_EXTENSION);
123 			compressedFile.createNewFile();
124 			ZipUtil.zipDirectory(decryptionDir,compressedFile);
125 			
126 		}
127 		
128 		//Here must be stored in xml the informations relative to the backup content...
129 		logger.debug("Building the backup's xml info file...");
130 		final File infoFile = new File(backupDirectory,JDBSConstant.XML_INFO_FILE_NAME);
131 		writeBackupXmlInfoFile(backup, infoFile);
132 		
133 		//Making a CRC32 for the compressed backup artifact...
134 		logger.debug("Writing backup's CRC32 Checksum...");
135 		final File crc32File = new File(backupDirectory,JDBSConstant.CRC32_FILE_NAME);
136 		writeBackupCRC32Checksum(crc32File, compressedFile);
137 		
138 		//Making an MD5 digest for the compressed backup artifact, this will be signed with the users'private key...
139 		logger.debug("Writing backup's MD5 Digest...");
140 		final File md5File = new File(backupDirectory,JDBSConstant.MD5_FILE_NAME);
141 		writeBackupMD5Digest(md5File, compressedFile);
142 		
143 		//In each case, PRIVATE or PUBLIC content the backup MD5 must be signed with the privateKey to check integrity and security...
144 		logger.debug("Signing the backup artifact's MD5 digest...");
145 		RSAAsymmetricCipher asymmetricCipher = new RSAAsymmetricCipher();
146 		final File signedDigest = new File(md5File+JDBSConstant.DOTTED_SIGNED_EXTENSION);
147 		if(keyPair == null)throw new IllegalArgumentException("AFFF1");
148 		if(keyPair.getPrivateKey() == null)throw new IllegalArgumentException("AFFF2");
149 		
150 		asymmetricCipher.sign(md5File, signedDigest,keyPair.getPrivateKey() );
151 		
152 		//The keyPair associated certificate must be stored to the output directory...
153 		logger.debug("Writing the X509Certificate...");
154 		File certificateFile = new File(backupDirectory,JDBSConstant.CERTIFICATE_FILE_NAME);
155 		writeX509Certificate(keyPair.getCertificate(), certificateFile);
156 		
157 		logger.debug("Encryption Directory Deletion Result: " + FileUtil.deleteDirectory(encryptionDir));
158 		logger.debug("Decryption Directory Deletion Result: " + FileUtil.deleteDirectory(decryptionDir));
159 		
160 		logger.debug("Backup artifact successfully created...");
161 		return backupDirectory;
162 	}
163 	
164 	/***
165 	 * This method writes to a file the info associated to a backup, in xml format.
166 	 * @param backup The backup whose info must be stored to the output file.
167 	 * @param outputInfo The outputFile where the info will be stored.
168 	 */
169 	protected static void writeBackupXmlInfoFile(Backup backup, File outputInfo){
170 		try {
171 			Document backupInfoDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
172 			backupInfoDocument.appendChild(backup.toXml(backupInfoDocument));	
173 			Transformer transformer = TransformerFactory.newInstance().newTransformer();
174 			DOMSource source = new DOMSource(backupInfoDocument);
175 			StreamResult streamResult = new StreamResult(new PrintStream(outputInfo));
176 			transformer.transform(source, streamResult);
177 		} catch (Exception ex) {
178 			logger.error(ex.getMessage());
179 			ex.printStackTrace();
180 		} 
181 	}
182 	
183 	/***
184 	 * This method writes a CRC32 Checksum to a file.
185 	 * @param crc32Output The CRC32 Checksum file to be written.
186 	 * @param compressedBackup The Compressed Backup Artifact from which the CRC32 must be computed.
187 	 */
188 	protected static void writeBackupCRC32Checksum(File crc32Output, File compressedBackup){
189 		FileWriter fileWriter;
190 		try {
191 			fileWriter = new FileWriter(crc32Output);
192 			String backupCRC32 = FileUtil.createCRC32Checksum(compressedBackup).toString();
193 			logger.debug("File: "+compressedBackup + " CRC32: "+backupCRC32);
194 			fileWriter.write(backupCRC32);
195 			fileWriter.close();
196 		} catch (IOException ex) {
197 			logger.error(ex.getMessage());
198 			ex.printStackTrace();
199 		}
200 	}
201 	
202 	/***
203 	 * This method writes a MD5 Digest to a file.
204 	 * @param MD5DigestOutput The MD5 Digest file to be written.
205 	 * @param compressedBackup The Compressed Backup Artifact from which the CRC32 must be computed.
206 	 */
207 	protected static void writeBackupMD5Digest(File MD5DigestOutput, File compressedBackup){
208 		FileWriter fileWriter;
209 		try {
210 			fileWriter = new FileWriter(MD5DigestOutput);
211 			String backupMD5Digest = FileUtil.createMD5Digest(compressedBackup);
212 			logger.debug("File: "+compressedBackup + " MD5: "+backupMD5Digest);
213 			fileWriter.write(backupMD5Digest);
214 			fileWriter.close();
215 		} catch (IOException ex) {
216 			logger.error(ex.getMessage());
217 			ex.printStackTrace();
218 		}
219 	}
220 	
221 
222 	/***
223 	 * This method writes to a file an X509Certificate. 
224 	 * @param certificate The certificate that must be saved.
225 	 * @param certificateFile The output file where the certificate must be stored.
226 	 */
227 	protected static void writeX509Certificate(java.security.cert.X509Certificate certificate, File certificateFile){
228 		FileWriter fileWriter;
229 		try {
230 			fileWriter = new FileWriter(certificateFile);
231 			logger.debug("Certificate: \n"+ certificate + "\nSaved in file: "+certificateFile);
232 			fileWriter.write(certificate.toString());
233 			fileWriter.close();
234 		} catch (IOException ex) {
235 			logger.error(ex.getMessage());
236 			ex.printStackTrace();
237 		}
238 	}
239 }