package org.commcare.models.encryption;
import org.commcare.logging.AndroidLogger;
import org.javarosa.core.services.Logger;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
/**
* Methods for dealing with encrypted input/output.
*
* @author Phillip Mates (pmates@dimagi.com).
*/
public class EncryptionIO {
public static OutputStream createFileOutputStream(String filename,
SecretKeySpec symetricKey)
throws FileNotFoundException {
final File path = new File(filename);
FileOutputStream fos = new FileOutputStream(path);
if (symetricKey == null) {
return fos;
} else {
try {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, symetricKey);
return new BufferedOutputStream(new CipherOutputStream(fos, cipher));
//All of these exceptions imply a bad platform and should be irrecoverable (Don't ever
//write out data if the key isn't good, or the crypto isn't available)
} catch (InvalidKeyException e) {
e.printStackTrace();
Logger.log(AndroidLogger.TYPE_ERROR_CRYPTO, "Invalid key: " + e.getMessage());
throw new RuntimeException(e.getMessage());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
Logger.log(AndroidLogger.TYPE_ERROR_CRYPTO, "Unavailable Crypto algorithm: " + e.getMessage());
throw new RuntimeException(e.getMessage());
} catch (NoSuchPaddingException e) {
e.printStackTrace();
Logger.log(AndroidLogger.TYPE_ERROR_CRYPTO, "Bad Padding: " + e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
}
public static InputStream getFileInputStream(String filepath,
SecretKeySpec symetricKey) throws FileNotFoundException {
final File file = new File(filepath);
InputStream is;
try {
is = new FileInputStream(file);
if (symetricKey != null) {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, symetricKey);
is = new BufferedInputStream(new CipherInputStream(is, cipher));
}
//CTS - Removed a lot of weird checks here. file size < max int? We're shoving this
//form into a _Byte array_, I don't think there's a lot of concern than 2GB of data
//are gonna sneak by.
return is;
//CTS - Removed the byte array length check here. Plenty of
//files are smaller than their contents (padded encryption data, etc),
//so you can't actually know that's correct. We should be relying on the
//methods we use to read data to make sure it's all coming out.
} catch (InvalidKeyException | NoSuchPaddingException
| NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}