use of org.odk.collect.android.exception.EncryptionException in project collect by opendatakit.
the class EncryptionUtils method encryptFile.
private static void encryptFile(File file, EncryptedFormInformation formInfo) throws IOException, EncryptionException {
File encryptedFile = new File(file.getParentFile(), file.getName() + ".enc");
if (encryptedFile.exists() && !encryptedFile.delete()) {
throw new IOException("Cannot overwrite " + encryptedFile.getAbsolutePath() + ". Perhaps the file is locked?");
}
// add elementSignatureSource for this file...
formInfo.appendFileSignatureSource(file);
RandomAccessFile randomAccessFile = null;
CipherOutputStream cipherOutputStream = null;
try {
Cipher c = formInfo.getCipher();
randomAccessFile = new RandomAccessFile(encryptedFile, "rws");
ByteArrayOutputStream encryptedData = new ByteArrayOutputStream();
cipherOutputStream = new CipherOutputStream(encryptedData, c);
InputStream fin = new FileInputStream(file);
byte[] buffer = new byte[2048];
int len = fin.read(buffer);
while (len != -1) {
cipherOutputStream.write(buffer, 0, len);
len = fin.read(buffer);
}
fin.close();
cipherOutputStream.flush();
cipherOutputStream.close();
randomAccessFile.write(encryptedData.toByteArray());
Timber.i("Encrpyted:%s -> %s", file.getName(), encryptedFile.getName());
} catch (Exception e) {
String msg = "Error encrypting: " + file.getName() + " -> " + encryptedFile.getName();
Timber.e(e, "%s due to %s ", msg, e.getMessage());
throw new EncryptionException(msg, e);
} finally {
IOUtils.closeQuietly(cipherOutputStream);
if (randomAccessFile != null) {
randomAccessFile.close();
}
}
}
use of org.odk.collect.android.exception.EncryptionException in project collect by opendatakit.
the class SaveToDiskTask method doInBackground.
/**
* Initialize {@link FormEntryController} with {@link org.javarosa.core.model.FormDef} from binary or from XML. If
* given
* an instance, it will be used to fill the {@link org.javarosa.core.model.FormDef}.
*/
@Override
protected SaveResult doInBackground(Void... nothing) {
SaveResult saveResult = new SaveResult();
FormController formController = Collect.getInstance().getFormController();
publishProgress(Collect.getInstance().getString(R.string.survey_saving_validating_message));
try {
int validateStatus = formController.validateAnswers(markCompleted);
if (validateStatus != FormEntryController.ANSWER_OK) {
// validation failed, pass specific failure
saveResult.setSaveResult(validateStatus, markCompleted);
return saveResult;
}
} catch (Exception e) {
Timber.e(e);
// SCTO-825
// that means that we have a bad design
// save the exception to be used in the error dialog.
saveResult.setSaveErrorMessage(e.getMessage());
saveResult.setSaveResult(SAVE_ERROR, markCompleted);
return saveResult;
}
// check if the "Cancel" was hit and exit.
if (isCancelled()) {
return null;
}
if (markCompleted) {
formController.postProcessInstance();
}
Collect.getInstance().getActivityLogger().logInstanceAction(this, "save", Boolean.toString(markCompleted));
// close all open databases of external data.
Collect.getInstance().getExternalDataManager().close();
// if there is a meta/instanceName field, be sure we are using the latest value
// just in case the validate somehow triggered an update.
String updatedSaveName = formController.getSubmissionMetadata().instanceName;
if (updatedSaveName != null) {
instanceName = updatedSaveName;
}
try {
exportData(markCompleted);
if (formController.getInstanceFile() != null) {
removeSavepointFiles(formController.getInstanceFile().getName());
}
saveResult.setSaveResult(save ? SAVED_AND_EXIT : SAVED, markCompleted);
} catch (EncryptionException e) {
saveResult.setSaveErrorMessage(e.getMessage());
saveResult.setSaveResult(ENCRYPTION_ERROR, markCompleted);
} catch (Exception e) {
Timber.e(e);
saveResult.setSaveErrorMessage(e.getMessage());
saveResult.setSaveResult(SAVE_ERROR, markCompleted);
}
return saveResult;
}
use of org.odk.collect.android.exception.EncryptionException in project collect by opendatakit.
the class EncryptionUtils method writeSubmissionManifest.
private static void writeSubmissionManifest(EncryptedFormInformation formInfo, File submissionXml, List<File> mediaFiles) throws EncryptionException {
Document d = new Document();
d.setStandalone(true);
d.setEncoding(UTF_8);
Element e = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, DATA);
e.setPrefix(null, XML_ENCRYPTED_TAG_NAMESPACE);
e.setAttribute(null, ID, formInfo.formId);
if (formInfo.formVersion != null) {
e.setAttribute(null, VERSION, formInfo.formVersion);
}
e.setAttribute(null, ENCRYPTED, "yes");
d.addChild(0, Node.ELEMENT, e);
int idx = 0;
Element c;
c = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, BASE64_ENCRYPTED_KEY);
c.addChild(0, Node.TEXT, formInfo.base64RsaEncryptedSymmetricKey);
e.addChild(idx++, Node.ELEMENT, c);
c = d.createElement(XML_OPENROSA_NAMESPACE, META);
c.setPrefix("orx", XML_OPENROSA_NAMESPACE);
{
Element instanceTag = d.createElement(XML_OPENROSA_NAMESPACE, INSTANCE_ID);
instanceTag.addChild(0, Node.TEXT, formInfo.instanceMetadata.instanceId);
c.addChild(0, Node.ELEMENT, instanceTag);
}
e.addChild(idx++, Node.ELEMENT, c);
e.addChild(idx++, Node.IGNORABLE_WHITESPACE, NEW_LINE);
if (mediaFiles != null) {
for (File file : mediaFiles) {
c = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, MEDIA);
Element fileTag = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, FILE);
fileTag.addChild(0, Node.TEXT, file.getName() + ".enc");
c.addChild(0, Node.ELEMENT, fileTag);
e.addChild(idx++, Node.ELEMENT, c);
e.addChild(idx++, Node.IGNORABLE_WHITESPACE, NEW_LINE);
}
}
c = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, ENCRYPTED_XML_FILE);
c.addChild(0, Node.TEXT, submissionXml.getName() + ".enc");
e.addChild(idx++, Node.ELEMENT, c);
c = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, BASE64_ENCRYPTED_ELEMENT_SIGNATURE);
c.addChild(0, Node.TEXT, formInfo.getBase64EncryptedElementSignature());
e.addChild(idx++, Node.ELEMENT, c);
FileOutputStream fout = null;
OutputStreamWriter writer = null;
try {
fout = new FileOutputStream(submissionXml);
writer = new OutputStreamWriter(fout, UTF_8);
KXmlSerializer serializer = new KXmlSerializer();
serializer.setOutput(writer);
// setting the response content type emits the xml header.
// just write the body here...
d.writeChildren(serializer);
serializer.flush();
writer.flush();
fout.getChannel().force(true);
writer.close();
} catch (Exception ex) {
String msg = "Error writing submission.xml for encrypted submission: " + submissionXml.getParentFile().getName();
Timber.e(ex, "%s due to : %s ", msg, ex.getMessage());
throw new EncryptionException(msg, ex);
} finally {
IOUtils.closeQuietly(writer);
IOUtils.closeQuietly(fout);
}
}
use of org.odk.collect.android.exception.EncryptionException in project collect by opendatakit.
the class EncryptionUtils method getEncryptedFormInformation.
/**
* Retrieve the encryption information for this uri.
*
* @param uri either an instance URI (if previously saved) or a form URI
*/
public static EncryptedFormInformation getEncryptedFormInformation(Uri uri, InstanceMetadata instanceMetadata) throws EncryptionException {
ContentResolver cr = Collect.getInstance().getContentResolver();
// fetch the form information
String formId;
String formVersion;
PublicKey pk;
Cursor formCursor = null;
try {
if (cr.getType(uri) == InstanceColumns.CONTENT_ITEM_TYPE) {
// chain back to the Form record...
String[] selectionArgs = null;
String selection = null;
Cursor instanceCursor = null;
try {
instanceCursor = cr.query(uri, null, null, null, null);
if (instanceCursor.getCount() != 1) {
String msg = Collect.getInstance().getString(R.string.not_exactly_one_record_for_this_instance);
Timber.e(msg);
throw new EncryptionException(msg, null);
}
instanceCursor.moveToFirst();
String jrFormId = instanceCursor.getString(instanceCursor.getColumnIndex(InstanceColumns.JR_FORM_ID));
int idxJrVersion = instanceCursor.getColumnIndex(InstanceColumns.JR_VERSION);
if (!instanceCursor.isNull(idxJrVersion)) {
selectionArgs = new String[] { jrFormId, instanceCursor.getString(idxJrVersion) };
selection = FormsColumns.JR_FORM_ID + " =? AND " + FormsColumns.JR_VERSION + "=?";
} else {
selectionArgs = new String[] { jrFormId };
selection = FormsColumns.JR_FORM_ID + " =? AND " + FormsColumns.JR_VERSION + " IS NULL";
}
} finally {
if (instanceCursor != null) {
instanceCursor.close();
}
}
formCursor = new FormsDao().getFormsCursor(selection, selectionArgs);
if (formCursor.getCount() != 1) {
String msg = Collect.getInstance().getString(R.string.not_exactly_one_blank_form_for_this_form_id);
Timber.e(msg);
throw new EncryptionException(msg, null);
}
formCursor.moveToFirst();
} else if (cr.getType(uri) == FormsColumns.CONTENT_ITEM_TYPE) {
formCursor = cr.query(uri, null, null, null, null);
if (formCursor.getCount() != 1) {
String msg = Collect.getInstance().getString(R.string.not_exactly_one_blank_form_for_this_form_id);
Timber.e(msg);
throw new EncryptionException(msg, null);
}
formCursor.moveToFirst();
}
formId = formCursor.getString(formCursor.getColumnIndex(FormsColumns.JR_FORM_ID));
if (formId == null || formId.length() == 0) {
String msg = Collect.getInstance().getString(R.string.no_form_id_specified);
Timber.e(msg);
throw new EncryptionException(msg, null);
}
int idxVersion = formCursor.getColumnIndex(FormsColumns.JR_VERSION);
int idxBase64RsaPublicKey = formCursor.getColumnIndex(FormsColumns.BASE64_RSA_PUBLIC_KEY);
formVersion = formCursor.isNull(idxVersion) ? null : formCursor.getString(idxVersion);
String base64RsaPublicKey = formCursor.isNull(idxBase64RsaPublicKey) ? null : formCursor.getString(idxBase64RsaPublicKey);
if (base64RsaPublicKey == null || base64RsaPublicKey.length() == 0) {
// this is legitimately not an encrypted form
return null;
}
byte[] publicKey = Base64.decode(base64RsaPublicKey, Base64.NO_WRAP);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKey);
KeyFactory kf;
try {
kf = KeyFactory.getInstance(RSA_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
String msg = Collect.getInstance().getString(R.string.phone_does_not_support_rsa);
Timber.e(e, "%s due to %s ", msg, e.getMessage());
throw new EncryptionException(msg, e);
}
try {
pk = kf.generatePublic(publicKeySpec);
} catch (InvalidKeySpecException e) {
String msg = Collect.getInstance().getString(R.string.invalid_rsa_public_key);
Timber.e(e, "%s due to %s ", msg, e.getMessage());
throw new EncryptionException(msg, e);
}
} finally {
if (formCursor != null) {
formCursor.close();
}
}
// instanceID value.
if (instanceMetadata.instanceId == null) {
Timber.e("No OpenRosa metadata block or no instanceId defined in that block");
return null;
}
// https://code.google.com/p/opendatakit/issues/detail?id=918
try {
Cipher.getInstance(EncryptionUtils.SYMMETRIC_ALGORITHM, ENCRYPTION_PROVIDER);
} catch (NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException e) {
String msg;
if (e instanceof NoSuchAlgorithmException) {
msg = "No BouncyCastle implementation of symmetric algorithm!";
} else if (e instanceof NoSuchProviderException) {
msg = "No BouncyCastle provider implementation of symmetric algorithm!";
} else {
msg = "No BouncyCastle provider for padding implementation of symmetric algorithm!";
}
Timber.e(msg);
return null;
}
return new EncryptedFormInformation(formId, formVersion, instanceMetadata, pk);
}
Aggregations