No matching key found for the ciphertext in the stream Exception - android

Hi, I am using jetpack security encryption library for encrypting the file. I have generate Master Key with below code.
MasterKey masterKey = null;
try {
masterKey = new
MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
} catch (GeneralSecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I have encrypted my text file Sample.txt and write encrypted file to device external storage. The code as given below.
InputStream inputStream = new BufferedInputStream(appCtx.getAssets().open("Sample.txt"));
byte[] fileBytes=new byte[inputStream.available()];
inputStream.read(fileBytes);
File file = new File(Environment.getExternalStorageDirectory(), "Sample.txt");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
EncryptedFile encryptedFile = new EncryptedFile.Builder(
appCtx,
file,
masterKey,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();
OutputStream outputStream = encryptedFile.openFileOutput();
outputStream.write(fileBytes);
outputStream.flush();
outputStream.close();
I put encrypted file in asset folder and now trying to decrypt but as per documentation EncryptedFile.Builder always have file Object as parameter and currently i have Inputstream after reading file from asset. So, to get file object i am writing this Inutstream to external storage as Temp.txt and passing this file for decryption. But I am getting exception as java.io.IOException: No matching key found for the ciphertext in the stream.
The code for decryption as follows:
InputStream myInputstream = new BufferedInputStream(appCtx.getAssets().open("Sample.txt"));
File enfile = createFileFromInputStream(myInputstream,appCtx);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
EncryptedFile encryptedFile = new EncryptedFile.Builder(
appCtx,
enfile,
masterKey,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();
InputStream inputStream1 = encryptedFile.openFileInput();
BufferedOutputStream os1 = new BufferedOutputStream( new FileOutputStream(new File(dstPath)));
int length = 0;
byte[] buffer = new byte[1024];
while ((length = inputStream1.read(buffer)) != -1) {
os1.write(buffer, 0, length);
}
os1.close();
}
private static File createFileFromInputStream(InputStream stream, Context context) {
File f = new File(Environment.getExternalStorageDirectory(), "Temp.txt");
BufferedOutputStream os1 = null;
try {
os1 = new BufferedOutputStream( new FileOutputStream(f));
int length = 0;
byte[] buffer = new byte[1024];
while ((length = stream.read(buffer)) != -1) {
os1.write(buffer, 0, length);
}
os1.close();
stream.close();
return f;
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
//Logging exception
}
return null;
}
Main Scenario:
If write encrypted file to external storage and read it for decryption directly from external storage, then everything is working file. But If i paste encrypted file in asset folder and write Inputstream getting from asset folder to some temporary file and then try to decrypt it is giving error java.io.IOException: No matching key found for the ciphertext in the stream.
Please anyone help me with this issue.
Thanks

This is android-crypto library internal implementation problem. Try to update to latest version, this helped me.

Related

How can I make pdf file readable only by my app?

Is it possible to download a PDF from server and save in format that only my application can read?
This is my working example used in my app ....hope this help you
Is it possible to download pdf from server and save
Yes i have use retrofit library to download pdf file from server you can use Volly or Loopj AsyncTask as well
After downloading pdf file you will get InputeStream object of file than encrypt that and store in app private folder (so no other application can able to use it)
public static File encryptAndSaveFileInPrivateFolder(
Context context, String albumName, InputStream inputStream, String fullFileName) {
File file = null;
try {
// Get the directory for the app's private pictures directory.
File fileDirectory = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES),""+albumName);
if (!fileDirectory.exists()) {
fileDirectory.mkdirs();
}
file = new File(fileDirectory,""+fullFileName);
if (file.exists()) {
file.delete();
}
FileOutputStream output = new FileOutputStream(file);
encrypt(inputStream,output);
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
This method encrypt your file
public static void encrypt(InputStream fis,FileOutputStream fos ) throws IOException, NoSuchAlgorithmException
, NoSuchPaddingException, InvalidKeyException {
// Here you read the cleartext.
//FileInputStream fis = new FileInputStream("data/cleartext");
// This stream write the encrypted text. This stream will be wrapped by another stream.
// FileOutputStream fos = new FileOutputStream("data/encrypted");
String password ="passwordProtectd";
// Length is 16 byte
byte[] inputByte = password.getBytes("UTF-8");
SecretKeySpec sks = new SecretKeySpec(inputByte, "AES");
// SecretKeySpec sks = new SecretKeySpec(password.getBytes(), "AES");
// Create cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, sks);
// Wrap the output stream
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
// Write bytes
int b;
byte[] d = new byte[8];
while((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
fis.close();
}
Than show pdf using intent
public void decryptFileAndShow(Context context,File mFile) {
try{
if (null != mFile) {
String parentPath = mFile.getAbsoluteFile().getParent();//Actual encrypted file path
File tempFile = new File(parentPath, "report.pdf"); //Created new file that decrypted format after view we will delete this
//tempFile =File.createTempFile("prefix","TestMyPDF.pdf", context.getExternalFilesDir(""));
Utilities.decrypt( new FileInputStream(mFile), new FileOutputStream(tempFile));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(tempFile), "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
context.startActivity(intent);
tempFile.deleteOnExit();
}
}catch (Exception e){
e.printStackTrace();
}
}
Last the method used for decryption
public static void decrypt(FileInputStream fis,FileOutputStream fos ) throws IOException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException {
// FileInputStream fis = new FileInputStream("data/encrypted");
// FileOutputStream fos = new FileOutputStream("data/decrypted");
String password ="passwordProtectd";
byte[] inputByte = password.getBytes("UTF-8");
SecretKeySpec sks = new SecretKeySpec(inputByte, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
}
Is it possible to download pdf from server.
Yes, it is possible. Download your pdf and encrypt and decrypt your file accordingly.
You can try like this using CipherOuputStream and CipherInputStream:
byte[] buf = new byte[1024];
Encryption:
public void encrypt(InputStream in, OutputStream out) {
try {
// Bytes written to out will be encrypted
out = new CipherOutputStream(out, ecipher);
// Read in the cleartext bytes and write to out to encrypt
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
}
}
Decryption:
public void decrypt(InputStream in, OutputStream out) {
try {
// Bytes read from in will be decrypted
in = new CipherInputStream(in, dcipher);
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
}
}
If I understand your question correctly, you want your application to be the only application that reads this particular PDF files. You want to know how you can ensure that you do that.
Since your requirement is not genuine(hacky), the solution also has to be a bit hacky.
You can download the file and store it with your own custom extension (eg. file.mypdf)
Have an intent filter, that supports mimetypes matching .mypdf files
You could have the server encrypt the download and your client side app decrypt it using a public/private key pair. This would prevent anyone with a snooping proxy from observing and saving your content, but it wouldn't deter the most determined users from stealing these documents as they would eventually exist in decrypted form somewhere. To achieve that you'd probably ave to create your own PDF viewer and damage the bytes of the PDF in a way that your viewer can do, but no other viewer can recover

Tesseract traineddata path

I am trying to use tesseract-ocr in my android app. When I am trying to init() I get IllegalArgumentException because in this folder there is no 'tessdata' dir! Here is my project structure. project structure
Here I used InputStream and cacheDir:
private String getDirPath() {
File f = new File(getCacheDir()+"/tessdata/");
if (!f.exists()) try {
InputStream is = getAssets().open("tessdata/eng.traineddata");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
FileOutputStream fos = new FileOutputStream(f);
fos.write(buffer);
fos.close();
} catch (Exception e) { Log.e("error", e.toString()); }
Log.i("wtf", f.getPath());
return getCacheDir();
}
To init the Tesseract I have to pass 2 arguments - path to dir which contains directory 'tessdata' and second one is traineddata.
Any ideas?
You can't refer to your app's raw asset files that way. Try using AssetManager instead.
The path to your assets is
Uri path = Uri.parse("file:///android_asset/")
String dataPath = path.toString();

Android - How to use new Storage Access Framework to copy files to external sd card

I'm implementing a file browser feature in my app. I know how to gain persistent permission for the external sd card using the ACTION_OPEN_DOCUMENT_TREE intent and how to create folders and delete files/folders using the DocumentFile class.
I can't however find a way to copy/move a file to an external sd card folder. Can you point me to the right direction ?
I have figured it out using lots of examples on SO. My solution for music files:
private String copyFile(String inputPath, String inputFile, Uri treeUri) {
InputStream in = null;
OutputStream out = null;
String error = null;
DocumentFile pickedDir = DocumentFile.fromTreeUri(getActivity(), treeUri);
String extension = inputFile.substring(inputFile.lastIndexOf(".")+1,inputFile.length());
try {
DocumentFile newFile = pickedDir.createFile("audio/"+extension, inputFile);
out = getActivity().getContentResolver().openOutputStream(newFile.getUri());
in = new FileInputStream(inputPath + inputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
} catch (FileNotFoundException fnfe1) {
error = fnfe1.getMessage();
} catch (Exception e) {
error = e.getMessage();
}
return error;
}

How do I address files in Asset folder?

I need to read "strings.json" file that lies in the "assets" folder of my Android project. But
File file = new File(filepath);
Logger.e(file.exists() ? "exists" : "doesn't exist");
says that the file doen't exist. I've tried the following variants of the filepath:
strings.json
android_asset/strings.json
/android_asset/strings.json
file:///android_asset/strings.json
What's wrong?
For read files in Assets:
InputStream is = context.getAssets().open("strings.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
fileResult = new String(buffer, "UTF-8");
In fileResult you should retrieve the content of your file.
AssetManager manager = getAssets();
try {
InputStream stream = manager.open(string+".xml");
} catch (IOException e) {
e.printStackTrace();
}

how to read .pdf file in assets folder

File file = new File("android.resource://com.baltech.PdfReader/assets/raw/"+filename);
if (file.exists()) {
Uri targetUri = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(targetUri, "application/pdf");
try {
startActivity(intent);
}
catch (ActivityNotFoundException e) {
Toast.makeText(PdfReaderActivity.this, "No Application Available to View PDF", Toast.LENGTH_SHORT).show();
}
i want to read .pdf file which is in assets folder. what path i hav to give in filename. plz help. Thanks
I'm not sure if you got an answer to this already, seems pretty old, but this worked for me.
//you need to copy the input stream to a new file, so store it elsewhere
//this stores it to the sdcard in a new folder "MyApp"
String filename = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyApp/solicitation_form.pdf";
AssetManager assetManager = getAssets();
try {
InputStream pdfFileStream = assetManager.open("solicitation_form.pdf");
CreateFileFromInputStream(pdfFileStream, filename);
} catch (IOException e1) {
e1.printStackTrace();
}
File pdfFile = new File(filename);
The CreateFileFromInputStream function is as follows
public void CreateFileFromInputStream(InputStream inStream, String path) throws IOException {
// write the inputStream to a FileOutputStream
OutputStream out = new FileOutputStream(new File(path));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
inStream.close();
out.flush();
out.close();
}
Really hope this helps anyone else who reads this.
File file = new File("file:///android_asset/raw/"+filename);
replace the above line with below and try..
File file = new File("android.resource://com.com.com/raw/"+filename);
and place your PDF file raw folder instead of asset. Also change com.com.com with your package name.
Since assets files are stored inside apk file, there is no absolute path of the assets folder.
You might use a workaround creating a new file used as a buffer.
You should use AssetManager:
AssetManager mngr = getAssets();
InputStream ip = mngr.open(<filename in the assets folder>);
File assetFile = createFileFromInputStream(ip);
private File createFileFromInputStream(InputStream ip);
try{
File f=new File(<filename>);
OutputStream out=new FileOutputStream(f);
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0)
out.write(buf,0,len);
out.close();
inputStream.close();
}catch (IOException e){}
}
}

Categories

Resources