/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.doplgangr.secrecy.filesystem.files; import android.graphics.Bitmap; import android.media.ThumbnailUtils; import android.provider.MediaStore; import com.doplgangr.secrecy.Config; import com.doplgangr.secrecy.exceptions.SecrecyCipherStreamException; import com.doplgangr.secrecy.exceptions.SecrecyFileException; import com.doplgangr.secrecy.filesystem.encryption.Crypter; import com.doplgangr.secrecy.filesystem.encryption.Vault; import com.doplgangr.secrecy.filesystem.Storage; import com.doplgangr.secrecy.utils.Util; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.UUID; import javax.crypto.CipherOutputStream; public class EncryptedFileFactory { private final static EncryptedFileFactory INSTANCE = new EncryptedFileFactory(); private final static String THUMBNAIL_PREFIX = "/.thumb_"; private static final String FILE_HEADER_PREFIX = "/.header_"; public static EncryptedFileFactory getInstance() { return EncryptedFileFactory.INSTANCE; } public EncryptedFile loadEncryptedFile(File encryptedFile, Crypter crypter, boolean isEcbVault) throws FileNotFoundException { File thumbnail = new File(encryptedFile.getParent() + THUMBNAIL_PREFIX + encryptedFile.getName()); File fileHeader = new File(encryptedFile.getParent() + FILE_HEADER_PREFIX + encryptedFile.getName()); if (!isEcbVault && !fileHeader.exists()){ throw new FileNotFoundException("File header not found!"); } if (thumbnail.exists()) { EncryptedThumbnail encryptedThumbnail = new EncryptedThumbnail( thumbnail, crypter); return new EncryptedFile(encryptedFile, crypter, encryptedThumbnail); } return new EncryptedFile(encryptedFile, crypter, null); } public EncryptedFile createNewEncryptedFile(File unencryptedFile, Crypter crypter, Vault vault) throws SecrecyFileException { Util.log(this.getClass().getName() + ": Creating new encrypted file!"); String outputFileName = UUID.randomUUID().toString(); File outputFile = new File(vault.getPath() + "/" + outputFileName); while (outputFile.exists()) { Util.log("Output file name already exists. Trying new file name!"); outputFileName = UUID.randomUUID().toString(); outputFile = new File(vault.getPath() + "/" + outputFileName); } BufferedInputStream bufferedInputStream; CipherOutputStream out; try { bufferedInputStream = new BufferedInputStream( new FileInputStream(unencryptedFile), Config.BLOCK_SIZE); out = crypter.getCipherOutputStream(unencryptedFile, outputFileName); } catch (FileNotFoundException e) { Util.log(this.getClass().getName() + ": File not found!"); throw new SecrecyFileException("File not found!"); } catch (SecrecyCipherStreamException e) { Util.log(this.getClass().getName() + ": SecrecyCipherStreamException: " + e.getMessage()); throw new SecrecyFileException("SecrecyCipherStreamException: " + e.getMessage()); } try { if (out != null) { byte buffer[] = new byte[Config.BUFFER_SIZE]; int count; while ((count = bufferedInputStream.read(buffer)) != -1) { out.write(buffer, 0, count); } } } catch (IOException e) { Util.log(this.getClass().getName() + ": IOException while encrypting file!"); throw new SecrecyFileException("IOException while encrypting file!"); } finally { try { bufferedInputStream.close(); if (out != null) { out.close(); } } catch (IOException e) { Util.log(this.getClass().getName() + ": IOException while closing IO streams"); } } // Create thumbnail File thumbnailOutputFile = new File(vault.getPath() + THUMBNAIL_PREFIX + outputFileName); createThumbnail(unencryptedFile, thumbnailOutputFile, crypter); EncryptedThumbnail encryptedThumbnail = new EncryptedThumbnail(thumbnailOutputFile, crypter); EncryptedFile encryptedFile; try { encryptedFile = new EncryptedFile(outputFile, crypter, encryptedThumbnail); } catch (FileNotFoundException e) { Util.log(this.getClass().getName() + ": Encrypted file not found!"); throw new SecrecyFileException("Encrypted file not found!"); } return encryptedFile; } private boolean createThumbnail(File inputFile, File outputFile, Crypter crypter) { Bitmap bitmap; Util.log("Trying to create thumbnail for: " + inputFile.getPath()); bitmap = Storage.decodeSampledBitmapFromPath(inputFile.getPath(), 150, 150); if (bitmap == null) { //If photo fails, try Video Util.log("Trying to create video thumbnail for: " + inputFile.getPath()); bitmap = ThumbnailUtils.createVideoThumbnail(inputFile.getPath(), MediaStore.Video.Thumbnails.MICRO_KIND); } if (bitmap == null) { Util.log("Could not create thumbnail for: " + inputFile.getPath()); return false; } CipherOutputStream out; try { out = crypter.getCipherOutputStream(outputFile, outputFile.getName()); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); } catch (SecrecyCipherStreamException e) { return false; } catch (FileNotFoundException e) { return false; } try { out.close(); } catch (IOException e) { e.printStackTrace(); } return true; } }