Search in sources :

Example 1 with EncryptionException

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();
        }
    }
}
Also used : CipherOutputStream(javax.crypto.CipherOutputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) IOException(java.io.IOException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) FileInputStream(java.io.FileInputStream) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) EncryptionException(org.odk.collect.android.exception.EncryptionException) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) IOException(java.io.IOException) BadPaddingException(javax.crypto.BadPaddingException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NoSuchProviderException(java.security.NoSuchProviderException) RandomAccessFile(java.io.RandomAccessFile) EncryptionException(org.odk.collect.android.exception.EncryptionException) Cipher(javax.crypto.Cipher) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File)

Example 2 with EncryptionException

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;
}
Also used : FormController(org.odk.collect.android.logic.FormController) EncryptionException(org.odk.collect.android.exception.EncryptionException) IOException(java.io.IOException) EncryptionException(org.odk.collect.android.exception.EncryptionException)

Example 3 with EncryptionException

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);
    }
}
Also used : Element(org.kxml2.kdom.Element) FileOutputStream(java.io.FileOutputStream) EncryptionException(org.odk.collect.android.exception.EncryptionException) OutputStreamWriter(java.io.OutputStreamWriter) Document(org.kxml2.kdom.Document) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File) KXmlSerializer(org.kxml2.io.KXmlSerializer) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) EncryptionException(org.odk.collect.android.exception.EncryptionException) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) IOException(java.io.IOException) BadPaddingException(javax.crypto.BadPaddingException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NoSuchProviderException(java.security.NoSuchProviderException)

Example 4 with EncryptionException

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);
}
Also used : FormsDao(org.odk.collect.android.dao.FormsDao) PublicKey(java.security.PublicKey) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) X509EncodedKeySpec(java.security.spec.X509EncodedKeySpec) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) Cursor(android.database.Cursor) ContentResolver(android.content.ContentResolver) EncryptionException(org.odk.collect.android.exception.EncryptionException) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) NoSuchProviderException(java.security.NoSuchProviderException) KeyFactory(java.security.KeyFactory)

Aggregations

EncryptionException (org.odk.collect.android.exception.EncryptionException)4 IOException (java.io.IOException)3 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)3 NoSuchProviderException (java.security.NoSuchProviderException)3 InvalidKeySpecException (java.security.spec.InvalidKeySpecException)3 NoSuchPaddingException (javax.crypto.NoSuchPaddingException)3 File (java.io.File)2 RandomAccessFile (java.io.RandomAccessFile)2 UnsupportedEncodingException (java.io.UnsupportedEncodingException)2 InvalidAlgorithmParameterException (java.security.InvalidAlgorithmParameterException)2 InvalidKeyException (java.security.InvalidKeyException)2 BadPaddingException (javax.crypto.BadPaddingException)2 IllegalBlockSizeException (javax.crypto.IllegalBlockSizeException)2 ContentResolver (android.content.ContentResolver)1 Cursor (android.database.Cursor)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 FileInputStream (java.io.FileInputStream)1 FileOutputStream (java.io.FileOutputStream)1 InputStream (java.io.InputStream)1 OutputStreamWriter (java.io.OutputStreamWriter)1